this repo has no description

ft: add day 12.2022

+320
+320
2022/day12.livemd
··· 1 + <!-- livebook:{"persist_outputs":true} --> 2 + 3 + # Day 12 4 + 5 + ```elixir 6 + Mix.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"},"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 + ``` 47 + nil 48 + ``` 49 + 50 + ```elixir 51 + min = ?a - ?a 52 + max = ?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 + 72 + graph = 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 + ``` 102 + warning: 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:7urrvoyk6ltuxa4kdqc63nncfh37x2fn:30 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 116 + length(Graph.get_shortest_path(graph, start, stop)) - 1 117 + ``` 118 + 119 + <!-- livebook:{"output":true} --> 120 + 121 + ``` 122 + 437 123 + ``` 124 + 125 + ```elixir 126 + graph.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 190 + tgraph = 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 200 + lowest = 201 + Enum.flat_map(map, fn 202 + {p, 0} -> [p] 203 + _ -> [] 204 + end) 205 + ``` 206 + 207 + <!-- livebook:{"output":true} --> 208 + 209 + ``` 210 + [32256290, 409066827, 186924390, 1502865800, 887663648, 2543466388, 697356458, 1070575781, 211 + 1659702078, 4000784021, 1947564743, 2361038489, 3904452243, 3615669650, 270460033, 1281654811, 212 + 3153535741, 2393890474, 3946102901, 2210758189, 2982223724, 2654353783, 2656280720, 3935389969, 213 + 2818948768, 4279780723, 3595206681, 3496428192, 2269119594, 2583881244, 3997991000, 520325395, 214 + 457672928, 1453390554, 3289433936, 2574402082, 1560492086, 3242480874, 389839366, 4176230802, 215 + 1147783117, 2469841095, 2034019869, 438932546, 1799582666, 1100008137, 467060197, 162439868, 216 + 3928107970, 800548913, ...] 217 + ``` 218 + 219 + ```elixir 220 + # Copied BF implementation from `libgraph` to optimise it 221 + 222 + defmodule BellmanFord do 223 + @moduledoc """ 224 + The Bellman–Ford algorithm is an algorithm that computes shortest paths from a single 225 + source vertex to all of the other vertices in a weighted digraph. 226 + It is capable of handling graphs in which some of the edge weights are negative numbers 227 + Time complexity: O(VLogV) 228 + """ 229 + 230 + @type distance :: %{Graph.vertex_id() => integer} 231 + 232 + @doc """ 233 + Returns nil when graph has negative cycle. 234 + """ 235 + @spec call(Graph.t(), Graph.vertex()) :: [Graph.vertex()] | nil 236 + def call(%Graph{vertices: vs, edges: meta}, source) do 237 + distances = source |> Graph.Utils.vertex_id() |> init_distances(vs) 238 + 239 + weights = Enum.map(meta, &edge_weight/1) 240 + 241 + distances = 242 + for _ <- 1..map_size(vs), 243 + {{u, v}, weight} <- weights, 244 + reduce: distances do 245 + distances -> 246 + case distances do 247 + %{^u => :infinity} -> 248 + distances 249 + 250 + %{^u => du, ^v => dv} when du + weight < dv -> 251 + %{distances | v => du + weight} 252 + 253 + _ -> 254 + distances 255 + end 256 + end 257 + 258 + if has_negative_cycle?(distances, weights) do 259 + nil 260 + else 261 + Map.new(distances, fn {k, v} -> {Map.fetch!(vertices, k), v} end) 262 + end 263 + end 264 + 265 + @spec init_distances(Graph.vertex(), Graph.vertices()) :: distance 266 + defp init_distances(vertex_id, vertices) do 267 + Map.new(vertices, fn 268 + {id, _vertex} when id == vertex_id -> {id, 0} 269 + {id, _} -> {id, :infinity} 270 + end) 271 + end 272 + 273 + @spec edge_weight(term) :: float 274 + defp edge_weight({e, edge_value}), do: {e, edge_value |> Map.values() |> List.first()} 275 + 276 + defp has_negative_cycle?(%{} = distances, meta) do 277 + Enum.any?(meta, fn {{u, v}, weight} -> 278 + %{^u => du, ^v => dv} = distances 279 + 280 + du != :infinity and du + weight < dv 281 + end) 282 + end 283 + end 284 + ``` 285 + 286 + <!-- livebook:{"output":true} --> 287 + 288 + ``` 289 + {:module, BellmanFord, <<70, 79, 82, 49, 0, 0, 19, ...>>, {:has_negative_cycle?, 2}} 290 + ``` 291 + 292 + ```elixir 293 + min_paths = 294 + tgraph 295 + # |> Graph.bellman_ford(stop) 296 + |> BellmanFord.call(stop) 297 + |> Map.take(lowest) 298 + |> Map.values() 299 + ``` 300 + 301 + <!-- livebook:{"output":true} --> 302 + 303 + ``` 304 + [:infinity, :infinity, :infinity, 454, :infinity, :infinity, :infinity, :infinity, :infinity, 305 + :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, 306 + :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, 307 + :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, 308 + :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, 309 + :infinity, :infinity, :infinity, :infinity, :infinity, ...] 310 + ``` 311 + 312 + ```elixir 313 + Enum.min(min_paths) 314 + ``` 315 + 316 + <!-- livebook:{"output":true} --> 317 + 318 + ``` 319 + 430 320 + ```