this repo has no description
at master 12 kB view raw
1<!-- livebook:{"persist_outputs":true} --> 2 3# Day 12 4 5```elixir 6Mix.install([ 7 {:kino_aoc, git: "https://github.com/ljgago/kino_aoc"}, 8 {:libgraph, ">= 0.0.0"} 9]) 10``` 11 12<!-- livebook:{"output":true} --> 13 14``` 15:ok 16``` 17 18## Section 19 20<!-- livebook:{"attrs":{"day":"12","session_secret":"ADVENT_OF_CODE_SESSION","variable":"puzzle_input","year":"2022"},"chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} --> 21 22```elixir 23{:ok, puzzle_input} = 24 KinoAOC.download_puzzle("2022", "12", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION")) 25``` 26 27<!-- livebook:{"output":true} --> 28 29``` 30{:ok, 31 "abccccaaacaccccaaaaacccccccaaccccccccaaaaaaccccccaaaaaccccccccccaaaaaaaaacccccccaaaaaaaaaaaaaaccaaaaaccccccccccccaccacccccccccccccccccccccccccccccccccccccccaaaaaa\nabccaacaaaaaccaaaaacccccaaaaaccccccccaaaaaaccccccaaaaaacccccccccaaaaaaaaaaaaacccaaaaaaaaaaaaaaaaaaaaaccccccccccccaaaacccccccccccccccccccccccccccccccccccccccaaaaaa\nabccaaaaaaaaccaaaaaacccccaaaaaccccccaaaaaaaacccccaaaaaaccccccccccaaaaaaaaaaaacccaaaaaacaaaaaacaaaaaaaaccccccccccaaaaacccccaccccccccccccccccccaaacccccccccccccaaaaa\nabcccaaaaaccccccaaaacccccaaaaacccccaaaaaaaaaaccccaaaaaacccccccccaaaaaaaaaaaaaacaaaaaaaaaaaaaacaaaaaaaaccccccccccaaaaaacccaaacccccccccccccccccaaaccccccccccccccaaaa\nabaaacaaaaacccccacccccccaaaaaccccccaaaaaaaaaaccccccaaaccccccccccaaaaaaaaacaaaaaaaaaaaaaaaaaaacccaaacaccaaaccccccaaaaaaaacaaacccccccccccaaccccaaacccccccccccccccaac\nabaaacaacaaaaccccccccccccccaaccccccacaaaaacccccaacccccccccccccccaaaacaaaaaaaaaacccaacccaaacaacccaaccccaaaaccccccccaacaaaaaaaaaaccccccccaaaaccaaaccccccccccccccaaac\nabaaccaaccaaacacccccccccccccccccccccccaaaacccaaaaaaccaaaccccccccccaacaaaaaaaaaacccaaccccccccccccccccccaaaaccccccccccccaaaaaaaaaccccccciiiiiaaaaacccccccccccccccccc\nabaaccccaaaaaaaacccccccccccccccccccccccaaccccaaaaaaccaaaaaccccacccaaccaaacaaaaacccccccccccccccaacccccccaaaccccccccccccccaaaaacccccccciiiiiiiiaaaaaccccccaaaccccccc\nabaaacccaaaaaaaacccccccccccccccccccccccccccccaaaaaacaaaaaccccaaaaaaaccaaccaaacccccccaaaaacacccaaccccccccccaacccccccccccaaaaaaccccccciiiiiiiiijjaaaaaccccaaacaccccc\nabaaaccccaaaaaaccccccccccccccccccccaaccccccccaaaaaccaaaaacccccaaaaaaaaccccccccccccccaaaaaaaaaaaaccccccccccaaacaaccccccaaaaaaaccccccciiinnnnoijjjjjjjjjjaaaaaaacccc\nabccccccccaaaaacccccaacccccccccccaaaacccccccccaaaacccaaaaaccccaaaaaaaaacccccccccccccaaaaaaaaaaaaaaccccccccaaaaaacccaacaaacaaacccccchhinnnnnoojjjjjjjjjkkaaaaaacccc\nabcccccccaaaaaacaaacaacccccccccccaaaaaaccccccccccccccaacccccccaaaaaaaaacaaccccccccccaaaaaaaaaaaaaaacccccaaaaaaacccaaaaccccccacaaccchhinnnnnoooojjjjjjkkkkaaaaccccc\nabaacccaccaaaccccaaaaaccccccccccccaaaaccccccccccccccccccccccccaaaaaaaacaaaaaaaccccccaaaaaaaaaaaaaaacccccaaaaaaacccaaaaccccaaacaaachhhnnntttuooooooooppkkkaaaaccccc\nabaacccaaaaaaaccccaaaaaacccccccccaaaaaccccccccccccccccccccccccaaaaaaacccaaaaacccccccccaaacaaaaaaaaccccccccaaaaacccaaaacccccaaaaacchhhnnnttttuooooooppppkkkaaaccccc\nabaacccaaaaaaccccaaaaaaacccccccccaacaaccccccccccccccccccccccaaaccaaaccaaaaaaacccccccccccccaaaaaaaccccccaacaacaaacccccccccccaaaaaahhhhnntttttuuouuuuupppkkkcccccccc\nabaaaacaaaaaaaaaaaaaaacccccccccccccccccccccccccccccccccccccaaaacccaaacaaaaaaaaccccccccccccaccaaaccccccaaacaaccccccccccccccaaaaaahhhhnnntttxxxuuuuuuupppkkkcccccccc\nabaaaacaaaaaaaaaaacaaacccaaacccccccccccccccccccccacccccccccaaaacccccccaaaaaaaaccccccccccccccccaaacccccaaacaaacccccccccccccaaaaaahhhhmnnttxxxxuuyuuuuuppkkkcccccccc\nabaaaccaaaaaaaaccccaaaccccaaaccacccccccccccaaaaaaaaccccccccaaaacccccccccaaacaacccccccccccccccccccccaaaaaaaaaacccccacccccccaacaghhhmmmmtttxxxxxxyyyuupppkkccccccccc\nabaaccaaaaaaaccccccccccccaaaaaaaacccccccccccaaaaaaccccccccccccccccccccccaaccccccaacccccccccccccccccaaaaaaaaacccccaaccccccccccagggmmmmttttxxxxxyyyyvvppkkkccccccccc\nabaacccaccaaacccccccccccaaaaaaaaccccccccccccaaaaaaccccccccccccccccccccccccccaaacaaaccccccccccccccccccaaaaaccccaaaaacaacccccccgggmmmmttttxxxxxyyyyvvpppiiiccccccccc\nSbaaaaaccccaaccccccccccaaaaaaaaacacccccccccaaaaaaaacccccccccccccccaacccccccccaaaaaccccccccccaaaacccccaaaaaacccaaaaaaaaccaaaccgggmmmsssxxxEzzzzyyvvvpppiiiccccccccc\nabaaaaaccccccccccccccccaaaaaaaaaaaaaaaaaccaaaaaaaaaacccccccccccaaaaacccccccccaaaaaaaccccccccaaaaaccccaaaaaaaccccaaaaacccaaaaagggmmmsssxxxxxyyyyyyvvqqqiiiccccccccc\nabaaaaacccccccccccccccccaaaaaaaacaaaaaacccaaaaaaaaaaccccccccccccaaaaacccccccaaaaaaaacccccccaaaaaaccccaaacaaacccaaaaacccaaaaaagggmmmssswwwwwyyyyyyyvvqqqiiicccccccc\nabaaaaccccccccccccccccccccaaaaaaaaaaaaacccacacaaacccccccccccccccaaaaacccccccaaaaaaaacccccccaaaaaaccccacccccccccaacaaaccaaaaaagggmmmsssswwwwyyyyyyyvvvqqiiicccccccc\nabaaaaacccccccccccccccccccaacccaaaaaaaaaccccccaaaccccccccccccccaaaaaccccccccaacaaacccccccccaaaaaacccccccccccccccccaaccccaaaaagggmmmmssssswwyywwvvvvvvqqiiicccccccc\nabaaaaacccccccccccccc" <> ...} 32``` 33 34```elixir 35# puzzle_input = """ 36# Sabqponm 37# abcryxxl 38# accszExk 39# acctuvwj 40# abdefghi 41# """ 42``` 43 44<!-- livebook:{"output":true} --> 45 46``` 47nil 48``` 49 50```elixir 51min = ?a - ?a 52max = ?z - ?a 53 54{map, start, stop} = 55 puzzle_input 56 |> String.split("\n", trim: true) 57 |> Enum.map(&to_charlist/1) 58 |> Enum.with_index() 59 |> Enum.flat_map(fn {line, y} -> 60 line 61 |> Enum.with_index() 62 |> Enum.map(fn {c, x} -> {{x, y}, c} end) 63 end) 64 |> Enum.reduce({%{}, nil, nil}, fn {p, v}, {map, s, e} -> 65 case v do 66 ?S -> {Map.put(map, p, min), p, e} 67 ?E -> {Map.put(map, p, max), s, p} 68 _ -> {Map.put(map, p, v - ?a), s, e} 69 end 70 end) 71 72graph = 73 map 74 |> Enum.reduce(Graph.new(), fn {p, v}, graph -> 75 {x, y} = p 76 77 graph = 78 if map[{x - 1, y}] && v + 1 >= map[{x - 1, y}], 79 do: Graph.add_edge(graph, {x, y}, {x - 1, y}, label: [v, map[{x - 1, y}]]), 80 else: graph 81 82 graph = 83 if map[{x + 1, y}] && v + 1 >= map[{x + 1, y}], 84 do: Graph.add_edge(graph, {x, y}, {x + 1, y}, label: [v, map[{x + 1, y}]]), 85 else: graph 86 87 graph = 88 if map[{x, y - 1}] && v + 1 >= map[{x, y - 1}], 89 do: Graph.add_edge(graph, {x, y}, {x, y - 1}, label: [v, map[{x, y - 1}]]), 90 else: graph 91 92 graph = 93 if map[{x, y + 1}] && v + 1 >= map[{x, y + 1}], 94 do: Graph.add_edge(graph, {x, y}, {x, y + 1}, label: [v, map[{x, y + 1}]]), 95 else: graph 96 end) 97``` 98 99<!-- livebook:{"output":true} --> 100 101``` 102warning: variable "graph" is unused (there is a variable with the same name in the context, use the pin operator (^) to match on it or prefix this variable with underscore if it is not meant to be used) 103 2022/day12.livemd#cell:6nz6sdhe57lxfvshc57dctj7qaalwwz3:42 104 105``` 106 107<!-- livebook:{"output":true} --> 108 109``` 110#Graph<type: directed, num_vertices: 6642, num_edges: 24117> 111``` 112 113## Task 1 114 115```elixir 116length(Graph.get_shortest_path(graph, start, stop)) - 1 117``` 118 119<!-- livebook:{"output":true} --> 120 121``` 122437 123``` 124 125```elixir 126graph.vertices 127``` 128 129<!-- livebook:{"output":true} --> 130 131``` 132%{ 133 1148931603 => {118, 31}, 134 15476201 => {158, 33}, 135 3480980581 => {19, 26}, 136 513279067 => {86, 0}, 137 1642831488 => {111, 2}, 138 669567979 => {38, 18}, 139 1898334127 => {77, 28}, 140 2414760132 => {41, 27}, 141 1433989350 => {134, 33}, 142 4010762779 => {100, 37}, 143 1619384061 => {142, 27}, 144 2736818014 => {105, 29}, 145 3132807327 => {56, 13}, 146 1603662291 => {94, 23}, 147 183280155 => {35, 27}, 148 2518352043 => {127, 27}, 149 824501714 => {15, 33}, 150 1813555375 => {70, 18}, 151 733666720 => {72, 5}, 152 4293490381 => {13, 24}, 153 4037128590 => {87, 10}, 154 1287605231 => {99, 3}, 155 2697150767 => {19, 29}, 156 3345146674 => {78, 5}, 157 811252706 => {132, 14}, 158 3035418479 => {156, 5}, 159 2090318173 => {149, 1}, 160 1306366779 => {71, 39}, 161 113692275 => {158, 28}, 162 1809958846 => {4, 0}, 163 2979249361 => {95, 23}, 164 712034521 => {2, 34}, 165 838646858 => {127, 2}, 166 2636390019 => {97, 34}, 167 200998860 => {73, 23}, 168 2440897975 => {91, 7}, 169 2757930521 => {103, 38}, 170 2626031906 => {92, 21}, 171 4000959801 => {44, 20}, 172 2762901234 => {69, 16}, 173 3967362516 => {72, 9}, 174 1858208296 => {81, 16}, 175 3063825234 => {140, 14}, 176 1669140133 => {46, 21}, 177 684221776 => {146, 38}, 178 623366404 => {63, 40}, 179 3623360588 => {149, 6}, 180 2885933829 => {137, 14}, 181 3219344086 => {136, ...}, 182 3451324297 => {...}, 183 ... 184} 185``` 186 187## Task 2 188 189```elixir 190tgraph = Graph.transpose(graph) 191``` 192 193<!-- livebook:{"output":true} --> 194 195``` 196#Graph<type: directed, num_vertices: 6642, num_edges: 24117> 197``` 198 199```elixir 200lowest = 201 Enum.flat_map(map, fn 202 {p, 0} -> [p] 203 _ -> [] 204 end) 205``` 206 207<!-- livebook:{"output":true} --> 208 209``` 210[ 211 {59, 38}, 212 {38, 5}, 213 {76, 17}, 214 {66, 36}, 215 {54, 26}, 216 {10, 18}, 217 {3, 21}, 218 {42, 40}, 219 {73, 32}, 220 {43, 36}, 221 {2, 9}, 222 {80, 31}, 223 {20, 12}, 224 {63, 11}, 225 {5, 15}, 226 {76, 4}, 227 {136, 4}, 228 {3, 9}, 229 {90, 11}, 230 {85, 39}, 231 {24, 29}, 232 {91, 28}, 233 {55, 27}, 234 {108, 10}, 235 {84, 4}, 236 {9, 9}, 237 {161, 38}, 238 {3, 33}, 239 {68, 22}, 240 {143, 3}, 241 {49, 8}, 242 {70, 26}, 243 {39, 25}, 244 {18, 13}, 245 {88, 0}, 246 {32, 21}, 247 {96, 3}, 248 {84, 40}, 249 {53, 1}, 250 {88, 30}, 251 {120, 10}, 252 {36, 4}, 253 {115, 13}, 254 {112, 3}, 255 {42, 0}, 256 {4, 17}, 257 {35, 12}, 258 {114, 19}, 259 {20, ...}, 260 {...}, 261 ... 262] 263``` 264 265```elixir 266# Copied BF implementation from `libgraph` to optimise it 267 268defmodule BellmanFord do 269 @moduledoc """ 270 The Bellman–Ford algorithm is an algorithm that computes shortest paths from a single 271 source vertex to all of the other vertices in a weighted digraph. 272 It is capable of handling graphs in which some of the edge weights are negative numbers 273 Time complexity: O(VLogV) 274 """ 275 276 @type distance :: %{Graph.vertex_id() => integer} 277 278 @doc """ 279 Returns nil when graph has negative cycle. 280 """ 281 @spec call(Graph.t(), Graph.vertex()) :: [Graph.vertex()] | nil 282 def call(%Graph{vertices: vs, edges: meta}, source) do 283 distances = source |> Graph.Utils.vertex_id() |> init_distances(vs) 284 285 weights = Enum.map(meta, &edge_weight/1) 286 287 distances = 288 for _ <- 1..map_size(vs), 289 {{u, v}, weight} <- weights, 290 reduce: distances do 291 distances -> 292 case distances do 293 %{^u => :infinity} -> 294 distances 295 296 %{^u => du, ^v => dv} when du + weight < dv -> 297 %{distances | v => du + weight} 298 299 _ -> 300 distances 301 end 302 end 303 304 if has_negative_cycle?(distances, weights) do 305 nil 306 else 307 Map.new(distances, fn {k, v} -> {Map.fetch!(vs, k), v} end) 308 end 309 end 310 311 @spec init_distances(Graph.vertex(), Graph.vertices()) :: distance 312 defp init_distances(vertex_id, vertices) do 313 Map.new(vertices, fn 314 {id, _vertex} when id == vertex_id -> {id, 0} 315 {id, _} -> {id, :infinity} 316 end) 317 end 318 319 @spec edge_weight(term) :: float 320 defp edge_weight({e, edge_value}), do: {e, edge_value |> Map.values() |> List.first()} 321 322 defp has_negative_cycle?(%{} = distances, meta) do 323 Enum.any?(meta, fn {{u, v}, weight} -> 324 %{^u => du, ^v => dv} = distances 325 326 du != :infinity and du + weight < dv 327 end) 328 end 329end 330``` 331 332<!-- livebook:{"output":true} --> 333 334``` 335{:module, BellmanFord, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:has_negative_cycle?, 2}} 336``` 337 338```elixir 339paths = 340 tgraph 341 # |> Graph.bellman_ford(stop) 342 |> BellmanFord.call(stop) 343``` 344 345<!-- livebook:{"output":true} --> 346 347``` 348%{ 349 {76, 13} => :infinity, 350 {38, 2} => :infinity, 351 {1, 26} => 430, 352 {140, 11} => 100, 353 {32, 15} => 388, 354 {89, 14} => 328, 355 {35, 30} => 392, 356 {156, 9} => :infinity, 357 {4, 5} => 454, 358 {74, 12} => :infinity, 359 {11, 39} => 425, 360 {131, 5} => 323, 361 {22, 38} => 413, 362 {29, 25} => 403, 363 {86, 10} => :infinity, 364 {83, 36} => 366, 365 {29, 26} => 402, 366 {47, 27} => :infinity, 367 {9, 34} => 426, 368 {137, 16} => 12, 369 {90, 0} => :infinity, 370 {103, 39} => 289, 371 {126, 13} => :infinity, 372 {47, 38} => :infinity, 373 {128, 35} => 268, 374 {20, 3} => 412, 375 {145, 20} => 24, 376 {143, 39} => 247, 377 {79, 17} => 335, 378 {75, 0} => :infinity, 379 {150, 18} => 167, 380 {147, 10} => 178, 381 {148, 26} => 75, 382 {76, 2} => :infinity, 383 {138, 9} => 104, 384 {58, 33} => 372, 385 {150, 5} => 296, 386 {54, 31} => 374, 387 {22, 37} => 412, 388 {75, 36} => :infinity, 389 {91, 35} => :infinity, 390 {143, 4} => :infinity, 391 {121, 27} => 283, 392 {91, 38} => :infinity, 393 {159, 26} => 268, 394 {131, 24} => 124, 395 {58, 10} => 367, 396 {111, 14} => :infinity, 397 {75, ...} => 345, 398 {...} => 411, 399 ... 400} 401``` 402 403```elixir 404paths 405|> Map.take(lowest) 406|> Map.values() 407|> Enum.min() 408``` 409 410<!-- livebook:{"output":true} --> 411 412``` 413430 414```