Powered by AppSignal & Oban Pro

Day 11: Dumbo Octopus

2021/11.livemd

Day 11: Dumbo Octopus

Intro

https://adventofcode.com/2021/day/11

Input

input_test =
  """
  5483143223
  2745854711
  5264556173
  6141336146
  6357385478
  4167524645
  2176841721
  6882881134
  4846848554
  5283751526
  """
  |> String.split("\n", trim: true)
["5483143223", "2745854711", "5264556173", "6141336146", "6357385478", "4167524645", "2176841721",
 "6882881134", "4846848554", "5283751526"]
input =
  """
  8624818384
  3725473343
  6618341827
  4573826616
  8357322142
  6846358317
  7286886112
  8138685117
  6161124267
  3848415383
  """
  |> String.split("\n", trim: true)
["8624818384", "3725473343", "6618341827", "4573826616", "8357322142", "6846358317", "7286886112",
 "8138685117", "6161124267", "3848415383"]

Part 1

defmodule Flash do
  def step(grid, run_grid) do
    increased_grid = Enum.map(grid, fn {pos, value} -> {pos, value + 1} end) |> Map.new()

    {g, flashed} =
      Enum.reduce(run_grid, {increased_grid, MapSet.new()}, fn pos, {gr, flashed} ->
        if gr[pos] in flashed or gr[pos] <= 9 do
          {gr, flashed}
        else
          flash([pos], gr, flashed, run_grid)
        end
      end)

    # IO.inspect(MapSet.size(flashed))
    {g, MapSet.size(flashed)}
  end

  def flash([], grid, flashed, _run_grid) do
    {grid, flashed}
  end

  def flash([pos | rest_to_check], grid, flashed, run_grid) do
    if grid[pos] < 9 do
      if pos not in flashed do
        flash(rest_to_check, %{grid | pos => grid[pos] + 1}, flashed, run_grid)
      else
        flash(rest_to_check, grid, flashed, run_grid)
      end
    else
      flashed = MapSet.put(flashed, pos)
      {x, y} = pos

      to_check =
        [
          {x - 1, y - 1},
          {x, y - 1},
          {x + 1, y - 1},
          {x - 1, y},
          {x + 1, y},
          {x - 1, y + 1},
          {x, y + 1},
          {x + 1, y + 1}
        ]
        |> Enum.filter(fn p -> p in run_grid end)
        |> Enum.filter(fn p -> p not in flashed end)

      flash(rest_to_check ++ to_check, %{grid | pos => 0}, flashed, run_grid)
    end
  end

  def print_grid(gr) do
    {{xmax, _y}, _v} = gr |> Enum.max_by(fn {{x, _y}, _v} -> x end)
    {{_x, ymax}, _v} = gr |> Enum.max_by(fn {{_x, y}, _v} -> y end)

    for x <- 0..xmax do
      for y <- 0..ymax do
        gr[{x, y}]
      end
    end
  end
end
{:module, Flash, <<70, 79, 82, 49, 0, 0, 19, ...>>, {:print_grid, 1}}
grid =
  for {line, row} <- Enum.with_index(input_test),
      {number, col} <- Enum.with_index(String.to_charlist(line)),
      into: %{} do
    {{row, col}, number - ?0}
  end

run_grid = Enum.map(grid, fn {pos, _value} -> pos end)

number_of_steps = 100

{g, number_of_flashes} =
  Enum.reduce(1..number_of_steps, {grid, 0}, fn _i, {gr, sum} ->
    {g2, nf} = Flash.step(gr, run_grid)
    {g2, sum + nf}
  end)

number_of_flashes
# Flash.print_grid(g)
1656

Correct (100 steps): 1656

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

run_grid = Enum.map(grid, fn {pos, _value} -> pos end)

number_of_steps = 100

{g, number_of_flashes} =
  Enum.reduce(1..number_of_steps, {grid, 0}, fn _i, {gr, sum} ->
    {g2, nf} = Flash.step(gr, run_grid)
    {g2, sum + nf}
  end)

number_of_flashes
1667

Correct: 1667

Part 2

defmodule Flash2 do
  def all_flashed?(grid) do
    Enum.all?(grid, fn {_pos, val} -> val == 0 end)
  end

  def find_first_all_flash(grid, run_grid) do
    find_first_all_flash(grid, run_grid, 0)
  end

  defp find_first_all_flash(grid, run_grid, step_count) do
    if all_flashed?(grid) == true do
      step_count
    else
      {next_grid, _nf} = Flash.step(grid, run_grid)
      find_first_all_flash(next_grid, run_grid, step_count + 1)
    end
  end
end
{:module, Flash2, <<70, 79, 82, 49, 0, 0, 8, ...>>, {:find_first_all_flash, 3}}
grid =
  for {line, row} <- Enum.with_index(input_test),
      {number, col} <- Enum.with_index(String.to_charlist(line)),
      into: %{} do
    {{row, col}, number - ?0}
  end

run_grid = Enum.map(grid, fn {pos, _value} -> pos end)

Flash2.find_first_all_flash(grid, run_grid)
195

Correct: 195

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

run_grid = Enum.map(grid, fn {pos, _value} -> pos end)

Flash2.find_first_all_flash(grid, run_grid)
488

Correct: 488