this repo has no description
1# Day 04
2
3```elixir
4Mix.install([:kino_aoc])
5```
6
7## Parse
8
9<!-- livebook:{"attrs":"eyJhc3NpZ25fdG8iOiJwdXp6bGVfaW5wdXQiLCJkYXkiOiI0Iiwic2Vzc2lvbl9zZWNyZXQiOiJBRFZFTlRfT0ZfQ09ERV9TRVNTSU9OIiwieWVhciI6IjIwMjUifQ","chunks":null,"kind":"Elixir.KinoAOC.HelperCell","livebook_object":"smart_cell"} -->
10
11```elixir
12{:ok, puzzle_input} =
13 KinoAOC.download_puzzle("2025", "4", System.fetch_env!("LB_ADVENT_OF_CODE_SESSION"))
14```
15
16```elixir
17rolls =
18 puzzle_input
19 |> String.split("\n", trim: true)
20 |> Enum.with_index()
21 |> Enum.flat_map(fn {line, row} ->
22 line
23 |> String.to_charlist()
24 |> Enum.with_index()
25 |> Enum.filter(&(elem(&1, 0) == ?@))
26 |> Enum.map(&{elem(&1, 1), row})
27 end)
28 |> MapSet.new()
29```
30
31## Implementation
32
33```elixir
34defmodule PaperRolls do
35 defp adjacent({x, y}) do
36 for dx <- -1..1,
37 dy <- -1..1,
38 {dx, dy} != {0, 0},
39 do: {x + dx, y + dy}
40 end
41
42 def movable?(pos, map) do
43 pos
44 |> adjacent()
45 |> Enum.count(&(&1 in map))
46 |> then(&(&1 < 4))
47 end
48end
49```
50
51<!-- livebook:{"branch_parent_index":1} -->
52
53## Part 1
54
55```elixir
56Enum.count(rolls, &PaperRolls.movable?(&1, rolls))
57```
58
59<!-- livebook:{"branch_parent_index":1} -->
60
61## Part 2
62
63```elixir
64cleaned =
65 Stream.repeatedly(fn -> [] end)
66 |> Enum.reduce_while(rolls, fn _, acc ->
67 removable =
68 Enum.filter(acc, &PaperRolls.movable?(&1, acc))
69 |> MapSet.new()
70
71 case MapSet.difference(acc, removable) do
72 ^acc -> {:halt, acc}
73 remaining -> {:cont, remaining}
74 end
75 end)
76```
77
78```elixir
79MapSet.size(rolls) - MapSet.size(cleaned)
80```
81
82<!-- livebook:{"offset":1586,"stamp":{"token":"XCP.-_kcJR24r3dthl7SnpOh24JBI5hDpqMlFjQQDQ0pxtv4UHyaTlGoG4rG5iZxKtgxQoNAxw0K-mowSwehidDfrqewK3r9FHoOcAOIDbOMFd3QGH2X2Ta6KeXd4PlzWSYDBw","version":2}} -->