this repo has no description

Compare changes

Choose any two refs to compare.

+187
2024/day06.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 06
+
+
```elixir
+
Mix.install([:kino_aoc, :arrays])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI2Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjQifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "6", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"...#..................#...................#......................#..............................#.............................#...\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..#...#...............................................#.#..#........................................................#....#......#.\n...............#...............#..........................#............................#..........#.............#.................\n............#.....#........#.........................................................#........#........#.....#........#......#....\n............................#.........#....#........#.....#...#.............#.................................#...................\n........#..................#....#.." <> ...}
+
```
+
+
```elixir
+
map =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.with_index()
+
|> Enum.flat_map(fn {row, y} ->
+
row
+
|> String.to_charlist()
+
|> Enum.with_index()
+
|> Enum.map(fn {v, x} -> {{y, x}, v} end)
+
end)
+
|> Map.new()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{
+
{18, 103} => 46,
+
{76, 13} => 46,
+
{61, 121} => 46,
+
{37, 47} => 46,
+
{65, 63} => 46,
+
{77, 129} => 46,
+
{120, 47} => 46,
+
{38, 2} => 46,
+
{1, 26} => 46,
+
{116, 69} => 46,
+
{124, 56} => 46,
+
{83, 76} => 46,
+
{117, 125} => 46,
+
{32, 15} => 46,
+
{103, 106} => 46,
+
{30, 113} => 46,
+
{123, 104} => 46,
+
{124, 60} => 46,
+
{89, 14} => 46,
+
{35, 30} => 46,
+
{37, 53} => 46,
+
{4, 5} => 46,
+
{8, 50} => 46,
+
{78, 98} => 46,
+
{101, 62} => 46,
+
{95, 56} => 46,
+
{74, 12} => 46,
+
{102, 74} => 46,
+
{11, 39} => 46,
+
{65, 43} => 46,
+
{22, 38} => 46,
+
{14, 86} => 46,
+
{49, 117} => 46,
+
{20, 41} => 46,
+
{29, 25} => 46,
+
{86, 10} => 46,
+
{83, 36} => 46,
+
{29, 26} => 46,
+
{47, 27} => 46,
+
{4, 81} => 46,
+
{31, 42} => 46,
+
{9, 34} => 46,
+
{13, 124} => 46,
+
{90, 0} => 46,
+
{14, 122} => 46,
+
{120, 42} => 46,
+
{121, 77} => 46,
+
{103, 39} => 46,
+
{102, ...} => 46,
+
{...} => 46,
+
...
+
}
+
```
+
+
```elixir
+
{start_pos, _} = start = Enum.find(map, fn {_pos, v} -> v in ~c'^>v<' end)
+
+
map = Map.replace(map, start_pos, ?.)
+
+
start
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{{93, 71}, 94}
+
```
+
+
```elixir
+
defmodule Guard do
+
def walk(map, start),
+
do: walk(map, start, MapSet.new())
+
+
defp walk(map, {pos, dir} = curr, visited) do
+
if curr in visited do
+
:loop
+
else
+
visited = MapSet.put(visited, curr)
+
+
case Map.fetch(map, next(pos, dir)) do
+
{:ok, ?#} ->
+
walk(map, {pos, turn(dir)}, visited)
+
+
{:ok, ?.} ->
+
walk(map, {next(pos, dir), dir}, visited)
+
+
:error ->
+
MapSet.new(visited, fn {pos, _} -> pos end)
+
end
+
end
+
end
+
+
defp next({y, x}, ?^), do: {y - 1, x}
+
defp next({y, x}, ?>), do: {y, x + 1}
+
defp next({y, x}, ?v), do: {y + 1, x}
+
defp next({y, x}, ?<), do: {y, x - 1}
+
+
defp turn(?^), do: ?>
+
defp turn(?>), do: ?v
+
defp turn(?v), do: ?<
+
defp turn(?<), do: ?^
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Guard, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:turn, 1}}
+
```
+
+
## Part 1
+
+
```elixir
+
orig_path = Guard.walk(map, start)
+
+
MapSet.size(orig_path)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
4433
+
```
+
+
## Part 2
+
+
```elixir
+
orig_path
+
|> MapSet.delete(start_pos)
+
|> Task.async_stream(fn point ->
+
map
+
|> Map.put(point, ?#)
+
|> Guard.walk(start)
+
|> Kernel.==(:loop)
+
end, ordered: false)
+
|> Enum.count(& &1)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
4432
+
```
+
+
<!-- livebook:{"offset":7376,"stamp":{"token":"XCP.Bv-aM7sns5Kb69SQdY4giDFl6fWiJ5L3lnISxUUjGi_DgTgM_r5rl-y8sy2RLl-KbEtOmW99QQsGItLYJhKJmkOZ5pPZ_7Aw3BhkL_ap8RnW8UkOt_OsNdpqoZT7FEDtmFQ","version":2}} -->
+205
2024/day07.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 07
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI3Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjQifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "7", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"644197722674: 5 9 46 99 1 5 9 2 22 6 74\n3424919: 67 51 7 561 358\n7160145: 9 9 7 4 8 3 91 2 3 3 5 731\n1133404163: 231 3 49 2 32 128 36\n198444: 9 77 90 347 308 46 3\n258135: 7 61 68 6 249 6\n10677865: 864 7 4 1 9 4 7 7 1 5 367\n1134: 54 7 3\n28760910: 1 6 627 9 752 831\n6740: 82 236 356 10\n983873830: 977 6 267 606 830\n101904: 5 71 29 2 264\n8536122: 5 3 7 388 120\n818217: 8 27 21 484 92 5 214\n9221: 219 23 270 18 5\n216699547: 2 24 46 9 1 55 6 61 9 88\n19040: 434 4 5 2 41 713 28 54\n113740483608: 52 951 38 417 23 17\n1837300: 627 46 5 1 91 6 6 4\n21564: 6 143 330 9 5 9\n100992468: 4 4 2 9 7 69 3 24 92 8 6 8\n522672: 5 226 7 5\n72660535: 181 857 70 5 2 4 1 11\n1553455: 57 842 4 650 374 79\n177565304: 177 5 6 530 7\n123464883: 65 67 315 7 2 45\n162378: 47 799 75 702 74 3\n75882558: 4 4 9 3 8 7 5 29 5 4 57 5\n15486: 5 771 6 1 2 2 8 8 8 8 2 4\n195018949: 237 9 76 61 19 95 4 9 9\n120067914: 12 7 1 282 9 17 7 2 7 79\n10625355: 6 16 906 3 533\n714034: 2 3 60 7 7 90 325 9\n147283595568: 3 311 33 3 57 822 8 93\n2316922: 8 26 41 831 2 94\n182954295: 438 22 56 5 993 4\n17143497694679: 73 169 33 1 4 71 6 79\n758512003463: 3 2 790 700 4 2 2 34 63\n4146569285: 280 8 9 5 6 7 68 4 9 1 2 5\n31770235539495: 589 8 9 1 1 95 3 63 492\n2140548: 7 6 1 4 3 4 8 929 1 3 8 12\n12113461: 291 3 50 772 17 5 2 2\n9197820380208: 1 58 583 110 58 207\n1539915: 88 340 19 5 689\n198635345304: 19 711 980 6 44 341\n43172: 426 8 4 318 1 1 439 3 5\n53202: 5 3 7 1 4 79 62 6 6\n999074: 1 4 221 5 9 71\n107010: 2 1 29 410 3\n1207: 8 600 5 9 567 17 1\n963: 56 902 7\n3661: 87 42 4 3\n55680: 8 7 2 58 8 4\n1443280: 1 33 16 68 39 592\n11791444132: 954 3 412 412 9\n40408: 8 8 513 70 19\n895: 45 9 784 52 8\n3630590257: 5 787 5 98 113 94 57\n1219939: 9 5 183 9 3\n7243377: 1 231 8 2 1 36 6 5 795 3\n10281688290: 728 359 69 874 8 45\n52129140: 78 1 7 407 547 5 2 4 5\n844925: 778 18 78 6 8\n1517768001: 56 213 629 27 17\n1586: 26 1 18 35 9\n897822305: 10 89 7 8 222 55 52\n307677984: 38 946 58 79 2\n11629377: 7 10 83 82 37 548 6 79\n5706366: 203 30 937 6 1 26\n545930: 1 8 696 5 770\n21436: 57 94 4 4 1\n601219587: 2 5 1 2 1 1 4 1 1 912 327\n1210568: 5 3 9 86 1 1 98 2 8 97 6 8\n163672: 311 939 4 1 130 522\n816: 3 9 7 9 5 25 84 186 56\n413330: 71 9 181 504 50\n275151204: 5 8 9 8 4 3 433 1 5 6 7 3\n5565: 47 19 8 7 1 276\n5528836: 1 552 789 9 936\n30771: 42 81 5 12 9\n113510: 99 58 723\n2552925934889: 802 8 795 54 8 372 4 6\n13201: 45 124 77 31 159\n720468: 17 6 92 4 7\n22380384159: 7 8 166 29 159 1 3 2 8 2\n45770: 4 41 765 2 3\n32957: 4 28 886 71\n5110126: 6 173 214 66 8\n1762745: 982 227 3 3 27 3 6 5\n130796643: 131 32 1 5 5 624\n78364255: 8 9 694 57 7 253\n844276: 8 42 224 792 1\n362023: 9 25 594 5 5 40 87 103\n1291399844: 5 6 1 9 39 1 73 9 6 44\n228417920: 25 37 71 9 26 794 8 4\n40050828: 3 27 763 6 9 9 5 1 9 12\n116627652: 7 4 7 1 446 8 4 5 2 4 75 6\n2516095717: 7 385 8 43 59 8 5 46\n655270872: 9 2 8 159 89 2 9 3 89 95\n35298709: 6 41 170 3 2 422 97\n558606: 4 6 5 74 6 53 7 7 100 1 5\n96911: 5 9 75 6 9 665 2 7 9 2 7 8\n429735: 7 72 58 6 9\n9402: 3 453 9 86 920 1 7 88 6\n2948456: 69 251 9 68 456\n254061: 603 70 2 6 789\n27948: 485 575 322 262 17\n90873: 58 49 8 27 31 31 725\n6444009: 5 6 195 7 6 33 13\n17255343: 78 867 42 3 85\n144630242: 490 2 39 11 7 4 39 86 1\n444869: 4 7 8 878 5 479\n253242155: 42 203 6 7 234 57\n1823338: 2 414 9 487 4 6\n25234118: 91 683 58 7 1\n642484013: 917 822 4 6 1 7 9 1 2\n10018629: 99 944 235 99 628\n52518012: 663 80 8 5 99\n52968775714: 217 3 8 2 3 2 9 6 9 9 94 6\n7014: 1 666 9 933 8 70\n1210591: 39 8 40 97 31\n61925382: 366 648 1 1 9 837 29\n1392623100: 92 3 6 6 8 18 8 815 990\n146952: 66 53 92 6 677 43\n16148106: 41 31 9 5 4 39\n972134: 4 36 905 3 28 9 75 54 3\n1699: 9 7 94 2\n38915712: 66 83 4 3 296 2 1\n24871732: 71 178 3 656 148\n1016303031: 229 634 7 499 532\n553520: 7 3 7 22 69\n588423590: 2 1 9 143 8 3 6 923 1 3 4\n8360806312: 1 3 9 850 24 7 857 5 7 5\n462718: 4 6 26 93 26\n21935424: 280 60 96 2 4 2 84\n885836: 8 850 4 5 2 27 704 58 9\n797703006: 1 3 1 8 9 4 9 495 3 7 60 6\n7714822: 2 4 757 959 3 25\n233319196: 881 27 45 10 4 979\n451620568437: 170 6 57 4 9 5 56 8 439\n2836062720: 7 88 111 9 6 6 2 4 3 8 3 2\n81217110: 827 98 9 501 2\n21081: 6 3 41 6 3 1 6 324 8 5 8\n861: 7 7 2 " <> ...}
+
```
+
+
```elixir
+
#puzzle_input =
+
"""
+
190: 10 19
+
3267: 81 40 27
+
83: 17 5
+
156: 15 6
+
7290: 6 8 6 15
+
161011: 16 10 13
+
192: 17 8 14
+
21037: 9 7 18 13
+
292: 11 6 16 20
+
"""
+
+
equations =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn row ->
+
{target, ": " <> rest} = Integer.parse(row)
+
+
values =
+
rest
+
|> String.split()
+
|> Enum.map(&String.to_integer/1)
+
+
{target, values}
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
warning: code block contains unused literal "190: 10 19\n3267: 81 40 27\n83: 17 5\n156: 15 6\n7290: 6 8 6 15\n161011: 16 10 13\n192: 17 8 14\n21037: 9 7 18 13\n292: 11 6 16 20\n" (remove the literal or assign it to _ to avoid warnings)
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day07.livemd#cell:7pxlqq2wa3oqdwfr:1
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{644197722674, [5, 9, 46, 99, 1, 5, 9, 2, 22, 6, 74]},
+
{3424919, [67, 51, 7, 561, 358]},
+
{7160145, [9, 9, 7, 4, 8, 3, 91, 2, 3, 3, 5, 731]},
+
{1133404163, [231, 3, 49, 2, 32, 128, 36]},
+
{198444, [9, 77, 90, 347, 308, 46, 3]},
+
{258135, [7, 61, 68, 6, 249, 6]},
+
{10677865, [864, 7, 4, 1, 9, 4, 7, 7, 1, 5, 367]},
+
{1134, [54, 7, 3]},
+
{28760910, [1, 6, 627, 9, 752, 831]},
+
{6740, [82, 236, 356, 10]},
+
{983873830, [977, 6, 267, 606, 830]},
+
{101904, [5, 71, 29, 2, 264]},
+
{8536122, [5, 3, 7, 388, 120]},
+
{818217, [8, 27, 21, 484, 92, 5, 214]},
+
{9221, [219, 23, 270, 18, 5]},
+
{216699547, [2, 24, 46, 9, 1, 55, 6, 61, 9, 88]},
+
{19040, [434, 4, 5, 2, 41, 713, 28, 54]},
+
{113740483608, [52, 951, 38, 417, 23, 17]},
+
{1837300, [627, 46, 5, 1, 91, 6, 6, 4]},
+
{21564, [6, 143, 330, 9, 5, 9]},
+
{100992468, [4, 4, 2, 9, 7, 69, 3, 24, 92, 8, 6, 8]},
+
{522672, [5, 226, 7, 5]},
+
{72660535, [181, 857, 70, 5, 2, 4, 1, 11]},
+
{1553455, [57, 842, 4, 650, 374, 79]},
+
{177565304, [177, 5, 6, 530, 7]},
+
{123464883, [65, 67, 315, 7, 2, 45]},
+
{162378, [47, 799, 75, 702, 74, 3]},
+
{75882558, [4, 4, 9, 3, 8, 7, 5, 29, 5, 4, 57, 5]},
+
{15486, [5, 771, 6, 1, 2, 2, 8, 8, 8, 8, 2, 4]},
+
{195018949, [237, 9, 76, 61, 19, 95, 4, 9, 9]},
+
{120067914, [12, 7, 1, 282, 9, 17, 7, 2, 7, 79]},
+
{10625355, [6, 16, 906, 3, 533]},
+
{714034, [2, 3, 60, 7, 7, 90, 325, 9]},
+
{147283595568, [3, 311, 33, 3, 57, 822, 8, 93]},
+
{2316922, [8, 26, 41, 831, 2, 94]},
+
{182954295, [438, 22, 56, 5, 993, 4]},
+
{17143497694679, [73, 169, 33, 1, 4, 71, 6, 79]},
+
{758512003463, [3, 2, 790, 700, 4, 2, 2, 34, 63]},
+
{4146569285, [280, 8, 9, 5, 6, 7, 68, 4, 9, ...]},
+
{31770235539495, [589, 8, 9, 1, 1, 95, 3, 63, ...]},
+
{2140548, [7, 6, 1, 4, 3, 4, 8, ...]},
+
{12113461, [291, 3, 50, 772, 17, 5, ...]},
+
{9197820380208, [1, 58, 583, 110, 58, ...]},
+
{1539915, [88, 340, 19, 5, ...]},
+
{198635345304, [19, 711, 980, ...]},
+
{43172, [426, 8, ...]},
+
{53202, [5, ...]},
+
{999074, [...]},
+
{107010, ...},
+
{...},
+
...
+
]
+
```
+
+
## Part 1
+
+
```elixir
+
defmodule Eq.P1 do
+
def possible?(0, []), do: true
+
def possible?(a, [a]), do: true
+
def possible?(0, [_ | _]), do: false
+
def possible?(_, []), do: false
+
def possible?(a, _) when a < 0, do: false
+
+
def possible?(a, [b | rest]) when rem(a, b) == 0 do
+
possible?(div(a, b), rest) or possible?(a - b, rest)
+
end
+
+
def possible?(a, [b | rest]), do: possible?(a - b, rest)
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Eq.P1, <<70, 79, 82, 49, 0, 0, 8, ...>>, {:possible?, 2}}
+
```
+
+
```elixir
+
equations
+
|> Enum.filter(fn {target, vals} ->
+
Eq.P1.possible?(target, Enum.reverse(vals))
+
end)
+
|> Enum.reduce(0, &(elem(&1, 0) + &2))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
3119088655389
+
```
+
+
## Part 2
+
+
```elixir
+
defmodule Eq.P2 do
+
def possible?(a, [hd | rest]), do: possible?(a, hd, rest)
+
+
defp possible?(a, a, []), do: true
+
defp possible?(_, _, []), do: false
+
defp possible?(a, b, _) when b > a, do: false
+
+
defp possible?(target, curr, [a | rest]) do
+
possible?(target, concat(curr, a), rest) or
+
possible?(target, curr * a, rest) or
+
possible?(target, curr + a, rest)
+
end
+
+
defp concat(a, b), do: a * l10(b) + b
+
+
defp l10(n) when n >= 100, do: 1000
+
defp l10(n) when n >= 10, do: 100
+
defp l10(_), do: 10
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Eq.P2, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:l10, 1}}
+
```
+
+
```elixir
+
equations
+
|> Task.async_stream(
+
fn {target, vals} ->
+
if Eq.P2.possible?(target, vals), do: target, else: 0
+
end,
+
ordered: false
+
)
+
|> Enum.reduce(0, fn {:ok, val}, acc -> val + acc end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
264184041398847
+
```
+
+
<!-- livebook:{"offset":9317,"stamp":{"token":"XCP.DCDL30p1jz3L9vRDdQ5EJLc3r7y1DTsVhQ3GXFK_huvoEXqgYu2TTOfTq8AFYpt5W6fEIo4MvfrnHttbqS-z4SjRkT7WM09v09mZ_FeyqstWzLMCK_oNqhrrdwPPv5BG_8c","version":2}} -->
+327
2024/day08.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 08
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI4Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjQifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "8", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"..........M..........j.............y.....O........\n...B...............q......m........lGO............\n....................q......2.l.GQ...O.............\n.....X.......................................4....\n.....................q............................\n....M......P...............xl.K.............2.....\n....F.........L.......C.K..............m..........\n..........FM......P....jy......m..........o...r...\n..X.......P.....RL..............G..x..........4...\n............L..........NC.....q...................\n.....C.X...............K....y..........4..........\n........S...R.............j.x.....V...4...........\n.....................R..x.....V..i......m.........\n...........................R.V......N.......X.....\n.....F.........M......N......E....................\n................v................T.......F......O.\n.............................N...V.......Q........\n...v.....................C.....i..................\n......c.....W..n.w........................E.......\n3...................c.....................Q..6....\n...........h......................j...............\n.......n.0......h.................E..............2\n.v.............7.......120.....c..................\n......n.0............w...........D.t.........E...r\n....8..3......0.w.hP....z...D..T...............r..\n.................f........T........G......eQ......\n......f.n.....7..p................................\n.....Y..7.......f......I......D......K............\n............Uf....T..W.....D..r...i...............\n......I...............................Z...........\n....5....B.......b..............s..............Z..\n..........d...W..Uwh.............c..........i.....\n..I.3..Y......................e...................\n.....p.b..........k......7........................\np...........k....I..b..........s..................\n.....k.......o...........W........................\n.A..Y..........U.................a........6.......\n..A...Y.p...................................6.....\nB......k..........................Z............u..\n...3.....................s..............a.........\n......A.........................g.....a...........\n.......A....8...b.U......H....sS..................\n.........................S1.............t.........\n.....................9z..e.....5..1.g.u...........\n.......................z....d....g....H.J....o.6..\n........B................d.....u....9.J.H.........\n.8........S.................u9.............J.....H\n.....................Z5.............t1...........a\n.....................e..v...................o..t..\n.....8...............L.....z.............J........"}
+
```
+
+
```elixir
+
# puzzle_input =
+
"""
+
............
+
........0...
+
.....0......
+
.......0....
+
....0.......
+
......A.....
+
............
+
............
+
........A...
+
.........A..
+
............
+
............
+
"""
+
+
freqs =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.with_index()
+
|> Enum.flat_map(fn {row, y} ->
+
row
+
|> String.to_charlist()
+
|> Enum.with_index()
+
|> Enum.filter(fn {freq, _} -> freq != ?. end)
+
|> Enum.map(fn {freq, x} -> {{x, y}, freq} end)
+
end)
+
|> Map.new()
+
|> Enum.group_by(&elem(&1, 1), &elem(&1, 0))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
warning: code block contains unused literal "............\n........0...\n.....0......\n.......0....\n....0.......\n......A.....\n............\n............\n........A...\n.........A..\n............\n............\n" (remove the literal or assign it to _ to avoid warnings)
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day08.livemd#cell:y5uv5vxll4fey6gh:1
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{
+
117 => [{28, 46}, {31, 45}, {38, 43}, {47, 38}],
+
73 => [{2, 32}, {17, 34}, {23, 27}, {6, 29}],
+
89 => [{4, 36}, {7, 32}, {6, 37}, {5, 27}],
+
48 => [{25, 22}, {9, 21}, {8, 23}, {14, 24}],
+
57 => [{29, 46}, {21, 43}, {36, 45}],
+
113 => [{30, 9}, {20, 2}, {21, 4}, {19, 1}],
+
69 => [{42, 18}, {34, 21}, {45, 23}, {29, 14}],
+
88 => [{7, 10}, {5, 3}, {44, 13}, {2, 8}],
+
100 => [{25, 45}, {28, 44}, {10, 31}],
+
71 => [{36, 1}, {35, 25}, {31, 2}, {32, 8}],
+
98 => [{16, 41}, {7, 33}, {20, 34}, {17, 30}],
+
81 => [{42, 19}, {41, 16}, {43, 25}, {32, 2}],
+
76 => [{12, 9}, {14, 6}, {17, 8}, {21, 49}],
+
85 => [{15, 36}, {12, 28}, {17, 31}, {18, 41}],
+
120 => [{27, 5}, {35, 8}, {28, 11}, {24, 12}],
+
109 => [{26, 1}, {39, 6}, {40, 12}, {31, 7}],
+
72 => [{38, 44}, {40, 45}, {49, 46}, {25, 41}],
+
110 => [{8, 26}, {7, 21}, {15, 18}, {6, 23}],
+
68 => [{30, 27}, {28, 24}, {27, 28}, {33, 23}],
+
86 => [{29, 13}, {33, 16}, {30, 12}, {34, 11}],
+
116 => [{35, 23}, {36, 47}, {47, 48}, {40, 42}],
+
51 => [{7, 24}, {0, 19}, {3, 39}, {4, 32}],
+
80 => [{18, 7}, {19, 24}, {10, 8}, {11, 5}],
+
77 => [{11, 7}, {15, 14}, {10, 0}, {4, 5}],
+
78 => [{22, 14}, {29, 16}, {36, 13}, {23, 9}],
+
108 => [{29, 2}, {28, 5}, {35, 1}],
+
103 => [{32, 40}, {36, 43}, {33, 44}],
+
122 => [{27, 49}, {23, 44}, {24, 24}, {22, 43}],
+
83 => [{10, 46}, {25, 42}, {31, 41}, {8, 11}],
+
74 => [{38, 45}, {41, 49}, {43, 46}, {40, 44}],
+
99 => [{31, 22}, {33, 31}, {20, 19}, {6, 18}],
+
112 => [{5, 33}, {17, 26}, {8, 37}, {0, 34}],
+
97 => [{38, 40}, {33, 36}, {49, 47}, {40, 39}],
+
104 => [{16, 21}, {19, 31}, {11, 20}, {18, 24}],
+
75 => [{30, 5}, {24, 6}, {23, 10}, {37, 27}],
+
90 => [{21, 47}, {47, 30}, {34, 38}, {38, 29}],
+
55 => [{15, 22}, {14, 26}, {8, 27}, {25, 33}],
+
52 => [{45, 3}, {38, 11}, {39, 10}, {46, 8}],
+
111 => [{13, 35}, {42, 7}, {45, 44}, {44, 48}],
+
87 => [{25, 35}, {12, 18}, {14, 31}, {21, 28}],
+
119 => [{21, 23}, {18, 31}, {17, 18}, {16, 24}],
+
82 => [{12, 11}, {27, 13}, {21, 12}, {16, 8}],
+
53 => [{22, 47}, {31, 43}, {4, 30}],
+
50 => [{27, 2}, {24, 22}, {44, 5}, {49, 21}],
+
66 => [{8, 45}, {9, 30}, {3, 1}, {0, ...}],
+
70 => [{5, 14}, {41, 15}, {10, ...}, {...}],
+
56 => [{12, 41}, {4, ...}, {...}, ...],
+
102 => [{17, ...}, {...}, ...],
+
105 => [{...}, ...],
+
121 => [...],
+
...
+
}
+
```
+
+
```elixir
+
{w, h} =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> then(fn [a | _] = lst ->
+
{byte_size(a), length(lst)}
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{50, 50}
+
```
+
+
```elixir
+
defmodule Antennas do
+
def each_pair([]), do: []
+
def each_pair([a | rest]) do
+
for(b <- rest, do: {a, b}) ++ each_pair(rest)
+
end
+
+
def antinodes({xa, ya}, {xb, yb}) do
+
dx = xa - xb
+
dy = ya - yb
+
+
Stream.from_index()
+
|> Stream.flat_map(fn n ->
+
dx = dx * n
+
dy = dy * n
+
[{xa + dx, ya + dy}, {xb - dx, yb - dy}]
+
end)
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Antennas, <<70, 79, 82, 49, 0, 0, 10, ...>>, {:antinodes, 2}}
+
```
+
+
## Part 1
+
+
```elixir
+
antinodes =
+
for {_, antennas} <- freqs,
+
{a, b} <- Antennas.each_pair(antennas),
+
{x, y} = node <- Antennas.antinodes(a, b) |> Stream.drop(2) |> Enum.take(2),
+
x in 0..(w - 1) and y in 0..(h - 1),
+
into: MapSet.new() do
+
node
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
MapSet.new([
+
{20, 41},
+
{20, 3},
+
{16, 10},
+
{26, 21},
+
{6, 18},
+
{10, 32},
+
{20, 30},
+
{33, 17},
+
{17, 30},
+
{29, 28},
+
{40, 35},
+
{28, 37},
+
{25, 49},
+
{10, 19},
+
{14, 17},
+
{35, 7},
+
{29, 48},
+
{1, 34},
+
{23, 8},
+
{35, 6},
+
{49, 17},
+
{46, 38},
+
{5, 39},
+
{37, 29},
+
{16, 15},
+
{48, 41},
+
{4, 18},
+
{24, 15},
+
{33, 44},
+
{39, 18},
+
{40, 25},
+
{35, 21},
+
{41, 17},
+
{20, 37},
+
{45, 24},
+
{0, 35},
+
{18, 3},
+
{1, 36},
+
{35, 41},
+
{37, 28},
+
{28, 15},
+
{29, 38},
+
{46, 43},
+
{31, 19},
+
{19, 39},
+
{43, 10},
+
{38, 10},
+
{21, 26},
+
{28, ...},
+
{...},
+
...
+
])
+
```
+
+
```elixir
+
MapSet.size(antinodes)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
398
+
```
+
+
## Part 2
+
+
```elixir
+
antinodes_res =
+
for {_, antennas} <- freqs,
+
{a, b} <- Antennas.each_pair(antennas),
+
{x, y} = node <- Enum.take(Antennas.antinodes(a, b), 100),
+
x in 0..(w - 1) and y in 0..(h - 1),
+
into: MapSet.new() do
+
node
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
MapSet.new([
+
{37, 47},
+
{35, 30},
+
{4, 5},
+
{20, 41},
+
{31, 42},
+
{9, 34},
+
{47, 38},
+
{20, 3},
+
{47, 44},
+
{22, 36},
+
{45, 7},
+
{19, 38},
+
{27, 21},
+
{9, 33},
+
{16, 10},
+
{21, 45},
+
{26, 21},
+
{21, 48},
+
{16, 38},
+
{35, 26},
+
{28, 20},
+
{45, 19},
+
{27, 22},
+
{16, 24},
+
{6, 18},
+
{10, 32},
+
{33, 15},
+
{36, 14},
+
{20, 30},
+
{33, 17},
+
{41, 1},
+
{36, 25},
+
{28, 48},
+
{5, 9},
+
{14, 16},
+
{17, 30},
+
{30, 49},
+
{32, 18},
+
{29, 28},
+
{40, 35},
+
{6, 23},
+
{17, 39},
+
{28, 37},
+
{6, 29},
+
{39, 23},
+
{49, 16},
+
{34, 0},
+
{11, 37},
+
{25, ...},
+
{...},
+
...
+
])
+
```
+
+
```elixir
+
MapSet.size(antinodes_res)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1333
+
```
+
+
<!-- livebook:{"offset":9159,"stamp":{"token":"XCP.vUy-wiQ1Ola4DEyyjRWCHAhmtmjmoDVd4jyZ0g5rhe0RM8-OKii82hOqtdVQ6B_yetZ17Z8avgol_Frq-whc91b45zMSMIRVIC-azF_IQmYLdHX0p3LEQ0xKLcBUuir19OQ","version":2}} -->
+243
2024/day09.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 09
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI5Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjQifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "9", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"6920945132536042828994482345396169724991532616269072173941615129441070989533549353544192338215647480107561245832285861135469128938656230362333818111433746344751894125805448321674418337459440436476402523264257512621383849394968854739721644705231266361534476141022646838663844981685665728936624151235476791584929822482292987334479824016888196957024425673938289753698621244157130975989396226731549454298144391686468562820376390235135108330238590316674261440783039581594584646247629719986582560203598244312596985279832984526808559405915881067383593502384107494586724976925694948216635952475703445963854271259175649271576378184603074946598276445248640841860479933368524996925945274749282264063148922416399632485376097486952663787643633316356949469798134153950341455917737349115548390535536536397237654519556679716185652595572754749672866345553911576628161614338861880658781637382837898686889463249126116447176285128303560134154431099612772162289797131303641655015516771696046959228585241299646581370538088916416989047515564526116366867367181678616439431284930379889626059473847818663132232979123503952455854489755245141781899866948543116887346827534697893607177987563154596774691267167851154138330695352108499217988406372425774968626985943665687196181233111972699532427257992757984672882888037943925818450345177398760216079692074854569485530377584183586279552981343712063437565138087959796501957177177884278405560475435141829787014884681355059571489723985901554488154898784759668954752934048679146776060562786272011429026535298115262548593878183498916571398351436431313482968486771572527901996664899792152552410493090499727835643526428881322227999149881884793853729989624533029587010105028429614225841889414576176753414877452414680577843459538128911939238704598815126186492327558383740971333501769852667796188543180462490517062819496532859194781303437743159526136553370517461484469733677187178992265612439155938358015666261906673153823768535183244601645561579916316476813124539675061263411515873626197742860301068615568696174716481151333516718804424987323957615961444822618946925923196806747458558553262735686467327309580525855605085698452928593956820699112556481136173708346321771719645737818963669665547522134505223646796667286359173528172301211931188731691358636677670346032949579894428251583802532214067603254278658698940647270167640764638397570409829821264846762426836572463386475815673329747876757249732659277388030843590439617143487927833367461978526979212861844382550791390358527895937281110537852835869713059958217969899704145215985377666628719451233132412294358444746793946343553683032671225858498134340537229859741987180829468238642605723478228646886791227546199853372232566387139711011753555879744151132642224546223435667375781861424845134566438891443785750344893853718679532879854483395621276216275644617996376282773738211864275304297979547422875934634992111232368475557713129934172577624852042405732858060209959806520925730394293739081861693532946112557827992852621975727432957291082907728921029905725787812513023871891551681262814572424452648875694586632916946898788794936727799526748807158546930659285568029733948646265541485187570661411984840326374573377475525442055851882711851241546246736884066686885724058588220382743451817154627144869212944944985727560911326298754699513901913775411631051155448259136813383243697125190592983671813131786588158152523929049549018258627964330945831994544156999373027523966329015316477207024639470312244244043635392684240435826402148884612989874566739774998162494686244143442812672951249922585423333957811202767768597518787769627151336335561386093158376767595684951873065594471827052965041948820794865486179401375326111497235854418829486872664452298163169179763609277741983868518845423468770227926607088302941698125295594475259881783566721809397453893791727816025381929613950311537338366491240658016437269618697401059446097141870959520762921795565136242743648578086232855147488427619213536145259919693337741268680894834764319547389247696113145205712656834305853252319218569748862345539664553175240528621328137233671331496239591159242157540311894387168" <> ...}
+
```
+
+
```elixir
+
#puzzle_input = "2333133121414131402"
+
+
tags =
+
Stream.from_index()
+
|> Stream.intersperse(:gap)
+
+
files =
+
puzzle_input
+
|> String.split("", trim: true)
+
|> Enum.map(&String.to_integer/1)
+
|> Enum.zip(tags)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{6, 0},
+
{9, :gap},
+
{2, 1},
+
{0, :gap},
+
{9, 2},
+
{4, :gap},
+
{5, 3},
+
{1, :gap},
+
{3, 4},
+
{2, :gap},
+
{5, 5},
+
{3, :gap},
+
{6, 6},
+
{0, :gap},
+
{4, 7},
+
{2, :gap},
+
{8, 8},
+
{2, :gap},
+
{8, 9},
+
{9, :gap},
+
{9, 10},
+
{4, :gap},
+
{4, 11},
+
{8, :gap},
+
{2, 12},
+
{3, :gap},
+
{4, 13},
+
{5, :gap},
+
{3, 14},
+
{9, :gap},
+
{6, 15},
+
{1, :gap},
+
{6, 16},
+
{9, :gap},
+
{7, 17},
+
{2, :gap},
+
{4, 18},
+
{9, :gap},
+
{9, 19},
+
{1, :gap},
+
{5, 20},
+
{3, :gap},
+
{2, 21},
+
{6, :gap},
+
{1, 22},
+
{6, :gap},
+
{2, 23},
+
{6, :gap},
+
{9, ...},
+
{...},
+
...
+
]
+
```
+
+
```elixir
+
defmodule Disk do
+
def checksum(files) do
+
files
+
|> Enum.reduce({0, 0}, fn
+
{gap, :gap}, {pos, sum} ->
+
{pos + gap, sum}
+
+
{len, idx}, {pos, sum} ->
+
new_pos = pos + len
+
score = Enum.sum(pos..(new_pos - 1)) * idx
+
+
{new_pos, score + sum}
+
end)
+
|> elem(1)
+
end
+
+
def display(lst) do
+
Enum.map(lst, fn
+
{len, val} ->
+
sym = if val == :gap, do: ".", else: to_string(val)
+
+
List.duplicate(sym, len)
+
end)
+
|> IO.iodata_to_binary()
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Disk, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:display, 1}}
+
```
+
+
## Part 1
+
+
```elixir
+
defmodule Compactor do
+
def run(files) do
+
occupied =
+
Enum.reduce(files, 0, fn
+
{_, :gap}, acc -> acc
+
{len, _idx}, acc -> acc + len
+
end)
+
+
compact([], occupied, files, Enum.reverse(files))
+
end
+
+
defp compact(acc, 0, _, _), do: Enum.reverse(acc)
+
+
defp compact(acc, left, [{0, :gap} | rest], rfiles),
+
do: compact(acc, left, rest, rfiles)
+
+
defp compact(acc, left, rest, [{_, :gap} | rfiles]),
+
do: compact(acc, left, rest, rfiles)
+
+
defp compact(acc, left, rest, [{0, _idx} | rfiles]) do
+
compact(acc, left, rest, rfiles)
+
end
+
+
defp compact(acc, left, [{gap, :gap} | rest], [{len, idx} | rfiles]) do
+
fill = min(gap, len)
+
+
compact([{fill, idx} | acc], left - fill, [{gap - fill, :gap} | rest], [
+
{len - fill, idx} | rfiles
+
])
+
end
+
+
defp compact(acc, left, [{len, idx} = file | rest], rfiles) when is_integer(idx) do
+
compact([file | acc], left - len, rest, rfiles)
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Compactor, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:compact, 4}}
+
```
+
+
```elixir
+
files
+
|> Compactor.run()
+
|> Disk.checksum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
6332189866718
+
```
+
+
## Part 2
+
+
```elixir
+
defmodule Defrag do
+
def run(files) do
+
files
+
|> Enum.reverse()
+
|> Enum.reduce(files, fn
+
{_, :gap}, acc -> acc
+
file, acc -> do_run(acc, file, [])
+
end)
+
end
+
+
defp do_run([], _, acc), do: Enum.reverse(acc)
+
+
defp do_run([file | _] = list, file, acc), do: Enum.reverse(acc, list)
+
+
defp do_run([{len, :gap} | rest], {len, idx}, acc),
+
do: Enum.reverse(acc, [{len, idx} | rep(rest, {len, idx})])
+
+
defp do_run([{gap, :gap} | rest], {len, idx}, acc) when len < gap,
+
do: Enum.reverse(acc, [{len, idx}, {gap - len, :gap} | rep(rest, {len, idx})])
+
+
defp do_run([hd | rest], file, acc), do: do_run(rest, file, [hd | acc])
+
+
defp rep([{a, :gap}, file, {b, :gap} | rest], {len, _} = file),
+
do: [{a + len + b, :gap} | rest]
+
+
defp rep([{a, :gap}, file | rest], {len, _} = file), do: [{a + len, :gap} | rest]
+
defp rep([file, {b, :gap} | rest], {len, _} = file), do: [{len + b, :gap} | rest]
+
defp rep([file | rest], {len, _} = file), do: [{len, :gap} | rest]
+
defp rep([hd | rest], file), do: [hd | rep(rest, file)]
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Defrag, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:rep, 2}}
+
```
+
+
```elixir
+
files
+
|> Defrag.run()
+
|> Disk.checksum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
6353648390778
+
```
+
+
<!-- livebook:{"offset":8665,"stamp":{"token":"XCP.-mRlAHFcVs4Mg2hQj8TCLWgOv8zjlatUnbxbgI43tZXllMXB8VfJTbRJrHTJ1k_FrGDhUdviUPyCSPNKqXk-ZOQ9PHWUPFkLaK5S4SMKa18Ny7WrQvSmaHuoE2R6vJhqrck","version":2}} -->
+218
2024/day10.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 10
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMCIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "10", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"543067650323210321032110356789890110710189878760134567\n612148941212306782345091235410765227893258759651021298\n701238932301456798106787549323454336794567549842330807\n898547215450589867287654678892961245987654456732498910\n987656306769678956398013234781870301256003301201567821\n234543215878760145478920105690210982340112210341056932\n109650124981232230569834124567345673451234985452347845\n018744323890341021656765033438454589298545676701037796\n199803210787650110765017842129823672107655677812378987\n785012345654789541874326956010510563201234389983405676\n174321498723498632903455467173421454102348210234514430\n065430239014323721212762398982567876218959650149623521\n145540128765017890101871081071018967327968743898734678\n236692134984178768718981012567894458456876212798604329\n987783005673269659654108923458763349663212108789015012\n896654012562154546743267830309854218767103419276126787\n765780123473043432890154321212903109878756578125435698\n434099874984012301740125654567812893469017647030165556\n323101065765101787434436763058906732154178736543256765\n013298187890678696325569892143215440043289128954343894\n010367296541549045016678765014300351234567037760012983\n329458305032132134787867410967891267653438546891898012\n458789414145010120196986323898763298344129655432743210\n567076523236678743285898456777654101201098766653658901\n456167654107549658374567689985403100312434985567877014\n343228943298938569843210576876312238920125676656986323\n651014543498127478755765435410278947437876985543235434\n743223672567078369876890324320127656506987234350145632\n894102981089569232125981210451256543215432122341076541\n765091234676352101034674323401237894101341001456789830\n014780365445443032126501012532345743103210112565898321\n123689876034321145098432107645236743254101101876543210\n094545763125210056788943258896107858969010332987674301\n785430432106782169877652349787567967678321245696784561\n876021569045893458965601654343478914565414326781093870\n987109878010432167014298710234323901258905015492012901\n789219894324569052123109620123217892109876012323458692\n654308765543678743013234538994106543010870965410069783\n789877787632189852101110145885287676521961871012178654\n034565896601087601211001406776896789437652676523468743\n121053795542194512389132312345445676548943989430549012\n262342187634765433498545434531230107401232104321678298\n876533014123892324567696526540043298340981010780890187\n983414523016101019876587017832134781256672125690743296\n032101654327892100345678789901295690764543434321652345\n123089789236743981234589654800387789835678987787601336\n854176590187656876104310343211456876544549016098543223\n965765410194545675465231230898565963233432145123210112\n876894321243232980370110141767653210112321039654101101\n146765232100101061289879852632154100203410128789210322\n036787103761267876518768763543069911012543454376325412\n123498654854356987405650654985678892327632567215436701\n210567569983543292314321569876301765438761078904589898\n325456478754330101223433478765432654349652987615678765"}
+
```
+
+
```elixir
+
map =
+
for {row, y} <- puzzle_input |> String.split("\n", trim: true) |> Enum.with_index(),
+
{h, x} <- row |> String.to_charlist() |> Enum.with_index(),
+
into: %{},
+
do: {{x, y}, h - ?0}
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{
+
{37, 47} => 3,
+
{38, 2} => 4,
+
{1, 26} => 5,
+
{32, 15} => 4,
+
{35, 30} => 3,
+
{37, 53} => 4,
+
{4, 5} => 4,
+
{8, 50} => 3,
+
{11, 39} => 1,
+
{22, 38} => 1,
+
{20, 41} => 8,
+
{29, 25} => 6,
+
{29, 26} => 0,
+
{47, 27} => 0,
+
{31, 42} => 4,
+
{9, 34} => 0,
+
{47, 38} => 2,
+
{20, 3} => 7,
+
{47, 44} => 1,
+
{22, 37} => 3,
+
{22, 36} => 0,
+
{45, 7} => 7,
+
{19, 38} => 0,
+
{27, 21} => 9,
+
{9, 33} => 1,
+
{26, 41} => 4,
+
{52, 42} => 8,
+
{21, 35} => 2,
+
{42, 8} => 6,
+
{19, 22} => 9,
+
{16, 10} => 3,
+
{21, 45} => 5,
+
{11, 8} => 7,
+
{26, 21} => 0,
+
{21, 48} => 1,
+
{50, 40} => 9,
+
{10, 25} => 9,
+
{11, 19} => 0,
+
{16, 38} => 5,
+
{35, 15} => 8,
+
{37, 15} => 6,
+
{35, 26} => 7,
+
{28, 20} => 1,
+
{45, 19} => 9,
+
{27, 22} => 8,
+
{16, 24} => 5,
+
{6, 18} => 0,
+
{10, 32} => 2,
+
{32, ...} => 8,
+
{...} => 7,
+
...
+
}
+
```
+
+
```elixir
+
starts = Enum.filter(map, fn {_, elev} -> elev == 0 end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{{38, 5}, 0},
+
{{24, 7}, 0},
+
{{11, 35}, 0},
+
{{3, 9}, 0},
+
{{15, 36}, 0},
+
{{41, 32}, 0},
+
{{51, 14}, 0},
+
{{51, 24}, 0},
+
{{5, 12}, 0},
+
{{4, 35}, 0},
+
{{40, 4}, 0},
+
{{46, 4}, 0},
+
{{22, 30}, 0},
+
{{27, 12}, 0},
+
{{7, 4}, 0},
+
{{24, 43}, 0},
+
{{31, 20}, 0},
+
{{29, 42}, 0},
+
{{29, 9}, 0},
+
{{10, 2}, 0},
+
{{0, 20}, 0},
+
{{15, 20}, 0},
+
{{14, 0}, 0},
+
{{42, 48}, 0},
+
{{40, 15}, 0},
+
{{43, 14}, 0},
+
{{19, 2}, 0},
+
{{14, 22}, 0},
+
{{34, 35}, 0},
+
{{38, 42}, 0},
+
{{23, 5}, 0},
+
{{0, 11}, 0},
+
{{44, 11}, 0},
+
{{15, 30}, 0},
+
{{17, 44}, 0},
+
{{31, 32}, 0},
+
{{48, 28}, 0},
+
{{21, 39}, 0},
+
{{49, 13}, 0},
+
{{29, 45}, 0},
+
{{4, 37}, 0},
+
{{53, 31}, 0},
+
{{45, 46}, 0},
+
{{43, 29}, 0},
+
{{8, 0}, 0},
+
{{47, 42}, 0},
+
{{7, 14}, 0},
+
{{52, ...}, 0},
+
{{...}, ...},
+
{...},
+
...
+
]
+
```
+
+
```elixir
+
defmodule Trail do
+
def traverse(start, map), do: MapSet.new(traverse(start, map, []))
+
+
defp traverse({curr, 9}, _map, acc), do: [[{curr, 9} | acc]]
+
defp traverse({curr, elev}, map, acc) do
+
curr
+
|> surroundings()
+
|> then(&Map.take(map, &1))
+
|> Enum.filter(fn {_, h} -> elev + 1 == h end)
+
|> Enum.flat_map(&traverse(&1, map, [{curr, elev} | acc]))
+
end
+
+
defp surroundings({x, y}) do
+
[
+
{x, y - 1},
+
{x - 1, y},
+
{x, y + 1},
+
{x + 1, y}
+
]
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Trail, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:surroundings, 1}}
+
```
+
+
## Part 1
+
+
```elixir
+
starts
+
|> Enum.map(fn start ->
+
Trail.traverse(start, map)
+
|> MapSet.new(&hd/1)
+
|> MapSet.size()
+
end)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
733
+
```
+
+
## Section
+
+
```elixir
+
starts
+
|> Enum.map(fn start ->
+
Trail.traverse(start, map)
+
|> MapSet.size()
+
end)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1514
+
```
+
+
<!-- livebook:{"offset":6605,"stamp":{"token":"XCP.68U6SzidJCV7il26kiMv6z5qLEx_50_v2V7x6LqV9t8LQG1-aShVMNE1DEgCj9SwpKOn02np0aeSu5T1parIYMF9MeWGGfqP-oc4UGnDiDGDtJ5RGqdwcxcPjuPUQmCtZj0","version":2}} -->
+110
2024/day11.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 11
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMSIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "11", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok, "554735 45401 8434 0 188 7487525 77 7"}
+
```
+
+
```elixir
+
# puzzle_input = "125 17"
+
+
stones =
+
puzzle_input
+
|> String.split()
+
|> Enum.map(&String.to_integer/1)
+
|> Enum.frequencies()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{0 => 1, 7 => 1, 77 => 1, 188 => 1, 8434 => 1, 45401 => 1, 554735 => 1, 7487525 => 1}
+
```
+
+
```elixir
+
defmodule Stones do
+
def blink(list), do: Enum.reduce(list, %{}, &alter/2)
+
+
defp alter({0, count}, map), do: update(map, 1, count)
+
+
defp alter({n, count}, map) do
+
len = len(n)
+
+
if rem(len, 2) == 0 do
+
half = 10 ** div(len, 2)
+
+
map
+
|> update(div(n, half), count)
+
|> update(rem(n, half), count)
+
else
+
update(map, n * 2024, count)
+
end
+
end
+
+
defp len(n) when n < 10, do: 1
+
defp len(n) when n < 100, do: 2
+
defp len(n) when n < 1000, do: 3
+
defp len(n) when n < 10000, do: 4
+
defp len(n), do: ceil(:math.log10(n))
+
+
defp update(map, key, val), do: Map.update(map, key, val, &(&1 + val))
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Stones, <<70, 79, 82, 49, 0, 0, 11, ...>>, {:update, 3}}
+
```
+
+
## Part 1
+
+
```elixir
+
1..25
+
|> Enum.reduce(stones, fn _, acc ->
+
Stones.blink(acc)
+
end)
+
|> Map.values()
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
209412
+
```
+
+
## Part 2
+
+
```elixir
+
1..75
+
|> Enum.reduce(stones, fn _, acc ->
+
Stones.blink(acc)
+
end)
+
|> Map.values()
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
248967696501656
+
```
+
+
<!-- livebook:{"offset":1963,"stamp":{"token":"XCP.YCGtDQl3XNWJm5oY1OPI2QDRB7EIjZxBmwK3eswS1ryD28kg8fS_fKGIFJGFbtL1NL7wYrv2ADW60yeAZnCv5KbDelUm_bxkPN4_K56iTJ1toOGfIRYlo2lj5beAjrmbhRw","version":2}} -->
+811
2024/day12.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 12
+
+
```elixir
+
Mix.install([:kino_aoc, :range_set])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMiIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "12", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"KKKKKKZZZZZZZZDDQQQQXXXXXXXXXXXXTTTTTTTTTTTTDHHHHHHHHHHHHHHHHHGGGGGGPPPGUUGGXXGGGGGGJJJJJJJJJIIIIIIIIIIIIIIIIIIIIDIIIIIIIIIIIKIIIIIIIIIIIIIM\nKKKKKKZZZZZZZDDDQQQQXXCXXXXXXXXXTTTTTTTTTTTTTHHHHHHHHHHHHHHHHHGGGGGGGGPGUUGGGGGGGGGJJJJJJJJIIIIIIIIIIIIIIIIIIVVVIDDIIIIIIIKKKKIIIIIIIIIIIIMM\nKKKKKZZZZZZZZZZQQQQQQXCCCXXXXXXTTTTTTTTTTTTTTTHHHHHHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGJJJJJJJJJJIIIIIIIIIIIIIIIIIIVIIIIDIHIIIIIIIKKIIIIIIIIIIIIMM\nKKKKKZZZZZZZZEEHQQQYQQZCCCCXXXTTTTTTTTTTTTTTHHHIIIIHHHHHHHHHHGGGGGGGGGGGGGGGGGGGGGJJJJJJJJIIIIIIIIKKKKKKIIIIIVIIIIDHHIIIIIIIIKIIIIIIIIIIIIIM\nKKKKKKOOEZEEEEHHQQQYYCCCCCCTTTTTTTTTTTTTTTTTVVVIIIIHHHHHHBBBBGGGGGGGGGGGGGGGGGGGGJJJJJJJJJIIIIIIIBCKKKKKIIIIIIIIHHHHHIIIIIIIIIIIIIIIIIIIMMMM\nKKKKKOOEEEEEEEHHHQQYYCCCCCCCCCTTTTTTTTTTTOOTTIIIIIHHHHHHHHHBBBGGGGGGGGGGGGGGGGGGGJJJJJJJJJIIIIIBBBCKKKKKKKIIIIIHHHHHIIIIIIIIIIIIIIIIIIIIIIMM\nKKKKKKOGGEEEGHHHHQDDYYCCCCCCCOOTTTTTTTTTTTIDIIIIIIIHHHHHHBBBBBGGGGGGGGGGGGGGGGGGGGJJJJJJJJIIIIBBBBKKKKKKKKIKIIIBHHHHHIIIIIIIIIIIIIIIIIIIIIIM\nKKKKTKOOGEGGGHGHDDDDDYYYCCCCCOOTTTTTTTTTTIIIIIIIIIIHHHHHBBBBBBGGGGGJGGGQGGLGGGGGGJJJJJJRRJJJBBBBKKKKKKKKKKKKKKFHHHHHHHIHHIIIIIRIIIIIIIIIIMMM\nKRRRVOOGGGGGGGGGDDDDPDDYDSSCCCOOOTTOTTTTTIIIIIIIIIIHHHBHBBBBBBGGGGGJGJJGGGGGGGGGGJJJJJRRRRRWBBBBBBVKKKKKKKKKKTHHHHHHHHHHIIIIIIIIIIIIIIGIIMMM\nYVRVVOOGGGGGGGDDDDDDDDDDDSSCCOOOOOOOTOOOIIIIIIIIIIIHHBBBBBBBBBGGGGGJJJJJGGGCGGFFGFFJRRRRRRRWWBBBBBBKKKKKKKKKKKHHHHHHHHHFFIIIIIIIIIIIIIGIVVMM\nYVRVVVVGGGGGGGDDDDDDDDDDDDDCCOOOOOOOOOOOIIIIIIIIIIIHHHBBBBBBBBBBGGJJJJJJJJJGGGFFFFRRRRRRRRRRRBBBBBKKKKKKKKKKKKKHHHHHHHHFIIIIIIIIIIIIIIIIVVVM\nYVVVVVVVVGGGGGGDDDDDDDDDDDDOOOOOOOOOOOOOOIIIIIIEEIIHHHOBBBBBBBBBBGJJJJJJJJJFFFFFFFFFRRRRRRRRRRBBBBKBKKKKKKKKKKKHHHHHHFFFFIIFIIIIZIIAIIIIVVMM\nVVVVVVVVVGGGGGGDDDDDDDDDDDOOOOOOOOOOOOOOOOOOOIOOEJJHHHOBBBBBBBBBBEEJEEEEEFFFFFFFFFFFRRRRRRRNBBBBBBBBKKKKKKKKKKRHHHHHHFFFFFFFIIIIIIIIBBIIVMMM\nVVVVVVVVVGGGGGDDDDDDDDDDDDEOOOOOOOOOOOOOOOOOOOOOEEJHHOOOBBBBGGGGBEEEHEEXFFFFFFFFFFFFRRRRRRBNBBBBBBBBKKKKKKKKKKHHHHHHHFFFFFFFIIIIIIIIBBVVVMMM\nVVVVVVVVGGGGGDPDDDDDDDDDDDEEOOOOOOOOOOOOOOOOOOOOEEJEOOOOBGGGGGGGHEEEEEEFFFLFFFFFFFFRRRRRRRBBBBBBBBBBBKKKKKKKKFHHHHHFFFFFFFFIIIIIIIIIIVVVVVMM\nVVVVVVVVGGGGGDDDDDDDDDDDDDDEOOOOOOOOGOOOOOEOIIOOEEEEOOOOOGGGGGGGEEEEEEEFFFFFFFFFFFFFRDRRXXBBBBBBBBBBBKKKKKKKKKBBHHHHFFFFFFFIIIIIIIIIVVVVVVLM\nVVVVVVVVWGGGGDDDDDDDDDDDDEEEOOOOOOGGGOOOOOOIIIIIEEOOOOBOOGGGGGGGUEEEEEGUFFFFFFFFFFFFDDDDMMSBBBBBBBBBBBBBKKKKKKBBBHHFFFFFFFFIIIIINNWIVVVVVVLL\nVVVVVVZZZFGGGRDDDDDDDDDDDEOOOOOOOFFFGOGOOIIIBIBBBEOBBBBBBGGGGGGGEEEEEGGUUFFFFFFFFFFFDDDDDMMMBBBBBBBBBBBKKKKKKBBBBHHFFFFFFFFFIINNNNNPPVVVVLLL\nVVVZZZZZZZIGRRADADDDDDDDDEOEEOYYGFFGGOGGGIIIBBBBBEBBBBBBBGGGGGGGFEEEGGGGUUFFFFFFFFFHDVVVVVVMBBBBBBBBBBBKKKKBBBBBBBBBFFFFFFFRRRRNNNNPPVVLLLLL\nVVZZZZZZZZZRRRADAADEEEDDDEEEEOYYGGGGGGGGGGIBBBBBBBBBBBBBBGGGGGGGEEEEBGGGUUFFFFFFFFFHHVVVVVVMBBBBBBBBBPBKKBBBBBBBBBBFFFFFFFFFRBRNNNNNNNVLLLLL\nVZZZZZBZZZNAAAAAAAAEEEEEEEEEGGYYGGGGGGGGGIIBBBBBBBBBBBBBBGGGGGFFFEEBBGGGGCFFFFFFFFFHHVVVVVVMBBBBBBBMMMMMBBBBBBBGBBBFFFFFFFGGBBBNNNNNLLLLLLLL\nBBBBBBBZZNNNAAAAAAEEEEEEGEEEEGYYGGGGGGGIIIIBBBBBBBBBBBBBBGGGGGFFCCCBGGGCCCFCCWWWWWWWHVVVVVVMMBBBMMMMMMMMBBBBBBBGBGGTTFFFFFFFFBBNNNNNLLLLLLLL\nJBBBBBBBZZNAAAAAAAAAAGGGGGGEGGGGGGGGGGGGGIHDBBBBBBBBBBBBBBFFFFFCCCCCGGGCCKCCCWHHHHHHHVVVVVVMMVVVVVVMMMMMBBBBBBGGBGGTFFFFTFFFFBBBBBBBBBLLLLLL\nJJJBBBBBBAAAAAAAAAAAGGGGGGGEGGGGGGGGGGGGIIHDBBBBBBBBBBBBBBBBFFFCZCCCCCCCCCCCCHHHHHHHHVVVVVVMMVVVVVVMMMMMBBBBBBGGGGGTTFFTTFFFBBBBBBBBBBLLLLLL\nJJJBBBBAAAAAAAAAAAAAGGGGGGGGGGGGGGGGGGGGIHHDHHHHBBBBBBSSSSFFFFFCCCCCCCCCCCCCCHHHHHHHHVVVVVVHHVVVVVVMMMMMBBBBBBGGGGGTTTTTTFHFBBBBBBBBBBBLBBLV\nJJJJJJAAAAAAAAAAAAAAGGGGGGGGGGGGGGGGGGGHHHHHHHHHHIJJJJJSSSSFFFCCFFCCCCCCCCCCCHHHHHHHHVVVVVVVVVVVVVVMMMMMMBBBBGGGGGGGGGTTTLLBBBBBBBBBBBBBBBBV\nJJJJJJAAAAAAAAAAAAAAGAAGGGGGGGGGGGGGGGGHHHHHHHHHHJJJHJSSSSSFFFFFFCCCCCCCCCCCCHRHHHHHHVVVVVVVVVVVVVVGMMMMMBBBBGGGGGGGGGTTLLLLLLBBBBBBBBBBBBBB\nJJJJJJAAAAAAAAAAAAAAAAGGGGGGGGHGGGGGGGGHHHHHHHHHHJJJJJJJSJSFFFFFCCCCCCCCCCCCCCHHHHHHHVVVVVVVVVVVVVVGGMMCMBBBGGGGGGGGPGGGLLZLLLBBBBBBBBBBBBBB\nJJJJJJAAAAAAAAAAAAAAGAGGGGGGGGGGGGZZGHGHHHHHHHHHJJJJJJJJJJSFFFFFCCCCCCCCCCCCCCHHHHHHHHHOHHOOMVVVVVVGGJGGIBBBTGGGGGGTGGGLLLLLLLLBBBBBBBBBBBBB\nJJJJJAA" <> ...}
+
```
+
+
```elixir
+
map =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.with_index()
+
|> Enum.flat_map(fn {row, y} ->
+
row
+
|> String.split("", trim: true)
+
|> Enum.with_index()
+
|> Enum.map(fn {plant, x} -> {{x, y}, plant} end)
+
end)
+
|> Map.new()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{
+
{18, 103} => "H",
+
{76, 13} => "F",
+
{61, 121} => "X",
+
{112, 138} => "T",
+
{37, 47} => "U",
+
{65, 63} => "G",
+
{77, 129} => "E",
+
{120, 47} => "L",
+
{38, 2} => "T",
+
{1, 26} => "J",
+
{116, 69} => "W",
+
{124, 56} => "O",
+
{83, 76} => "N",
+
{117, 125} => "Q",
+
{100, 134} => "W",
+
{78, 139} => "D",
+
{32, 15} => "O",
+
{103, 106} => "N",
+
{30, 113} => "J",
+
{123, 104} => "W",
+
{68, 134} => "Q",
+
{124, 60} => "O",
+
{89, 14} => "R",
+
{35, 30} => "E",
+
{37, 53} => "H",
+
{77, 130} => "E",
+
{2, 132} => "Q",
+
{4, 5} => "K",
+
{8, 50} => "X",
+
{78, 98} => "Y",
+
{101, 62} => "X",
+
{98, 136} => "W",
+
{95, 56} => "D",
+
{74, 12} => "F",
+
{17, 138} => "F",
+
{102, 74} => "S",
+
{11, 39} => "P",
+
{131, 5} => "I",
+
{65, 43} => "S",
+
{22, 38} => "R",
+
{14, 86} => "N",
+
{139, 46} => "U",
+
{12, 135} => "Q",
+
{65, 131} => "A",
+
{49, 117} => "O",
+
{20, 41} => "D",
+
{29, 25} => "G",
+
{86, 10} => "R",
+
{83, ...} => "I",
+
{...} => "G",
+
...
+
}
+
```
+
+
```elixir
+
defmodule Garden do
+
def plots(map) do
+
map
+
|> Enum.group_by(&elem(&1, 1), &elem(&1, 0))
+
|> Enum.flat_map(fn {kind, pts} ->
+
for parcel <- parcels(MapSet.new(pts), []) do
+
{kind, parcel}
+
end
+
end)
+
end
+
+
def parcels(set, acc) do
+
case Enum.take(set, 1) do
+
[] ->
+
acc
+
+
[p] ->
+
{parcel, rest} = flood(p, MapSet.new(), set)
+
+
parcels(rest, [parcel | acc])
+
end
+
end
+
+
def flood({x, y} = curr, visited, potential) do
+
visited = MapSet.put(visited, curr)
+
potential = MapSet.delete(potential, curr)
+
+
for next <- [
+
{x - 1, y},
+
{x + 1, y},
+
{x, y - 1},
+
{x, y + 1}
+
],
+
next in potential,
+
reduce: {visited, potential} do
+
{v, p} -> flood(next, v, p)
+
end
+
end
+
+
def as_int(false), do: 0
+
def as_int(true), do: 1
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Garden, <<70, 79, 82, 49, 0, 0, 15, ...>>, {:as_int, 1}}
+
```
+
+
```elixir
+
plots = Garden.plots(map)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{"A", MapSet.new([{131, 11}])},
+
{"A",
+
MapSet.new([
+
{54, 38},
+
{54, 39},
+
{55, 38},
+
{56, 36},
+
{56, 37},
+
{56, 38},
+
{57, 37},
+
{57, 38},
+
{57, 39},
+
{57, 40},
+
{58, 36},
+
{58, 37},
+
{58, 38},
+
{58, 39},
+
{58, 40},
+
{59, 36},
+
{59, 37},
+
{59, 38},
+
{60, 36},
+
{60, 37},
+
{60, 38},
+
{61, 36},
+
{61, 37},
+
{61, 38},
+
{62, 38},
+
{63, 38}
+
])},
+
{"A", MapSet.new([{18, 56}])},
+
{"A",
+
MapSet.new([
+
{93, 86},
+
{94, 86},
+
{95, 86},
+
{95, 87},
+
{95, 88},
+
{96, 86},
+
{96, 87},
+
{97, 80},
+
{97, 81},
+
{97, 82},
+
{97, 83},
+
{97, 84},
+
{97, 85},
+
{97, 86},
+
{97, 87},
+
{98, 80},
+
{98, 81},
+
{98, 82},
+
{98, 83},
+
{98, 84},
+
{98, 85},
+
{99, 81},
+
{99, 82},
+
{99, 84}
+
])},
+
{"A",
+
MapSet.new([
+
{35, 102},
+
{42, 111},
+
{38, 112},
+
{38, 108},
+
{39, 111},
+
{35, 106},
+
{41, 105},
+
{36, 105},
+
{36, 108},
+
{42, 110},
+
{35, 104},
+
{36, 109},
+
{43, 111},
+
{42, 107},
+
{41, 107},
+
{37, 108},
+
{41, 111},
+
{42, 108},
+
{39, 107},
+
{35, 103},
+
{36, 111},
+
{37, 113},
+
{37, 105},
+
{40, 110},
+
{38, 107},
+
{43, 107},
+
{38, 105},
+
{41, 110},
+
{34, 108},
+
{37, 109},
+
{35, 108},
+
{36, 106},
+
{42, 109},
+
{38, 114},
+
{37, 112},
+
{39, 110},
+
{39, 109},
+
{36, 103},
+
{38, 110},
+
{37, 111},
+
{39, 108},
+
{38, ...},
+
{...},
+
...
+
])},
+
{"A", MapSet.new([{70, 115}, {70, 116}, {70, 117}, {71, 116}, {71, 117}, {72, 116}, {72, 117}])},
+
{"A",
+
MapSet.new([
+
{85, 84},
+
{88, 82},
+
{87, 83},
+
{83, 84},
+
{87, 79},
+
{86, 82},
+
{86, 84},
+
{83, 85},
+
{87, 78},
+
{87, 84},
+
{85, 79},
+
{87, 81},
+
{85, 80},
+
{88, 83},
+
{84, 84},
+
{86, 81},
+
{86, 80},
+
{82, 85},
+
{85, 82},
+
{82, 84},
+
{82, 86},
+
{88, 81},
+
{87, 82},
+
{86, 83},
+
{85, 81},
+
{83, 83},
+
{84, 80},
+
{88, 84},
+
{83, 86},
+
{87, 80},
+
{87, 77},
+
{81, 85},
+
{85, 83},
+
{84, 85},
+
{84, 82},
+
{84, 81},
+
{84, 83}
+
])},
+
{"A",
+
MapSet.new([
+
{19, 22},
+
{10, 25},
+
{16, 24},
+
{10, 32},
+
{17, 30},
+
{6, 29},
+
{18, 29},
+
{17, 22},
+
{13, 25},
+
{14, 24},
+
{10, 23},
+
{8, 29},
+
{13, 22},
+
{14, 28},
+
{6, 26},
+
{18, 26},
+
{16, 23},
+
{21, 26},
+
{19, 30},
+
{13, 27},
+
{16, 18},
+
{18, 23},
+
{9, 25},
+
{16, 29},
+
{7, 26},
+
{12, 27},
+
{16, 30},
+
{17, 24},
+
{18, 24},
+
{18, 22},
+
{6, 28},
+
{13, 20},
+
{9, 26},
+
{7, 27},
+
{11, 22},
+
{8, 25},
+
{17, 23},
+
{13, 23},
+
{20, ...},
+
{...},
+
...
+
])},
+
{"A",
+
MapSet.new([
+
{111, 103},
+
{107, 102},
+
{110, 102},
+
{110, 106},
+
{112, 103},
+
{114, 103},
+
{112, 100},
+
{108, 97},
+
{103, 96},
+
{109, 104},
+
{103, 99},
+
{108, 95},
+
{110, 104},
+
{113, 101},
+
{105, 105},
+
{108, 108},
+
{106, 105},
+
{111, 100},
+
{104, 98},
+
{109, 101},
+
{111, 104},
+
{107, 100},
+
{106, 102},
+
{112, 106},
+
{105, 95},
+
{104, 104},
+
{112, 97},
+
{108, 94},
+
{104, 97},
+
{111, 99},
+
{108, 102},
+
{108, 109},
+
{101, 97},
+
{104, 103},
+
{102, 96},
+
{112, 101},
+
{113, 97},
+
{100, ...},
+
{...},
+
...
+
])},
+
{"A",
+
MapSet.new([
+
{132, 99},
+
{136, 110},
+
{137, 104},
+
{139, 106},
+
{134, 98},
+
{139, 101},
+
{136, 102},
+
{139, 104},
+
{136, 96},
+
{134, 107},
+
{132, 100},
+
{138, 96},
+
{138, 102},
+
{135, 109},
+
{137, 107},
+
{133, 97},
+
{135, 107},
+
{137, 101},
+
{139, 97},
+
{137, 100},
+
{139, 109},
+
{135, 100},
+
{137, 97},
+
{132, 97},
+
{138, 105},
+
{137, 106},
+
{138, 99},
+
{136, 100},
+
{135, 98},
+
{139, 98},
+
{138, 103},
+
{138, 107},
+
{136, 108},
+
{139, 99},
+
{133, 96},
+
{139, 105},
+
{132, ...},
+
{...},
+
...
+
])},
+
{"A",
+
MapSet.new([
+
{84, 102},
+
{82, 100},
+
{86, 101},
+
{82, 91},
+
{86, 93},
+
{90, 93},
+
{88, 93},
+
{86, 96},
+
{82, 95},
+
{84, 93},
+
{85, 97},
+
{87, 95},
+
{81, 95},
+
{83, 100},
+
{87, 93},
+
{81, 100},
+
{84, 96},
+
{88, 95},
+
{81, 98},
+
{84, 100},
+
{85, 102},
+
{84, 91},
+
{82, 97},
+
{85, 99},
+
{83, 95},
+
{89, 96},
+
{88, 94},
+
{84, 104},
+
{86, 102},
+
{80, 92},
+
{89, 94},
+
{86, 103},
+
{83, 92},
+
{83, 96},
+
{82, 102},
+
{84, ...},
+
{...},
+
...
+
])},
+
{"A",
+
MapSet.new([
+
{65, 131},
+
{65, 129},
+
{74, 135},
+
{72, 134},
+
{71, 133},
+
{66, 130},
+
{73, 135},
+
{69, 130},
+
{74, 134},
+
{66, 132},
+
{68, 132},
+
{67, 128},
+
{69, 133},
+
{71, 132},
+
{70, 134},
+
{72, 132},
+
{72, 133},
+
{69, 132},
+
{71, 130},
+
{74, 136},
+
{73, 136},
+
{70, 128},
+
{68, 130},
+
{69, 129},
+
{73, 133},
+
{69, 131},
+
{70, 129},
+
{70, 130},
+
{67, 133},
+
{68, 131},
+
{68, 129},
+
{72, 135},
+
{68, 128},
+
{73, 134},
+
{66, ...},
+
{...},
+
...
+
])},
+
{"B", MapSet.new([{132, 12}, {132, 13}, {133, 12}, {133, 13}])},
+
{"B", MapSet.new([{111, 6}])},
+
{"B", MapSet.new([{104, 115}])},
+
{"B", MapSet.new([{83, 87}, {84, 87}, {84, 88}])},
+
{"B", MapSet.new([{83, 82}])},
+
{"B", MapSet.new([{71, 79}])},
+
{"B",
+
MapSet.new([
+
{69, 112},
+
{70, 109},
+
{70, 111},
+
{70, 112},
+
{71, 108},
+
{71, 109},
+
{71, 110},
+
{71, 111},
+
{72, 108}
+
])},
+
{"B", MapSet.new([{67, 20}, {67, 21}, {68, 19}, {68, 20}])},
+
{"B", MapSet.new([{63, 100}])},
+
{"B", MapSet.new([{44, 121}, {44, 122}])},
+
{"B", MapSet.new([{41, 45}])},
+
{"B", MapSet.new([{30, 54}])},
+
{"B", MapSet.new([{18, 90}])},
+
{"B", MapSet.new([{10, 127}])},
+
{"B", MapSet.new([{9, 126}])},
+
{"B",
+
MapSet.new([
+
{37, 75},
+
{39, 77},
+
{42, 73},
+
{35, 75},
+
{39, 81},
+
{40, 75},
+
{41, 75},
+
{40, 77},
+
{40, 81},
+
{40, 76},
+
{32, 78},
+
{33, 78},
+
{32, 77},
+
{37, 80},
+
{35, 79},
+
{34, 75},
+
{30, 78},
+
{39, 76},
+
{34, ...},
+
{...},
+
...
+
])},
+
{"B", MapSet.new([{42, 69}])},
+
{"B",
+
MapSet.new([
+
{0, 21},
+
{1, 21},
+
{1, 22},
+
{2, 21},
+
{2, 22},
+
{3, 21},
+
{3, 22},
+
{3, 23},
+
{3, 24},
+
{4, 21},
+
{4, 22},
+
{4, 23},
+
{4, 24},
+
{5, 21},
+
{5, 22},
+
{5, 23},
+
{5, ...},
+
{...},
+
...
+
])},
+
{"B", MapSet.new([{100, 130}])},
+
{"B",
+
MapSet.new([
+
{108, 25},
+
{108, 21},
+
{104, 24},
+
{104, 21},
+
{109, 18},
+
{107, 25},
+
{107, 18},
+
{109, 17},
+
{107, 27},
+
{106, 22},
+
{113, 20},
+
{112, 17},
+
{106, 26},
+
{108, 24},
+
{105, ...},
+
{...},
+
...
+
])},
+
{"B",
+
MapSet.new([
+
{15, 93},
+
{18, 93},
+
{17, 93},
+
{19, 97},
+
{13, 98},
+
{16, 93},
+
{17, 97},
+
{13, 95},
+
{14, 93},
+
{12, 95},
+
{15, 98},
+
{15, 96},
+
{14, 95},
+
{14, ...},
+
{...},
+
...
+
])},
+
{"B",
+
MapSet.new([
+
{45, 19},
+
{53, 23},
+
{54, 16},
+
{55, 17},
+
{53, 19},
+
{55, 20},
+
{56, 18},
+
{55, 21},
+
{49, 20},
+
{56, 22},
+
{47, 22},
+
{54, 23},
+
{47, ...},
+
{...},
+
...
+
])},
+
{"B",
+
MapSet.new([
+
{98, 9},
+
{97, 20},
+
{95, 16},
+
{100, 18},
+
{94, 21},
+
{97, 10},
+
{102, 16},
+
{93, 17},
+
{98, 19},
+
{95, 17},
+
{96, 13},
+
{92, ...},
+
{...},
+
...
+
])},
+
{"B",
+
MapSet.new([
+
{58, 10},
+
{61, 7},
+
{53, 9},
+
{58, 8},
+
{55, 11},
+
{60, 10},
+
{60, 11},
+
{60, 12},
+
{61, 11},
+
{59, 13},
+
{56, ...},
+
{...},
+
...
+
])},
+
{"B",
+
MapSet.new([
+
{131, 24},
+
{129, 25},
+
{130, 28},
+
{132, 31},
+
{127, 22},
+
{132, 33},
+
{130, 25},
+
{123, 25},
+
{130, 27},
+
{126, ...},
+
{...},
+
...
+
])},
+
{"B", MapSet.new([{30, 42}, {31, 42}, {32, 42}])},
+
{"C", MapSet.new([{114, 87}, {114, 88}])},
+
{"C", MapSet.new([{103, 27}])},
+
{"C", MapSet.new([{98, 4}, {98, 5}])},
+
{"C", MapSet.new([{92, 104}])},
+
{"C", MapSet.new([{83, 33}])},
+
{"C", MapSet.new([{82, 87}])},
+
{"C", MapSet.new([{76, 32}])},
+
{"C", MapSet.new([{75, ...}])},
+
{"C", MapSet.new([{...}])},
+
{"C", MapSet.new([...])},
+
{"C", ...},
+
{...},
+
...
+
]
+
```
+
+
## Part 1
+
+
```elixir
+
defmodule Garden.Circ do
+
def circumfence(set) do
+
{{sx, _}, {ex, _}} = Enum.min_max_by(set, &elem(&1, 0))
+
{{_, sy}, {_, ey}} = Enum.min_max_by(set, &elem(&1, 1))
+
+
rows = (sx - 1)..(ex + 1)//1
+
cols = (sy - 1)..(ey + 1)//1
+
+
vert =
+
rows
+
|> Enum.map(fn x -> count_flips(cols, &({x, &1} in set)) end)
+
|> Enum.sum()
+
+
hori =
+
cols
+
|> Enum.map(fn y -> count_flips(rows, &({&1, y} in set)) end)
+
|> Enum.sum()
+
+
vert + hori
+
end
+
+
defp count_flips(enum, init \\ false, func) do
+
Enum.reduce(enum, {0, init}, fn elem, {count, last} ->
+
curr = func.(elem)
+
{count + Garden.as_int(last != curr), curr}
+
end)
+
|> elem(0)
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Garden.Circ, <<70, 79, 82, 49, 0, 0, 15, ...>>, {:count_flips, 3}}
+
```
+
+
```elixir
+
plots
+
|> Enum.map(fn {_, points} ->
+
Garden.Circ.circumfence(points) * MapSet.size(points)
+
end)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1464678
+
```
+
+
## Part 2
+
+
```elixir
+
defmodule Garden.Sides do
+
def sides(set) do
+
xy = do_count(set, 0, 1)
+
yx = do_count(set, 1, 0)
+
+
xy + yx
+
end
+
+
defp do_count(set, a, b) do
+
set
+
|> Enum.group_by(&elem(&1, a), &elem(&1, b))
+
|> Enum.sort()
+
|> Enum.map(fn {_, row} -> row |> Enum.map(&(&1..&1)) |> RangeSet.new() end)
+
|> Enum.chunk_every(2, 1, [RangeSet.new()])
+
|> Enum.flat_map(fn [top, bot] ->
+
top.ranges
+
|> Enum.map(fn a..b//_ ->
+
Garden.as_int(not Enum.any?(bot.ranges, &(a == &1.first))) +
+
Garden.as_int(not Enum.any?(bot.ranges, &(b == &1.last)))
+
end)
+
end)
+
|> Enum.sum()
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Garden.Sides, <<70, 79, 82, 49, 0, 0, 16, ...>>, {:do_count, 3}}
+
```
+
+
```elixir
+
plots
+
|> Enum.map(fn {_, plot} ->
+
Garden.Sides.sides(plot) * MapSet.size(plot)
+
end)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
877492
+
```
+
+
<!-- livebook:{"offset":17848,"stamp":{"token":"XCP.d5P0-cESwFZ7qUYI4K40J_3AxksZ7WIqnIE6sn4smJvJahembJKNW-3db5gLxIgp_FEyn1pBBioGJSDsU7MO2fi1HjFgxeFNU0dLXi9Z4tf68Ey8dtld73d7SrSGlcv2DDM","version":2}} -->
+272
2024/day13.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 13
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMyIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "13", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"Button A: X+22, Y+88\nButton B: X+90, Y+28\nPrize: X=6496, Y=3076\n\nButton A: X+54, Y+14\nButton B: X+14, Y+44\nPrize: X=8084, Y=1284\n\nButton A: X+96, Y+15\nButton B: X+55, Y+63\nPrize: X=5535, Y=3966\n\nButton A: X+17, Y+42\nButton B: X+40, Y+25\nPrize: X=12176, Y=3136\n\nButton A: X+87, Y+31\nButton B: X+15, Y+36\nPrize: X=6672, Y=2500\n\nButton A: X+59, Y+27\nButton B: X+21, Y+56\nPrize: X=1475, Y=15098\n\nButton A: X+39, Y+51\nButton B: X+98, Y+14\nPrize: X=7890, Y=3126\n\nButton A: X+23, Y+37\nButton B: X+35, Y+14\nPrize: X=16537, Y=6184\n\nButton A: X+21, Y+89\nButton B: X+74, Y+23\nPrize: X=2407, Y=8748\n\nButton A: X+47, Y+17\nButton B: X+35, Y+59\nPrize: X=17994, Y=16242\n\nButton A: X+14, Y+45\nButton B: X+52, Y+16\nPrize: X=18768, Y=3912\n\nButton A: X+29, Y+45\nButton B: X+85, Y+11\nPrize: X=3149, Y=4161\n\nButton A: X+81, Y+95\nButton B: X+67, Y+12\nPrize: X=5489, Y=2110\n\nButton A: X+48, Y+58\nButton B: X+86, Y+22\nPrize: X=4802, Y=2280\n\nButton A: X+27, Y+59\nButton B: X+47, Y+15\nPrize: X=2602, Y=2090\n\nButton A: X+39, Y+87\nButton B: X+94, Y+38\nPrize: X=8830, Y=6134\n\nButton A: X+23, Y+61\nButton B: X+82, Y+16\nPrize: X=8405, Y=3957\n\nButton A: X+54, Y+14\nButton B: X+24, Y+63\nPrize: X=894, Y=1708\n\nButton A: X+26, Y+14\nButton B: X+18, Y+35\nPrize: X=5510, Y=12541\n\nButton A: X+65, Y+55\nButton B: X+21, Y+69\nPrize: X=430, Y=620\n\nButton A: X+11, Y+62\nButton B: X+50, Y+11\nPrize: X=11414, Y=3683\n\nButton A: X+21, Y+54\nButton B: X+93, Y+22\nPrize: X=7683, Y=5642\n\nButton A: X+20, Y+95\nButton B: X+52, Y+29\nPrize: X=5580, Y=10155\n\nButton A: X+37, Y+13\nButton B: X+11, Y+66\nPrize: X=18250, Y=14983\n\nButton A: X+54, Y+28\nButton B: X+37, Y+58\nPrize: X=17939, Y=14902\n\nButton A: X+87, Y+65\nButton B: X+11, Y+79\nPrize: X=3765, Y=4087\n\nButton A: X+74, Y+30\nButton B: X+16, Y+59\nPrize: X=9858, Y=8342\n\nButton A: X+74, Y+31\nButton B: X+17, Y+59\nPrize: X=14764, Y=6598\n\nButton A: X+12, Y+95\nButton B: X+27, Y+33\nPrize: X=945, Y=3324\n\nButton A: X+21, Y+36\nButton B: X+34, Y+14\nPrize: X=7247, Y=5012\n\nButton A: X+48, Y+62\nButton B: X+90, Y+29\nPrize: X=9150, Y=5973\n\nButton A: X+93, Y+43\nButton B: X+49, Y+91\nPrize: X=7090, Y=6422\n\nButton A: X+28, Y+70\nButton B: X+68, Y+21\nPrize: X=17176, Y=3693\n\nButton A: X+33, Y+16\nButton B: X+27, Y+51\nPrize: X=1884, Y=2771\n\nButton A: X+11, Y+43\nButton B: X+51, Y+19\nPrize: X=4114, Y=10066\n\nButton A: X+26, Y+70\nButton B: X+87, Y+46\nPrize: X=3532, Y=6874\n\nButton A: X+22, Y+35\nButton B: X+38, Y+13\nPrize: X=7508, Y=16592\n\nButton A: X+33, Y+16\nButton B: X+48, Y+72\nPrize: X=12065, Y=15896\n\nButton A: X+67, Y+25\nButton B: X+14, Y+55\nPrize: X=4093, Y=10275\n\nButton A: X+36, Y+17\nButton B: X+43, Y+77\nPrize: X=3253, Y=1933\n\nButton A: X+84, Y+24\nButton B: X+42, Y+69\nPrize: X=8862, Y=4869\n\nButton A: X+70, Y+16\nButton B: X+17, Y+68\nPrize: X=5690, Y=3224\n\nButton A: X+58, Y+27\nButton B: X+44, Y+92\nPrize: X=1890, Y=1595\n\nButton A: X+64, Y+30\nButton B: X+29, Y+57\nPrize: X=15004, Y=15224\n\nButton A: X+13, Y+90\nButton B: X+64, Y+33\nPrize: X=6560, Y=6048\n\nButton A: X+37, Y+91\nButton B: X+64, Y+49\nPrize: X=5214, Y=8379\n\nButton A: X+12, Y+80\nButton B: X+75, Y+25\nPrize: X=6684, Y=8460\n\nButton A: X+27, Y+53\nButton B: X+53, Y+30\nPrize: X=4897, Y=14148\n\nButton A: X+41, Y+11\nButton B: X+39, Y+72\nPrize: X=2818, Y=493\n\nButton A: X+74, Y+45\nButton B: X+14, Y+35\nPrize: X=8996, Y=13510\n\nButton A: X+11, Y+36\nButton B: X+86, Y+58\nPrize: X=18273, Y=14722\n\nButton A: X+99, Y+72\nButton B: X+11, Y+39\nPrize: X=2530, Y=3390\n\nButton A: X+55, Y+17\nButton B: X+22, Y+80\nPrize: X=3652, Y=6326\n\nButton A: X+11, Y+17\nButton B: X+76, Y+16\nPrize: X=5480, Y=1976\n\nButton A: X+18, Y+73\nButton B: X+28, Y+22\nPrize: X=3222, Y=4827\n\nButton A: X+14, Y+46\nButton B: X+33, Y+29\nPrize: X=2212, Y=3932\n\nButton A: X+11, Y+14\nButton B: X+80, Y+28\nPrize: X=4187, Y=2450\n\nButton A: X+28, Y+70\nButton B: X+78, Y+25\nPrize: X=2220, Y=1810\n\nButton A: X+53, Y+19\nButton B: X+73, Y+91\nPrize: X=4514, Y=2850\n\nButton A: X+21, Y+54\nButton B: X+54, Y+25\nPrize: X=5609, Y=7594\n\nButton A: X+79, Y+15\nButton B: X+16, Y+80\nPrize: X=14993, Y=17105\n\nButton A: X+20, Y+59\nButton B: X+35, Y+17\nPrize: X=10820, Y=1709\n\nButton A: X+96, Y+22\nButton B: X+24, Y+43\n" <> ...}
+
```
+
+
```elixir
+
#puzzle_input =
+
"""
+
Button A: X+94, Y+34
+
Button B: X+22, Y+67
+
Prize: X=8400, Y=5400
+
+
Button A: X+26, Y+66
+
Button B: X+67, Y+21
+
Prize: X=12748, Y=12176
+
+
Button A: X+17, Y+86
+
Button B: X+84, Y+37
+
Prize: X=7870, Y=6450
+
+
Button A: X+69, Y+23
+
Button B: X+27, Y+71
+
Prize: X=18641, Y=10279
+
"""
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
warning: outdented heredoc line. The contents inside the heredoc should be indented at the same level as the closing """. The following is forbidden:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
Instead make sure the contents are indented as much as the heredoc closing:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
The current heredoc line is indented too little
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day13.livemd#cell:b6uoz4dag7jywljr:3:3
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
"Button A: X+94, Y+34\nButton B: X+22, Y+67\nPrize: X=8400, Y=5400\n\nButton A: X+26, Y+66\nButton B: X+67, Y+21\nPrize: X=12748, Y=12176\n\nButton A: X+17, Y+86\nButton B: X+84, Y+37\nPrize: X=7870, Y=6450\n\nButton A: X+69, Y+23\nButton B: X+27, Y+71\nPrize: X=18641, Y=10279\n"
+
```
+
+
```elixir
+
games =
+
puzzle_input
+
|> String.split("\n\n", trim: true)
+
|> Enum.map(fn game ->
+
[
+
"Button A: X+" <> <<ax::2-binary>> <> ", Y+" <> <<ay::2-binary>>,
+
"Button B: X+" <> <<bx::2-binary>> <> ", Y+" <> <<by::2-binary>>,
+
"Prize: " <> prize_pos
+
] = String.split(game, "\n", trim: true)
+
+
["X=" <> px, "Y=" <> py] = String.split(prize_pos, ", ")
+
+
%{
+
btn_a: {String.to_integer(ax), String.to_integer(ay)},
+
btn_b: {String.to_integer(bx), String.to_integer(by)},
+
prize: {String.to_integer(px), String.to_integer(py)}
+
}
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
%{btn_a: {22, 88}, btn_b: {90, 28}, prize: {6496, 3076}},
+
%{btn_a: {54, 14}, btn_b: {14, 44}, prize: {8084, 1284}},
+
%{btn_a: {96, 15}, btn_b: {55, 63}, prize: {5535, 3966}},
+
%{btn_a: {17, 42}, btn_b: {40, 25}, prize: {12176, 3136}},
+
%{btn_a: {87, 31}, btn_b: {15, 36}, prize: {6672, 2500}},
+
%{btn_a: {59, 27}, btn_b: {21, 56}, prize: {1475, 15098}},
+
%{btn_a: {39, 51}, btn_b: {98, 14}, prize: {7890, 3126}},
+
%{btn_a: {23, 37}, btn_b: {35, 14}, prize: {16537, 6184}},
+
%{btn_a: {21, 89}, btn_b: {74, 23}, prize: {2407, 8748}},
+
%{btn_a: {47, 17}, btn_b: {35, 59}, prize: {17994, 16242}},
+
%{btn_a: {14, 45}, btn_b: {52, 16}, prize: {18768, 3912}},
+
%{btn_a: {29, 45}, btn_b: {85, 11}, prize: {3149, 4161}},
+
%{btn_a: {81, 95}, btn_b: {67, 12}, prize: {5489, 2110}},
+
%{btn_a: {48, 58}, btn_b: {86, 22}, prize: {4802, 2280}},
+
%{btn_a: {27, 59}, btn_b: {47, 15}, prize: {2602, 2090}},
+
%{btn_a: {39, 87}, btn_b: {94, 38}, prize: {8830, 6134}},
+
%{btn_a: {23, 61}, btn_b: {82, 16}, prize: {8405, 3957}},
+
%{btn_a: {54, 14}, btn_b: {24, 63}, prize: {894, 1708}},
+
%{btn_a: {26, 14}, btn_b: {18, 35}, prize: {5510, 12541}},
+
%{btn_a: {65, 55}, btn_b: {21, 69}, prize: {430, 620}},
+
%{btn_a: {11, 62}, btn_b: {50, 11}, prize: {11414, 3683}},
+
%{btn_a: {21, 54}, btn_b: {93, 22}, prize: {7683, 5642}},
+
%{btn_a: {20, 95}, btn_b: {52, 29}, prize: {5580, 10155}},
+
%{btn_a: {37, 13}, btn_b: {11, 66}, prize: {18250, 14983}},
+
%{btn_a: {54, 28}, btn_b: {37, 58}, prize: {17939, 14902}},
+
%{btn_a: {87, 65}, btn_b: {11, 79}, prize: {3765, 4087}},
+
%{btn_a: {74, 30}, btn_b: {16, 59}, prize: {9858, 8342}},
+
%{btn_a: {74, 31}, btn_b: {17, 59}, prize: {14764, 6598}},
+
%{btn_a: {12, 95}, btn_b: {27, 33}, prize: {945, 3324}},
+
%{btn_a: {21, 36}, btn_b: {34, 14}, prize: {7247, 5012}},
+
%{btn_a: {48, 62}, btn_b: {90, 29}, prize: {9150, 5973}},
+
%{btn_a: {93, 43}, btn_b: {49, 91}, prize: {7090, 6422}},
+
%{btn_a: {28, 70}, btn_b: {68, 21}, prize: {17176, 3693}},
+
%{btn_a: {33, 16}, btn_b: {27, 51}, prize: {1884, 2771}},
+
%{btn_a: {11, 43}, btn_b: {51, 19}, prize: {4114, 10066}},
+
%{btn_a: {26, 70}, btn_b: {87, 46}, prize: {3532, 6874}},
+
%{btn_a: {22, 35}, btn_b: {38, 13}, prize: {7508, 16592}},
+
%{btn_a: {33, 16}, btn_b: {48, 72}, prize: {12065, 15896}},
+
%{btn_a: {67, 25}, btn_b: {14, 55}, prize: {4093, 10275}},
+
%{btn_a: {36, 17}, btn_b: {43, 77}, prize: {3253, 1933}},
+
%{btn_a: {84, 24}, btn_b: {42, 69}, prize: {8862, 4869}},
+
%{btn_a: {70, 16}, btn_b: {17, 68}, prize: {5690, 3224}},
+
%{btn_a: {58, 27}, btn_b: {44, 92}, prize: {1890, 1595}},
+
%{btn_a: {64, 30}, btn_b: {29, 57}, prize: {15004, 15224}},
+
%{btn_a: {13, 90}, btn_b: {64, 33}, prize: {6560, 6048}},
+
%{btn_a: {37, 91}, btn_b: {64, 49}, prize: {5214, ...}},
+
%{btn_a: {12, 80}, btn_b: {75, ...}, prize: {...}},
+
%{btn_a: {27, ...}, btn_b: {...}, ...},
+
%{btn_a: {...}, ...},
+
%{...},
+
...
+
]
+
```
+
+
Yay, matrices again. We need to solve linear equations in form of:
+
+
$$
+
\begin{cases}
+
a_x x & + & b_x y & = & p_x \\
+
a_y x & + & b_x y & = & p_y
+
\end{cases}
+
$$
+
+
So we need to solve:
+
+
$$
+
\begin{bmatrix}
+
a_x & b_x \\
+
a_y & b_y
+
\end{bmatrix}
+
\begin{bmatrix}
+
x \\
+
y
+
\end{bmatrix}
+
= \begin{bmatrix}
+
p_x \\
+
p_y
+
\end{bmatrix}
+
$$
+
+
For each game. So we can use [Cramer's Rule](https://en.wikipedia.org/wiki/Cramer%27s_rule).
+
+
$$
+
\begin{gather*}
+
x = \frac{\text{det}(A_x)}{\text{det}(A)} \\
+
y = \frac{\text{det}(A_y)}{\text{det}(A)}
+
\end{gather*}
+
$$
+
+
Assuming that $\text{det}(A) \ne 0$ (otherwise there will be no solution). In case of $2\times2$ matrices determinant is simple to compute:
+
+
$$
+
\text{det}
+
\begin{vmatrix}
+
a & b \\
+
c & d
+
\end{vmatrix}
+
= ad - bc
+
$$
+
+
So in the end we need to compute:
+
+
$$
+
\begin{gather*}
+
x = \frac{p_x b_y - b_x p_y}{a_x b_y - b_x a_y} \\
+
y = \frac{a_x p_y - p_x a_y}{a_x b_y - b_x a_y}
+
\end{gather*}
+
$$
+
+
And reject cases where $x$ or $y$ is non-integer value.
+
+
```elixir
+
defmodule Game do
+
def solve(%{btn_a: {ax, ay}, btn_b: {bx, by}, prize: {px, py}}) do
+
det_a = ax * by - bx * ay
+
det_x = px * by - bx * py
+
det_y = ax * py - px * ay
+
+
if rem(det_x, det_a) == 0 do
+
{div(det_x, det_a), div(det_y, det_a)}
+
end
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Game, <<70, 79, 82, 49, 0, 0, 8, ...>>, {:solve, 1}}
+
```
+
+
## Part 1
+
+
```elixir
+
games
+
|> Enum.map(&Game.solve/1)
+
|> Enum.map(fn
+
nil -> 0
+
{a, b} -> a * 3 + b * 1
+
end)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
31897
+
```
+
+
## Part 2
+
+
```elixir
+
games
+
|> Enum.map(fn %{prize: {px, py}} = game ->
+
add = 10_000_000_000_000
+
%{game | prize: {px + add, py + add}}
+
end)
+
|> Enum.map(&Game.solve/1)
+
|> Enum.map(fn
+
nil -> 0
+
{a, b} -> a * 3 + b * 1
+
end)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
87596249540359
+
```
+
+
<!-- livebook:{"offset":11449,"stamp":{"token":"XCP.AhVykQ8wyKxhTI29dXZZ0BnWEqWCuVGz8E2TRFpScgbUfqJJtY47yrvU9g9OzcejZVc8LbU3ak4YrgSGy5A5XeARPC3qt5fGPV4K9PYS3YabI7-q8rCKi8R6ZpGBpmZeDNQ","version":2}} -->
+219
2024/day14.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 14
+
+
```elixir
+
Mix.install([:kino_aoc, :image])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxNCIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "14", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"p=49,14 v=-82,-41\np=27,80 v=67,31\np=76,93 v=-15,-66\np=90,62 v=-84,86\np=62,86 v=46,20\np=7,72 v=25,26\np=30,32 v=-92,60\np=91,40 v=6,1\np=50,58 v=57,-21\np=71,79 v=-3,58\np=84,44 v=36,-59\np=87,12 v=-62,-95\np=69,46 v=76,39\np=50,51 v=-26,-64\np=41,58 v=30,5\np=80,97 v=-13,9\np=52,84 v=98,-50\np=52,32 v=64,39\np=52,91 v=61,20\np=31,22 v=49,45\np=85,73 v=-43,32\np=77,15 v=20,-52\np=17,10 v=74,-3\np=88,92 v=-54,26\np=20,46 v=31,-63\np=42,49 v=-26,44\np=3,101 v=40,-95\np=78,77 v=-17,48\np=10,88 v=-88,55\np=100,68 v=74,76\np=42,11 v=-97,-25\np=88,57 v=-37,93\np=11,36 v=-33,54\np=88,61 v=-58,43\np=66,47 v=-55,82\np=11,52 v=52,-60\np=9,48 v=41,-64\np=70,57 v=61,27\np=22,80 v=11,11\np=73,11 v=65,56\np=79,84 v=-28,41\np=50,79 v=-93,-12\np=55,35 v=23,-64\np=48,26 v=45,29\np=38,23 v=-86,-54\np=71,48 v=-21,6\np=60,98 v=28,-54\np=75,70 v=59,7\np=24,71 v=-20,-46\np=55,88 v=79,-23\np=13,48 v=44,49\np=37,73 v=-86,-99\np=82,12 v=-26,80\np=13,16 v=-8,30\np=86,34 v=84,99\np=45,90 v=-31,68\np=23,93 v=44,8\np=3,52 v=-65,-54\np=64,7 v=16,-30\np=97,88 v=-67,-39\np=58,87 v=72,42\np=8,70 v=-27,5\np=25,67 v=99,22\np=48,92 v=19,31\np=23,46 v=-16,-76\np=13,101 v=70,13\np=55,4 v=-25,-39\np=44,10 v=10,-59\np=56,2 v=83,67\np=90,83 v=28,42\np=28,84 v=7,-12\np=49,87 v=-7,-50\np=11,56 v=-76,87\np=27,72 v=46,-28\np=76,43 v=-59,32\np=19,50 v=80,62\np=12,1 v=44,-84\np=53,29 v=83,61\np=57,12 v=-63,-90\np=67,39 v=38,71\np=38,78 v=86,26\np=14,19 v=-72,-85\np=75,9 v=42,-43\np=89,33 v=65,-43\np=77,21 v=-64,54\np=32,72 v=-45,-71\np=9,21 v=55,-4\np=22,49 v=70,-71\np=86,73 v=-35,-7\np=32,5 v=-41,-62\np=14,51 v=89,-92\np=71,34 v=24,-69\np=87,18 v=69,-10\np=58,67 v=4,-28\np=22,75 v=15,26\np=73,14 v=-77,24\np=2,26 v=-12,91\np=53,3 v=38,-57\np=49,35 v=-37,-59\np=25,87 v=52,-83\np=47,74 v=46,-22\np=70,22 v=-81,24\np=46,57 v=23,-76\np=59,96 v=27,-40\np=72,77 v=99,28\np=66,89 v=61,-67\np=46,43 v=70,-23\np=30,55 v=-67,48\np=8,75 v=89,-17\np=15,29 v=-86,-3\np=53,2 v=38,-56\np=6,90 v=55,-83\np=44,83 v=8,-50\np=2,56 v=-54,-43\np=30,13 v=19,-62\np=21,97 v=-78,-46\np=13,53 v=70,22\np=2,5 v=59,56\np=2,48 v=18,50\np=81,94 v=92,57\np=1,1 v=6,-59\np=99,61 v=-65,-76\np=99,95 v=-24,35\np=17,53 v=-84,19\np=33,77 v=-4,53\np=100,32 v=-3,-43\np=60,74 v=-10,97\np=23,54 v=-57,-75\np=56,69 v=27,21\np=58,100 v=-51,44\np=43,77 v=-41,-93\np=75,3 v=80,13\np=66,32 v=72,34\np=67,67 v=-32,69\np=80,80 v=-23,-3\np=62,23 v=-4,48\np=77,0 v=87,30\np=2,96 v=-35,-73\np=15,4 v=4,-38\np=92,56 v=-54,-16\np=90,46 v=26,-16\np=75,2 v=1,67\np=59,71 v=-59,-33\np=79,21 v=-62,24\np=34,99 v=45,14\np=49,18 v=-37,-76\np=63,26 v=79,-41\np=97,54 v=-80,71\np=66,18 v=69,-30\np=14,25 v=74,-90\np=9,95 v=-87,96\np=24,39 v=-8,83\np=32,98 v=-75,79\np=36,50 v=-23,-92\np=97,36 v=-73,86\np=66,36 v=23,-53\np=84,3 v=2,95\np=89,73 v=48,26\np=3,94 v=-46,68\np=61,75 v=-52,-98\np=51,36 v=8,50\np=70,48 v=80,-2\np=32,39 v=-54,4\np=73,85 v=-92,-72\np=22,70 v=-12,38\np=92,48 v=-92,93\np=100,79 v=-76,-12\np=1,52 v=-43,65\np=22,98 v=78,52\np=35,76 v=-97,48\np=52,14 v=-48,-74\np=7,55 v=29,98\np=79,40 v=-2,-38\np=90,91 v=57,-72\np=60,3 v=-14,-94\np=34,69 v=-56,32\np=63,19 v=-44,24\np=48,71 v=-18,-98\np=90,42 v=-87,9\np=73,59 v=27,-28\np=30,66 v=18,-48\np=9,54 v=-79,-43\np=57,73 v=-73,-34\np=75,93 v=-39,60\np=31,75 v=-98,86\np=93,86 v=-95,-45\np=64,33 v=33,4\np=62,27 v=12,46\np=76,93 v=91,58\np=92,23 v=-13,29\np=54,93 v=69,51\np=19,53 v=59,-16\np=78,90 v=84,-7\np=17,93 v=33,25\np=100,73 v=5,59\np=74,39 v=80,28\np=88,4 v=84,19\np=63,98 v=-65,-2\np=81,98 v=32,4\np=64,89 v=-7,9\np=88,3 v=-35,9\np=77,14 v=-62,-79\np=15,15 v=18,-41\np=40,4 v=41,-24\np=14,68 v=89,-98\np=77,71 v=-14,97\np=69,28 v=1,-9\np=16,102 v=-87,52\np=26,20 v=-62,15\np=100,25 v=28,-37\np=22,63 v=93,-5\np=9,47 v=77,-47\np=78,36 v=76,-95\np=41,84 v=52,63\np=14,6 v=30,-88\np=99,72 v=59,42\np=72,45 v=7,-21\np=99,71 v=-20,-98\np=30,40 v=-6,82\np=75,50 v=-99,97\np=91,80 v=8,44\np=7,44 v=52,-91\np=96,12 v=-50,-74\np=72,48 v=-88,-33\np=21,7 v=-29,-3\np=96,38 v=2,-48\np=33,22 v=86,-36\np=79,84 v=-36,-77\np=87,65 v=2,48\np=46,42 v=98,-11\np=60,79 v=80,-27\np=95,3 v=-2,-94\np=94,75 v=88,-29\np=16,66 v=-24,48\np=83,51 v=-24,-64\np=54,94 v=-10,-7\np=0,96 v=-8,-96\np=4,50 v=-31,71\np=21,98 v=-66,-4\np=50,85 v=-48,69\np=71,14 v=5,67\np=19,56 v=71,6\np=18,43 v=-16,-49\np=11,25 v=18,45\np=38,90 v=-52,-34\np=50,9 v=-89,73\np=15,23 v=" <> ...}
+
```
+
+
```elixir
+
robots =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn row ->
+
["p=" <> pos, "v=" <> v] = String.split(row, " ")
+
+
pos = pos |> String.split(",") |> Enum.map(&String.to_integer/1) |> List.to_tuple()
+
v = v |> String.split(",") |> Enum.map(&String.to_integer/1) |> List.to_tuple()
+
+
%{pos: pos, v: v}
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
%{pos: {49, 14}, v: {-82, -41}},
+
%{pos: {27, 80}, v: {67, 31}},
+
%{pos: {76, 93}, v: {-15, -66}},
+
%{pos: {90, 62}, v: {-84, 86}},
+
%{pos: {62, 86}, v: {46, 20}},
+
%{pos: {7, 72}, v: {25, 26}},
+
%{pos: {30, 32}, v: {-92, 60}},
+
%{pos: {91, 40}, v: {6, 1}},
+
%{pos: {50, 58}, v: {57, -21}},
+
%{pos: {71, 79}, v: {-3, 58}},
+
%{pos: {84, 44}, v: {36, -59}},
+
%{pos: {87, 12}, v: {-62, -95}},
+
%{pos: {69, 46}, v: {76, 39}},
+
%{pos: {50, 51}, v: {-26, -64}},
+
%{pos: {41, 58}, v: {30, 5}},
+
%{pos: {80, 97}, v: {-13, 9}},
+
%{pos: {52, 84}, v: {98, -50}},
+
%{pos: {52, 32}, v: {64, 39}},
+
%{pos: {52, 91}, v: {61, 20}},
+
%{pos: {31, 22}, v: {49, 45}},
+
%{pos: {85, 73}, v: {-43, 32}},
+
%{pos: {77, 15}, v: {20, -52}},
+
%{pos: {17, 10}, v: {74, -3}},
+
%{pos: {88, 92}, v: {-54, 26}},
+
%{pos: {20, 46}, v: {31, -63}},
+
%{pos: {42, 49}, v: {-26, 44}},
+
%{pos: {3, 101}, v: {40, -95}},
+
%{pos: {78, 77}, v: {-17, 48}},
+
%{pos: {10, 88}, v: {-88, 55}},
+
%{pos: {100, 68}, v: {74, 76}},
+
%{pos: {42, 11}, v: {-97, -25}},
+
%{pos: {88, 57}, v: {-37, 93}},
+
%{pos: {11, 36}, v: {-33, 54}},
+
%{pos: {88, 61}, v: {-58, 43}},
+
%{pos: {66, 47}, v: {-55, 82}},
+
%{pos: {11, 52}, v: {52, -60}},
+
%{pos: {9, 48}, v: {41, -64}},
+
%{pos: {70, 57}, v: {61, 27}},
+
%{pos: {22, 80}, v: {11, 11}},
+
%{pos: {73, 11}, v: {65, 56}},
+
%{pos: {79, 84}, v: {-28, 41}},
+
%{pos: {50, 79}, v: {-93, -12}},
+
%{pos: {55, 35}, v: {23, -64}},
+
%{pos: {48, 26}, v: {45, 29}},
+
%{pos: {38, 23}, v: {-86, -54}},
+
%{pos: {71, 48}, v: {-21, 6}},
+
%{pos: {60, 98}, v: {28, ...}},
+
%{pos: {75, ...}, v: {...}},
+
%{pos: {...}, ...},
+
%{...},
+
...
+
]
+
```
+
+
```elixir
+
room = {w, h} = {101, 103}
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{101, 103}
+
```
+
+
```elixir
+
defmodule Robot do
+
def walk(robots, room, n \\ 1), do: Enum.map(robots, &move(&1, room, n))
+
+
def move(%{pos: {x, y}, v: {vx, vy}}, {w, h}, by \\ 1) do
+
x = Integer.mod(x + vx * by, w)
+
y = Integer.mod(y + vy * by, h)
+
+
%{pos: {x, y}, v: {vx, vy}}
+
end
+
+
def quad(%{pos: {x, y}}, {w, h}) do
+
hw = div(w - 1, 2)
+
hh = div(h - 1, 2)
+
+
if x == hw or y == hh do
+
:middle
+
else
+
{sign(x - hw), sign(y - hh)}
+
end
+
end
+
+
defp sign(0), do: 0
+
defp sign(n) when n < 0, do: -1
+
defp sign(n) when n > 0, do: 1
+
+
def with_neighbours(robots) do
+
set = MapSet.new(robots, & &1.pos)
+
+
with_neighbours =
+
Enum.count(robots, fn %{pos: {x, y}} ->
+
[{x + 1, y}, {x - 1, y}, {x, y - 1}, {x, y + 1}] |> Enum.any?(&(&1 in set))
+
end)
+
+
div(with_neighbours * 100, length(robots))
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Robot, <<70, 79, 82, 49, 0, 0, 18, ...>>, {:with_neighbours, 1}}
+
```
+
+
## Part 1
+
+
```elixir
+
robots
+
|> Robot.walk(room, 100)
+
|> Enum.group_by(fn robot -> Robot.quad(robot, room) end)
+
|> Map.new(fn {k, l} -> {k, length(l)} end)
+
|> Map.drop([:middle])
+
|> Map.values()
+
|> Enum.product()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
219150360
+
```
+
+
## Part 2
+
+
Hack that I have found over the internet - if more than 60% of the robots have neighbours, you have found solution.
+
+
Othe hack that I have found - checking whether there are no robots that are occupying the same position - didn't work for me.
+
+
```elixir
+
{tree, steps} =
+
Stream.from_index()
+
|> Task.async_stream(
+
fn step ->
+
robots = Robot.walk(robots, room, step)
+
+
if Robot.with_neighbours(robots) >= 60, do: {robots, step}
+
end,
+
ordered: false
+
)
+
|> Enum.find_value(fn {:ok, val} -> val end)
+
+
steps
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
8053
+
```
+
+
```elixir
+
Image.new!(w, h)
+
|> Image.mutate(fn img ->
+
for %{pos: {x, y}} <- tree do
+
# Add some festivity
+
color =
+
if abs(:math.sin(x + y)) < 0.5 do
+
:red
+
else
+
:green
+
end
+
+
Image.Draw.point(img, x, y, color: color)
+
end
+
+
{:ok, img}
+
end)
+
|> elem(1)
+
|> Image.resize!(4, interpolate: :nearest)
+
```
+
+
<!-- livebook:{"offset":9213,"stamp":{"token":"XCP.bbViODF6Z4_TcNSzpaXWzuFflurdyZ5JsvKHJZr6NjgJ4MQaH2OorTxA-YR5uDBN5HxiB0uC5hX0vi-Kgdm26HMcOubYpE_c39bjuPfPH_BH4SVxLeEac5c8aaRtPdt7CJk","version":2}} -->
+395
2024/day15.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 15
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxNSIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "15", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"##################################################\n##...O...#OO...O.#....#....#O#O..O..O......O..O..#\n#OOOO.#.O.O.....OO#...O.OO.O....O.#..OO....O#OOO.#\n#...#.#O..O...OO......O.......#....O..O#.O..OO...#\n#.O.....O..#.........O......OO..O..OO.OO....O.O..#\n#.....O.OO.O.#.O...O..#.OOOO..#...#.O.OO.O.#.#OO##\n#...OO.#..O.O.#.O..OO..O....O...OO.OOO.......O...#\n##.O.....O..#O...........O..O.....O.......OO.....#\n#...O..O....O...O...O...O..O..O...O......O..OO...#\n#.O##.O.OO.....O.O.#....O#.....OO.O.O.#..O....#O.#\n#.............#.O........OOO.OO..#.............O.#\n#OOO..O.O.........OO....O.#......#.OO.......O..O.#\n#.......#...O..#O.OO...O..#O.O...##O#O......O##..#\n#O#.O..#........O....O.....O...#O..#......O.O..O.#\n#O..O..O#...#.......OO.OO..O.....O..O..O.O.O...O.#\n#...O.O...OO.......#O#O...O.##.....#..O.O.....O..#\n#.#OOOO..OO..O....O.O....OO.#.OO..O.......O....#.#\n#..O...#.....#.....OO..#O....O#.O....O..OOO.O...O#\n#.O.......OO.O.#........OO...O..O#..O.#..##...#.O#\n#.O..#..........OO.O.O..O..O.......O...O.O.OO....#\n#.O..##..........OO..O..O.....#OO#...#..O....O...#\n#O.OOOO.O..O........O#.#OO.OO...OO.#OO..OO#O.....#\n#..OO..........O...O....O.O.....O.....O...#..O..O#\n#.#O..O..O.....#.O...#........O.O.O..O.......#.O.#\n#..##..O.....O......O..O@........O....O#.O..OO..O#\n#...O..##O.#....#.......O..OO#..O.O.....##O....O.#\n#....O.O...O.OOO.O.O#..O..OOOOOOOOOO#.....O...#.O#\n#O.....#O..O..#..O....O.O..OOOO.#.O.O#....#.O.O#.#\n#..O.O..#O..............O....###..O#.O.....O.#O#O#\n#O...O.O.#.#..O......OO.OO#..O...O.O....O#.O...OO#\n#..OO.O#.....O##.O##....O..#..#..#O..O.....#....O#\n#....#..O..O....O.OO...O.......OO.OO...O.O.....O.#\n#....O.O.#O.#OO.......O......O........OOO..O.....#\n#..#...##.O......##.....O..O.O#.O...O....O..#.O..#\n#...O.O..O....O..O.OOOOOO...#.O...OO.#.....OO.O..#\n#O.......O....#.OO.OO...OO...##O......O.O........#\n##.O.OO.OO...O..O#......O.O....#.............O.#.#\n#O#O...O..O..OO.O.O...OO..O.O..OOOO..O..O...O..O.#\n#..OO.O#O..O..#.O..O.#...#..O.....OO..OOO..O...O.#\n#.O.O..OO.....O...O.....O..#..O..#.O.#.OOO...O.O.#\n#.O..O.......O...OO#.#..O....O...O....O..........#\n#....O..O.OO...OO..#....#O.OO.OO##.....O.........#\n#..O..O....O...O....OO#.#O..O.#.#O.O..O...#....O.#\n#.O.....O.#.O#.O..O.OO.O#............O..........O#\n#..O#O.O.........O.#.O#O..#O.O.........O....O..O.#\n#..O.....#OO..O..#.#.#....O.O.OO.O.O......O#.#O..#\n#.O.O..O.O.O.O...O..O..OO..................#OO...#\n#..O....O....O.....OOO...OO..OO.......O....OO....#\n#.O....OO.O................OO....O.O#O.O.........#\n##################################################\n\n>v>>>^>>v>vv^v^^v^^^<v^vv^vv<<>^v^^^<<<vv<>vv^^>v>v^^><>^<v<v><>>^>^<^^v>v<>^^v<><<^><v>v^v<<^>^>^>^>>vvv>^<<^^^^^><vv>>^>^^>^vv>><v^^v^<<<>^^<<<^^^vv^<^<<<>v<^v<v>^<>v<^>>^v^<>><><<^<>v>^>^>v>>v>vv^><v<v^v>vv>><^^<<>>vv<<^vv>^^vv>>><^v^>>v<<<<v>^<><>^>v^vv>v>><><^vvv>^><<>^<<<vvv^>^vv<<>v^^^>v<>^^vv>vv^<>^<>vvv<vvvv^^^<^vv^<v^<<vv^v<><vvvv^>vv<>><><<v>><^>v<>v<v<v>^v>^<>^v>>><^>>v<<<v^>^v>v>^^>^v<v^v^^<vv^v^><<^^<v^v>>^v>>>>>v<v^>^>^v^>vv^v^><^<v>^^<>^v^>><>>><vv<<>^v<^vvv<v^vvv^>v<<v>>^>><<^v^^v>^^>^<<<>v^^>><<v>^<v^<^>v>>>^^^<<vvv^>vvv>^><v>^>vvv^^^v^^>v^><v>><>^<v<<vv^^>>^^v>><vv>vvv>^>>>vv^><^<v<<<^^v>v^<v^^>^^<<<>v^vv<vvv>^v>v<^^>vv>v<>>vv<><v>v<^^<<^>>v<v^<>^<<v>><<vv^<<<<v^^^v^^<^<^<>v><^<>>v>v>v>v>v><v>>v<<^>>><v^v<v>>v^><^v^>>>^>^<<>>^^v><^<v^vv^<><>>v^^>v<vvv>v<>><<<<<>><<><v<>vv><^^^><vv<v<<>v^>v>>^^v^v^>vvv<v^<>><<<^>vvv><^^v>v<>v><^<v>v<^<<^<>v>>>>^<>^^^>v<v<<vv><v>>>^<^>v^><vv>^<<v<>><<^<>>>^v>><<>v^^v<^>v^v^>vvvv>vv<<>^^^<v>^<<v>>><<>>>vv^<^><><^^^>^v^<><>^<vv<^vv^^v>^<\n<^>vv>v>^^>^vvvv<<^><^<>>^<v>v>>^^<v><^<>><<<>^vv<>v<v^>>>^<<^<><<>^^vv^^<<><<vvv>v^^>vv^<v<<>>v><^>v^>>^^v<<<<^v<v<<>>v><v^>vv^<vv^>^v>^^>>><>v<><^v><vvvv^v<<>>^^v><>>vv^>v>v^>^>v<><^v>v^^<<>^v^>^>v<><^v<^^vv<>^^^v^>>><<><<<<v^v^><v<v<^^^><><^<<^^^vv<^^<^<v>v<<v^>>v<>>^<vv<^<v><>^<^v^>^v>>>^v>>v^>^^v^>><<v>>^<v>^vvv<v<<<v>^<>vv<^<v<>^<>v^v^>vv^v>><^>><>^^^<<v<vv^<vv>>v<^^^>vv<^^>vv^^^^<<^<v^>v<v>vvv<v<<^^><v<<^>^^<>v>>v><^v^<v>vv^<v<<v>v>vvv^>v<vv>>>>>^^v<<>^><>v^^^>^^>^>^^vvvv^v<v>>^^^v>>^<v<^^v>>><<>^^><<<^>v^^^v><v<v<v^v^><>^>v<v<^^^>" <> ...}
+
```
+
+
```elixir
+
#puzzle_input =
+
"""
+
##########
+
#..O..O.O#
+
#......O.#
+
#.OO..O.O#
+
#..O@..O.#
+
#O#..O...#
+
#O..O..O.#
+
#.OO.O.OO#
+
#....O...#
+
##########
+
+
<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^
+
vvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v
+
><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<
+
<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^
+
^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><
+
^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^
+
>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^
+
<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>
+
^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>
+
v^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^
+
"""
+
+
#puzzle_input =
+
"""
+
########
+
#..O.O.#
+
##@.O..#
+
#...O..#
+
#.#.O..#
+
#...O..#
+
#......#
+
########
+
+
<^^>>>vv<v>>v<<
+
"""
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
warning: outdented heredoc line. The contents inside the heredoc should be indented at the same level as the closing """. The following is forbidden:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
Instead make sure the contents are indented as much as the heredoc closing:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
The current heredoc line is indented too little
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day15.livemd#cell:7w6bq5lw7vctw7mk:3:3
+
+
warning: outdented heredoc line. The contents inside the heredoc should be indented at the same level as the closing """. The following is forbidden:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
Instead make sure the contents are indented as much as the heredoc closing:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
The current heredoc line is indented too little
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day15.livemd#cell:7w6bq5lw7vctw7mk:28:3
+
+
warning: code block contains unused literal "##########\n#..O..O.O#\n#......O.#\n#.OO..O.O#\n#..O@..O.#\n#O#..O...#\n#O..O..O.#\n#.OO.O.OO#\n#....O...#\n##########\n\n<vv>^<v^>v>^vv^v>v<>v^v<v<^vv<<<^><<><>>v<vvv<>^v^>^<<<><<v<<<v^vv^v>^\nvvv<<^>^v^^><<>>><>^<<><^vv^^<>vvv<>><^^v>^>vv<>v<<<<v<^v>^<^^>>>^<v<v\n><>vv>v^v^<>><>>>><^^>vv>v<^^^>>v^v^<^^>v^^>v^<^v>v<>>v^v^<v>v^^<^^vv<\n<<v<^>>^^^^>>>v^<>vvv^><v<<<>^^^vv^<vvv>^>v<^^^^v<>^>vvvv><>>v^<<^^^^^\n^><^><>>><>^^<<^^v>>><^<v>^<vv>>v>>>^v><>^v><<<<v>>v<v<v>vvv>^<><<>^><\n^>><>^v<><^vvv<^^<><v<<<<<><^v<<<><<<^^<v<^^^><^>>^<v^><<<^>>^v<v^v<v^\n>^>>^v>vv>^<<^v<>><<><<v<<v><>v<^vv<<<>^^v^>^^>>><<^v>>v^v><^^>>^<>vv^\n<><^^>^^^<><vvvvv^v<v<<>^v<v>v<<^><<><<><<<^^<<<^<<>><<><^^^>^^<>^>v<>\n^^>vv<^v^v<vv>^<><v<^v>^^^>>>^^vvv^>vvv<>>>^<^>>>>>^<<^v>^vvv<>^<><<v>\nv^^>>><<^^<>>^v^<v^vv<>v^<<>^<^v^v><^<<<><<^<v><v<>vv>>v><v^<vv<>v^<<^\n" (remove the literal or assign it to _ to avoid warnings)
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day15.livemd#cell:7w6bq5lw7vctw7mk:1
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
"########\n#..O.O.#\n##@.O..#\n#...O..#\n#.#.O..#\n#...O..#\n#......#\n########\n\n<^^>>>vv<v>>v<<\n"
+
```
+
+
```elixir
+
[map, moves] = String.split(puzzle_input, "\n\n")
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
["##################################################\n##...O...#OO...O.#....#....#O#O..O..O......O..O..#\n#OOOO.#.O.O.....OO#...O.OO.O....O.#..OO....O#OOO.#\n#...#.#O..O...OO......O.......#....O..O#.O..OO...#\n#.O.....O..#.........O......OO..O..OO.OO....O.O..#\n#.....O.OO.O.#.O...O..#.OOOO..#...#.O.OO.O.#.#OO##\n#...OO.#..O.O.#.O..OO..O....O...OO.OOO.......O...#\n##.O.....O..#O...........O..O.....O.......OO.....#\n#...O..O....O...O...O...O..O..O...O......O..OO...#\n#.O##.O.OO.....O.O.#....O#.....OO.O.O.#..O....#O.#\n#.............#.O........OOO.OO..#.............O.#\n#OOO..O.O.........OO....O.#......#.OO.......O..O.#\n#.......#...O..#O.OO...O..#O.O...##O#O......O##..#\n#O#.O..#........O....O.....O...#O..#......O.O..O.#\n#O..O..O#...#.......OO.OO..O.....O..O..O.O.O...O.#\n#...O.O...OO.......#O#O...O.##.....#..O.O.....O..#\n#.#OOOO..OO..O....O.O....OO.#.OO..O.......O....#.#\n#..O...#.....#.....OO..#O....O#.O....O..OOO.O...O#\n#.O.......OO.O.#........OO...O..O#..O.#..##...#.O#\n#.O..#..........OO.O.O..O..O.......O...O.O.OO....#\n#.O..##..........OO..O..O.....#OO#...#..O....O...#\n#O.OOOO.O..O........O#.#OO.OO...OO.#OO..OO#O.....#\n#..OO..........O...O....O.O.....O.....O...#..O..O#\n#.#O..O..O.....#.O...#........O.O.O..O.......#.O.#\n#..##..O.....O......O..O@........O....O#.O..OO..O#\n#...O..##O.#....#.......O..OO#..O.O.....##O....O.#\n#....O.O...O.OOO.O.O#..O..OOOOOOOOOO#.....O...#.O#\n#O.....#O..O..#..O....O.O..OOOO.#.O.O#....#.O.O#.#\n#..O.O..#O..............O....###..O#.O.....O.#O#O#\n#O...O.O.#.#..O......OO.OO#..O...O.O....O#.O...OO#\n#..OO.O#.....O##.O##....O..#..#..#O..O.....#....O#\n#....#..O..O....O.OO...O.......OO.OO...O.O.....O.#\n#....O.O.#O.#OO.......O......O........OOO..O.....#\n#..#...##.O......##.....O..O.O#.O...O....O..#.O..#\n#...O.O..O....O..O.OOOOOO...#.O...OO.#.....OO.O..#\n#O.......O....#.OO.OO...OO...##O......O.O........#\n##.O.OO.OO...O..O#......O.O....#.............O.#.#\n#O#O...O..O..OO.O.O...OO..O.O..OOOO..O..O...O..O.#\n#..OO.O#O..O..#.O..O.#...#..O.....OO..OOO..O...O.#\n#.O.O..OO.....O...O.....O..#..O..#.O.#.OOO...O.O.#\n#.O..O.......O...OO#.#..O....O...O....O..........#\n#....O..O.OO...OO..#....#O.OO.OO##.....O.........#\n#..O..O....O...O....OO#.#O..O.#.#O.O..O...#....O.#\n#.O.....O.#.O#.O..O.OO.O#............O..........O#\n#..O#O.O.........O.#.O#O..#O.O.........O....O..O.#\n#..O.....#OO..O..#.#.#....O.O.OO.O.O......O#.#O..#\n#.O.O..O.O.O.O...O..O..OO..................#OO...#\n#..O....O....O.....OOO...OO..OO.......O....OO....#\n#.O....OO.O................OO....O.O#O.O.........#\n##################################################",
+
">v>>>^>>v>vv^v^^v^^^<v^vv^vv<<>^v^^^<<<vv<>vv^^>v>v^^><>^<v<v><>>^>^<^^v>v<>^^v<><<^><v>v^v<<^>^>^>^>>vvv>^<<^^^^^><vv>>^>^^>^vv>><v^^v^<<<>^^<<<^^^vv^<^<<<>v<^v<v>^<>v<^>>^v^<>><><<^<>v>^>^>v>>v>vv^><v<v^v>vv>><^^<<>>vv<<^vv>^^vv>>><^v^>>v<<<<v>^<><>^>v^vv>v>><><^vvv>^><<>^<<<vvv^>^vv<<>v^^^>v<>^^vv>vv^<>^<>vvv<vvvv^^^<^vv^<v^<<vv^v<><vvvv^>vv<>><><<v>><^>v<>v<v<v>^v>^<>^v>>><^>>v<<<v^>^v>v>^^>^v<v^v^^<vv^v^><<^^<v^v>>^v>>>>>v<v^>^>^v^>vv^v^><^<v>^^<>^v^>><>>><vv<<>^v<^vvv<v^vvv^>v<<v>>^>><<^v^^v>^^>^<<<>v^^>><<v>^<v^<^>v>>>^^^<<vvv^>vvv>^><v>^>vvv^^^v^^>v^><v>><>^<v<<vv^^>>^^v>><vv>vvv>^>>>vv^><^<v<<<^^v>v^<v^^>^^<<<>v^vv<vvv>^v>v<^^>vv>v<>>vv<><v>v<^^<<^>>v<v^<>^<<v>><<vv^<<<<v^^^v^^<^<^<>v><^<>>v>v>v>v>v><v>>v<<^>>><v^v<v>>v^><^v^>>>^>^<<>>^^v><^<v^vv^<><>>v^^>v<vvv>v<>><<<<<>><<><v<>vv><^^^><vv<v<<>v^>v>>^^v^v^>vvv<v^<>><<<^>vvv><^^v>v<>v><^<v>v<^<<^<>v>>>>^<>^^^>v<v<<vv><v>>>^<^>v^><vv>^<<v<>><<^<>>>^v>><<>v^^v<^>v^v^>vvvv>vv<<>^^^<v>^<<v>>><<>>>vv^<^><><^^^>^v^<><>^<vv<^vv^^v>^<\n<^>vv>v>^^>^vvvv<<^><^<>>^<v>v>>^^<v><^<>><<<>^vv<>v<v^>>>^<<^<><<>^^vv^^<<><<vvv>v^^>vv^<v<<>>v><^>v^>>^^v<<<<^v<v<<>>v><v^>vv^<vv^>^v>^^>>><>v<><^v><vvvv^v<<>>^^v><>>vv^>v>v^>^>v<><^v>v^^<<>^v^>^>v<><^v<^^vv<>^^^v^>>><<><<<<v^v^><v<v<^^^><><^<<^^^vv<^^<^<v>v<<v^>>v<>>^<vv<^<v><>^<^v^>^v>>>^v>>v^>^^v^>><<v>>^<v>^vvv<v<<<v>^<>vv<^<v<>^<>v^v^>vv^v>><^>><>^^^<<v<vv^<vv>>v<^^^>vv<^^>vv^^^^<<^<v^>v<v>vvv<v<<^^><v<<^>^^<>v>>v><^v^<v>vv^<v<<v>v>vvv^>v<vv>>>>>^^v<<>^><>v^^^>^^>^>^^vvvv^v<v>>^^^v>>^<v<^^v>>><<>^^><<<^>v^^^v><v<v<v^v^><>^>v<v<^^^>>>vv><<^>><v>><<v<<vv><^^^<<^<>v>^v^v><<<<<<>>vv^<<<><<><><<^<^>^<v<^v>>>^>v^>^v>^v^<^>^v>><<<v>v^^vvv><<^>v^^<><v^>><<v><^^>>v<<<<<^>>><><vv>v<<>>^v<><<^>>v<<<^<^>>^>v^>^v<v>^v>>v<^>><<>><>vvv<<>vv^>v>><><<^><vvv>v><^>^<^v><>>v><v><^v^vv><>^^>>>v<^v^<^v>^v><vv<<v<<v><>>><v<vv<>>v^^>>>vv><v<<<<><v^^>>v>^<v^^>^v<<<><v>v>>^^<vv<v^v>><^<^^<>><v>^<^^<><^^^><>^<v^^^<v<^>>^v>vv^^<^v>><<vv><<v>><v>>>^>>><<<v<<><^vvv^<v>^>vvv^v>>v><<>v><<v<vvvvv^>^>><v^>vv^>>^\nvvv^v^><<v<>><><><<<^v>^v^><>^vvv<<^<<v^v<>>v<v^^>>^>v<v>^v<v^v>^<<vvv<^^v<<<<>v^v<<<v<^>><v^vv^vvvv^v><><v<<^>v>v^v^<v<v<^<><^>^vv<^^v<^^>vv<<>^^<>><<<<^^>>>^<^^>vv<>>>^^^^vv^>^v^v^^>^<<<>v^<v>^^^>v<^^<<^<v><^vvv>v>v>v<^>><^<^<>>>^^<<<vv^>>><>>v><>^<>^^<v^><<vv>vv^v<<>^>v><vvv>v^>>v^^^v<<>>^v><^<>^>^<^>^^<vv<>>><v^v^>>>^^>>^v^^^>>^v>v><^^^v<>>vv>>v^^<><^^v>v<^>>v<v^v^v^v^vv^vvv>v^vv>^v>vv<vv<^<<<v^v><<v>v<<^>vvv^^^^>>^>v>^^<>vv<>^^v><v<<^v><><><^<vv^>v^^>>>^^vv>^v>^<>vvv^v<^vv^<<^<^^<>>^<<><vv^>^>^^v^<v><v^>><^^>><<><<<<<<^>^><^v>^v>><v><v<>vvv>^^<^<<>v>>vv<v<><^<<^<>v<v>><><>^v><v<^^^<>>vvv>^^>>>v><v><^^>><<^<v><<^<v<<vv>>^vv<>v>^><><<<<<v>>>v^^v>^<>^<>v^^>>^<>>v^>^<>>>><>><v^v>>v>^<<^v^><<>>^v>><>><>>>><>vv<<>>^>v^v^<vvvvvvv^>v<<<^^<>vvvv^<<><<v^<<vv^^^v^^<<><v>v^^<^^v^^<>^v<>vvv>>^^v^^^<v>v^^vv<^^^<<>^v^>>^^<<^^v^^v<<vv^<<>>>v<>vv<v^v<<>vvv>^<v>v>^v<^^v<>^>^<><<v>v<>v^>v^v>><<><v><>>>>v^<^<^><>^v^<^><<v<^v><>>^v^^^v^><>^v>v<<^v>>^<<v<>v<^<<<<>>^><<<vv<^v^<^>^^><^^vvv^><v<><^^<>^v^>\nvvvv^vv^>>^v^v<^<vvv<>v>v>vv>^>^><^vv><v^v>v<><>v^v^>vvvv<<>v<^^^vv<^v><>^>^>v<>^>^vvv<>^>^<^^v^<><<>^>^v><v>^v>v^<v^<>>^^>^>v^>v>>^^<v><^<^vv>^vv^v^>v><^vv>^>v>^><>v>v^^>>v>^<<v^<vvv>>v<v>v^^<>^v^vv^<^^<v>>>v>>^v>vvv^^v^>v<vvv^<><v>v>v<>^^v^^<vv<>v<vvv>>><><<>>v>^^<^^^^><v>^>v<^<^>v^^>v>^>>^><<<^vv>vv^v^><v^<v>vv>^<>^vvvv^>vv>^>v^>v<<v^^<v^<v>>vvv<<v<>>>v^>^vv>^<v<>>^^v<vv<^>v<>^<<^^><>^^v>^v>>^<v>vv^v<<^^>^<v<><v>vv<><vv<>>v<^^^><<^^>^v<>vv<v>><<<v><<>>vv^>>^vvvv^><<v<vv^v<vv<>v<><v<<><v>vvv>>vv^^^<><^v<><v<^<v<v<^>>vv<><<>^^>><<v><^>vvv^>^vvv<>v^^<<^<vv>>v>^>v>^^><<>v<v^>^<<<<vv<<^^^>^>^>v<>>vv^><v<><<><^><><^^vv>>^<^vv<^^v<><<><>vvvv^^^<>v>>v^<vvv<v<vv><<v^v<v>>^v^<<^>>vvvv^v<<^<^vv<v<v>^v<^<^^>vv<v^^^>>^<^><^^v<v^v^>^^^v^v>^>^><^>>^v<v<^^^v^>>^v>vv>^v<>^v^^^v^v^>v>><^^<^v<<v<^v<>v^<>^<>^v<v^^v<^>v<v>^v<<><<<>^v><<<^>vvvvv^v^^^<<v>>v^>>^^<<v^^>vv^^vvvv>^>v^<<<^<>v><<^>^v^<^>><<<v<vv>vv<<^>^<^^><>>^^v>vvv^<^>^^^^<^v<<>^<>^>>v>^<><><>>^^vv^<<>><^<v><>^v^vvv<<>>^<>^>v<<^><<^>^<^>^<<><\n<<^<^>><<<vv>v<v<^<>>>v^>vv><>>vvvv<<^><<<>v<>v^v^<>v>v<^^<<v<vv^<<<vv>^<>^^vv<><v<<^v^v<^<v" <> ...]
+
```
+
+
```elixir
+
%{robot: [robot], wall: walls, box: boxes} =
+
map
+
|> String.split("\n", trim: true)
+
|> Enum.with_index()
+
|> Enum.flat_map(fn {row, y} ->
+
row
+
|> String.to_charlist()
+
|> Enum.with_index()
+
|> Enum.reject(fn {kind, _} -> kind == ?. end)
+
|> Enum.map(fn {kind, x} ->
+
kind =
+
case kind do
+
?# -> :wall
+
?O -> :box
+
?@ -> :robot
+
end
+
+
{{x, y}, kind}
+
end)
+
end)
+
|> Enum.group_by(&elem(&1, 1), &elem(&1, 0))
+
+
walls = MapSet.new(walls)
+
boxes = MapSet.new(boxes)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
MapSet.new([
+
{38, 2},
+
{29, 26},
+
{9, 34},
+
{47, 38},
+
{47, 44},
+
{22, 37},
+
{19, 38},
+
{27, 21},
+
{19, 22},
+
{16, 10},
+
{16, 38},
+
{35, 26},
+
{10, 32},
+
{36, 14},
+
{28, 48},
+
{17, 30},
+
{32, 18},
+
{40, 35},
+
{6, 23},
+
{28, 37},
+
{29, 47},
+
{29, 40},
+
{29, 10},
+
{6, 42},
+
{23, 46},
+
{10, 33},
+
{4, 46},
+
{43, 47},
+
{12, 8},
+
{3, 16},
+
{15, 3},
+
{20, 46},
+
{33, 48},
+
{35, 6},
+
{41, 9},
+
{25, 29},
+
{1, 2},
+
{3, 30},
+
{8, 5},
+
{18, 37},
+
{37, 43},
+
{3, 47},
+
{30, 26},
+
{41, 31},
+
{4, 15},
+
{33, 40},
+
{6, 21},
+
{5, 26},
+
{1, ...},
+
{...},
+
...
+
])
+
```
+
+
```elixir
+
moves = moves |> String.to_charlist() |> Enum.reject(& &1 not in ~c"^>v<")
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
~c">v>>>^>>v>vv^v^^v^^^<v^vv^vv<<>^v^^^<<<vv<>vv^^>v>v^^><>^<v<v><>>^>^<^^v>v<>^^v<><<^><v>v^v<<^>^>^>^>>vvv>^<<^^^^^><vv>>^>^^>^vv>><v^^v^<<<>^^<<<^^^vv^<^<<<>v<^v<v>^<>v<^>>^v^<>><><<^<>v>^>^>v>>v>vv^><v<v^v>vv>><^^<<>>vv<<^vv>^^vv>>><^v^>>v<<<<v>^<><>^>v^vv>v>><><^vvv>^><<>^<<<vvv^>^vv<<>v^^^>v<>^^vv>vv^<>^<>vvv<vvvv^^^<^vv^<v^<<vv^v<><vvvv^>vv<>><><<v>><^>v<>v<v<v>^v>^<>^v>>><^>>v<<<v^>^v>v>^^>^v<v^v^^<vv^v^><<^^<v^v>>^v>>>>>v<v^>^>^v^>vv^v^><^<v>^^<>^v^>><>>><vv<<>^v<^vvv<v^vvv^>v<<v>>^>><<^v^^v>^^>^<<<>v^^>><<v>^<v^<^>v>>>^^^<<vvv^>vvv>^><v>^>vvv^^^v^^>v^><v>><>^<v<<vv^^>>^^v>><vv>vvv>^>>>vv^><^<v<<<^^v>v^<v^^>^^<<<>v^vv<vvv>^v>v<^^>vv>v<>>vv<><v>v<^^<<^>>v<v^<>^<<v>><<vv^<<<<v^^^v^^<^<^<>v><^<>>v>v>v>v>v><v>>v<<^>>><v^v<v>>v^><^v^>>>^>^<<>>^^v><^<v^vv^<><>>v^^>v<vvv>v<>><<<<<>><<><v<>vv><^^^><vv<v<<>v^>v>>^^v^v^>vvv<v^<>><<<^>vvv><^^v>v<>v><^<v>v<^<<^<>v>>>>^<>^^^>v<v<<vv><v>>>^<^>v^><vv>^<<v<>><<^<>>>^v>><<>v^^v<^>v^v^>vvvv>vv<<>^^^<v>^<<v>>><<>>>vv^<^><><^^^>^v^<><>^<vv<^vv^^v>^<<^>vv>v>^^>^vvvv<<^><^<>>^<v>v>>^^<v><^<>><<<>^vv<>v<v^>>>^<<^<><<>^^vv^^<<><<vvv>v^^>vv^<v<<>>v><^>v^>>^^v<<<<^v<v<<>>v><v^>vv^<vv^>^v>^^>>><>v<><^v><vvvv^v<<>>^^v><>>vv^>v>v^>^>v<><^v>v^^<<>^v^>^>v<><^v<^^vv<>^^^v^>>><<><<<<v^v^><v<v<^^^><><^<<^^^vv<^^<^<v>v<<v^>>v<>>^<vv<^<v><>^<^v^>^v>>>^v>>v^>^^v^>><<v>>^<v>^vvv<v<<<v>^<>vv<^<v<>^<>v^v^>vv^v>><^>><>^^^<<v<vv^<vv>>v<^^^>vv<^^>vv^^^^<<^<v^>v<v>vvv<v<<^^><v<<^>^^<>v>>v><^v^<v>vv^<v<<v>v>vvv^>v<vv>>>>>^^v<<>^><>v^^^>^^>^>^^vvvv^v<v>>^^^v>>^<v<^^v>>><<>^^><<<^>v^^^v><v<v<v^v^><>^>v<v<^^^>>>vv><<^>><v>><<v<<vv><^^^<<^<>v>^v^v><<<<<<>>vv^<<<><<><><<^<^>^<v<^v>>>^>v^>^v>^v^<^>^v>><<<v>v^^vvv><<^>v^^<><v^>><<v><^^>>v<<<<<^>>><><vv>v<<>>^v<><<^>>v<<<^<^>>^>v^>^v<v>^v>>v<^>><<>><>vvv<<>vv^>v>><><<^><vvv>v><^>^<^v><>>v><v><^v^vv><>^^>>>v<^v^<^v>^v><vv<<v<<v><>>><v<vv<>>v^^>>>vv><v<<<<><v^^>>v>^<v^^>^v<<<><v>v>>^^<vv<v^v>><^<^^<>><v>^<^^<><^^^><>^<v^^^<v<^>>^v>vv^^<^v>><<vv><<v>><v>>>^>>><<<v<<><^vvv^<v>^>vvv^v>>v><<>v><<v<vvvvv^>^>><v^>vv^>>^vvv^v^><<v<>><><><<<^v>^v^><>^vvv<<^<<v^v<>>v<v^^>>^>v<v>^v<v^v>^<<vvv<^^v<<<<>v^v<<<v<^>><v^vv^vvvv^v><><v<<^>v>v^v^<v<v<^<><^>^vv<^^v<^^>vv<<>^^<>><<<<^^>>>^<^^>vv<>>>^^^^vv^>^v^v^^>^<<<>v^<v>^^^>v<^^<<^<v><^vvv>v>v>v<^>><^<^<>>>^^<<<vv^>>><>>v><>^<>^^<v^><<vv>vv^v<<>^>v><vvv>v^>>v^^^v<<>>^v><^<>^>^<^>^^<vv<>>><v^v^>>>^^>>^v^^^>>^v>v><^^^v<>>vv>>v^^<><^^v>v<^>>v<v^v^v^v^vv^vvv>v^vv>^v>vv<vv<^<<<v^v><<v>v<<^>vvv^^^^>>^>v>^^<>vv<>^^v><v<<^v><><><^<vv^>v^^>>>^^vv>^v>^<>vvv^v<^vv^<<^<^^<>>^<<><vv^>^>^^v^<v><v^>><^^>><<><<<<<<^>^><^v>^v>><v><v<>vvv>^^<^<<>v>>vv<v<><^<<^<>v<v>><><>^v><v<^^^<>>vvv>^^>>>v><v><^^>><<^<v><<^<v<<vv>>^vv<>v>^><><<<<<v>>>v^^v>^<>^<>v^^>>^<>>v^>^<>>>><>><v^v>>v>^<<^v^><<>>^v>><>><>>>><>vv<<>>^>v^v^<vvvvvvv^>v<<<^^<>vvvv^<<><<v^<<vv^^^v^^<<><v>v^^<^^v^^<>^v<>vvv>>^^v^^^<v>v^^vv<^^^<<>^v^>>^^<<^^v^^v<<vv^<<>>>v<>vv<v^v<<>vvv>^<v>v>^v<^^v<>^>^<><<v>v<>v^>v^v>><<><v><>>>>v^<^<^><>^v^<^><<v<^v><>>^v^^^v^><>^v>v<<^v>>^<<v<>v<^<<<<>>^><<<vv<^v^<^>^^><^^vvv^><v<><^^<>^v^>vvvv^vv^>>^v^v<^<vvv<>v>v>vv>^>^><^vv><v^v>v<><>v^v^>vvvv<<>v<^^^vv<^v><>^>^>v<>^>^vvv<>^>^<^^v^<><<>^>^v><v>^v>v^<v^<>>^^>^>v^>v>>^^<v><^<^vv>^vv^v^>v><^vv>^>v>^><>v>v^^>>v>^<<v^<vvv>>v<v>v^^<>^v^vv^<^^<v>>>v>>^v>vvv^^v^>v<vvv^<><v>v>v<>^^v^^<vv<>v<vvv>>><><<>>v>^^<^^^^><v>^>v<^<^>v^^>v>^>>^><<<^vv>vv^v^><v^<v>vv>^<>^vvvv^>vv>^>v^>v<<v^^<v^<v>>vvv<<v<>>>v^>^vv>^<v<>>^^v<vv<^>v<>^<<^^><>^^v>^v>>^<v>vv^v<<^^>^<v<><v>vv<><vv<>>v<^^^><<^^>^v<>vv<v>><<<v><<>>vv^>>^vvvv^><<v<vv^v<vv<>v<><v<<><v>vvv>>vv^^^<><^v<><v<^<v<v<^>>vv<><<>^^>><<v><^>vvv^>^vvv<>v^^<<^<vv>>v>^>v>^^><<>v<v^>^<<<<vv<<^^^>^>^>v<>>vv^><v<><<><^><><^^vv>>^<^vv<^^v<><<><>vvvv^^^<>v>>v^<vvv<v<vv><<v^v<v>>^v^<<^>>vvvv^v<<^<^vv<v<v>^v<^<^^>vv<v^^^>>^<^><^^v<v^v^>^^^v^v>^>^><^>>^v<v<^^^v^>>^v>vv>^v<>^v^^^v^v^>v>><^^<^v<<v<^v<>v^<>^<>^v<v^^v<^>v<v>^v<<><<<>^v><<<^>vvvvv^v^^^<<v>>v^>>^^<<v^^>vv^^vvvv>^>v^<<<^<>v><<^>^v^<^>><<<v<vv>vv<<^>^<^^><>>^^v>vvv^<^>^^^^<^v<<>^<>^>>v>^<><><>>^^vv^<<>><^<v><>^v^vvv<<>>^<>^>v<<^><<^>^<^>^<<><<<^<^>><<<vv>v<v<^<>>>v^>vv><>>vvvv<<^><<<>v<>v^v^<>v>v<^^<<v<vv^<<<vv>^<>^^vv<><v<<^v^v<^<v>>vv" ++ ...
+
```
+
+
## Part 1
+
+
```elixir
+
defmodule Warehouse.A do
+
def walk(start, path, walls, boxes) do
+
Enum.reduce(path, {start, boxes}, fn dir, {pos, boxes} ->
+
move(pos, walls, boxes, dir)
+
end)
+
|> elem(1)
+
end
+
+
def move({x, y}, walls, boxes, dir) do
+
next = next({x, y}, dir)
+
+
cond do
+
next in walls ->
+
{{x, y}, boxes}
+
+
next in boxes ->
+
if new_boxes = move_box(next, boxes, walls, dir) do
+
{next, new_boxes}
+
else
+
{{x, y}, boxes}
+
end
+
+
true ->
+
{next, boxes}
+
end
+
end
+
+
defp move_box(pos, boxes, walls, dir) do
+
next = next(pos, dir)
+
cond do
+
next in walls -> nil
+
+
next in boxes ->
+
if new_boxes = move_box(next, boxes, walls, dir) do
+
new_boxes |> MapSet.delete(pos) |> MapSet.put(next)
+
end
+
+
true ->
+
boxes |> MapSet.delete(pos) |> MapSet.put(next)
+
end
+
end
+
+
defp next({x, y}, ?^), do: {x, y - 1}
+
defp next({x, y}, ?>), do: {x + 1, y}
+
defp next({x, y}, ?v), do: {x, y + 1}
+
defp next({x, y}, ?<), do: {x - 1, y}
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Warehouse.A, <<70, 79, 82, 49, 0, 0, 14, ...>>, {:next, 2}}
+
```
+
+
```elixir
+
robot
+
|> Warehouse.A.walk(moves, walls, boxes)
+
|> Enum.map(fn {x, y} -> x + y * 100 end)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1406628
+
```
+
+
## Part 2
+
+
```elixir
+
defmodule Warehouse.B do
+
def resize({x, y}, walls, boxes) do
+
start = {2 * x, y}
+
+
walls =
+
walls
+
|> Enum.flat_map(fn {x, y} ->
+
[{2 * x, y}, {2 * x + 1, y}]
+
end)
+
|> MapSet.new()
+
+
boxes =
+
boxes
+
|> Enum.flat_map(fn {x, y} ->
+
pos = [{2 * x, y}, {2 * x + 1, y}]
+
box = %{p: pos}
+
+
for p <- pos do
+
{p, box}
+
end
+
end)
+
+
{start, walls, boxes}
+
end
+
+
def walk(start, path, walls, boxes) do
+
Enum.reduce(path, {start, boxes}, fn dir, {pos, boxes} ->
+
move(pos, walls, boxes, dir)
+
end)
+
|> elem(1)
+
end
+
+
def move({x, y}, walls, boxes, dir) do
+
next = next({x, y}, dir)
+
+
cond do
+
next in walls ->
+
{{x, y}, boxes}
+
+
box = boxes[next] ->
+
if new_boxes = move_box(box, boxes, walls, dir) do
+
{next, new_boxes}
+
else
+
{{x, y}, boxes}
+
end
+
+
true ->
+
{next, boxes}
+
end
+
end
+
+
defp move_box(%{p: pos}, boxes, walls, dir) do
+
next = next(pos, dir)
+
+
cond do
+
Enum.any?(pos, & &1 in walls) ->
+
throw(:wall)
+
+
(next_boxes = select_boxes_at(pos, boxes)) != [] ->
+
if new_boxes = move_box(next, boxes, walls, dir) do
+
new_boxes |> MapSet.delete(pos) |> MapSet.put(next)
+
end
+
+
true ->
+
boxes |> Map.drop(pos) |> MapSet.put(next)
+
end
+
catch
+
:throw, :wall -> nil
+
end
+
+
defp select_boxes_at(pos, boxes) do
+
boxes
+
|> Map.take(pos)
+
|> Enum.uniq()
+
end
+
+
defp next({x, y}, ?^), do: {x, y - 1}
+
defp next({x, y}, ?>), do: {x + 1, y}
+
defp next({x, y}, ?v), do: {x, y + 1}
+
defp next({x, y}, ?<), do: {x - 1, y}
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
warning: variable "next_boxes" is unused (if the variable is not meant to be used, prefix it with an underscore)
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day15.livemd#cell:3ajets4kgmkyknvu:59: Warehouse.B.move_box/4
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Warehouse.B, <<70, 79, 82, 49, 0, 0, 20, ...>>, {:next, 2}}
+
```
+
+
<!-- livebook:{"offset":23559,"stamp":{"token":"XCP.GtnzBtRKuk3dCuG1gVPqYVHJwR27FPAQixvDel9XY7YKKtIR-fLOYjYE9q5s_RDyt_V8hQtSWHWE0pTlg7ukiaTmklnlkowdbH-y0AJ21EtpRoXXQ3C48_7vRp_64BdLpHY","version":2}} -->
+303
2024/day16.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 16
+
+
```elixir
+
Mix.install([:kino_aoc, :image])
+
```
+
+
## Setup
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxNiIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "16", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"#############################################################################################################################################\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#.#.#########.#######.#.#.#.###.###.###.#.###########.###.#.###.#.###.#.###.#####.#.#########.#.#.###.#.#.###.#.#.#.#.#." <> ...}
+
```
+
+
```elixir
+
%{?# => walls, ?S => [start], ?E => [finish]} =
+
puzzle_input
+
|> String.trim()
+
|> String.split("\n", trim: true)
+
|> Enum.with_index()
+
|> Enum.flat_map(fn {row, y} ->
+
row
+
|> String.trim()
+
|> String.to_charlist()
+
|> Enum.with_index()
+
|> Enum.map(fn {char, x} ->
+
{{x, y}, char}
+
end)
+
end)
+
|> Enum.group_by(&elem(&1, 1), &elem(&1, 0))
+
+
walls = MapSet.new(walls)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
MapSet.new([
+
{76, 13},
+
{112, 138},
+
{38, 2},
+
{124, 56},
+
{83, 76},
+
{140, 11},
+
{100, 134},
+
{75, 140},
+
{103, 106},
+
{68, 134},
+
{124, 60},
+
{35, 30},
+
{2, 132},
+
{8, 50},
+
{78, 98},
+
{101, 62},
+
{98, 136},
+
{95, 56},
+
{74, 12},
+
{102, 74},
+
{22, 38},
+
{14, 86},
+
{12, 135},
+
{86, 10},
+
{29, 26},
+
{4, 81},
+
{31, 42},
+
{9, 34},
+
{137, 16},
+
{86, 138},
+
{90, 0},
+
{14, 122},
+
{120, 42},
+
{102, 57},
+
{84, 102},
+
{138, 124},
+
{0, 101},
+
{116, 96},
+
{54, 138},
+
{18, 134},
+
{82, 60},
+
{15, 92},
+
{58, 58},
+
{78, 75},
+
{75, 0},
+
{16, 73},
+
{76, 2},
+
{58, 84},
+
{138, ...},
+
{...},
+
...
+
])
+
```
+
+
```elixir
+
{_, {w, h}} = Enum.min_max(walls)
+
+
w = w + 1
+
h = h + 1
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
141
+
```
+
+
```elixir
+
put_in(%{}, [Access.key(:a, %{}), :b], 10)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{a: %{b: 10}}
+
```
+
+
```elixir
+
defmodule Race.B do
+
@turns ~w'^ > v <'a
+
+
defguardp score(elements, pos, dir) when :erlang.map_get({pos, dir}, elements).score
+
+
def search_paths(start, finish, dir \\ :>, walls) when dir in @turns do
+
result = do_search([{0, [{start, dir}]}], walls, %{})
+
+
%{paths: visited, score: score} = result[{finish, :>}]
+
+
all = get_all(visited, result)
+
+
{score, all}
+
end
+
+
def get_all(path, seen) do
+
Enum.reduce(path, MapSet.new(), fn p, acc ->
+
path = MapSet.new(seen[p].paths, fn {p, _} -> p end)
+
MapSet.union(acc, path)
+
end)
+
end
+
+
def do_search([], _, visited), do: visited
+
+
def do_search([{cost, [{curr, dir} | _] = path} | rest], walls, visited)
+
when cost == score(visited, curr, dir) do
+
visited = Map.update!(visited, {curr, dir}, &%{&1 | paths: path})
+
+
do_search(rest, walls, visited)
+
end
+
+
def do_search([{cost, [{curr, prev} | _] = path} | rest], walls, visited)
+
when not is_map_key(visited, {curr, prev})
+
when cost < score(visited, curr, prev) do
+
visited = Map.put(visited, {curr, prev}, %{score: cost, paths: path})
+
+
@turns
+
|> Enum.map(fn dir -> {cost + cost(prev, dir), [{step(curr, dir), dir} | path]} end)
+
|> Enum.reject(fn {_cost, [{pos, _} | _]} -> pos in walls end)
+
|> sort_merge(rest)
+
|> do_search(walls, visited)
+
end
+
+
def do_search([{_, [_curr | _]} | rest], walls, visited),
+
do: do_search(rest, walls, visited)
+
+
# Going straight is cheap and turning is costly
+
defp cost(a, a), do: 1
+
defp cost(_, _), do: 1001
+
+
defp step({x, y}, :^), do: {x, y - 1}
+
defp step({x, y}, :>), do: {x + 1, y}
+
defp step({x, y}, :v), do: {x, y + 1}
+
defp step({x, y}, :<), do: {x - 1, y}
+
+
defp sort_merge([], bs), do: bs
+
defp sort_merge(as, []), do: as
+
+
defp sort_merge([a | as], [b | bs]) do
+
if a < b do
+
[a | sort_merge(as, [b | bs])]
+
else
+
[b | sort_merge([a | as], bs)]
+
end
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Race.B, <<70, 79, 82, 49, 0, 0, 23, ...>>, {:sort_merge, 2}}
+
```
+
+
```elixir
+
{score, paths} = Race.B.search_paths(start, finish, walls)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{134588,
+
MapSet.new([
+
{77, 129},
+
{17, 138},
+
{17, 137},
+
{37, 139},
+
{19, 137},
+
{100, 131},
+
{139, 68},
+
{14, 139},
+
{79, 128},
+
{19, 138},
+
{50, 137},
+
{139, 67},
+
{137, 104},
+
{137, 117},
+
{131, 49},
+
{107, 125},
+
{3, 127},
+
{135, 64},
+
{4, 131},
+
{21, 134},
+
{63, 127},
+
{101, 124},
+
{5, 139},
+
{125, 14},
+
{129, 48},
+
{139, 70},
+
{21, 119},
+
{17, 129},
+
{137, 120},
+
{17, 136},
+
{131, 120},
+
{32, 139},
+
{133, 21},
+
{102, 123},
+
{12, 111},
+
{123, 19},
+
{112, 127},
+
{73, 129},
+
{7, 116},
+
{127, 22},
+
{7, 137},
+
{9, 131},
+
{24, 133},
+
{137, 95},
+
{8, 133},
+
{134, 7},
+
{129, ...},
+
{...},
+
...
+
])}
+
```
+
+
## Part 1
+
+
```elixir
+
score
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
134588
+
```
+
+
```elixir
+
Image.new!(w, h)
+
|> Image.mutate(fn img ->
+
for {x, y} <- walls do
+
Image.Draw.point(img, x, y, color: [128, 0, 0])
+
end
+
+
for {x, y} <- paths do
+
Image.Draw.point(img, x, y, color: [0, 255, 0])
+
end
+
+
img
+
end)
+
|> elem(1)
+
|> Image.resize!(6, interpolate: :nearest)
+
```
+
+
## Part 2
+
+
```elixir
+
MapSet.size(paths)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
625
+
```
+
+
<!-- livebook:{"offset":9337,"stamp":{"token":"XCP.AVI7h-Nq9jZKx9YmL5qYerJkeKKqddhzKrKUkab-HwNDUM8nQItD1O_rd2ROsJxc96gwIzwrMAixlIdLeZAgOVhtCs22LZM44Wl1VwcpYbg3RNCdgwIjqGheO5YrCGrEGJc","version":2}} -->
+206
2024/day17.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 17
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxNyIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "17", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"Register A: 66245665\nRegister B: 0\nRegister C: 0\n\nProgram: 2,4,1,7,7,5,1,7,4,6,0,3,5,5,3,0"}
+
```
+
+
```elixir
+
defmodule Computer do
+
@instructions ~w[adv bxl bst jnz bxc out bdv cdv]a
+
|> Enum.with_index()
+
|> Map.new(fn {name, ins} -> {ins, name} end)
+
+
def load(opcodes) do
+
opcodes
+
|> Enum.chunk_every(2)
+
|> Enum.map(fn [opcode, op] ->
+
{@instructions[opcode], op}
+
end)
+
|> List.to_tuple()
+
end
+
+
def process(program, reg) do
+
reg = Map.merge(%{a: 0, b: 0, c: 0}, Map.new(reg))
+
do_process(program, 0, reg, [])
+
end
+
+
defp do_process(program, idx, _reg, out) when idx >= tuple_size(program) do
+
Enum.reverse(out)
+
end
+
+
defp do_process(program, idx, reg, out) do
+
ins = elem(program, idx)
+
+
case compute(ins, reg) do
+
new_reg when is_map(new_reg) ->
+
do_process(program, idx + 1, new_reg, out)
+
+
{:out, op} ->
+
do_process(program, idx + 1, reg, [op | out])
+
+
{:jump, op} ->
+
do_process(program, op, reg, out)
+
end
+
end
+
+
def compute({:adv, op}, reg),
+
do: %{reg | a: div(reg.a, 2 ** combo(op, reg))}
+
+
def compute({:bdv, op}, reg),
+
do: %{reg | b: div(reg.a, 2 ** combo(op, reg))}
+
+
def compute({:cdv, op}, reg),
+
do: %{reg | c: div(reg.a, 2 ** combo(op, reg))}
+
+
def compute({:bxl, op}, reg),
+
do: %{reg | b: Bitwise.bxor(reg.b, op)}
+
+
def compute({:bxc, _op}, reg),
+
do: %{reg | b: Bitwise.bxor(reg.b, reg.c)}
+
+
def compute({:bst, op}, reg),
+
do: %{reg | b: Bitwise.band(combo(op, reg), 0b111)}
+
+
def compute({:out, op}, reg),
+
do: {:out, Bitwise.band(combo(op, reg), 0b111)}
+
+
def compute({:jnz, op}, reg) do
+
if reg.a != 0 do
+
{:jump, op}
+
else
+
reg
+
end
+
end
+
+
defp combo(v, _) when v in 0..3, do: v
+
defp combo(4, %{a: a}), do: a
+
defp combo(5, %{b: b}), do: b
+
defp combo(6, %{c: c}), do: c
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Computer, <<70, 79, 82, 49, 0, 0, 21, ...>>, {:combo, 2}}
+
```
+
+
```elixir
+
[
+
"Register A: " <> a,
+
"Register B: " <> b,
+
"Register C: " <> c,
+
"Program: " <> raw_code
+
] = String.split(puzzle_input, "\n", trim: true)
+
+
reg = %{
+
a: String.to_integer(a),
+
b: String.to_integer(b),
+
c: String.to_integer(c)
+
} |> dbg()
+
+
code =
+
raw_code
+
|> String.split(",")
+
|> Enum.map(&String.to_integer/1)
+
+
program = Computer.load(code)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{a: 66245665, b: 0, c: 0}
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{{:bst, 4}, {:bxl, 7}, {:cdv, 5}, {:bxl, 7}, {:bxc, 6}, {:adv, 3}, {:out, 5}, {:jnz, 0}}
+
```
+
+
## Part 1
+
+
```elixir
+
out = Computer.process(program, reg)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[1, 4, 6, 1, 6, 4, 3, 0, 3]
+
```
+
+
```elixir
+
IO.puts(Enum.join(out, ","))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1,4,6,1,6,4,3,0,3
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
:ok
+
```
+
+
## Part 2
+
+
```elixir
+
defmodule Quine do
+
def find(program, target) do
+
do_find(program, Enum.reverse(target), Enum.to_list(0..7))
+
end
+
+
def do_find(_program, [], out), do: out
+
+
def do_find(program, [n | rest], out) do
+
potential =
+
for a <- out,
+
i <- 0..7,
+
hd(Computer.process(program, a: a * 8 + i)) == n,
+
do: a * 8 + i
+
+
do_find(program, rest, potential)
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Quine, <<70, 79, 82, 49, 0, 0, 10, ...>>, {:do_find, 3}}
+
```
+
+
```elixir
+
Quine.find(program, code) |> Enum.min()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
265061364597659
+
```
+
+
<!-- livebook:{"offset":4021,"stamp":{"token":"XCP.PwUWTErrjClVJj6ZS87ZLrfbzleELwxqD__HBvfB1y_Yc633Wj72_Jigo2Z3T7V2ONi1nVguQ_AE_NSyLCF5sjSmWldUKuW294o_wsQqiM_gKhXOjSLzJOnslN9iIEFIEww","version":2}} -->
+194
2024/day18.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 18
+
+
```elixir
+
Mix.install([:kino_aoc, :image])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxOCIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "18", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"21,9\n69,53\n31,24\n2,9\n50,53\n2,5\n3,44\n69,49\n25,26\n50,31\n68,41\n54,67\n19,8\n11,9\n9,29\n1,31\n13,12\n28,5\n69,41\n51,66\n53,43\n65,35\n40,67\n43,13\n21,34\n49,3\n65,61\n25,9\n39,21\n59,37\n11,24\n9,30\n63,62\n41,69\n6,29\n68,47\n45,1\n9,1\n11,14\n59,19\n67,54\n12,5\n41,44\n59,45\n3,28\n57,42\n7,25\n43,11\n31,19\n9,6\n53,60\n29,8\n53,67\n17,1\n11,17\n31,3\n55,35\n2,21\n67,61\n37,5\n6,1\n51,24\n39,1\n31,1\n69,58\n61,19\n49,63\n40,21\n28,25\n59,59\n66,69\n30,1\n7,5\n53,49\n4,17\n39,23\n23,20\n62,67\n51,36\n55,39\n41,3\n57,30\n18,7\n6,37\n29,25\n55,48\n37,16\n65,69\n21,5\n43,48\n3,11\n3,9\n63,39\n23,23\n43,67\n47,3\n69,47\n67,53\n65,24\n67,52\n35,20\n46,45\n57,26\n15,32\n35,68\n15,16\n41,1\n63,29\n15,3\n15,18\n51,50\n60,43\n50,1\n35,12\n41,10\n58,39\n27,18\n50,69\n55,40\n2,3\n51,47\n1,11\n16,9\n23,9\n19,7\n29,12\n37,3\n1,15\n11,1\n25,11\n65,56\n37,70\n60,41\n48,69\n62,29\n53,38\n12,35\n67,42\n49,67\n31,5\n39,7\n65,43\n5,25\n23,24\n43,68\n11,11\n9,32\n62,39\n69,39\n51,46\n38,21\n67,37\n5,26\n62,19\n27,21\n48,51\n55,62\n11,33\n25,4\n13,20\n61,58\n62,55\n41,66\n11,40\n16,7\n9,17\n67,65\n1,1\n9,33\n7,35\n1,3\n11,4\n29,21\n47,47\n61,67\n41,70\n42,65\n55,47\n54,49\n36,13\n61,36\n18,23\n26,23\n45,5\n9,18\n61,27\n36,21\n59,32\n4,9\n6,35\n51,23\n1,17\n12,11\n65,67\n41,65\n37,65\n1,24\n21,8\n59,28\n17,14\n63,68\n20,19\n17,10\n63,69\n57,44\n55,56\n45,64\n25,27\n27,4\n22,23\n5,13\n19,14\n47,46\n49,4\n21,15\n63,58\n60,31\n25,28\n6,3\n61,38\n33,5\n58,37\n11,32\n21,7\n44,61\n55,45\n55,37\n35,22\n10,15\n36,5\n19,11\n59,31\n33,19\n30,5\n69,69\n69,63\n57,69\n5,33\n60,27\n29,7\n57,43\n61,61\n3,26\n13,33\n57,59\n66,39\n63,27\n33,11\n51,1\n52,67\n5,29\n35,3\n17,2\n9,31\n37,24\n61,23\n9,5\n68,35\n21,28\n2,25\n51,48\n68,49\n4,19\n43,66\n7,34\n13,15\n36,1\n42,63\n13,0\n23,7\n48,47\n56,31\n55,43\n47,45\n18,15\n56,45\n61,64\n48,45\n69,65\n40,11\n51,68\n51,51\n53,46\n3,30\n49,62\n4,13\n17,27\n38,69\n41,0\n5,23\n65,32\n9,35\n55,21\n65,55\n51,39\n67,51\n5,9\n39,5\n58,49\n21,17\n63,41\n21,18\n57,65\n53,51\n2,13\n53,0\n53,6\n27,17\n55,59\n61,42\n27,7\n25,25\n39,13\n62,53\n51,44\n2,27\n19,17\n58,65\n8,1\n30,23\n14,5\n33,3\n43,65\n18,27\n35,7\n11,35\n12,29\n57,68\n59,63\n44,19\n36,25\n68,37\n15,19\n53,39\n62,69\n35,4\n61,55\n59,43\n23,17\n69,45\n18,5\n50,59\n39,6\n69,32\n17,5\n11,8\n21,2\n39,4\n64,65\n33,2\n17,22\n33,50\n25,24\n44,51\n31,7\n11,38\n11,25\n63,59\n25,21\n42,7\n8,11\n33,9\n45,63\n62,63\n33,4\n66,59\n61,29\n5,27\n59,27\n55,20\n38,9\n8,7\n51,3\n23,1\n53,65\n69,55\n1,34\n70,49\n61,57\n22,9\n17,26\n17,12\n61,69\n49,43\n9,28\n33,26\n15,35\n13,34\n55,27\n68,45\n45,61\n59,47\n13,29\n59,33\n65,53\n10,1\n35,21\n13,27\n28,1\n23,10\n61,37\n69,57\n23,21\n5,28\n57,48\n41,21\n11,13\n20,11\n1,21\n61,66\n66,47\n63,26\n5,15\n3,20\n17,4\n43,5\n16,29\n63,44\n63,55\n55,69\n5,22\n37,11\n50,39\n59,39\n25,16\n48,1\n43,60\n13,6\n49,37\n3,32\n57,23\n46,69\n2,35\n37,1\n53,27\n31,22\n63,36\n46,43\n68,57\n45,67\n32,9\n48,65\n15,15\n8,29\n13,1\n55,41\n65,65\n13,31\n49,69\n19,6\n29,19\n32,23\n49,41\n15,24\n65,22\n15,33\n6,21\n7,9\n69,64\n63,23\n5,21\n15,1\n44,1\n11,27\n63,34\n15,13\n39,9\n63,20\n58,29\n28,21\n7,37\n39,65\n41,16\n21,6\n49,47\n47,61\n50,63\n23,15\n68,67\n64,57\n19,13\n69,61\n1,22\n27,3\n28,13\n19,31\n23,2\n3,31\n25,6\n61,47\n51,63\n59,64\n27,2\n7,33\n63,63\n65,42\n5,12\n12,15\n27,9\n15,7\n6,17\n17,17\n15,2\n59,61\n63,47\n57,33\n13,17\n47,67\n11,26\n20,3\n13,7\n17,33\n10,5\n57,32\n58,53\n7,18\n66,65\n6,5\n11,5\n41,9\n21,21\n69,43\n11,20\n41,14\n38,3\n67,69\n15,17\n45,58\n51,61\n54,23\n49,39\n59,29\n53,63\n45,69\n16,1\n55,51\n21,13\n56,47\n63,40\n63,37\n37,19\n43,3\n7,17\n27,5\n14,25\n17,3\n44,69\n31,8\n14,9\n14,7\n63,45\n4,1\n49,34\n19,44\n46,53\n38,17\n33,0\n50,55\n27,25\n63,21\n19,12\n35,10\n54,3\n65,50\n47,62\n38,65\n61,39\n33,1\n65,52\n5,5\n0,3\n63,33\n30,27\n29,27\n29,1\n48,67\n33,23\n46,5\n60,35\n39,14\n59,46\n51,49\n64,21\n69,60\n3,3\n59,58\n9,36\n9,37\n48,41\n23,5\n7,3\n61,65\n61,22\n3,15\n4,37\n43,20\n66,45\n69,66\n43,12\n54,43\n52,49\n15,23\n33,21\n36,67\n61,24\n5,7\n37,7\n60,55\n53,70\n52,1\n21,33\n53,69\n67,43\n61,34\n6,31\n55,55\n59,40\n16,17\n65,25\n24,29\n59,21\n66,63\n61,41\n17,24\n0,15\n17,19\n1,13\n23,3\n49,45\n39,2\n59,49\n31,25\n65,40\n7,7\n70,43\n57,63\n65,54\n18,1\n41,15\n25,19\n33,18\n5,24\n13,3\n64,37\n43,7\n31,9\n30,11\n56,63\n65,34\n67,39\n17,18\n65,37\n49,56\n59,25\n7,11\n65,38\n37,18\n5,3\n21,22\n47,69\n19,9\n70,39\n15,14\n40,3\n5,31\n19,21\n55,34\n67,49\n45,11\n17,23\n41,5\n33,6\n37,10\n55,2\n17,9\n57,39\n5,1\n9,10\n17,7\n60,23\n55,68\n5,11\n63,67\n59,65\n7,19\n51,56\n26,1\n30,3\n15,20\n19,15\n3,21\n59,51\n11,7\n61,26\n19,23\n22,11\n25,8\n18,17\n27,26\n17,29\n7,13\n65,33\n44,5\n22,13\n56,65\n24,19\n25,17\n55,66\n65,39\n32,19\n3,19\n9,15\n54,63\n55,23\n61,59\n21,11\n46,39\n57,40\n65,19\n65,59\n65,48\n64,47\n32,21\n1,5\n15,11\n65,23\n4,2" <> ...}
+
```
+
+
```elixir
+
bytes =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn row ->
+
[x, y] = String.split(row, ",")
+
+
{String.to_integer(x), String.to_integer(y)}
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{21, 9},
+
{69, 53},
+
{31, 24},
+
{2, 9},
+
{50, 53},
+
{2, 5},
+
{3, 44},
+
{69, 49},
+
{25, 26},
+
{50, 31},
+
{68, 41},
+
{54, 67},
+
{19, 8},
+
{11, 9},
+
{9, 29},
+
{1, 31},
+
{13, 12},
+
{28, 5},
+
{69, 41},
+
{51, 66},
+
{53, 43},
+
{65, 35},
+
{40, 67},
+
{43, 13},
+
{21, 34},
+
{49, 3},
+
{65, 61},
+
{25, 9},
+
{39, 21},
+
{59, 37},
+
{11, 24},
+
{9, 30},
+
{63, 62},
+
{41, 69},
+
{6, 29},
+
{68, 47},
+
{45, 1},
+
{9, 1},
+
{11, 14},
+
{59, 19},
+
{67, 54},
+
{12, 5},
+
{41, 44},
+
{59, 45},
+
{3, 28},
+
{57, 42},
+
{7, 25},
+
{43, 11},
+
{31, ...},
+
{...},
+
...
+
]
+
```
+
+
```elixir
+
Image.new!(71, 71, color: :forestgreen)
+
|> Image.mutate(fn img ->
+
for x <- 0..70, y <- 0..70, {x, y} in Enum.take(bytes, 1024) do
+
Image.Draw.point(img, x, y, color: :firebrick)
+
end
+
+
img
+
end)
+
|> elem(1)
+
|> Image.resize!(4, interpolate: :nearest)
+
```
+
+
```elixir
+
defmodule Memory do
+
@d [{-1, 0}, {1, 0}, {0, -1}, {0, 1}]
+
def find_path(from, to, bytes), do: do_find([{0, from}], to, MapSet.new(bytes), %{})
+
+
def do_find([], _, _, _), do: :none
+
+
def do_find([{dist, to} | _], to, _, _visited), do: dist
+
+
def do_find([{dist, {x, y} = p} | rest], {w, h} = to, bytes, visited)
+
when not is_map_key(visited, p)
+
when dist < :erlang.map_get(p, visited)
+
do
+
visited = Map.put(visited, p, dist)
+
+
next =
+
for {dx, dy} <- @d,
+
(x + dx) in 0..w,
+
(y + dy) in 0..h,
+
p = {x + dx, y + dy},
+
p not in bytes,
+
not is_map_key(visited, p),
+
do: {dist + 1, p}
+
+
next
+
|> Enum.concat(rest)
+
|> Enum.sort()
+
|> do_find(to, bytes, visited)
+
end
+
+
def do_find([_ | rest], to, bytes, visited), do: do_find(rest, to, bytes, visited)
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Memory, <<70, 79, 82, 49, 0, 0, 13, ...>>, {:do_find, 4}}
+
```
+
+
## Part 1
+
+
## Part 1
+
+
```elixir
+
Memory.find_path({0, 0}, {70, 70}, Enum.take(bytes, 1024))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
250
+
```
+
+
## Part 2
+
+
```elixir
+
{x, y} =
+
bytes
+
|> Enum.reverse()
+
|> Stream.unfold(fn
+
[] -> nil
+
[_ | rest] = curr -> {curr, rest}
+
end)
+
|> Enum.find_value(fn [pos | fallen] ->
+
path = Memory.find_path({0, 0}, {70, 70}, fallen)
+
+
if path != :none do
+
pos
+
end
+
end)
+
+
IO.puts("#{x},#{y}")
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
56,8
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
:ok
+
```
+
+
<!-- livebook:{"offset":7984,"stamp":{"token":"XCP.CPT4l_BNbZGxGbR_fK_dYfzmCSPzRQfyiJPfaGWsNChhlNQI36bgn8XXEOmsc56qlDi2H-j-H4aYpxwTYXzlirEAyckZaTUuHdujjNaTLq1pQEjB3uTTMbVmMkdf1KvN3g0","version":2}} -->
+126
2024/day19.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 19
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxOSIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "19", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"rrbb, rgrb, rbbwbw, ruw, grwb, wbg, rrggu, wugbb, gwr, rrgu, wbbb, bwrgugb, rgww, brrw, gwwg, brgbb, ubbbu, rbgruw, bwub, rru, grbu, grw, bwrbr, wrwbwu, bgbr, urrb, bbb, guggb, gwuwuw, ubu, wbr, bb, ubwwrb, bruuwu, buw, wrr, gbgrr, ggw, ru, wub, uub, gbrw, uwrwrb, uwuu, wbbu, gwu, brrr, grggur, wugrbrw, rwuurgg, wrbg, wuugrgw, brr, wrgwu, rwwuur, wgug, guu, brru, bgr, buwruw, bbg, bw, brwuwbb, buwbrgrb, wrwuw, ubb, rgu, wru, ugw, rruubrr, bwur, rrb, uwg, wwbbuwu, rbw, uwrgbr, ubuw, uurwr, uggw, uuguur, guuww, bbrgw, ubuwbuu, buwgg, gru, uuu, u, wgguw, bruu, bu, gwurrw, rbgwur, gubg, ubgrubw, buwrgw, uu, rwgw, rrw, wgru, gwrb, bgguu, gwugwu, urrbg, ruwwb, wuw, wwgg, wwbbu, gggb, rgrruwrw, uugr, rwb, rggw, gbr, guuurru, wurubggw, gww, wuugb, rbbww, urwgb, wrruurr, guuurgg, bwbgbg, bubwb, ggrwwg, gugr, uwrrr, guurbu, uruw, gbguruu, grb, bwr, wrubggr, rbu, wgwgru, buuww, gub, wu, uw, rrbrb, ur, wrgbb, gbbu, wgw, ggwbgwb, wb, urwr, uggwbwu, wwwg, rbru, bwbw, brb, wbugw, r, gbb, rw, bru, wbbwbr, gwww, wgrr, rugg, bgrbrub, w, gwwb, wrwgu, wwgb, uwgbgwwb, wrrwb, ubw, rr, gbbuug, bbr, wugb, rbuww, uur, wgur, ugg, wwu, wwrww, uuwur, rwbbww, gbu, bgbuur, rrbugguw, ugrgwg, wurruu, rrrgww, ggbbgbb, bgbb, brrb, rwwr, brwwr, ubrbru, uburwwb, ggwu, rwbgrbu, bbwuwbr, urwggbwr, bbrgu, wbbuww, rbwwuwr, gu, brbb, wbwgu, ugbrrguw, urbu, gbgbbrub, gbuuuww, rww, gwwgwwg, buwu, bur, uubrw, rur, rgurr, rwbgrg, urr, wugw, wuur, wuub, wbgb, bgb, uubrbur, rrbugbu, ugru, guwr, uwu, uru, wbw, wugrwgb, ggwg, guw, ubbbg, grbuwg, gw, wgb, bbrbwgub, gr, rbruu, urwwu, gbuwbw, bug, rgrgb, uwr, wrw, urb, wgbw, rbbgr, rwww, wbubur, buubw, ruwgwbug, wwwgggub, uuwrwbww, burr, rubg, wgub, bww, urbuubb, bubugrb, rgwbbw, rb, ggu, gwg, rgw, ruwggbg, wrrwbg, gur, wwbgugb, ruu, rrgg, rwrr, uwb, bwbbwbg, rbgg, rwgwg, rrgrwg, gb, bgbg, urubwugb, ruww, grbbg, gwb, bugrr, wgwr, wuug, b, gbwgr, uugw, wwr, wuu, ggr, bbwb, ubbbwrg, wugbw, gguuw, bbw, ugr, wbbrrbu, grbub, ubuwuw, bwgw, bggw, bwu, ub, bwubw, rgru, brg, uruwr, rug, wrwwuubg, brw, wggurb, br, wgr, gug, wrww, gg, uuw, bguwbru, rrrw, uubgb, gbww, buu, rbbuw, bgru, ubbwr, bg, gbgrww, wrg, ugubw, rgrg, bwbbgw, ggubrwbg, uurgwg, gbw, ww, wr, wbgu, bbu, brrwb, wug, uurug, rgb, gwbwbgg, uuubg, ugub, bruw, rub, rgggrr, ruubrwuw, brguru, wbrbg, rrwr, bgrwbbr, ugu, grwbb, rgg, wwg, rgbuwr, wuwur, bbgub, ubg, rrg, wrur, bggbr, wgg, bbwbbru, bwwbrgu, rugrr, rgwbu, ugubwbgu, wwb, ggg, bwwu, gwuguu, rrwgwg, uuwu, rrug, bgwruw, brrgrb, rurg, bugb, grwbg, rwr, urug, rwg, bgg, gbggr, rrr, gbbrw, wgu, bwbg, bbgurggg, wuwguw, wwwuru, grg, grggbw, rubu, burw, grr, bgbbw, wgrbgg, rwrww, gwurgr, bruww, bub, wbu, rbb, uwgbb, rgr, ugb, buubb, wg, wwwgr, bgw, wbwr, wuwruu, wrgrrrw, rbr, wuwwr, wrwb, ggwgwbrw, urw, uwrubb, wuwg, wguu, ugwwuw, ggb, rrggr, wrb, urwgub, bgwwrw, rwu, wurug, gbgu, brrwbb, wwbub, uwrgw, bwb, ubr, uww, gbg, wgrugwbb, bwg, wbb, bbwwgr, www\n\nbgrwwwbuugwrruurrwgbgrbwrrruurgbuwbgbwuuruubwuubruwgubw\nugguwugrwrgwruwguuwurubggwgwbrwwwubburwrburg\nrbbbgwgbbbrrrubguwggubwburbrrwgbbuwgbwwuwrbwugurbbwuubruu\nwuuuwbwuwuwgbugwggwwuwurrgwubbugbbuuubbrwbgbubr\nubbrubwuurgbuwgguubgbrguwbguuwbwruguubwbbgguwrrgwwbubwb\nrbbwuwrrrgwrwwbwgwrruubggrrggbbgwuwbrgubgwwrbwwbggwwrwrwgb\nbgggbruguuguwwwurruwgubrwrruubgbrbwwwgrrgurb\ngubugrguurwgwwubrwguggbgbbuubbubuwurgbgugrubgrgggruugw\ngwrggrbrrrbwwrrggwrwggrwuguubgggrrwwrggubruwrrgbubg\nbgubggrrbuwwwggbwbrbguwuwwbburgururuguwuwgbguuwwwub\nuuggggggurgrgugugrwbrbrwururwurburrurggwgwbrwrwwwuuugwu\nuuubwrurwwrbbgrbrrbuwbrbwrurgrrwwwgugugrbugwu\nwbbbwrgbwrbgggwgbbwbbwrwbbbwwbbwbgbwuwubbrrggurbugwrgwbuug\nuruwrwugbbwruugrguuwrrbbguwwrrrruubrwgwrruug\nbguurwugrrgurubbuwbrgrbwggrrgrwguwgrwubgbubbw\nwwgubbbbgggrgrwwwuwwwbbbbbbrwwwguggrwurgwbguwgwubww\nwgbrwgbbgwuuwbwwuwwrruruwururwbwbguuwgbrgw\nwbrgwrrurwuubrruruwwbgwrgwrbbrwrbbbrwwbwwrgwbr\nggwgwrrwwruubruwgbwwuwrbwbgurubwugbbwurwbwrbuggubwwww\nbuurbrbwrgbgbgwgwbruwubbbgwgguruggrrwwgwgwuruwggrbbbbbugw\nbubgwugwubwwwgrurgurbubwbguurrwbubuubggbgbrbuwgrwbbgbuwr\ngggbbwgugrguguwubrbwbrgwwbubwuwwgbwrbrgbuugwrrb\nbgguuuwwbrubgrubwrwugbbwwrruwrgrrubwwuubgwrwwrgrgbgbg\nw" <> ...}
+
```
+
+
```elixir
+
[towels | patterns] = String.split(puzzle_input, "\n", trim: true)
+
+
towels =
+
towels
+
|> String.split(", ")
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
["rrbb", "rgrb", "rbbwbw", "ruw", "grwb", "wbg", "rrggu", "wugbb", "gwr", "rrgu", "wbbb", "bwrgugb",
+
"rgww", "brrw", "gwwg", "brgbb", "ubbbu", "rbgruw", "bwub", "rru", "grbu", "grw", "bwrbr",
+
"wrwbwu", "bgbr", "urrb", "bbb", "guggb", "gwuwuw", "ubu", "wbr", "bb", "ubwwrb", "bruuwu", "buw",
+
"wrr", "gbgrr", "ggw", "ru", "wub", "uub", "gbrw", "uwrwrb", "uwuu", "wbbu", "gwu", "brrr",
+
"grggur", "wugrbrw", "rwuurgg", ...]
+
```
+
+
```elixir
+
defmodule Towels do
+
def count(target, towels) do
+
possible =
+
towels
+
|> Enum.filter(&String.contains?(target, &1))
+
|> Enum.sort()
+
+
do_count([{target, 1}], possible)
+
end
+
+
defp do_count([], _), do: 0
+
defp do_count([{"", count} | _], _), do: count
+
+
defp do_count([{target, score} | rest], towels) do
+
towels
+
|> Enum.reduce(rest, fn h, acc ->
+
case target do
+
^h <> rest -> insert(acc, {rest, score})
+
_ -> acc
+
end
+
end)
+
|> do_count(towels)
+
end
+
+
defp insert([{longest, _} = top | t], {text, _} = new)
+
when byte_size(text) < byte_size(longest) do
+
[top | insert(t, new)]
+
end
+
+
defp insert([{same, count} | t], {same, add}),
+
do: [{same, count + add} | t]
+
+
defp insert(t, new), do: [new | t]
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Towels, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:insert, 2}}
+
```
+
+
```elixir
+
ways = Enum.map(patterns, &Towels.count(&1, towels))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[6620974293119, 0, 35074418436970, 51307147748, 1695253946038, 12806406135744, 4413048272,
+
52744440529, 21533960420, 189633269638, 308662314336, 28930988196, 0, 0, 2335754782, 105920229640,
+
6464319032, 87075196587, 3720984622862, 2177845982468, 5546717284590, 8535586138, 834112091460,
+
6647844832, 21252082644, 5923960105816, 22344301329, 0, 0, 582455705324, 5162034941182,
+
368835846080, 30797645913, 0, 5315701730, 1953742172864, 910841596, 5512526952, 673582370688,
+
2029241325402, 13227054560, 81761616492, 0, 184404641300, 19196318323832, 773246829645,
+
97032877104, 0, 0, 0, ...]
+
```
+
+
## Part 1
+
+
```elixir
+
Enum.count(ways, & &1 > 0)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
306
+
```
+
+
## Part 2
+
+
```elixir
+
Enum.sum(ways)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
604622004681855
+
```
+
+
<!-- livebook:{"offset":7059,"stamp":{"token":"XCP.002DySFes8xjfbs_CVpc_QP75dkQcDFc5l37WdKhIJnRNctYjy9B2s3kTIev5coTlF4OCw1O-s8QuxIAU1HRaVoeZUHdw248FBapl1Ki5EyAYF1LHsn0MfuWbSukOOamT4I","version":2}} -->
+420
2024/day20.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 20
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIyMCIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "20", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"#############################################################################################################################################\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#.#.....#.................#.###.#.#.#.#.#.#...#...#.#...#...#...#.#.#...#...#.#.#...#...#...#.#...#...#.#.#.#.#.#.....#.......#.....#...#...#\n#.#####.#.#################.###.#.#.#.#.#.###.#.###.###.#.#.#.###.#.#.###.#.#.#.#.#####.###.#.###.#.###.#.#.#.#.#.###.#." <> ...}
+
```
+
+
```elixir
+
#puzzle_input =
+
"""
+
###############
+
#...#...#.....#
+
#.#.#.#.#.###.#
+
#S#...#.#.#...#
+
#######.#.#.###
+
#######.#.#...#
+
#######.#.###.#
+
###..E#...#...#
+
###.#######.###
+
#...###...#...#
+
#.#####.#.###.#
+
#.#...#.#.#...#
+
#.#.#.#.#.#.###
+
#...#...#...###
+
###############
+
"""
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
warning: outdented heredoc line. The contents inside the heredoc should be indented at the same level as the closing """. The following is forbidden:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
Instead make sure the contents are indented as much as the heredoc closing:
+
+
def text do
+
"""
+
contents
+
"""
+
end
+
+
The current heredoc line is indented too little
+
โ””โ”€ Workspace/hauleth/advent-of-code/2024/day20.livemd#cell:iyjl3w4kz3srtwoq:3:3
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
"###############\n#...#...#.....#\n#.#.#.#.#.###.#\n#S#...#.#.#...#\n#######.#.#.###\n#######.#.#...#\n#######.#.###.#\n###..E#...#...#\n###.#######.###\n#...###...#...#\n#.#####.#.###.#\n#.#...#.#.#...#\n#.#.#.#.#.#.###\n#...#...#...###\n###############\n"
+
```
+
+
```elixir
+
map =
+
puzzle_input
+
|> String.split("\n")
+
|> Enum.with_index()
+
|> Enum.flat_map(fn {row, y} ->
+
row
+
|> String.split("", trim: true)
+
|> Enum.with_index()
+
|> Enum.map(fn {c, x} ->
+
{{x, y}, c}
+
end)
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{{0, 0}, "#"},
+
{{1, 0}, "#"},
+
{{2, 0}, "#"},
+
{{3, 0}, "#"},
+
{{4, 0}, "#"},
+
{{5, 0}, "#"},
+
{{6, 0}, "#"},
+
{{7, 0}, "#"},
+
{{8, 0}, "#"},
+
{{9, 0}, "#"},
+
{{10, 0}, "#"},
+
{{11, 0}, "#"},
+
{{12, 0}, "#"},
+
{{13, 0}, "#"},
+
{{14, 0}, "#"},
+
{{15, 0}, "#"},
+
{{16, 0}, "#"},
+
{{17, 0}, "#"},
+
{{18, 0}, "#"},
+
{{19, 0}, "#"},
+
{{20, 0}, "#"},
+
{{21, 0}, "#"},
+
{{22, 0}, "#"},
+
{{23, 0}, "#"},
+
{{24, 0}, "#"},
+
{{25, 0}, "#"},
+
{{26, 0}, "#"},
+
{{27, 0}, "#"},
+
{{28, 0}, "#"},
+
{{29, 0}, "#"},
+
{{30, 0}, "#"},
+
{{31, 0}, "#"},
+
{{32, 0}, "#"},
+
{{33, 0}, "#"},
+
{{34, 0}, "#"},
+
{{35, 0}, "#"},
+
{{36, 0}, "#"},
+
{{37, 0}, "#"},
+
{{38, 0}, "#"},
+
{{39, 0}, "#"},
+
{{40, 0}, "#"},
+
{{41, 0}, "#"},
+
{{42, 0}, "#"},
+
{{43, 0}, "#"},
+
{{44, 0}, "#"},
+
{{45, 0}, "#"},
+
{{46, 0}, "#"},
+
{{47, ...}, "#"},
+
{{...}, ...},
+
{...},
+
...
+
]
+
```
+
+
```elixir
+
%{"#" => walls, "." => road, "S" => [start], "E" => [finish]} =
+
Enum.group_by(map, &elem(&1, 1), &elem(&1, 0))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{
+
"#" => [
+
{0, 0},
+
{1, 0},
+
{2, 0},
+
{3, 0},
+
{4, 0},
+
{5, 0},
+
{6, 0},
+
{7, 0},
+
{8, 0},
+
{9, 0},
+
{10, 0},
+
{11, 0},
+
{12, 0},
+
{13, 0},
+
{14, 0},
+
{15, 0},
+
{16, 0},
+
{17, 0},
+
{18, 0},
+
{19, 0},
+
{20, 0},
+
{21, 0},
+
{22, 0},
+
{23, 0},
+
{24, 0},
+
{25, 0},
+
{26, 0},
+
{27, 0},
+
{28, 0},
+
{29, 0},
+
{30, 0},
+
{31, 0},
+
{32, 0},
+
{33, 0},
+
{34, 0},
+
{35, 0},
+
{36, 0},
+
{37, 0},
+
{38, 0},
+
{39, 0},
+
{40, 0},
+
{41, 0},
+
{42, 0},
+
{43, 0},
+
{44, 0},
+
{45, 0},
+
{46, 0},
+
{47, ...},
+
{...},
+
...
+
],
+
"." => [
+
{1, 1},
+
{2, 1},
+
{3, 1},
+
{5, 1},
+
{6, 1},
+
{7, 1},
+
{9, 1},
+
{10, 1},
+
{11, 1},
+
{13, 1},
+
{14, 1},
+
{15, 1},
+
{17, 1},
+
{18, 1},
+
{19, 1},
+
{20, 1},
+
{21, 1},
+
{22, 1},
+
{23, 1},
+
{24, 1},
+
{25, 1},
+
{27, 1},
+
{28, 1},
+
{29, 1},
+
{30, 1},
+
{31, 1},
+
{32, 1},
+
{33, 1},
+
{34, 1},
+
{35, 1},
+
{39, 1},
+
{40, 1},
+
{41, 1},
+
{43, 1},
+
{44, 1},
+
{45, 1},
+
{46, 1},
+
{47, 1},
+
{49, 1},
+
{50, 1},
+
{51, 1},
+
{53, 1},
+
{54, 1},
+
{55, 1},
+
{56, 1},
+
{57, 1},
+
{59, ...},
+
{...},
+
...
+
],
+
"E" => [{27, 59}],
+
"S" => [{49, 53}]
+
}
+
```
+
+
```elixir
+
defmodule Race do
+
def distances(start, finish, walls) do
+
do_distances(start, finish, 0, MapSet.new(walls), %{})
+
end
+
+
defp do_distances(finish, finish, n, _, acc),
+
do: Map.put(acc, finish, n)
+
+
defp do_distances(current, finish, n, walls, acc) do
+
acc = Map.put(acc, current, n)
+
+
current
+
|> neigh()
+
|> Enum.reject(&(&1 in walls or Map.has_key?(acc, &1)))
+
|> hd()
+
|> do_distances(finish, n + 1, walls, acc)
+
end
+
+
def neigh({x, y}, d \\ 1) do
+
for {dx, dy} <- [{0, d}, {0, -d}, {d, 0}, {-d, 0}], do: {x + dx, y + dy}
+
end
+
+
def neighbours({x, y}, r \\ 1) do
+
for dx <- -r..r,
+
dy <- -r..r,
+
{dx, dy} != {0, 0},
+
d = abs(dx) + abs(dy),
+
d <= r,
+
do: {x + dx, y + dy}
+
end
+
+
def d({xa, ya}, {xb, yb}) do
+
abs(xa - xb) + abs(ya - yb)
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Race, <<70, 79, 82, 49, 0, 0, 17, ...>>, {:d, 2}}
+
```
+
+
```elixir
+
steps = Race.distances(start, finish, walls)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{
+
{18, 103} => 8261,
+
{61, 121} => 7060,
+
{65, 63} => 2098,
+
{77, 129} => 6964,
+
{1, 26} => 695,
+
{116, 69} => 4441,
+
{83, 76} => 4281,
+
{117, 125} => 5656,
+
{103, 106} => 5785,
+
{30, 113} => 8041,
+
{89, 14} => 2511,
+
{35, 30} => 1133,
+
{37, 53} => 32,
+
{11, 39} => 384,
+
{131, 5} => 2998,
+
{65, 43} => 1754,
+
{139, 46} => 3615,
+
{12, 135} => 7871,
+
{65, 131} => 7046,
+
{49, 117} => 7412,
+
{29, 25} => 1108,
+
{83, 36} => 2319,
+
{47, 27} => 1556,
+
{4, 81} => 8645,
+
{13, 124} => 8295,
+
{121, 77} => 4608,
+
{103, 39} => 3756,
+
{119, 60} => 4389,
+
{13, 85} => 8604,
+
{63, 81} => 6682,
+
{111, 108} => 5755,
+
{111, 103} => 5764,
+
{15, 92} => 8587,
+
{1, 101} => 8500,
+
{20, 3} => 939,
+
{61, 95} => 6878,
+
{23, 67} => 9208,
+
{78, 75} => 6545,
+
{79, 17} => 2358,
+
{17, 137} => 7852,
+
{124, 93} => 4933,
+
{138, 9} => 3283,
+
{58, 33} => 1667,
+
{67, 105} => 6818,
+
{47, 44} => 1195,
+
{122, 137} => 5595,
+
{13, 55} => 154,
+
{97, 138} => 6129,
+
{75, ...} => 2165,
+
{...} => 1616,
+
...
+
}
+
```
+
+
## Part 1
+
+
```elixir
+
Enum.reduce(steps, 0, fn {pos, start}, acc ->
+
count =
+
steps
+
|> Map.take(Race.neighbours(pos, 2))
+
|> Enum.count(fn {last, finish} ->
+
finish - start - Race.d(pos, last) >= 100
+
end)
+
+
count + acc
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1393
+
```
+
+
## Part 2
+
+
We can notice that we are looking for shortcuts in circle of radius $r$ defined in Taxicab metric ($d(a, b) = \sum_{i} |a_i - b_i|$). That makes code pretty simple and allows us to reuse ideas from Part 1.
+
+
```elixir
+
steps
+
|> Task.async_stream(
+
fn {pos, start} ->
+
steps
+
|> Map.take(Race.neighbours(pos, 20))
+
|> Enum.count(fn {last, finish} ->
+
finish - start - Race.d(pos, last) >= 100
+
end)
+
end,
+
ordered: false
+
)
+
|> Enum.reduce(0, fn {:ok, count}, acc ->
+
count + acc
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
990096
+
```
+
+
<!-- livebook:{"offset":11400,"stamp":{"token":"XCP.ONwDp6zRpWXsXASH95Q0puANk15Li1hG2FDCrv6Gqu42Q7k9pb_Te_6RDoUE0dp3yYbG7jry8-6iHGJvcZtsDFstlznyVHk9HVhXRZiC2uQczaOfF4K8HQL9QuzNguTht7A","version":2}} -->
+182
2024/day21.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 21
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIyMSIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "21", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok, "638A\n965A\n780A\n803A\n246A"}
+
```
+
+
```elixir
+
codes =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn <<num::3-binary>> <> "A" = code ->
+
{String.to_charlist(code), String.to_integer(num)}
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[{~c"638A", 638}, {~c"965A", 965}, {~c"780A", 780}, {~c"803A", 803}, {~c"246A", 246}]
+
```
+
+
```elixir
+
dirpad = %{
+
[?A, ?>] => ~c[vA],
+
[?A, ?^] => ~c[<A],
+
[?A, ?v] => ~c[<vA],
+
[?A, ?<] => ~c[v<<A],
+
+
[?>, ?A] => ~c[^A],
+
[?>, ?^] => ~c[<^A],
+
[?>, ?v] => ~c[<A],
+
[?>, ?<] => ~c[<<A],
+
+
[?^, ?A] => ~c[>A],
+
[?^, ?>] => ~c[v>A],
+
[?^, ?v] => ~c[vA],
+
[?^, ?<] => ~c[v<A],
+
+
[?<, ?A] => ~c[>>^A],
+
[?<, ?^] => ~c[>^A],
+
[?<, ?v] => ~c[>A],
+
[?<, ?>] => ~c[>>A],
+
+
[?v, ?A] => ~c[>^A],
+
[?v, ?^] => ~c[^A],
+
[?v, ?<] => ~c[<A],
+
[?v, ?>] => ~c[>A]
+
}
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
%{
+
~c"<>" => ~c">>A",
+
~c"<A" => ~c">>^A",
+
~c"<^" => ~c">^A",
+
~c"<v" => ~c">A",
+
~c"><" => ~c"<<A",
+
~c">A" => ~c"^A",
+
~c">^" => ~c"<^A",
+
~c">v" => ~c"<A",
+
~c"A<" => ~c"v<<A",
+
~c"A>" => ~c"vA",
+
~c"A^" => ~c"<A",
+
~c"Av" => ~c"<vA",
+
~c"^<" => ~c"v<A",
+
~c"^>" => ~c"v>A",
+
~c"^A" => ~c">A",
+
~c"^v" => ~c"vA",
+
~c"v<" => ~c"<A",
+
~c"v>" => ~c">A",
+
~c"vA" => ~c">^A",
+
~c"v^" => ~c"^A"
+
}
+
```
+
+
```elixir
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
nil
+
```
+
+
```elixir
+
defmodule Keypad do
+
def naive(input, lut) do
+
[?A | input]
+
|> Enum.chunk_every(2, 1, :discard)
+
|> Enum.flat_map(&Map.get(lut, &1, [?A]))
+
end
+
+
def expand(input, lut) do
+
Stream.concat([?A], input)
+
|> Stream.chunk_every(2, 1, :discard)
+
|> Stream.flat_map(&Map.get(lut, &1, [?A]))
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Keypad, <<70, 79, 82, 49, 0, 0, 9, ...>>, {:expand, 2}}
+
```
+
+
```elixir
+
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
nil
+
```
+
+
```elixir
+
Keypad.expand(~c[<A^A>^^AvvvA], dirpad)
+
|> Enum.count()
+
+
#|> Enum.map(fn {k, v} ->
+
# [?A | Map.get(dirpad, k, [?A])]
+
# |> Enum.chunk_every(2, 1, :discard)
+
# |> Enum.map()
+
#end)
+
#|> Enum.group_by(&elem(&1, 0), &elem(&1, 1))
+
#|> Map.new(fn {k, v} -> {k, Enum.sum(v)} end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
28
+
```
+
+
```elixir
+
Keypad.naive(~c[<A^A>^^AvvvA], dirpad)
+
|> Keypad.naive(dirpad)
+
|> Enum.chunk_every(2, 1, [?A])
+
|> Enum.frequencies()
+
|> Map.values()
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
68
+
```
+
+
```elixir
+
~c"<vA<AA>>^AvAA<^A>Av<<A>>^AvA^A<vA>^Av<<A>^A>AAvA^Av<<A>A>^AAAvA<^A>A"
+
~c"<vA<AA>>^AvAA<^A>A<v<A>>^AvA^A<vA>^A<v<A>^A>AAvA^A<v<A>A>^AAAvA<^A>A" |> length
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
68
+
```
+
+
<!-- livebook:{"offset":3144,"stamp":{"token":"XCP.rEBKR0PbENlE02mf_Mo6R3RTWsHU-tFuA9VTPd907vq3-8e37LytxC6qWBmZAHZHLc_e1t3ZaG85X5KBWsYq0WGEzo7HC0U9-oE0dpPKGKeF7oBGgFeiEoDsX6GDKTwp76o","version":2}} -->
+198
2024/day22.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 22
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIyMiIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "22", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"4832674\n14802956\n7210529\n7709095\n6063251\n12294789\n15666951\n12074106\n15427686\n1214891\n15165649\n3609602\n10200989\n16451437\n10915511\n3479515\n173864\n1238342\n3381843\n14767788\n16088065\n15637051\n15981887\n15854806\n4988920\n7980791\n11263142\n8044640\n4572291\n328777\n11851557\n13706949\n16451719\n15991644\n14668984\n8852039\n1685443\n13814197\n14117797\n6281998\n12395020\n1681090\n16476099\n2171296\n10155667\n15490827\n6723206\n7272972\n1788575\n2950054\n10917267\n6862495\n8153949\n16559239\n8572595\n1821668\n3417901\n11375457\n3878450\n10863466\n10890116\n13055126\n7451580\n5815531\n8335506\n431487\n201975\n5841753\n11744013\n4498615\n9261071\n9953929\n4630027\n2227105\n6260342\n10375281\n3015284\n3789175\n15843612\n14432075\n14847622\n11501912\n9079366\n2550341\n6931972\n13371306\n9601571\n14504463\n6162939\n5361897\n14900517\n12748562\n7519640\n14694035\n5566950\n7688680\n13810532\n5654369\n10957671\n6886767\n13114128\n9355299\n14808826\n11001280\n4983663\n9915373\n3356476\n16519750\n15826279\n11122172\n12902904\n1010762\n16214923\n9519057\n15931832\n15664252\n12750269\n1110882\n7854151\n3509827\n10328167\n1494530\n8712493\n396534\n15995697\n7396815\n3419574\n14789278\n14099072\n15389372\n6910648\n649063\n3609071\n6004556\n5054128\n13730203\n3554012\n2766085\n7133343\n7566747\n1194302\n10446649\n1529903\n9036124\n11725198\n6479244\n10287711\n2219155\n2360315\n8169407\n7841353\n7486466\n15297309\n9336789\n7225072\n6248515\n16154198\n11100038\n8584563\n3753173\n7371112\n2481160\n10954049\n8009781\n7381801\n280810\n11001420\n14114713\n4242475\n1237360\n6496866\n15267044\n1880781\n8798544\n5033766\n5079684\n11633848\n16509688\n8226900\n15858455\n16041151\n5334220\n15421957\n2633967\n8343560\n14729378\n9702409\n5482505\n2041087\n9712582\n3430735\n10644043\n9195957\n1784419\n14046333\n2031279\n12766582\n12165573\n14207224\n14929506\n11436548\n13623882\n12370036\n7592923\n228169\n8988171\n6688080\n5492092\n8212636\n3736928\n15352784\n2612376\n14843761\n12308540\n8404032\n11632730\n4404470\n2599992\n6807809\n12044159\n9795957\n5307557\n13144362\n13941181\n9362743\n4957570\n9950852\n4069207\n699043\n13667685\n12869414\n5834836\n8434557\n13512362\n5446646\n16663243\n10059682\n231185\n14405863\n10532295\n13752653\n3266523\n12926376\n9013886\n15683001\n10524950\n325867\n15226063\n15175724\n15991383\n13961546\n15823957\n9310375\n5534565\n2674761\n13444598\n9915920\n1755544\n1429896\n14788650\n5453166\n10081466\n2149840\n16613385\n2519989\n7555351\n7295534\n12099546\n3223009\n2684428\n8436395\n5406395\n836225\n9962036\n2847179\n12880336\n13215841\n3498334\n5985622\n7700379\n5785351\n9938722\n15810882\n2349820\n906893\n2513825\n10432278\n13789913\n2913486\n9683268\n2862417\n4807276\n16264545\n6607564\n10222512\n2190055\n11839341\n2132714\n153996\n10874457\n12023939\n7748310\n13452955\n3246986\n2892967\n9561561\n3280827\n991231\n13105708\n16641479\n273523\n4832864\n13832855\n7903624\n13242917\n13379831\n9085055\n1473661\n11031255\n4126827\n12754058\n456062\n14316218\n6580848\n11147440\n1828704\n15262845\n557484\n2406569\n10393027\n3363996\n15821838\n16365523\n5566374\n3723957\n5186897\n501767\n10639559\n3256585\n2354615\n1888438\n11574106\n11798800\n12629659\n6316600\n3119025\n14801938\n7025953\n14949782\n7577552\n14785389\n8868837\n11642113\n14574465\n8689963\n16223594\n14705685\n16363438\n1393194\n5961465\n16603208\n8121071\n15143692\n7531645\n6777163\n8168251\n15905711\n2373414\n1269213\n2506356\n1080789\n2154403\n11578189\n6232867\n10065427\n15116084\n15449140\n12675436\n14126594\n8470014\n2106625\n12556109\n12771090\n1437370\n16145074\n6244539\n6832665\n13217078\n5152936\n15205635\n12092447\n15115231\n2112929\n13215959\n11124896\n14598714\n15256810\n9994507\n11687859\n11599901\n5330801\n13829820\n1720133\n11040068\n4351948\n9597919\n10673331\n6148104\n12360792\n9687192\n11668420\n10272257\n7823976\n6113203\n8827921\n5600165\n6950138\n9581746\n15917691\n6453798\n11788226\n15057269\n9639028\n5073513\n15459362\n14118507\n7979569\n4210224\n5726357\n10649449\n14645020\n3062620\n14613306\n13963982\n14770179\n15097265\n1789308\n12405157\n7360698\n6983540\n9752726\n8200080\n5784060\n13456865\n4677699\n3783161\n13650051\n9865655\n13066800\n1868022\n5855823\n15061710\n11742417\n2116233\n15002417\n904747\n9455335\n5203086\n704685\n902384\n15284593\n8328120\n13587250\n11550241\n10950646\n14876694\n11393724\n14576237\n898540\n8874901\n5548732\n11351523\n2315166\n9532824\n11462685\n1297628\n3862586\n16331382\n9291789\n2887008\n2582973\n4861709\n15301133\n8978897\n533818\n1565155\n3829639\n8438476\n11901529" <> ...}
+
```
+
+
```elixir
+
inits =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(&String.to_integer/1)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[4832674, 14802956, 7210529, 7709095, 6063251, 12294789, 15666951, 12074106, 15427686, 1214891,
+
15165649, 3609602, 10200989, 16451437, 10915511, 3479515, 173864, 1238342, 3381843, 14767788,
+
16088065, 15637051, 15981887, 15854806, 4988920, 7980791, 11263142, 8044640, 4572291, 328777,
+
11851557, 13706949, 16451719, 15991644, 14668984, 8852039, 1685443, 13814197, 14117797, 6281998,
+
12395020, 1681090, 16476099, 2171296, 10155667, 15490827, 6723206, 7272972, 1788575, 2950054, ...]
+
```
+
+
```elixir
+
defmodule Buyer do
+
def hash(number, rounds \\ 2000) do
+
Enum.map_reduce(1..rounds//1, number, fn _, acc ->
+
r = do_round(acc)
+
{rem(r, 10), r}
+
end)
+
end
+
+
defp do_round(num) do
+
num = subround(num, num * 64)
+
num = subround(num, div(num, 32))
+
subround(num, num * 2048)
+
end
+
+
defp subround(a, b), do: rem(Bitwise.bxor(a, b), 16_777_216)
+
+
def sequences(prices) do
+
prices
+
|> Enum.chunk_every(5, 1, :discard)
+
|> Enum.reduce(%{}, fn seq, map ->
+
Map.put_new(map, diffs(seq), List.last(seq))
+
end)
+
end
+
+
defp diffs(vals) do
+
vals
+
|> Enum.chunk_every(2, 1, :discard)
+
|> Enum.map(fn [a, b] -> b - a end)
+
|> Integer.undigits(256)
+
end
+
end
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:module, Buyer, <<70, 79, 82, 49, 0, 0, 13, ...>>, {:diffs, 1}}
+
```
+
+
```elixir
+
hashes = Enum.map(inits, &Buyer.hash(&1))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{[5, 9, 7, 9, 4, 6, 2, 9, 4, 3, 6, 5, 0, 6, 5, 7, 2, 7, 9, 7, 0, 2, 5, 8, 8, 2, 0, 8, 4, 8, 3, 1,
+
4, 3, 3, 8, 0, 5, 2, 1, 2, 8, 6, 2, 2, 3, 6, 9, ...], 8186085},
+
{[8, 6, 8, 8, 3, 4, 6, 9, 0, 1, 1, 5, 4, 9, 5, 4, 1, 2, 5, 2, 6, 7, 8, 7, 5, 4, 4, 2, 5, 6, 4, 6,
+
2, 4, 5, 9, 5, 8, 5, 0, 6, 9, 3, 2, 3, 4, 4, ...], 16060909},
+
{[6, 0, 5, 8, 8, 7, 3, 6, 0, 9, 1, 0, 7, 2, 7, 5, 6, 4, 0, 5, 4, 0, 1, 9, 6, 5, 7, 1, 7, 9, 9, 9,
+
5, 6, 0, 7, 3, 0, 9, 4, 8, 4, 0, 2, 2, 7, ...], 3581487},
+
{[6, 3, 1, 0, 2, 6, 8, 9, 1, 6, 7, 4, 5, 0, 9, 9, 8, 9, 1, 0, 6, 4, 9, 0, 1, 0, 9, 3, 0, 0, 9, 1,
+
9, 6, 6, 7, 2, 1, 7, 2, 7, 3, 2, 7, 3, ...], 14331752},
+
{[3, 5, 1, 7, 1, 4, 6, 0, 4, 9, 8, 3, 7, 3, 3, 2, 2, 9, 1, 3, 3, 4, 9, 2, 3, 2, 5, 6, 9, 4, 3, 8,
+
1, 6, 7, 3, 8, 8, 7, 5, 3, 3, 2, 3, ...], 11096256},
+
{[9, 5, 4, 8, 1, 3, 9, 8, 2, 6, 7, 9, 0, 8, 6, 3, 4, 8, 7, 0, 0, 2, 2, 7, 2, 2, 0, 9, 7, 4, 9, 5,
+
7, 1, 3, 1, 7, 9, 3, 3, 6, 2, 4, ...], 8119288},
+
{[3, 0, 8, 6, 0, 0, 3, 4, 2, 0, 0, 8, 7, 6, 3, 7, 5, 2, 4, 8, 4, 4, 5, 4, 8, 9, 2, 1, 6, 8, 3, 9,
+
2, 8, 0, 5, 0, 9, 7, 2, 5, 9, ...], 4175670},
+
{[9, 6, 3, 2, 9, 6, 8, 1, 7, 8, 0, 7, 2, 2, 0, 8, 6, 5, 5, 3, 9, 6, 5, 7, 1, 4, 6, 7, 9, 7, 2, 4,
+
6, 2, 0, 2, 9, 7, 8, 0, 9, ...], 9128738},
+
{[5, 8, 5, 2, 2, 9, 4, 4, 8, 8, 9, 9, 8, 3, 4, 9, 2, 2, 9, 1, 2, 2, 0, 8, 1, 2, 3, 4, 0, 4, 6, 4,
+
3, 6, 8, 1, 9, 6, 1, 5, ...], 13899897},
+
{[0, 9, 4, 3, 5, 9, 1, 2, 1, 1, 8, 1, 8, 8, 3, 8, 4, 4, 3, 7, 7, 2, 9, 8, 5, 8, 8, 4, 4, 8, 4, 0,
+
5, 9, 7, 0, 3, 3, 6, ...], 12087848},
+
{[5, 6, 7, 3, 2, 0, 5, 4, 8, 8, 2, 6, 8, 4, 9, 7, 2, 0, 9, 3, 4, 1, 3, 0, 6, 5, 2, 6, 4, 6, 9, 4,
+
3, 9, 9, 9, 7, 2, ...], 11514818},
+
{[0, 9, 7, 9, 2, 6, 4, 9, 7, 0, 3, 1, 6, 4, 3, 2, 0, 2, 8, 4, 7, 6, 7, 7, 1, 1, 5, 2, 6, 6, 1, 4,
+
9, 5, 6, 9, 3, ...], 4150418},
+
{[5, 5, 0, 8, 5, 6, 2, 7, 0, 5, 4, 2, 1, 0, 5, 6, 6, 3, 6, 2, 4, 3, 9, 4, 3, 0, 8, 0, 6, 7, 1, 8,
+
0, 2, 7, 1, ...], 2679493},
+
{[4, 0, 8, 1, 5, 9, 0, 3, 6, 0, 2, 8, 5, 7, 1, 1, 9, 1, 5, 1, 5, 0, 7, 3, 5, 5, 4, 3, 9, 4, 3, 9,
+
6, 9, 6, ...], 84072},
+
{[0, 5, 2, 6, 6, 4, 1, 2, 5, 2, 3, 8, 4, 1, 2, 4, 7, 5, 2, 7, 7, 0, 8, 0, 6, 0, 6, 3, 4, 3, 7, 0,
+
5, 8, ...], 3938870},
+
{[5, 5, 5, 5, 6, 0, 6, 9, 2, 0, 0, 5, 3, 0, 3, 3, 0, 7, 7, 0, 1, 5, 8, 8, 6, 5, 3, 3, 2, 5, 8, 8,
+
8, ...], 15186439},
+
{[5, 1, 6, 4, 5, 2, 2, 2, 0, 9, 6, 3, 2, 1, 5, 6, 2, 6, 0, 4, 2, 8, 9, 2, 8, 7, 8, 7, 9, 2, 5, 1,
+
...], 4224277},
+
{[8, 7, 6, 6, 8, 0, 1, 8, 9, 1, 7, 5, 0, 6, 4, 4, 9, 2, 1, 6, 1, 5, 4, 1, 9, 9, 9, 4, 7, 3, 0,
+
...], 6637814},
+
{[7, 4, 4, 8, 3, 9, 5, 6, 1, 1, 7, 4, 7, 2, 5, 3, 8, 5, 3, 4, 7, 7, 0, 0, 4, 1, 7, 1, 4, 5, ...],
+
15335578},
+
{[1, 3, 9, 5, 1, 4, 9, 6, 9, 0, 6, 7, 7, 5, 4, 8, 8, 4, 4, 0, 3, 0, 0, 2, 8, 8, 8, 7, 5, ...],
+
14808063},
+
{[3, 8, 6, 7, 8, 8, 1, 5, 4, 2, 3, 3, 6, 0, 4, 4, 6, 3, 6, 3, 5, 3, 3, 7, 4, 7, 1, 8, ...],
+
2236221},
+
{[4, 2, 4, 3, 0, 3, 6, 2, 7, 9, 6, 6, 9, 3, 2, 0, 1, 8, 1, 5, 7, 7, 3, 8, 8, 1, 9, ...], 9777274},
+
{[8, 5, 1, 6, 9, 9, 1, 6, 3, 9, 9, 4, 5, 9, 4, 2, 8, 5, 7, 9, 2, 1, 6, 9, 0, 9, ...], 14777742},
+
{[4, 6, 0, 4, 6, 3, 2, 3, 8, 0, 2, 3, 2, 2, 0, 7, 7, 4, 5, 8, 8, 2, 8, 9, 4, ...], 3528684},
+
{[3, 6, 3, 3, 3, 2, 5, 2, 8, 8, 8, 0, 3, 1, 2, 2, 6, 2, 3, 1, 2, 6, 1, 9, ...], 15225220},
+
{[2, 1, 2, 4, 0, 6, 0, 8, 6, 5, 9, 5, 1, 7, 1, 3, 9, 3, 2, 8, 5, 4, 8, ...], 4484251},
+
{[1, 5, 9, 2, 0, 5, 7, 4, 6, 2, 3, 4, 7, 9, 9, 7, 9, 8, 3, 4, 2, 3, ...], 12505941},
+
{[3, 2, 8, 0, 7, 6, 7, 8, 6, 2, 0, 4, 7, 6, 2, 8, 2, 7, 3, 0, 3, ...], 12324709},
+
{[3, 6, 3, 2, 2, 5, 4, 5, 3, 2, 2, 8, 5, 8, 7, 6, 5, 9, 3, 0, ...], 12840916},
+
{[7, 4, 1, 3, 5, 7, 1, 9, 4, 8, 2, 0, 2, 6, 7, 1, 7, 8, 4, ...], 13939301},
+
{[0, 4, 4, 4, 6, 9, 8, 0, 2, 3, 9, 9, 4, 0, 6, 0, 4, 2, ...], 7392065},
+
{[7, 8, 0, 0, 4, 1, 6, 1, 5, 9, 0, 3, 1, 4, 5, 8, 9, ...], 13395486},
+
{[5, 5, 1, 7, 9, 8, 0, 1, 5, 5, 6, 2, 1, 6, 6, 5, ...], 14846825},
+
{[4, 1, 5, 9, 7, 1, 3, 6, 6, 5, 8, 9, 1, 0, 7, ...], 15647415},
+
{[5, 0, 0, 5, 4, 4, 9, 3, 4, 0, 4, 9, 0, 0, ...], 15491670},
+
{[5, 3, 1, 3, 6, 7, 3, 2, 8, 6, 2, 5, 0, ...], 12602693},
+
{[9, 6, 3, 2, 6, 3, 9, 6, 6, 5, 2, 6, ...], 16470307},
+
{[8, 4, 3, 6, 0, 4, 0, 8, 5, 5, 9, ...], 10819101},
+
{[0, 9, 4, 4, 6, 0, 2, 4, 0, 3, ...], 8658998},
+
{[0, 2, 8, 3, 0, 4, 5, 0, 5, ...], 11616760},
+
{[4, 8, 3, 5, 2, 8, 0, 8, ...], 4294043},
+
{[8, 1, 0, 8, 2, 1, 0, ...], 11210309},
+
{[5, 8, 6, 9, 6, 8, ...], 1113711},
+
{[1, 6, 5, 5, 4, ...], 16530315},
+
{[5, 1, 3, 9, ...], 8014000},
+
{[7, 4, 5, ...], 13932057},
+
{[8, 9, ...], 9987703},
+
{[4, ...], 10745797},
+
{[...], ...},
+
{...},
+
...
+
]
+
```
+
+
## Part 1
+
+
```elixir
+
hashes
+
|> Enum.map(&elem(&1, 1))
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
13461553007
+
```
+
+
## Part 2
+
+
```elixir
+
hashes
+
|> Task.async_stream(
+
fn {prices, _} -> Buyer.sequences(prices) end,
+
ordered: false
+
)
+
|> Enum.reduce(%{}, fn {:ok, a}, b -> Map.merge(a, b, fn _k, v, k -> v + k end) end)
+
|> Enum.max_by(&elem(&1, 1))
+
|> elem(1)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1499
+
```
+
+
<!-- livebook:{"offset":11738,"stamp":{"token":"XCP.GjkWCjlMBRZbt2b3Ic6te1lRoiRN-o788mezmoiandQKEk9mR1MC2aSWY6otgof8lHDa_afMMYYnBV9YHmLjoK0wooHF17OPyx6ruqV5hYpKoVBVZuhSx_gT8_2Ac2S73Pk","version":2}} -->
+203
2024/day23.livemd
···
+
<!-- livebook:{"persist_outputs":true} -->
+
+
# Day 23
+
+
```elixir
+
Mix.install([:kino_aoc, {:libgraph, github: "bitwalker/libgraph"}, :combination])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIyMyIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI0In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2024", "23", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
{:ok,
+
"on-za\nbp-hs\nvc-bg\ntm-us\nzf-ox\nib-lc\nuo-zs\nov-qj\nll-eb\niy-tq\nbg-by\nun-ix\ngi-do\nrv-ou\nyp-qu\nqb-um\nqs-dn\nru-ro\net-fw\nyx-jt\nns-iz\nod-rc\nny-ap\nvb-fd\nwf-wr\nyh-qy\nfa-ct\nqo-fv\nig-jv\nqi-ff\nnj-ii\nsa-gg\ncp-un\nez-kh\nvs-du\ngp-qs\npt-qj\nyp-my\njf-sz\nyo-gm\nfn-xw\niu-xr\nse-ox\nmw-ie\nfw-br\nxy-iu\nqw-wi\nxc-dq\nvb-cq\ntw-zj\nka-aq\ngo-ds\nvi-cn\npz-kz\npy-nd\npt-ws\nog-lw\nlb-hj\nef-ac\ncv-qa\nsq-jv\nfw-xk\nlu-fc\nbj-bp\nzh-fi\ntg-nm\nsp-at\nke-dh\nut-ly\ngr-vr\nko-qg\nxg-df\nrc-up\nbd-it\ngz-en\nqj-ev\nwf-dx\nxn-hi\npq-th\nkr-gw\ngu-sm\ncv-xr\nzq-fp\nep-kq\nfv-dx\nlc-rw\ney-ef\nek-rw\ntw-eg\nfc-zw\nxm-ho\ngj-oy\nhy-og\nec-tw\npy-hw\nqr-jh\nvh-ea\nvz-ja\nov-ev\nyh-vh\nyk-fc\nfm-yi\nyf-kx\ner-bi\nbi-qq\ngc-fk\nie-gf\njk-fn\nxl-il\nbs-dl\nsh-op\npy-vx\ncn-jl\ntl-ee\nxw-wn\nzv-br\nkr-yn\ndj-wd\nwj-bz\nhf-bg\nzh-ql\nbs-ls\ntq-jk\nmz-dz\nav-jr\ngj-dr\npo-iy\nof-aq\nun-fw\nnv-bx\njz-nl\nze-ae\nvd-df\nix-et\nrn-ik\ndz-ou\nmz-ej\nec-kx\nxr-cf\njt-vr\nix-fw\nes-er\nbv-no\nwj-df\nyv-cl\njd-xl\nlu-vo\nxo-td\nvq-ow\nlc-vm\nca-lf\noq-on\nwj-xg\nfn-rp\nka-np\nbx-ez\ndz-sz\nkt-xl\ndd-jd\nla-qn\nqe-pt\ngl-ly\nqj-cc\nat-rf\nke-om\ndc-hu\nqb-rr\nov-ku\ntq-xw\nfz-tn\nma-hi\nbr-yw\nno-sp\ndj-kn\nyn-gw\ngo-ir\nbz-xg\nwo-se\nrz-wa\nqy-sx\nqn-ym\npo-tq\nxr-jh\ndf-tn\noe-vi\nsw-el\nvm-vr\ntg-nf\ncg-zt\nwf-fl\ncd-nc\nsw-qa\nfo-jg\nhj-av\nwd-rn\nwc-wq\noq-vw\nkx-ux\nop-nq\nsm-ru\nch-fw\nqx-uy\nti-fw\nrp-qm\npo-tj\nse-nw\npj-rs\nbo-sn\nsy-ur\niy-jb\ntm-rz\ndg-jt\nfa-sq\nok-th\nzq-ps\nhr-kr\npz-zs\nwq-ze\nms-an\nnp-aq\ntl-ka\npw-dh\nbm-sz\nuu-gm\nft-vb\nau-ab\nlx-lw\ncp-ri\nep-xm\nry-hk\nyi-gf\ncj-qr\nfl-lu\nbv-za\nyw-xk\nne-ss\nln-wv\nwf-vo\nlx-jy\noy-xy\nkq-fa\neh-lv\nuq-mi\nis-mx\nwn-eo\nqr-xy\nlr-ms\nkt-jd\nyk-lu\nqe-cc\naj-si\nqq-bp\nlw-xa\nus-pp\nen-mq\nct-te\nod-db\ncp-br\nrg-ou\nev-ku\nqg-ec\nuv-np\njn-sw\nxj-ie\nqr-xr\ntr-zp\nha-gg\nrx-pz\nsa-fl\ngx-vz\nmg-oi\nyc-zn\nxw-jo\nae-ou\nhj-gn\nix-ri\nsq-ct\nwo-xr\nbl-wl\ntt-ac\nbs-ij\nmh-re\nhg-lv\nwu-fh\nrt-rq\nsn-vq\nzy-vh\nyh-zy\ntu-oz\nbk-ai\nds-gq\nss-ob\ndv-di\nvw-on\nxr-zb\nfr-jl\nro-om\nrk-mg\nyc-hi\nvv-nf\nkz-nt\nrt-qw\nzj-ux\nox-wv\nfz-dc\nya-xo\ngq-du\nmx-fk\nsi-mo\nmo-ef\ndb-ex\nhw-rc\njy-qd\noz-lb\nvi-cm\nvx-ec\nxr-aa\nnx-ni\nny-fv\nta-vc\nnq-yi\nzt-gp\nnd-iu\nvv-yd\nsh-gf\nyf-hm\ndq-ee\nbg-bt\nnc-kz\ngq-py\nek-sy\nty-le\njo-eo\ndy-ko\nxa-qd\nrm-ns\ngk-xp\ngz-jr\ncr-ez\nwr-fc\nhe-cg\nin-og\ndw-sh\nuk-bf\nbr-un\nok-gi\nch-gr\ncx-gz\ndv-ho\nbx-cr\nex-go\nik-nv\nkh-wb\nol-vk\nhg-bf\nod-du\nvj-qk\nyd-uj\nfu-lq\nbi-bj\nvl-il\ncd-ob\nax-us\nmw-nq\nvr-rw\nhx-uf\nwz-vb\nem-xe\nee-of\nhm-ec\nek-ds\nys-sy\nqq-jq\ngu-jg\nzc-oi\nji-yb\nou-kw\nep-lh\nid-nx\ngp-wp\nph-ns\ncn-io\nwn-tq\nrw-vm\nnx-fv\nce-gn\nvr-lt\nxl-dd\nzw-sa\nwr-ty\nkz-jx\njd-rx\nna-hk\nnc-ob\nnw-re\nwt-jq\naj-sw\nkc-bi\nwq-qx\njt-ib\ncb-ly\nuj-zp\ncy-ps\nsm-om\nbu-bd\nux-ko\nxa-hy\nbc-uq\nsi-sw\nyc-ma\nyk-sa\ngf-mw\nbp-eq\nfh-zh\nmn-bo\nbw-hj\nes-bj\nop-xj\nup-hh\nds-db\ngx-qu\nyo-fp\nwg-ls\net-zc\ndn-vw\nyb-bt\nsk-sb\nxe-ea\nni-ap\nhw-go\ndn-zc\nno-vw\npt-cc\nrv-wc\nwc-xq\njg-ke\noo-jg\ndo-ss\nie-nq\npq-is\nrf-oq\nzn-vb\neb-ef\ngp-rs\npt-pf\nmd-lb\nle-zw\nxn-tf\nui-cb\nbz-fz\npj-gp\nzr-ee\npp-ax\nkl-jq\nxc-of\nox-lr\nuy-rv\nvd-sb\nyy-bh\nvn-dq\ndt-hg\nnp-vn\nla-fh\ngw-eh\ncq-wz\nno-ia\nqj-ws\npl-pt\ndf-ge\nzq-vj\njg-om\nnq-sh\nzy-kr\npv-im\naq-vn\nsq-yx\nsb-df\nih-gx\ngn-av\ndc-ff\nwg-ph\nsm-fo\nux-dk\ngi-kv\nhr-dt\nrc-go\nax-tm\npp-bo\nnn-xe\njf-mz\nvl-jd\nfs-cl\ngz-gn\nui-ly\nrx-hy\nrn-dj\nqe-pf\njx-gy\ntr-qb\neu-lr\nyt-ih\ntr-oi\nnc-ss\nnh-pb\nir-nd\nel-qf\ntl-aq\nkj-es\nru-fo\nfw-bu\nps-qk\nlq-lx\ncm-fg\nel-si\nvs-hw\neg-ux\nmt-lh\ntt-yy\njz-sq\nfm-nq\nvx-ko\nbl-lx\nrc-ex\nby-ji\neq-kl\ntk-vd\nmo-qf\nzr-xd\nbt-vc\nux-mi\nha-us\nvr-ib\nhx-rq\nat-no\nui-tx\nvs-od\nfp-ay\nzj-kx\nvs-ds\nqo-vk\nhw-db\npf-ku\nmd-jr\nfp-fe\nyg-tx\nmz-gs\nnl-ct\ncn-oe\nxj-ri\nya-ku\nnw-mh\nvh-ff\nft-hz\nen-md\nps-fp\naf-rx\nvx-kx\nkv-fd\nkr-lf\nae-rg\nsp-vw\nvn-zr\nea-pi\nat-vw\nrw-ax\nkg-vh\nxy-cv\nca-gw\nem-nn\nhj-en\ngw-ra\nfr-cy\ned-wu\nyf-tw\nuo-lz\ngc-pq\ntw-ux\nqy-kg\ncx-fo\nit-ly\nuj-mg\nrp-po\nsq-yv\nzh-zs\nth-ne\nes-fe\nrn-nv\naa-gj\nzb-aa\nwt-kl\nwu-uo\nbb-ce\nby-bt\nqb-gv\nbp-es\nbd-tx\nma-cq\nyt-qu\nuu-mn\nke-fa\nmx-jn\ndq-ew\nax-ow\nhv-dx\nyh-sx\ngx-ry\njz-jv\nsb-wj\ndo-ok\ngj-qn\nbr-ri\nlu-zw\nsb-ge\nkg-ao\nuu-fp\nus-xh\ndd-jb\nxp-wi\ncf-cj\nhm-zj\nle-sa\nwf-ty\nqx-xq\noi-rr\nbl-og\nmq-hj\ndw-xi\naw-ap\nsk-cs\nwu-yq\ngm-zq\nna-ry\nwp-pj\nne-gy\ndt-yn\nau-bm\nrk-ur\nnm-oi\naf-zm\ncd-ss\ndj-ez\ncf-oy\nce-md\nth-kz\nnt-cd\nrm-iz\njz-fs\nni-qo\njx-do\nzy-xe\nls-uq\nsy-jt\nwa-xh\nlf-lv\nys-jt\nij-wg\njw-mw\nbk-ef\nyx-ek\nvr-cm\njv-sk\ndw-ej\nmo-pq\nov-pl\nfz-ge\nmt-ep\ncq-hz\nza-zc\nlj-uy\nrv-ae\nse-ln\nkw-ze\nwo-ln\nvo-zw\nwd-fd\nxo-pl\nmx-gc\nln-lr\nsy-rw\ngy-fs\nzy-ea\nkc-er\nfl-l" <> ...}
+
```
+
+
```elixir
+
connections =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn <<a::binary-2, "-", b::binary-2>> ->
+
{a, b}
+
end)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
{"on", "za"},
+
{"bp", "hs"},
+
{"vc", "bg"},
+
{"tm", "us"},
+
{"zf", "ox"},
+
{"ib", "lc"},
+
{"uo", "zs"},
+
{"ov", "qj"},
+
{"ll", "eb"},
+
{"iy", "tq"},
+
{"bg", "by"},
+
{"un", "ix"},
+
{"gi", "do"},
+
{"rv", "ou"},
+
{"yp", "qu"},
+
{"qb", "um"},
+
{"qs", "dn"},
+
{"ru", "ro"},
+
{"et", "fw"},
+
{"yx", "jt"},
+
{"ns", "iz"},
+
{"od", "rc"},
+
{"ny", "ap"},
+
{"vb", "fd"},
+
{"wf", "wr"},
+
{"yh", "qy"},
+
{"fa", "ct"},
+
{"qo", "fv"},
+
{"ig", "jv"},
+
{"qi", "ff"},
+
{"nj", "ii"},
+
{"sa", "gg"},
+
{"cp", "un"},
+
{"ez", "kh"},
+
{"vs", "du"},
+
{"gp", "qs"},
+
{"pt", "qj"},
+
{"yp", "my"},
+
{"jf", "sz"},
+
{"yo", "gm"},
+
{"fn", "xw"},
+
{"iu", "xr"},
+
{"se", "ox"},
+
{"mw", "ie"},
+
{"fw", "br"},
+
{"xy", "iu"},
+
{"qw", "wi"},
+
{"xc", "dq"},
+
{"vb", ...},
+
{...},
+
...
+
]
+
```
+
+
```elixir
+
party =
+
Graph.new(type: :undirected)
+
|> Graph.add_edges(connections)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
#Graph<type: undirected, num_vertices: 520, num_edges: 3380>
+
```
+
+
```elixir
+
cliques = Graph.cliques(party)
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
[
+
["yf", "dk", "dy", "hm", "vx", "zj", "ec", "eg", "ko", "kx", "tw", "ux"],
+
["yf", "dk", "hm", "vx", "zj", "ec", "eg", "qg", "ko", "kx", "tw", "ux"],
+
["yf", "ob"],
+
["xa", "wl", "lx", "lq", "jy", "in", "hy", "lw", "qd", "fu", "ub", "og"],
+
["xa", "wl", "lx", "jy", "bl", "in", "hy", "lw", "qd", "fu", "ub", "og"],
+
["xa", "wi"],
+
["bd", "cb", "it", "ut", "fq", "hs", "ur", "ly", "tx", "yg", "ui", "gl"],
+
["bd", "cb", "it", "ut", "fq", "ur", "ly", "tx", "yg", "ui", "gl", "rk"],
+
["bd", "bu"],
+
["nm", "qb", "gv", "nf", "oi", "tg", "uj", "yd", "rr", "tr", "vv", "mg"],
+
["nm", "qb", "gv", "nf", "oi", "tg", "uj", "yd", "rr", "tr", "vv", "zp"],
+
["nm", "ge"],
+
["dk", "jn"],
+
["cn", "lh", "di", "xm", "cm", "oe", "vi", "ho", "fg", "mt", "io", "dv"],
+
["cn", "zt"],
+
["cn", "jl"],
+
["qp", "xd"],
+
["qp", "zq", "qk", "uu", "cy", "fp", "ay", "yo", "gm", "vj", "ps", "fr"],
+
["qp", "zq", "qk", "uu", "cy", "ay", "yo", "gm", "vj", "jl", "ps", "fr"],
+
["xq", "qx", "rg", "wc", "um", "rv", "ae", "kw", "lj", "ze", "wq", "ou"],
+
["xq", "kg"],
+
["xq", "qo"],
+
["ti", "et", "bu", "xk", "ix", "fw", "un", "ri", "cp", "br", "gr", "ch"],
+
["ti", "et", "bu", "xk", "fw", "un", "ri", "cp", "br", "gr", "ch", "yw"],
+
["ti", "ab"],
+
["nh", "hv", "id", "ap", "fv", "ny", "pb", "ni", "aw", "nx", "vk", "qo"],
+
["nh", "pj"],
+
["nh", "lk"],
+
["ys", "ib", "dg", "vr", "yx", "jt", "ek", "lt", "sy", "vm", "lc", "rw"],
+
["ys", "ib", "dg", "yx", "jt", "pg", "ek", "lt", "sy", "vm", "lc", "rw"],
+
["ys", "tl"],
+
["cb", "ha"],
+
["ue", "dd", "kd", "zm", "kt", "il", "af", "xx", "vl", "xl", "jd", "rx"],
+
["ue", "dd", "kd", "kt", "il", "af", "xx", "vl", "xl", "jd", "rx", "pz"],
+
["ue", "bh"],
+
["jg", "cx", "fo", "ro", "ru", "oo", "dh", "as", "zx", "ke", "om", "gu"],
+
["jg", "cx", "fo", "ro", "ru", "dh", "as", "sm", "zx", "ke", "om", "gu"],
+
["jg", "cy"],
+
["bz", "fz", "qi", "tn", "xg", "dc", "ge", "sb", "df", "hu", "vd", ...],
+
["bz", "ae"],
+
["bz", "gm"],
+
["im", "dz", "ab", "sz", "ej", "mz", "pv", "rj", ...],
+
["im", "dz", "sz", "ej", "mz", "pv", "rj", ...],
+
["im", "ps"],
+
["sw", "gc", "si", "aj", "is", ...],
+
["sw", "gc", "si", "aj", ...],
+
["sw", "fn"],
+
["cg", "zt", ...],
+
["cg", ...],
+
[...],
+
...
+
]
+
```
+
+
## Part 1
+
+
```elixir
+
cliques
+
|> Stream.flat_map(fn clique ->
+
if length(clique) >= 3 do
+
Combination.combine(clique, 3)
+
else
+
[]
+
end
+
end)
+
|> Stream.filter(fn clique -> Enum.any?(clique, &String.starts_with?(&1, "t")) end)
+
|> MapSet.new()
+
|> MapSet.size()
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
1248
+
```
+
+
## Part 2
+
+
```elixir
+
cliques
+
|> Enum.max_by(&length/1)
+
|> Enum.sort()
+
|> Enum.join(",")
+
```
+
+
<!-- livebook:{"output":true} -->
+
+
```
+
"aa,cf,cj,cv,dr,gj,iu,jh,oy,qr,xr,xy,zb"
+
```
+
+
<!-- livebook:{"offset":9387,"stamp":{"token":"XCP.YMMjV81j86GOTx0hGVW-U0w7aqvuBdig59tmj2pqELbNIP0HXjbZA1WSQwLRMCUIuzZ1PLs6_0ehAVdgp7sj4Wuc6QaM8KCZ3j-zJrTUmr2_hxaACLOnkijsz6m2hIS8E6Q","version":2}} -->
+67
2025/day01.livemd
···
+
# Day 01
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Setup
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxIiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "1", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
instructions =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn <<dir>> <> rest ->
+
num = String.to_integer(rest)
+
+
if dir == ?R do
+
{div(num, 100), rem(num, 100)}
+
else
+
{div(num, 100), -rem(num, 100)}
+
end
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 1
+
+
```elixir
+
Enum.scan(instructions, 50, fn {_rot, val}, curr ->
+
Integer.mod(curr + val, 100)
+
end)
+
|> Enum.count(& &1 == 0)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 2
+
+
```elixir
+
<<0x434C49434B::40>>
+
```
+
+
```elixir
+
Enum.reduce(instructions, {50, 0}, fn {rot, val}, {curr, sum} ->
+
next = curr + val
+
+
pass =
+
cond do
+
curr == 0 and next < 0 -> 0
+
next not in 0..99 -> 1
+
rem(next, 100) == 0 -> 1
+
true -> 0
+
end
+
+
{Integer.mod(next, 100), sum + pass + rot}
+
end)
+
|> elem(1)
+
```
+
+
<!-- livebook:{"offset":1270,"stamp":{"token":"XCP.fAfBqYepop325WQHLC6mJPz_Wpl7bDiz0qRbslvjG31mRJWcHALfstxgj_iOj3nf9_GCzh_WmPiNR4MnzZidF2bz_zMMXHTEo18hp1z3gQDdi5hTSO8UG4YSYnUEtGxO2g","version":2}} -->
+85
2025/day02.livemd
···
+
# Day 02
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Parsing
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIyIiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "2", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
ranges =
+
puzzle_input
+
|> String.trim()
+
|> String.split(",")
+
|> Enum.map(fn range ->
+
range
+
|> String.split("-")
+
|> Enum.map(&String.to_integer/1)
+
|> then(&apply(Range, :new, &1))
+
end)
+
|> Enum.sort_by(& &1.last)
+
```
+
+
## Implementation
+
+
```elixir
+
defmodule ElfRanges do
+
def valid?(num) do
+
len = floor(:math.log10(num)) + 1
+
+
valid_n?(num, len, 2)
+
end
+
+
def valid_any?(num) do
+
len = floor(:math.log10(num)) + 1
+
+
Enum.all?(2..len//1, &valid_n?(num, len, &1))
+
end
+
+
def valid_n?(num, len, n) do
+
if rem(len, n) == 0 do
+
step = 10 ** div(len, n)
+
+
Stream.unfold(num, fn
+
0 -> nil
+
val -> {rem(val, step), div(val, step)}
+
end)
+
|> Enum.dedup()
+
|> then(&(not match?([_], &1)))
+
else
+
true
+
end
+
end
+
end
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 1
+
+
```elixir
+
ranges
+
|> Stream.flat_map(& &1)
+
|> Stream.reject(&ElfRanges.valid?/1)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 2
+
+
```elixir
+
ranges
+
|> Stream.flat_map(& &1)
+
|> Stream.reject(&ElfRanges.valid_any?/1)
+
|> Enum.sum()
+
```
+
+
<!-- livebook:{"offset":1551,"stamp":{"token":"XCP.GvC7N5ZC0xuQ3hRuVxd-rh5rJDKVZKJfmwspDkAuCFbjn8qdOUksP9Iy1GRtd7t5yLCV6nkfhXZlp_lTw8eZZBcwItn6IlML-jrjiORJQvkuXOHvzlOY17rIAaASRKvS3w","version":2}} -->
+56
2025/day03.livemd
···
+
# Day 03
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Parse
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIzIiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "3", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
batteries =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn row ->
+
row
+
|> String.to_charlist()
+
|> Enum.map(& &1 - ?0)
+
end)
+
```
+
+
```elixir
+
defmodule Joltage do
+
def make_largest(list, n) do
+
to_remove = length(list) - n
+
Enum.reduce(1..to_remove, list, fn _, acc -> make_larger(acc) end)
+
end
+
+
def make_larger([_]), do: []
+
def make_larger([a, b | rest]) when a < b, do: [b | rest]
+
def make_larger([b | rest]), do: [b | make_larger(rest)]
+
end
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 1
+
+
```elixir
+
Enum.sum_by(batteries, &Integer.undigits(Joltage.make_largest(&1, 2)))
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 2
+
+
```elixir
+
Enum.sum_by(batteries, &Integer.undigits(Joltage.make_largest(&1, 12)))
+
```
+
+
<!-- livebook:{"offset":1212,"stamp":{"token":"XCP.fo1ohV8LylIz8VmOAj7rlJ4Jn5KPGtiiFfsDRmp0pFSXCESjhfmQ11wOwEVmq9HM-Zn8fozQDsOoJbfgbM5LJPVE9c0pw2tYKbteOOGNqHI3PTIkuBnv8ZPW6oYwWAZy4A","version":2}} -->
+82
2025/day04.livemd
···
+
# Day 04
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Parse
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI0Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "4", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
rolls =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.with_index()
+
|> Enum.flat_map(fn {line, row} ->
+
line
+
|> String.to_charlist()
+
|> Enum.with_index()
+
|> Enum.filter(&(elem(&1, 0) == ?@))
+
|> Enum.map(&{elem(&1, 1), row})
+
end)
+
|> MapSet.new()
+
```
+
+
## Implementation
+
+
```elixir
+
defmodule PaperRolls do
+
defp adjacent({x, y}) do
+
for dx <- -1..1,
+
dy <- -1..1,
+
{dx, dy} != {0, 0},
+
do: {x + dx, y + dy}
+
end
+
+
def movable?(pos, map) do
+
pos
+
|> adjacent()
+
|> Enum.count(&(&1 in map))
+
|> then(&(&1 < 4))
+
end
+
end
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 1
+
+
```elixir
+
Enum.count(rolls, &PaperRolls.movable?(&1, rolls))
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 2
+
+
```elixir
+
cleaned =
+
Stream.repeatedly(fn -> [] end)
+
|> Enum.reduce_while(rolls, fn _, acc ->
+
removable =
+
Enum.filter(acc, &PaperRolls.movable?(&1, acc))
+
|> MapSet.new()
+
+
case MapSet.difference(acc, removable) do
+
^acc -> {:halt, acc}
+
remaining -> {:cont, remaining}
+
end
+
end)
+
```
+
+
```elixir
+
MapSet.size(rolls) - MapSet.size(cleaned)
+
```
+
+
<!-- livebook:{"offset":1586,"stamp":{"token":"XCP.-_kcJR24r3dthl7SnpOh24JBI5hDpqMlFjQQDQ0pxtv4UHyaTlGoG4rG5iZxKtgxQoNAxw0K-mowSwehidDfrqewK3r9FHoOcAOIDbOMFd3QGH2X2Ta6KeXd4PlzWSYDBw","version":2}} -->
+54
2025/day05.livemd
···
+
# Day 05
+
+
```elixir
+
Mix.install([
+
:kino_aoc,
+
:range_set
+
])
+
```
+
+
## Parse
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI1Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "5", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
[fresh, ingridients] = String.split(puzzle_input, "\n\n")
+
+
fresh =
+
fresh
+
|> String.split()
+
|> Enum.map(fn range ->
+
[a, b] = range |> String.split("-") |> Enum.map(&String.to_integer/1)
+
+
a..b//1
+
end)
+
|> RangeSet.new()
+
+
ingridients =
+
ingridients
+
|> String.split()
+
|> Enum.map(&String.to_integer/1)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 1
+
+
```elixir
+
Enum.count(ingridients, & &1 in fresh)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 2
+
+
```elixir
+
Enum.count(fresh)
+
```
+
+
<!-- livebook:{"offset":973,"stamp":{"token":"XCP.GHEtbWlG6LHz6I0d5Y_d4738EDILulvQyP1NtPISLeYWo9atG0Ailm43-eswn0JGS5h2z5Yxb8Xi8nGJLqUkj41eqpnT_u7NxVCT4ceeKMBsd5R-EuxBw0P7vLlBab68MA","version":2}} -->
+68
2025/day06.livemd
···
+
# Day 06
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Setup
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI2Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "6", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
{tasks, [ops]} =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.split(-1)
+
```
+
+
```elixir
+
ops =
+
ops
+
|> String.split()
+
|> Enum.map(&String.to_atom/1)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 1
+
+
```elixir
+
tasks
+
|> Enum.map(&String.split/1)
+
|> Enum.zip_with(fn numbers -> Enum.map(numbers, &String.to_integer/1) end)
+
|> Enum.zip(ops)
+
|> Enum.sum_by(fn
+
{nums, :+} -> Enum.sum(nums)
+
{nums, :*} -> Enum.product(nums)
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 2
+
+
```elixir
+
tasks
+
|> Enum.map(&String.to_charlist/1)
+
|> Enum.zip_with(&(&1 |> List.to_string() |> String.trim()))
+
|> Enum.chunk_while(
+
[],
+
fn
+
"", acc -> {:cont, acc, []}
+
num, acc -> {:cont, [String.to_integer(num) | acc]}
+
end,
+
&{:cont, &1, []}
+
)
+
|> Enum.zip(ops)
+
|> Enum.sum_by(fn
+
{nums, :+} -> Enum.sum(nums)
+
{nums, :*} -> Enum.product(nums)
+
end)
+
```
+
+
<!-- livebook:{"offset":1319,"stamp":{"token":"XCP.wqKPUf7KHN-UzqY1O8_n61vLL2ksAE_kGnIsQL0IpamJTD-NEX9_HbYK4H0y_NM8lKhqDz4rZ-TMFsXjuQ3n2-URGSNh_SCmDtJIbJBAP3mbiCwyN52oyGL0Nq5eD424MQ","version":2}} -->
+117
2025/day07.livemd
···
+
# Day 07
+
+
```elixir
+
Mix.install([:kino_aoc, :image])
+
```
+
+
## Parse
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI3Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "7", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
[start | rest] = String.split(puzzle_input)
+
+
start_col = byte_size(start) - byte_size(String.trim_leading(start, "."))
+
```
+
+
```elixir
+
splitters =
+
Enum.map(rest, fn row ->
+
row
+
|> String.to_charlist()
+
|> Enum.with_index()
+
|> Enum.filter(&(elem(&1, 0) == ?^))
+
|> MapSet.new(&elem(&1, 1))
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 1
+
+
```elixir
+
Enum.reduce(splitters, {MapSet.new([start_col]), 0}, fn splits, {beams, count} ->
+
import MapSet, only: [intersection: 2, difference: 2, union: 2]
+
+
hits = intersection(beams, splits)
+
new_beams = for hit <- hits, dx <- [-1, 1], into: MapSet.new(), do: hit + dx
+
beams = beams |> difference(hits) |> union(new_beams)
+
+
{beams, MapSet.size(hits) + count}
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 2
+
+
```elixir
+
Enum.reduce(splitters, %{start_col => 1}, fn splits, beams ->
+
Enum.reduce(splits, beams, fn s, acc ->
+
case Map.pop(acc, s) do
+
{nil, map} ->
+
map
+
+
{count, map} ->
+
Map.merge(
+
map,
+
%{
+
(s + 1) => count,
+
(s - 1) => count
+
},
+
fn _k, a, b -> a + b end
+
)
+
end
+
end)
+
end)
+
|> Enum.sum_by(&elem(&1, 1))
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Image
+
+
```elixir
+
height = length([start | rest])
+
width = byte_size(start)
+
+
{height, width}
+
```
+
+
```elixir
+
Image.new!(width, height)
+
|> Image.mutate(fn img ->
+
Image.Draw.point!(img, start_col, 0, color: :yellow)
+
+
splitters
+
|> Enum.with_index(1)
+
|> Enum.reduce(MapSet.new([start_col]), fn {splits, y}, beams ->
+
import MapSet, only: [intersection: 2, difference: 2, union: 2]
+
+
for x <- beams do
+
Image.Draw.point(img, x, y, color: :green)
+
end
+
+
for x <- splits do
+
Image.Draw.point(img, x, y, color: :red)
+
end
+
+
hits = intersection(beams, splits)
+
new_beams = for hit <- hits, dx <- [-1, 1], into: MapSet.new(), do: hit + dx
+
beams = beams |> difference(hits) |> union(new_beams)
+
+
beams
+
end)
+
+
img
+
end)
+
|> then(fn {:ok, img} -> img end)
+
|> Image.resize!(5, interpolate: :nearest)
+
```
+
+
<!-- livebook:{"offset":2553,"stamp":{"token":"XCP.6lQNAY-yntHErm41fMi4xgwAxGSGZ7l6ekgYSe6b3Exm48kBKgyIoCK62LLVaeQP-1PfZFpd3tzHwAIA8OWTsnRBuWsxmex5qixMa-l4DaThm-jrSaVsE3Qj4aO-TrqdqA","version":2}} -->
+116
2025/day08.livemd
···
+
# Day 08
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Parse
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI4Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "8", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
boxes =
+
puzzle_input
+
|> String.split()
+
|> Enum.map(fn raw ->
+
raw
+
|> String.split(",")
+
|> Enum.map(&String.to_integer/1)
+
|> List.to_tuple()
+
end)
+
|> Enum.sort()
+
```
+
+
## Setup
+
+
```elixir
+
defmodule JunctionBoxes do
+
def all_pairs([]), do: []
+
+
def all_pairs([x | rest]) do
+
for(y <- rest, do: {x, y}) ++ all_pairs(rest)
+
end
+
+
def dist2({ax, ay, az}, {bx, by, bz}) do
+
dx = ax - bx
+
dy = ay - by
+
dz = az - bz
+
+
dx ** 2 + dy ** 2 + dz ** 2
+
end
+
+
def group([], {a, b}), do: [MapSet.new([a, b])]
+
def group([set | rest], {a, b}) do
+
cond do
+
a in set and b in set -> [set | rest]
+
a in set or b in set -> set |> MapSet.put(a) |> MapSet.put(b) |> do_squash(rest, a, b, [])
+
true -> [set | group(rest, {a, b})]
+
end
+
end
+
+
defp do_squash(curr, [], _, _, acc), do: [curr | acc]
+
defp do_squash(curr, [x | rest], a, b, acc) do
+
if a in x or b in x do
+
[MapSet.union(curr, x) | acc ++ rest]
+
else
+
do_squash(curr, rest, a, b, [x | acc])
+
end
+
end
+
end
+
```
+
+
```elixir
+
sorted_pairs =
+
JunctionBoxes.all_pairs(boxes)
+
|> Enum.sort_by(fn {a, b} -> JunctionBoxes.dist2(a, b) end)
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 1
+
+
```elixir
+
sorted_pairs
+
|> Enum.take(1000)
+
|> Enum.reduce([], &JunctionBoxes.group(&2, &1))
+
|> Enum.map(&MapSet.size/1)
+
|> Enum.sort(:desc)
+
|> Enum.take(3)
+
|> Enum.product()
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 2
+
+
```elixir
+
box_count = length(boxes)
+
```
+
+
```elixir
+
{a, b} =
+
sorted_pairs
+
|> Enum.reduce_while([], fn pair, acc ->
+
new_acc = JunctionBoxes.group(acc, pair)
+
+
if MapSet.size(hd(new_acc)) == box_count do
+
{:halt, pair}
+
else
+
{:cont, new_acc}
+
end
+
end)
+
```
+
+
```elixir
+
{ax, _, _} = a
+
{bx, _, _} = b
+
+
ax * bx
+
```
+
+
<!-- livebook:{"offset":2222,"stamp":{"token":"XCP.sY5bJOGXuU_ZotobOVN6-zcg0TDJGEWVaJESs_-qDHzeEplFoStZ8_c6TRpS5eVpqnzoaj-gsLs_drksuYvMCDcM3T7_M6p9s09DRSKgMU2YB_Ogb0CB6_gAZamF2zEIUw","version":2}} -->
+167
2025/day09.livemd
···
+
# Day 09
+
+
```elixir
+
Mix.install([:kino_aoc, :image])
+
```
+
+
## Setup
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI5Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "9", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
tiles =
+
puzzle_input
+
|> String.split()
+
|> Enum.map(fn raw ->
+
raw
+
|> String.split(",")
+
|> Enum.map(&String.to_integer/1)
+
|> List.to_tuple()
+
end)
+
```
+
+
## Implementation
+
+
```elixir
+
defmodule Combinatorics do
+
def combinations2(list) do
+
Stream.unfold(list, fn
+
[] -> nil
+
[x | rest] ->
+
curr = for y <- rest, do: [x, y]
+
+
{curr, rest}
+
end)
+
|> Stream.flat_map(& &1)
+
end
+
end
+
```
+
+
```elixir
+
defmodule Rect do
+
require Record
+
+
Record.defrecordp(:rect, l: 0, t: 0, r: 0, b: 0)
+
+
def new({ax, ay}, {bx, by}) do
+
rect(l: min(ax, bx), r: max(ax, bx), t: min(ay, by), b: max(ay, by))
+
end
+
+
def area(rect() = r) do
+
width(r) * height(r)
+
end
+
+
def intersect?(
+
rect(l: al, r: ar, t: at, b: ab),
+
rect(l: bl, r: br, t: bt, b: bb)
+
) do
+
al < br and ar > bl and at < bb and ab > bt
+
end
+
+
def width(rect(r: r, l: l)), do: r - l + 1
+
def height(rect(t: t, b: b)), do: b - t + 1
+
+
def to_svg(rect(l: x, t: y) = r, opts \\ []) do
+
~s"""
+
<rect x="#{x}" y="#{y}" width="#{width(r)}" height="#{height(r)}"
+
#{Enum.map_join(opts, " ", fn {k, v} -> ~s(#{k}="#{v}") end)} />
+
"""
+
end
+
end
+
```
+
+
```elixir
+
rects =
+
Combinatorics.combinations2(tiles)
+
|> Stream.map(fn [a, b] -> Rect.new(a, b) end)
+
|> Enum.sort()
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 1
+
+
```elixir
+
rects
+
|> Enum.max_by(&Rect.area/1)
+
|> IO.inspect()
+
|> Rect.area()
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 2
+
+
```elixir
+
edges =
+
tiles
+
|> Enum.chunk_every(2, 1, tiles)
+
|> Enum.map(&apply(Rect, :new, &1))
+
|> Enum.sort()
+
```
+
+
```elixir
+
# [{1916, 50285}, {94619, 50285}, {94619, 48466}, {1668, 48466}]
+
# |> Stream.flat_map(fn a ->
+
# for b <- tiles do
+
# Rect.new(a, b)
+
# end
+
# end)
+
rects
+
|> Enum.reduce({0, nil}, fn r, {max, p} ->
+
a = Rect.area(r)
+
+
if a > max and not Enum.any?(edges, &Rect.intersect?(r, &1)) do
+
{a, r}
+
else
+
{max, p}
+
end
+
end)
+
```
+
+
## Draw
+
+
```elixir
+
{{min_x, _}, {max_x, _}} = Enum.min_max(tiles)
+
```
+
+
```elixir
+
{{_, min_y}, {_, max_y}} = Enum.min_max_by(tiles, &elem(&1, 1))
+
```
+
+
```elixir
+
h = max_y + min_y
+
w = max_x + min_x
+
```
+
+
```elixir
+
{x, y} = hd(tiles)
+
+
p1 = {:rect, 16055, 14805, 85282, 83613}
+
p2 = {:rect, 5741, 50285, 94619, 67351}
+
+
svg = """
+
<svg xmlns="http://www.w3.org/2000/svg" width="500" viewBox="0 0 #{w} #{h}">
+
<rect width="100%" height="100%" fill="black" />
+
<path d="M#{x} #{y}#{
+
for {x, y} <- tl(tiles), do: "L#{x} #{y} "
+
} L#{x} #{y}" stroke="darkgreen" fill="green" stroke-width="200" />
+
#{Rect.to_svg(p1, stroke: :orange, fill: :transparent, "stroke-width": 200)}
+
#{Rect.to_svg(p2, stroke: :yellow, fill: :transparent, "stroke-width": 200)}
+
#{
+
for {x, y} <- tiles do
+
~s(<rect x="#{x - 100}" y="#{y - 100}" width="200" height="200" fill="red" />)
+
end
+
}
+
</svg>
+
"""
+
+
Kino.Image.new(svg, :svg)
+
```
+
+
<!-- livebook:{"offset":3329,"stamp":{"token":"XCP.SSlM8wg30CucU7IP0n8MTbPIvnvvcZRXcglo9DY17kk0O0fwtLfUUiYJauWdspkXUlp0Axl5YscQNBKK5mSycPLd0iNdz8JFPfjCg4rS2pyM3JuQj73ipXd27t8Yd0ylig","version":2}} -->
+188
2025/day10.livemd
···
+
# Day 10
+
+
```elixir
+
Mix.install([:kino_aoc, {:dantzig, github: "hauleth/dantzig", ref: "use-proper-binary"}],
+
config: [
+
dantzig: [
+
highs_binary_path: System.find_executable("highs")
+
]
+
])
+
```
+
+
## Section
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMCIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI1In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "10", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
defmodule Decoder do
+
def decode("[" <> pattern), do: do_lights(String.reverse(String.trim_trailing(pattern, "]")), 0)
+
+
def decode("(" <> rest) do
+
<<seq::binary-size(byte_size(rest) - 1), ")">> = rest
+
+
seq
+
|> String.split(",")
+
|> Enum.map(&String.to_integer/1)
+
end
+
+
def decode("{" <> rest) do
+
<<seq::binary-size(byte_size(rest) - 1), "}">> = rest
+
+
seq
+
|> String.split(",")
+
|> Enum.map(&String.to_integer/1)
+
end
+
+
defp do_lights("", num), do: num
+
defp do_lights("." <> rest, num), do: do_lights(rest, 2 * num)
+
defp do_lights("#" <> rest, num), do: do_lights(rest, 2 * num + 1)
+
end
+
```
+
+
```elixir
+
indicators =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Enum.map(fn raw ->
+
[lights | rest] =
+
raw
+
|> String.split()
+
|> Enum.map(&Decoder.decode/1)
+
+
{buttons, [whatever]} = Enum.split(rest, -1)
+
+
{lights, buttons, whatever}
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 1
+
+
We are looking for such sequence of buttons that will provide pattern we are looking for. It can be solved by brute force with simple observation that buttons $a_n$ as well as light pattern $p$ can be represented by binary pattern. This allows us to use $\oplus$ (exclusive or, aka `XOR`) as an operation for pressing button.
+
+
Thanks to that observation we can see, that order in which we press buttons doesn't matter, as $\oplus$ is reflexive, i.e.:
+
+
$$
+
\begin{equation}
+
a \oplus b = b \oplus a
+
\end{equation}
+
$$
+
+
Additionally, wrt. $\oplus$ we have identity element $0$ and inverse element is the same as an original element, i.e.
+
+
$$
+
\begin{align}
+
a \oplus 0 = a \\
+
a \oplus a = 0
+
\end{align}
+
$$
+
+
Additionally we can observe that:
+
+
$$
+
\begin{equation}
+
(a \oplus b) \oplus c = a \oplus (b \oplus c)
+
\end{equation}
+
$$
+
+
With that observation we can deduce that each button will be pressed at most once and the order in which we press buttons doesn't matter.
+
+
---
+
+
So now we look for set $A = \{a_n\}$ of buttons that
+
+
$$
+
A \in \mathcal{P}(\text{Buttons}) \\
+
\forall_{i, j} \; i \ne j \implies a_i \ne a_j \\
+
\bigoplus A = p
+
$$
+
+
```elixir
+
defmodule Comb do
+
def all_possible([]), do: [[]]
+
def all_possible([a | rest]) do
+
sub = all_possible(rest)
+
+
sub ++ Enum.map(sub, &[a | &1])
+
end
+
end
+
```
+
+
```elixir
+
indicators
+
|> Enum.sum_by(fn {p, a, _} ->
+
a
+
|> Enum.map(&Enum.sum_by(&1, fn p -> 2 ** p end))
+
|> Comb.all_possible()
+
|> Enum.sort_by(&length/1)
+
|> Enum.find(fn seq ->
+
r = Enum.reduce(seq, 0, &Bitwise.bxor/2)
+
+
p == r
+
end)
+
|> length()
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 2
+
+
```elixir
+
defmodule Joltage do
+
alias Dantzig.Polynomial
+
alias Dantzig.Constraint
+
alias Dantzig.Problem
+
+
def solve({_pat, buttons, goal}) do
+
p = Problem.new(direction: :minimize)
+
+
{vars, {p, map}} =
+
buttons
+
|> Enum.with_index()
+
|> Enum.map_reduce({p, %{}}, fn {list, idx}, {p, acc} ->
+
{p, var} = Problem.new_variable(p, "v#{idx}", min: 0, type: :integer)
+
+
acc =
+
Enum.reduce(list, acc, fn key, map ->
+
Map.update(map, key, [var], &[var | &1])
+
end)
+
+
{var, {p, acc}}
+
end)
+
+
p =
+
map
+
|> Enum.sort()
+
|> Enum.map(&elem(&1, 1))
+
|> Enum.zip(goal)
+
|> Enum.reduce(p, fn {vars, target}, p ->
+
poly = Polynomial.sum(vars)
+
const = Constraint.new(poly, :==, target)
+
+
Problem.add_constraint(p, const)
+
end)
+
+
p = Problem.increment_objective(p, Polynomial.sum(vars))
+
+
{:ok, s} = Dantzig.HiGHS.solve(p)
+
+
Enum.sum_by(vars, &Dantzig.Solution.evaluate(s, &1))
+
end
+
end
+
```
+
+
```elixir
+
indicators
+
|> Task.async_stream(&Joltage.solve/1, ordered: false)
+
|> Enum.sum_by(&elem(&1, 1))
+
|> trunc()
+
```
+
+
<!-- livebook:{"offset":4336,"stamp":{"token":"XCP.sfoBGIHkFvWbEHVrY-dL-QiEcwRz_ZCIjn3lQ0RFHActIOwEapmOPBt0ygbQAmrnEjYPlFm5KrcWx4LfIPbSznxxcea0fYORG9GbBBpRCm-tYbGXYTCGgqgTvOsifyWDNg","version":2}} -->
+85
2025/day11.livemd
···
+
# Day 11
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Parse
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMSIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI1In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "11", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
graph =
+
puzzle_input
+
|> String.split("\n", trim: true)
+
|> Map.new(fn <<from::binary-3>> <> ": " <> rest ->
+
{from, String.split(rest)}
+
end)
+
```
+
+
## Implementation
+
+
```elixir
+
defmodule Servers do
+
def paths(graph, from, to), do: paths(graph, from, to, [from])
+
+
defp paths(_graph, to, to, acc), do: [Enum.reverse(acc)]
+
+
defp paths(graph, from, to, acc) do
+
if next = graph[from] do
+
Stream.flat_map(next, &paths(graph, &1, to, [&1 | acc]))
+
else
+
[]
+
end
+
end
+
+
def paths_through(graph, from, to, required),
+
do: path_through(graph, from, to, MapSet.new(required), %{})
+
+
defp path_through(_graph, to, to, required, memo),
+
do: {if(Enum.empty?(required), do: 1, else: 0), memo}
+
+
defp path_through(graph, from, to, required, memo) do
+
state = MapSet.delete(required, from)
+
+
with :error <- Map.fetch(memo, {from, state}),
+
{:ok, next} <- Map.fetch(graph, from) do
+
{sum, memo} =
+
Enum.reduce(next, {0, memo}, fn n, {sum, acc} ->
+
{c, next_acc} = path_through(graph, n, to, state, acc)
+
+
{c + sum, next_acc}
+
end)
+
+
{sum, Map.put(memo, {from, state}, sum)}
+
else
+
:error -> {0, memo}
+
{:ok, val} -> {val, memo}
+
end
+
end
+
end
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 1
+
+
```elixir
+
Servers.paths(graph, "you", "out") |> Enum.count()
+
```
+
+
<!-- livebook:{"branch_parent_index":1} -->
+
+
## Part 2
+
+
```elixir
+
Servers.paths_through(graph, "svr", "out", ["dac", "fft"])
+
|> elem(0)
+
```
+
+
<!-- livebook:{"offset":1933,"stamp":{"token":"XCP.fzzPot48c9xb6ftw8IEb1V6uTX6csBICnoXjN1PU6c3DylXjP-bco9PgawAoc2GSeNJRzS3NCPmJ9aO9Jm2ehPXnam5fN-bZvUbEcxKmNA8SqH2_fJ5o_qp8rIaxpH6DRQ","version":2}} -->
+73
2025/day12.livemd
···
+
# Day 12
+
+
```elixir
+
Mix.install([:kino_aoc])
+
```
+
+
## Parsing
+
+
<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiIxMiIsInNlc3Npb25fc2VjcmV0IjoiQURWRU5UX09GX0NPREVfU0VTU0lPTiIsInllYXIiOiIyMDI1In0","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
+
+
```elixir
+
{:ok, puzzle_input} =
+
KinoAOC.download_puzzle("2025", "12", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
+
```
+
+
```elixir
+
{areas, boxes} =
+
puzzle_input
+
|> String.split("\n\n")
+
|> List.pop_at(-1)
+
```
+
+
```elixir
+
areas =
+
areas
+
|> String.split("\n")
+
|> Enum.map(fn raw ->
+
[area | counts] = String.split(raw)
+
+
area =
+
area
+
|> String.trim(":")
+
|> String.split("x")
+
|> Enum.map(&String.to_integer/1)
+
|> Enum.product()
+
+
counts = Enum.map(counts, &String.to_integer/1)
+
+
{area, counts}
+
end)
+
```
+
+
```elixir
+
boxes =
+
boxes
+
|> Enum.map(fn <<_::binary-3>> <> rest ->
+
rest
+
|> String.to_charlist()
+
|> Enum.count(&(&1 == ?#))
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 1
+
+
```elixir
+
areas
+
|> Enum.count(fn {max, counts} ->
+
counts
+
|> Enum.zip_with(boxes, &*/2)
+
|> Enum.sum()
+
|> then(& &1 <= max)
+
end)
+
```
+
+
<!-- livebook:{"branch_parent_index":0} -->
+
+
## Part 2
+
+
FIN
+
+
<!-- livebook:{"offset":1266,"stamp":{"token":"XCP.VAO97d30rTEs0AWIHkPD4J0fLm3S60tQ3fKoA-riReFbzMnqL1jIoxttGhvNSnCfZVNfeUBuSYVe6PrIshxVGBwjr3pjNHCyFLSb4iSPNh277lkMmh6Gtrlfr8dvsYvw0g","version":2}} -->