this repo has no description
1# Day 04
2
3```elixir
4Mix.install([:kino_aoc])
5```
6
7## Setup
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 def 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 free?(pos, map) do
43 pos
44 |> adjacent()
45 |> Enum.count(&(&1 in map))
46 |> then(&(&1 < 4))
47 end
48end
49```
50
51## Part 1
52
53```elixir
54Enum.count(rolls, &PaperRolls.free?(&1, rolls))
55```
56
57## Part 2
58
59```elixir
60cleaned =
61 Stream.repeatedly(fn -> [] end)
62 |> Enum.reduce_while(rolls, fn _, acc ->
63 removable =
64 Enum.filter(acc, &PaperRolls.free?(&1, acc))
65 |> MapSet.new()
66
67 case MapSet.difference(acc, removable) do
68 ^acc -> {:halt, acc}
69 remaining -> {:cont, remaining}
70 end
71 end)
72```
73
74```elixir
75MapSet.size(rolls) - MapSet.size(cleaned)
76```
77
78<!-- livebook:{"offset":1486,"stamp":{"token":"XCP.deDYlsmx1l6_24twLKmjhZpjVr-zKpCk4kKaQFxGe1gppbfdc-7UyFIZxpcR_jVCGfX6vDlmYQ7ACpVB7bxafYi0X3Avsi-upj46ogSc5zRBoDdxStrGLSLdSmW_EsudIg","version":2}} -->