this repo has no description
at master 9.5 kB view raw
1<!-- livebook:{"persist_outputs":true} --> 2 3# Day 16 4 5```elixir 6Mix.install([:kino_aoc, :image]) 7``` 8 9## Setup 10 11<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxNiIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 12 13```elixir 14{:ok, puzzle_input} = 15 KinoAOC.download_puzzle("2024", "16", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) 16``` 17 18<!-- livebook:{"output":true} --> 19 20``` 21{:ok, 22 "#############################################################################################################################################\n#.....#.......#.............#.........#.......................#.......#...#...............#.....#.#.................................#.#....E#\n#.#####.###.###.#######.###.#.#.#######.#.###.#####.###.#######.#.###.###.#.#####.#####.###.#.#.#.#.#####.###.#.###.#######.###.#.#.#.#.#.#.#\n#.......#...#...#.....#.#.#.#.#.#...#...#.....#...#.#...#.......#...#.#...#...#...#.#...#...............#...#...#.#.......#.#...#.#.#...#.#.#\n#########.#.#.###.#####.#.#.#.#.#.#.#.#########.#.#.###.#.#########.#.#.#.#.###.#.#.#.###.###.#####.###.###.#.#.#.###.###.#.#.###.#.#.###.#.#\n#.......#.#.#.#...#...#.#.#.#.#...#.....#.......#.#...#.#.#...#...#.#...#.#.#...#.....#...#.#...#...#.....#.#.....#.....#.#...#...#.#.#...#.#\n#.#####.#.###.#.#.#.#.#.#.#.###########.#######.#.###.#.#.###.#.#.#.#.#####.#.###.###.#.###.###.#.###.#.###.#.#.#.#.#.#.#.#.#.#.###.###.#####\n#...#...#.......#.#.#...#.#...........................#.#.#...#.#...#.#.....#.#.....#.#...#...#.....................#.#.#...................#\n#.#.#.#######.#####.#####.###########.#######.#####.#.###.#.###.#######.#####.###.#.#.###.#.#.#.#.#######.###.#.#####.#.#.#.#.###.###.#.###.#\n#.#...#.....#.#...#...#.......#.......#.....#...#...#.....#.#...#.....#...#...#.....#...#...#.#...#.......#...#.#...#.#.#.#.#...#.#...#...#.#\n#.#.###.###.###.#.#.#.###.###.#.#.#####.###.###.#.#########.#.###.###.###.#.###.#.###.#######.#####.#######.#.#.#.#.#.###.###.#.#.#.#######.#\n#.#.....#.......#.#.#...#.#...#.#...#...#.#.#.#.#.......#...#...#...#.......................#...#.#.#.....#.#.....#.#.........#...#.#.....#.#\n#.###.###########.#####.#.#####.#.#.#.#.#.#.#.#.###.###.#.#.###.###.#########.###.#.#.#.###.#.#.#.#.#####.#.#.#.#####.#######.#####.#.###.#.#\n#...#...................#.....#.#.#.#.#.#.....#.....#.#...#.#.#...#.....#...#.....#.#.#.#.#.....#.#.....#.#...#.#.........#...........#.....#\n#.#.#.#.###.#.###############.#.#.#.#.#.#############.#####.#.###.#####.#.#.#####.#.#.#.#.#######.#####.#.###.#.#.###.###.#.#.###.###########\n#.#.#.#.#.#.#.#.....#.......#.#...#...#...............#...#...#.#...#...#.#.......#.#.#.#.......#...#...#.....#.#.#.......#.#...#.#.........#\n#.#.###.#.#.###.###.###.#.#.#.###.#.#####.###.###.###.#.#.###.#.#.###.###.###.###.#.#.#.###.###.###.#.###.#####.#.#.#.###.#.#.#.###.#######.#\n#.#.....#.#...#.#.#...#.#.#.#...#.#.#...#...#...#...#...#...#...#.....#...#...#.......#.....#.#.....#...#.......#...#.#...#...#...#.#.#.....#\n#.#######.###.#.#.###.#.#.#.#.#.#.###.#.#####.#.#.#.#########.#.#######.#.#.#.#.#############.#####.###.#########.#####.###.#####.#.#.#.#.###\n#.#.......#.#.....#...#.#.#...#.#.#...#.....#.#.#.#.........#.#.........#.#.#.#.#.................#.#.#...#.......#.........#...#...#.#.....#\n#.#.#####.#.#######.#####.#######.#.#####.#.###.#.#########.#.#.#########.#.#.#.###.#######.#.#####.#.###.#.#######.#.###.###.#.#####.###.#.#\n#.#.....#.......#...#...#...#.....#.#...........#.#.......#...#.#...#.....#.#.#...#.#.......#.#...#...#...#.....#...#...#.#.................#\n#.#####.#######.#.###.#.###.#.#####.#######.#####.#.#.###.#####.#.#.###.###.#.###.###.#####.###.#.###.#.#######.#.#####.#.#####.#.#.###.#.#.#\n#.#...#.#.....#...#...#...#.#.......#.....#.#.....#.#...#.#...#.#.#...#.#...#.#.#...#.#...#.#...#...#.#.........#.....#.#.......#...#...#.#.#\n#.#.#.#.#.###.#.###.#####.#.#.#####.#.###.###.#########.###.#.#.#.###.#.#.###.#.###.#.#.#.###.###.###.###############.#.###########.#.###.#.#\n#.#.#.#.#.#.....#...#...#...#.....#...#.#...#.#...#...#.#...#.#...#...#.#.#.#.#.........#.#...#.#.....#.......#.......#.........#...#.#.....#\n#.#.#.#.#.#######.###.#.#.#.#####.###.#.###.#.#.#.#.#.#.#.###.#####.#####.#.#.#########.#.#.###.#######.#######.###############.#.###.#.#.###\n#.#.#...#.........#...#.#.#.....#...#...#.#.....#...#...#.#.#...#...#.....#.#.....#.....#...#.....#.....#.....#...#...#...#.....#...#.#.#...#\n#.#.#########.#######.#.#.#.###.###.###.#.###########.###.#.###.#.###.#.###.#####.#.#########.#.#.###.#.#.###.#.#.#.#.#." <> ...} 23``` 24 25```elixir 26%{?# => walls, ?S => [start], ?E => [finish]} = 27 puzzle_input 28 |> String.trim() 29 |> String.split("\n", trim: true) 30 |> Enum.with_index() 31 |> Enum.flat_map(fn {row, y} -> 32 row 33 |> String.trim() 34 |> String.to_charlist() 35 |> Enum.with_index() 36 |> Enum.map(fn {char, x} -> 37 {{x, y}, char} 38 end) 39 end) 40 |> Enum.group_by(&elem(&1, 1), &elem(&1, 0)) 41 42walls = MapSet.new(walls) 43``` 44 45<!-- livebook:{"output":true} --> 46 47``` 48MapSet.new([ 49 {76, 13}, 50 {112, 138}, 51 {38, 2}, 52 {124, 56}, 53 {83, 76}, 54 {140, 11}, 55 {100, 134}, 56 {75, 140}, 57 {103, 106}, 58 {68, 134}, 59 {124, 60}, 60 {35, 30}, 61 {2, 132}, 62 {8, 50}, 63 {78, 98}, 64 {101, 62}, 65 {98, 136}, 66 {95, 56}, 67 {74, 12}, 68 {102, 74}, 69 {22, 38}, 70 {14, 86}, 71 {12, 135}, 72 {86, 10}, 73 {29, 26}, 74 {4, 81}, 75 {31, 42}, 76 {9, 34}, 77 {137, 16}, 78 {86, 138}, 79 {90, 0}, 80 {14, 122}, 81 {120, 42}, 82 {102, 57}, 83 {84, 102}, 84 {138, 124}, 85 {0, 101}, 86 {116, 96}, 87 {54, 138}, 88 {18, 134}, 89 {82, 60}, 90 {15, 92}, 91 {58, 58}, 92 {78, 75}, 93 {75, 0}, 94 {16, 73}, 95 {76, 2}, 96 {58, 84}, 97 {138, ...}, 98 {...}, 99 ... 100]) 101``` 102 103```elixir 104{_, {w, h}} = Enum.min_max(walls) 105 106w = w + 1 107h = h + 1 108``` 109 110<!-- livebook:{"output":true} --> 111 112``` 113141 114``` 115 116```elixir 117put_in(%{}, [Access.key(:a, %{}), :b], 10) 118``` 119 120<!-- livebook:{"output":true} --> 121 122``` 123%{a: %{b: 10}} 124``` 125 126```elixir 127defmodule Race.B do 128 @turns ~w'^ > v <'a 129 130 defguardp score(elements, pos, dir) when :erlang.map_get({pos, dir}, elements).score 131 132 def search_paths(start, finish, dir \\ :>, walls) when dir in @turns do 133 result = do_search([{0, [{start, dir}]}], walls, %{}) 134 135 %{paths: visited, score: score} = result[{finish, :>}] 136 137 all = get_all(visited, result) 138 139 {score, all} 140 end 141 142 def get_all(path, seen) do 143 Enum.reduce(path, MapSet.new(), fn p, acc -> 144 path = MapSet.new(seen[p].paths, fn {p, _} -> p end) 145 MapSet.union(acc, path) 146 end) 147 end 148 149 def do_search([], _, visited), do: visited 150 151 def do_search([{cost, [{curr, dir} | _] = path} | rest], walls, visited) 152 when cost == score(visited, curr, dir) do 153 visited = Map.update!(visited, {curr, dir}, &%{&1 | paths: path}) 154 155 do_search(rest, walls, visited) 156 end 157 158 def do_search([{cost, [{curr, prev} | _] = path} | rest], walls, visited) 159 when not is_map_key(visited, {curr, prev}) 160 when cost < score(visited, curr, prev) do 161 visited = Map.put(visited, {curr, prev}, %{score: cost, paths: path}) 162 163 @turns 164 |> Enum.map(fn dir -> {cost + cost(prev, dir), [{step(curr, dir), dir} | path]} end) 165 |> Enum.reject(fn {_cost, [{pos, _} | _]} -> pos in walls end) 166 |> sort_merge(rest) 167 |> do_search(walls, visited) 168 end 169 170 def do_search([{_, [_curr | _]} | rest], walls, visited), 171 do: do_search(rest, walls, visited) 172 173 # Going straight is cheap and turning is costly 174 defp cost(a, a), do: 1 175 defp cost(_, _), do: 1001 176 177 defp step({x, y}, :^), do: {x, y - 1} 178 defp step({x, y}, :>), do: {x + 1, y} 179 defp step({x, y}, :v), do: {x, y + 1} 180 defp step({x, y}, :<), do: {x - 1, y} 181 182 defp sort_merge([], bs), do: bs 183 defp sort_merge(as, []), do: as 184 185 defp sort_merge([a | as], [b | bs]) do 186 if a < b do 187 [a | sort_merge(as, [b | bs])] 188 else 189 [b | sort_merge([a | as], bs)] 190 end 191 end 192end 193``` 194 195<!-- livebook:{"output":true} --> 196 197``` 198{:module, Race.B, <<70, 79, 82, 49, 0, 0, 23, ...>>, {:sort_merge, 2}} 199``` 200 201```elixir 202{score, paths} = Race.B.search_paths(start, finish, walls) 203``` 204 205<!-- livebook:{"output":true} --> 206 207``` 208{134588, 209 MapSet.new([ 210 {77, 129}, 211 {17, 138}, 212 {17, 137}, 213 {37, 139}, 214 {19, 137}, 215 {100, 131}, 216 {139, 68}, 217 {14, 139}, 218 {79, 128}, 219 {19, 138}, 220 {50, 137}, 221 {139, 67}, 222 {137, 104}, 223 {137, 117}, 224 {131, 49}, 225 {107, 125}, 226 {3, 127}, 227 {135, 64}, 228 {4, 131}, 229 {21, 134}, 230 {63, 127}, 231 {101, 124}, 232 {5, 139}, 233 {125, 14}, 234 {129, 48}, 235 {139, 70}, 236 {21, 119}, 237 {17, 129}, 238 {137, 120}, 239 {17, 136}, 240 {131, 120}, 241 {32, 139}, 242 {133, 21}, 243 {102, 123}, 244 {12, 111}, 245 {123, 19}, 246 {112, 127}, 247 {73, 129}, 248 {7, 116}, 249 {127, 22}, 250 {7, 137}, 251 {9, 131}, 252 {24, 133}, 253 {137, 95}, 254 {8, 133}, 255 {134, 7}, 256 {129, ...}, 257 {...}, 258 ... 259 ])} 260``` 261 262## Part 1 263 264```elixir 265score 266``` 267 268<!-- livebook:{"output":true} --> 269 270``` 271134588 272``` 273 274```elixir 275Image.new!(w, h) 276|> Image.mutate(fn img -> 277 for {x, y} <- walls do 278 Image.Draw.point(img, x, y, color: [128, 0, 0]) 279 end 280 281 for {x, y} <- paths do 282 Image.Draw.point(img, x, y, color: [0, 255, 0]) 283 end 284 285 img 286end) 287|> elem(1) 288|> Image.resize!(6, interpolate: :nearest) 289``` 290 291## Part 2 292 293```elixir 294MapSet.size(paths) 295``` 296 297<!-- livebook:{"output":true} --> 298 299``` 300625 301``` 302 303<!-- livebook:{"offset":9337,"stamp":{"token":"XCP.AVI7h-Nq9jZKx9YmL5qYerJkeKKqddhzKrKUkab-HwNDUM8nQItD1O_rd2ROsJxc96gwIzwrMAixlIdLeZAgOVhtCs22LZM44Wl1VwcpYbg3RNCdgwIjqGheO5YrCGrEGJc","version":2}} -->