Powered by AppSignal & Oban Pro

🎄 Year 2025 🔔 Day 04

elixir/notebooks/2025/day04.livemd

🎄 Year 2025 🔔 Day 04

Section

rows = File.read!("#{__DIR__}/../../../inputs/2025/day04.txt") |> String.split("\n", trim: true)
{min_x, min_y} = {0, 0}
max_x = Enum.at(rows, 0) |> String.graphemes() |> Enum.count() |> then(&(&1 - 1))
max_y = Enum.count(rows) |> then(&(&1 - 1))
max_coords = {max_x, max_y}

map =
  rows
  |> Enum.with_index(fn row, y ->
    row
    |> String.graphemes()
    |> Enum.with_index(fn e, x -> {{x, y}, e} end)
  end)
  |> Enum.concat()
  |> Map.new()
defmodule Helper do
  def get_adjacents(map, coords, max_coords)
  def get_adjacents(map, {x, y}, {max_x, max_y}) do
    for new_x <- (x-1)..(x+1),
        new_y <- (y-1)..(y+1),
        (x != new_x || y != new_y) &amp;&amp; new_x >=0 &amp;&amp; new_y >= 0 &amp;&amp; new_x <= max_x &amp;&amp; new_y <= max_y do
      {new_x, new_y}
    end
    |> Enum.map(&amp;Map.fetch!(map, &amp;1))
  end

  def can_remove(map, coords, max_coords) do
    get_adjacents(map, coords, max_coords)
    |> Enum.count(fn e -> e == "@" end)
    |> then(&amp;(&amp;1 < 4))
  end

  def recursively_remove(map, max_coords) do
    to_remove =
      map
      |> Enum.filter(fn {_coords, char} -> char == "@" end)
      |> Enum.filter(fn {coords, _char} -> Helper.can_remove(map, coords, max_coords) end)
      |> Enum.map(&amp;elem(&amp;1, 0))

    case to_remove do
      [] -> map
      to_remove ->
        Enum.reduce(to_remove, map, fn e, acc ->
          Map.update!(acc, e, fn _ -> "." end)
        end)
        |> Map.new()
        |> recursively_remove(max_coords)
    end
  end
end

Part 1

map
|> Enum.filter(fn {_coords, char} -> char == "@" end)
|> Enum.filter(fn {coords, _char} -> Helper.can_remove(map, coords, max_coords) end)
|> Enum.count()

Part 2

Helper.recursively_remove(map, max_coords)
|> Enum.filter(fn {coords, char} ->
  og_char = Map.fetch!(map, coords)
  og_char != char
end)
|> Enum.count()