Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Day 11

2021/day-11.livemd

Day 11

Setup

Mix.install([{:kino, "~> 0.4.1"}])
example_input =
  Kino.Input.textarea("example input:")
  |> Kino.render()

real_input = Kino.Input.textarea("real input:")
defmodule Grid do
  def step(grid), do: increment(grid, Map.keys(grid), [], MapSet.new())

  defp increment(grid, [], [], flashes), do: {grid, MapSet.size(flashes)}
  defp increment(grid, [], affected, flashes), do: increment(grid, affected, [], flashes)

  defp increment(grid, [c | rest], affected, flashes) do
    energy = grid[c]

    cond do
      energy == nil or MapSet.member?(flashes, c) ->
        increment(grid, rest, affected, flashes)

      energy == 9 ->
        increment(Map.put(grid, c, 0), rest, neighbors(c) ++ affected, MapSet.put(flashes, c))

      true ->
        increment(Map.put(grid, c, energy + 1), rest, affected, flashes)
    end
  end

  defp neighbors({r, c}),
    do: [
      {r - 1, c - 1},
      {r - 1, c},
      {r - 1, c + 1},
      {r, c + 1},
      {r + 1, c + 1},
      {r + 1, c},
      {r + 1, c - 1},
      {r, c - 1}
    ]
end
lines =
  real_input
  |> Kino.Input.read()
  |> String.split("\n")

grid =
  for {line, row} <- Enum.with_index(lines),
      {energy, col} <- Enum.with_index(String.to_charlist(line)),
      into: %{} do
    {{row, col}, energy - ?0}
  end

Part 1

{_grid, count} =
  Enum.reduce(1..100, {grid, 0}, fn _, {grid, sum} ->
    {grid, count} = Grid.step(grid)
    {grid, sum + count}
  end)

count

Part 2

Enum.reduce_while(1..400, grid, fn step, grid ->
  {grid, count} = Grid.step(grid)
  if count == 100, do: {:halt, step}, else: {:cont, grid}
end)