tangled
alpha
login
or
join now
hauleth.dev
/
advent-of-code
3
fork
atom
this repo has no description
3
fork
atom
overview
issues
pulls
pipelines
ft: add day 12.2022
hauleth.dev
3 years ago
b3c0ceca
2311494b
+320
1 changed file
expand all
collapse all
unified
split
2022
day12.livemd
+320
2022/day12.livemd
···
1
1
+
<!-- livebook:{"persist_outputs":true} -->
2
2
+
3
3
+
# Day 12
4
4
+
5
5
+
```elixir
6
6
+
Mix.install([
7
7
+
{:kino_aoc, git: "https://github.com/ljgago/kino_aoc"},
8
8
+
{:libgraph, ">= 0.0.0"}
9
9
+
])
10
10
+
```
11
11
+
12
12
+
<!-- livebook:{"output":true} -->
13
13
+
14
14
+
```
15
15
+
:ok
16
16
+
```
17
17
+
18
18
+
## Section
19
19
+
20
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
21
+
22
22
+
```elixir
23
23
+
{:ok, puzzle_input} =
24
24
+
KinoAOC.download_puzzle("2022", "12", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
25
25
+
```
26
26
+
27
27
+
<!-- livebook:{"output":true} -->
28
28
+
29
29
+
```
30
30
+
{:ok,
31
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
32
+
```
33
33
+
34
34
+
```elixir
35
35
+
# puzzle_input = """
36
36
+
# Sabqponm
37
37
+
# abcryxxl
38
38
+
# accszExk
39
39
+
# acctuvwj
40
40
+
# abdefghi
41
41
+
# """
42
42
+
```
43
43
+
44
44
+
<!-- livebook:{"output":true} -->
45
45
+
46
46
+
```
47
47
+
nil
48
48
+
```
49
49
+
50
50
+
```elixir
51
51
+
min = ?a - ?a
52
52
+
max = ?z - ?a
53
53
+
54
54
+
{map, start, stop} =
55
55
+
puzzle_input
56
56
+
|> String.split("\n", trim: true)
57
57
+
|> Enum.map(&to_charlist/1)
58
58
+
|> Enum.with_index()
59
59
+
|> Enum.flat_map(fn {line, y} ->
60
60
+
line
61
61
+
|> Enum.with_index()
62
62
+
|> Enum.map(fn {c, x} -> {{x, y}, c} end)
63
63
+
end)
64
64
+
|> Enum.reduce({%{}, nil, nil}, fn {p, v}, {map, s, e} ->
65
65
+
case v do
66
66
+
?S -> {Map.put(map, p, min), p, e}
67
67
+
?E -> {Map.put(map, p, max), s, p}
68
68
+
_ -> {Map.put(map, p, v - ?a), s, e}
69
69
+
end
70
70
+
end)
71
71
+
72
72
+
graph =
73
73
+
map
74
74
+
|> Enum.reduce(Graph.new(), fn {p, v}, graph ->
75
75
+
{x, y} = p
76
76
+
77
77
+
graph =
78
78
+
if map[{x - 1, y}] && v + 1 >= map[{x - 1, y}],
79
79
+
do: Graph.add_edge(graph, {x, y}, {x - 1, y}, label: [v, map[{x - 1, y}]]),
80
80
+
else: graph
81
81
+
82
82
+
graph =
83
83
+
if map[{x + 1, y}] && v + 1 >= map[{x + 1, y}],
84
84
+
do: Graph.add_edge(graph, {x, y}, {x + 1, y}, label: [v, map[{x + 1, y}]]),
85
85
+
else: graph
86
86
+
87
87
+
graph =
88
88
+
if map[{x, y - 1}] && v + 1 >= map[{x, y - 1}],
89
89
+
do: Graph.add_edge(graph, {x, y}, {x, y - 1}, label: [v, map[{x, y - 1}]]),
90
90
+
else: graph
91
91
+
92
92
+
graph =
93
93
+
if map[{x, y + 1}] && v + 1 >= map[{x, y + 1}],
94
94
+
do: Graph.add_edge(graph, {x, y}, {x, y + 1}, label: [v, map[{x, y + 1}]]),
95
95
+
else: graph
96
96
+
end)
97
97
+
```
98
98
+
99
99
+
<!-- livebook:{"output":true} -->
100
100
+
101
101
+
```
102
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
103
+
2022/day12.livemd#cell:7urrvoyk6ltuxa4kdqc63nncfh37x2fn:30
104
104
+
105
105
+
```
106
106
+
107
107
+
<!-- livebook:{"output":true} -->
108
108
+
109
109
+
```
110
110
+
#Graph<type: directed, num_vertices: 6642, num_edges: 24117>
111
111
+
```
112
112
+
113
113
+
## Task 1
114
114
+
115
115
+
```elixir
116
116
+
length(Graph.get_shortest_path(graph, start, stop)) - 1
117
117
+
```
118
118
+
119
119
+
<!-- livebook:{"output":true} -->
120
120
+
121
121
+
```
122
122
+
437
123
123
+
```
124
124
+
125
125
+
```elixir
126
126
+
graph.vertices
127
127
+
```
128
128
+
129
129
+
<!-- livebook:{"output":true} -->
130
130
+
131
131
+
```
132
132
+
%{
133
133
+
1148931603 => {118, 31},
134
134
+
15476201 => {158, 33},
135
135
+
3480980581 => {19, 26},
136
136
+
513279067 => {86, 0},
137
137
+
1642831488 => {111, 2},
138
138
+
669567979 => {38, 18},
139
139
+
1898334127 => {77, 28},
140
140
+
2414760132 => {41, 27},
141
141
+
1433989350 => {134, 33},
142
142
+
4010762779 => {100, 37},
143
143
+
1619384061 => {142, 27},
144
144
+
2736818014 => {105, 29},
145
145
+
3132807327 => {56, 13},
146
146
+
1603662291 => {94, 23},
147
147
+
183280155 => {35, 27},
148
148
+
2518352043 => {127, 27},
149
149
+
824501714 => {15, 33},
150
150
+
1813555375 => {70, 18},
151
151
+
733666720 => {72, 5},
152
152
+
4293490381 => {13, 24},
153
153
+
4037128590 => {87, 10},
154
154
+
1287605231 => {99, 3},
155
155
+
2697150767 => {19, 29},
156
156
+
3345146674 => {78, 5},
157
157
+
811252706 => {132, 14},
158
158
+
3035418479 => {156, 5},
159
159
+
2090318173 => {149, 1},
160
160
+
1306366779 => {71, 39},
161
161
+
113692275 => {158, 28},
162
162
+
1809958846 => {4, 0},
163
163
+
2979249361 => {95, 23},
164
164
+
712034521 => {2, 34},
165
165
+
838646858 => {127, 2},
166
166
+
2636390019 => {97, 34},
167
167
+
200998860 => {73, 23},
168
168
+
2440897975 => {91, 7},
169
169
+
2757930521 => {103, 38},
170
170
+
2626031906 => {92, 21},
171
171
+
4000959801 => {44, 20},
172
172
+
2762901234 => {69, 16},
173
173
+
3967362516 => {72, 9},
174
174
+
1858208296 => {81, 16},
175
175
+
3063825234 => {140, 14},
176
176
+
1669140133 => {46, 21},
177
177
+
684221776 => {146, 38},
178
178
+
623366404 => {63, 40},
179
179
+
3623360588 => {149, 6},
180
180
+
2885933829 => {137, 14},
181
181
+
3219344086 => {136, ...},
182
182
+
3451324297 => {...},
183
183
+
...
184
184
+
}
185
185
+
```
186
186
+
187
187
+
## Task 2
188
188
+
189
189
+
```elixir
190
190
+
tgraph = Graph.transpose(graph)
191
191
+
```
192
192
+
193
193
+
<!-- livebook:{"output":true} -->
194
194
+
195
195
+
```
196
196
+
#Graph<type: directed, num_vertices: 6642, num_edges: 24117>
197
197
+
```
198
198
+
199
199
+
```elixir
200
200
+
lowest =
201
201
+
Enum.flat_map(map, fn
202
202
+
{p, 0} -> [p]
203
203
+
_ -> []
204
204
+
end)
205
205
+
```
206
206
+
207
207
+
<!-- livebook:{"output":true} -->
208
208
+
209
209
+
```
210
210
+
[32256290, 409066827, 186924390, 1502865800, 887663648, 2543466388, 697356458, 1070575781,
211
211
+
1659702078, 4000784021, 1947564743, 2361038489, 3904452243, 3615669650, 270460033, 1281654811,
212
212
+
3153535741, 2393890474, 3946102901, 2210758189, 2982223724, 2654353783, 2656280720, 3935389969,
213
213
+
2818948768, 4279780723, 3595206681, 3496428192, 2269119594, 2583881244, 3997991000, 520325395,
214
214
+
457672928, 1453390554, 3289433936, 2574402082, 1560492086, 3242480874, 389839366, 4176230802,
215
215
+
1147783117, 2469841095, 2034019869, 438932546, 1799582666, 1100008137, 467060197, 162439868,
216
216
+
3928107970, 800548913, ...]
217
217
+
```
218
218
+
219
219
+
```elixir
220
220
+
# Copied BF implementation from `libgraph` to optimise it
221
221
+
222
222
+
defmodule BellmanFord do
223
223
+
@moduledoc """
224
224
+
The Bellman–Ford algorithm is an algorithm that computes shortest paths from a single
225
225
+
source vertex to all of the other vertices in a weighted digraph.
226
226
+
It is capable of handling graphs in which some of the edge weights are negative numbers
227
227
+
Time complexity: O(VLogV)
228
228
+
"""
229
229
+
230
230
+
@type distance :: %{Graph.vertex_id() => integer}
231
231
+
232
232
+
@doc """
233
233
+
Returns nil when graph has negative cycle.
234
234
+
"""
235
235
+
@spec call(Graph.t(), Graph.vertex()) :: [Graph.vertex()] | nil
236
236
+
def call(%Graph{vertices: vs, edges: meta}, source) do
237
237
+
distances = source |> Graph.Utils.vertex_id() |> init_distances(vs)
238
238
+
239
239
+
weights = Enum.map(meta, &edge_weight/1)
240
240
+
241
241
+
distances =
242
242
+
for _ <- 1..map_size(vs),
243
243
+
{{u, v}, weight} <- weights,
244
244
+
reduce: distances do
245
245
+
distances ->
246
246
+
case distances do
247
247
+
%{^u => :infinity} ->
248
248
+
distances
249
249
+
250
250
+
%{^u => du, ^v => dv} when du + weight < dv ->
251
251
+
%{distances | v => du + weight}
252
252
+
253
253
+
_ ->
254
254
+
distances
255
255
+
end
256
256
+
end
257
257
+
258
258
+
if has_negative_cycle?(distances, weights) do
259
259
+
nil
260
260
+
else
261
261
+
Map.new(distances, fn {k, v} -> {Map.fetch!(vertices, k), v} end)
262
262
+
end
263
263
+
end
264
264
+
265
265
+
@spec init_distances(Graph.vertex(), Graph.vertices()) :: distance
266
266
+
defp init_distances(vertex_id, vertices) do
267
267
+
Map.new(vertices, fn
268
268
+
{id, _vertex} when id == vertex_id -> {id, 0}
269
269
+
{id, _} -> {id, :infinity}
270
270
+
end)
271
271
+
end
272
272
+
273
273
+
@spec edge_weight(term) :: float
274
274
+
defp edge_weight({e, edge_value}), do: {e, edge_value |> Map.values() |> List.first()}
275
275
+
276
276
+
defp has_negative_cycle?(%{} = distances, meta) do
277
277
+
Enum.any?(meta, fn {{u, v}, weight} ->
278
278
+
%{^u => du, ^v => dv} = distances
279
279
+
280
280
+
du != :infinity and du + weight < dv
281
281
+
end)
282
282
+
end
283
283
+
end
284
284
+
```
285
285
+
286
286
+
<!-- livebook:{"output":true} -->
287
287
+
288
288
+
```
289
289
+
{:module, BellmanFord, <<70, 79, 82, 49, 0, 0, 19, ...>>, {:has_negative_cycle?, 2}}
290
290
+
```
291
291
+
292
292
+
```elixir
293
293
+
min_paths =
294
294
+
tgraph
295
295
+
# |> Graph.bellman_ford(stop)
296
296
+
|> BellmanFord.call(stop)
297
297
+
|> Map.take(lowest)
298
298
+
|> Map.values()
299
299
+
```
300
300
+
301
301
+
<!-- livebook:{"output":true} -->
302
302
+
303
303
+
```
304
304
+
[:infinity, :infinity, :infinity, 454, :infinity, :infinity, :infinity, :infinity, :infinity,
305
305
+
:infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity,
306
306
+
:infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity,
307
307
+
:infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity,
308
308
+
:infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity, :infinity,
309
309
+
:infinity, :infinity, :infinity, :infinity, :infinity, ...]
310
310
+
```
311
311
+
312
312
+
```elixir
313
313
+
Enum.min(min_paths)
314
314
+
```
315
315
+
316
316
+
<!-- livebook:{"output":true} -->
317
317
+
318
318
+
```
319
319
+
430
320
320
+
```