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

aoc 2021 day 11

2021/elixir/day-11.livemd

aoc 2021 day 11

Section

Mix.install([{:kino, "~> 0.4.1"}])
input = Kino.Input.textarea("paste input")
inputs = """
5483143223
2745854711
5264556173
6141336146
6357385478
4167524645
2176841721
6882881134
4846848554
5283751526
"""

lines =
  input
  |> Kino.Input.read()
  |> String.split("\n", trim: true)

grid =
  for {line, r} <- Enum.with_index(lines),
      {v, c} <- line |> String.to_charlist() |> Enum.with_index() do
    {{r, c}, v - ?0}
  end
  |> Enum.into(%{})

Part 1

defmodule Part1.Recursion do
  @directions for r <- -1..1, c <- -1..1, {r, c} != {0, 0}, do: {r, c}

  def flash(grid) do
    next_grid =
      grid
      |> Enum.map(fn {pos, v} -> {pos, v + 1} end)
      |> Enum.into(%{})

    targets =
      next_grid
      |> Enum.filter(&amp;match?({{_, _}, 10}, &amp;1))
      |> Enum.map(fn {pos, _v} -> pos end)

    do_flash(targets, next_grid, length(targets))
  end

  defp do_flash([], grid, count),
    do:
      {count,
       grid
       |> Enum.map(fn
         {pos, 10} -> {pos, 0}
         o -> o
       end)
       |> Enum.into(%{})}

  defp do_flash([{r, c} | rest], grid, count) do
    {next_grid, new_targets} =
      @directions
      |> Enum.reduce({grid, MapSet.new()}, fn {dr, dc}, {g, set} ->
        {nr, nc} = {dr + r, dc + c}
        nset = if g[{nr, nc}] == 9, do: MapSet.put(set, {nr, nc}), else: set
        ng = if g[{nr, nc}] in 1..9, do: Map.put(g, {nr, nc}, rem(g[{nr, nc}] + 1, 10)), else: g
        {ng, nset}
      end)

    do_flash(rest ++ Enum.to_list(new_targets), next_grid, count + Enum.count(new_targets))
  end
end
{flashes, _} =
  1..100
  |> Enum.map_reduce(grid, fn _, prev_grid ->
    Part1.Recursion.flash(prev_grid)
  end)

flashes
|> Enum.sum()

Part 2

grid_size = Enum.count(grid)

step =
  1..1000
  |> Enum.reduce_while(grid, fn step, prev_grid ->
    {count, next_grid} = Part1.Recursion.flash(prev_grid)
    if count == grid_size, do: {:halt, step}, else: {:cont, next_grid}
  end)