day09.R (4543B)
1 #!/usr/bin/env Rscript 2 3 source("src/utils.R") 4 5 test_input <- c( 6 "7,1", 7 "11,1", 8 "11,7", 9 "9,7", 10 "9,5", 11 "2,5", 12 "2,3", 13 "7,3" 14 ) 15 puzzle_input <- aoc_input(9) 16 17 parse_input <- function(input_lines) { 18 input_lines |> 19 strsplit(",") |> 20 lapply(as.numeric) |> 21 (\(x) do.call(rbind, x))() 22 } 23 24 tabulate_edges <- function(input_points) { 25 edge_info <- list( 26 tab = utils::hashtab("identical", nrow(input_points)), 27 ind = rep(NA_real_, nrow(input_points)) 28 ) 29 for (p1 in seq_len(nrow(input_points))) { 30 p2 <- (p1 %% nrow(input_points)) + 1 31 l_h <- input_points[p1, 2] 32 if (l_h == input_points[p2, 2]) { 33 edge_info$ind[length(edge_info$ind) + 1] <- l_h 34 utils::sethash( 35 edge_info$tab, 36 l_h, 37 c( 38 list(c(input_points[p1, 1], input_points[p2, 1])), 39 utils::gethash(edge_info$tab, l_h, list()) 40 ) 41 ) 42 } 43 } 44 edge_info$ind <- unique(sort(edge_info$ind[!is.na(edge_info$ind)])) 45 edge_info 46 } 47 48 # Part 1 ===================================================================== 49 50 measure_rect <- function(p1, p2) { 51 (abs(p1[1] - p2[1]) + 1) * (abs(p1[2] - p2[2]) + 1) 52 } 53 54 find_max_rect <- function(edge_info) { 55 max_rectangle <- NULL 56 for (sl in seq_along(edge_info$ind)) { 57 for (sl2 in sl:length(edge_info$ind)) { 58 for (p1 in range(unlist(edge_info$tab[[edge_info$ind[sl]]]))) { 59 for (p2 in range(unlist(edge_info$tab[[edge_info$ind[sl2]]]))) { 60 max_rectangle <- max( 61 max_rectangle, 62 measure_rect( 63 c(p1, edge_info$ind[sl]), 64 c(p2, edge_info$ind[sl2]) 65 ) 66 ) 67 } 68 } 69 } 70 } 71 max_rectangle 72 } 73 74 part1 <- function(input_lines) { 75 input_lines |> 76 parse_input() |> 77 tabulate_edges() |> 78 find_max_rect() 79 } 80 81 test_part1 <- function() { 82 stopifnot(part1(test_input) == 50) 83 } 84 85 # Part 2 ===================================================================== 86 87 edge_inside <- function(e1, e2) { 88 min(e2) < max(e1) && max(e2) > min(e1) 89 } 90 91 remove_edge <- function(e1, e2) { 92 if (max(e2) >= max(e1)) { 93 if (min(e2) <= min(e1)) { 94 NULL 95 } else { 96 list(c(min(e1), min(e2))) 97 } 98 } else if (min(e2) <= min(e1)) { 99 list(c(max(e2), max(e1))) 100 } else { 101 list(c(min(e1), min(e2)), c(max(e2), max(e1))) 102 } 103 } 104 105 add_or_remove_edge <- function(edge_front, edge, can_add = TRUE) { 106 for (i in seq_along(edge_front)) { 107 if (edge_inside(edge_front[[i]], edge)) { 108 return(c( 109 edge_front[-i], 110 remove_edge(edge_front[[i]], edge) 111 )) 112 } 113 } 114 if (can_add) { 115 edge_front <- c(edge_front, list(edge)) 116 edge_front <- edge_front[order(vapply(edge_front, \(x) x[1], numeric(1)))] 117 i <- 1 118 repeat { 119 if (i >= length(edge_front)) break 120 if (max(edge_front[[i]]) == min(edge_front[[i + 1]])) { 121 edge_front[[i]] <- c(min(edge_front[[i]]), max(edge_front[[i + 1]])) 122 edge_front[[i + 1]] <- NULL 123 } else { 124 i <- i + 1 125 } 126 } 127 } 128 edge_front 129 } 130 131 points_in_edge_front <- function(edge_front, p) { 132 points_in_edge <- function(edge) { 133 min(p) >= min(edge) && max(p) <= max(edge) 134 } 135 any(vapply(edge_front, points_in_edge, logical(1))) 136 } 137 138 sweep_edge_front <- function(edge_info) { 139 max_rectangle <- NULL 140 start_front <- list() 141 for (y1_idx in 1:(length(edge_info$ind) - 1)) { 142 y1 <- edge_info$ind[y1_idx] 143 start_edges <- edge_info$tab[[y1]] 144 start_front <- Reduce(add_or_remove_edge, start_edges, start_front) 145 end_front <- start_front 146 for (x1 in unlist(start_edges)) { 147 for (y2_idx in (y1_idx + 1):length(edge_info$ind)) { 148 y2 <- edge_info$ind[y2_idx] 149 end_edges <- edge_info$tab[[y2]] 150 for (x2 in unlist(end_edges)) { 151 if (points_in_edge_front(start_front, c(x1, x2)) && 152 points_in_edge_front(end_front, c(x1, x2))) { 153 max_rectangle <- max( 154 max_rectangle, 155 measure_rect(c(y1, x1), c(y2, x2)) 156 ) 157 } 158 } 159 end_front <- Reduce(\(x, y) add_or_remove_edge(x, y, FALSE), end_edges, end_front) 160 if (!points_in_edge_front(end_front, x1)) break 161 } 162 } 163 } 164 max_rectangle 165 } 166 167 part2 <- function(input_lines) { 168 input_lines |> 169 parse_input() |> 170 tabulate_edges() |> 171 sweep_edge_front() 172 } 173 174 test_part2 <- function() { 175 stopifnot(part2(test_input) == 24) 176 } 177 178 main <- function() { 179 test_part1() 180 cat("Part 1 solution: ", part1(puzzle_input), "\n") 181 test_part2() 182 cat("Part 2 solution: ", part2(puzzle_input), "\n") 183 } 184 185 main()