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

--- Day 11: Dumbo Octopus ---

2021/elixir/day-11/day-11.livemd

— Day 11: Dumbo Octopus —

Mix.install([{:kino, "~> 0.9.4"}])

test

https://www.twitch.tv/videos/1231618729?collection=k_DLnk2tvBa-fQ

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

https://en.wikipedia.org/wiki/Cellular_automaton

Takeaway: reduce problem dimensionality (dont solve 2D when you can solve a 1D problem)

test = Kino.Input.textarea("test")
puzzle1 = Kino.Input.textarea("step1")
lines_to_grid = fn lines ->
  lines =
    lines
    |> Kino.Input.read()
    |> String.split("\n")
    |> Enum.map(&(String.split(&1, "", trim: true) |> Enum.map(fn s -> String.to_integer(s) end)))

  for {line, row} <- Enum.with_index(lines),
      {position, col} <- Enum.with_index(line),
      into: %{},
      do: {{row, col}, position}
end
lines =
  test
  |> Kino.Input.read()
  |> String.split("\n", trim: true)

grid =
  for {line, row} <- Enum.with_index(lines),
      {position, col} <- Enum.with_index(String.to_charlist(line)),
      into: %{},
      do: {{row, col}, position - ?0}
defmodule Flash do
  def step(grid, steps), do: step(grid, steps, 0)
  def step(grid, 0, flashes), do: {grid, flashes}

  def step(grid, steps, flashes) do
    grid = Enum.map(grid, &amp;incr_octo/1) |> Enum.into(%{})

    # their neibs get +1, do flash(grid)
    flashers = get_flashers(grid)
    new_grid = spread(grid, flashers)

    # part2
    # sync? = Map.values(new_grid) |> Enum.sum() |> Kernel.==(0)
    # |> IO.inspect()
    # if sync?, 
    # do: 1000 - steps + 1,
    # else: 
    step(new_grid, steps - 1, flashes + Enum.count(get_flashers(new_grid)))
  end

  def spread(grid, []), do: grid

  def spread(grid, [{{row, col}, _} = flasher | flashers]) do
    # IO.inspect(flasher)
    # aka Moore neighborhood https://en.wikipedia.org/wiki/Moore_neighborhood
    neibs =
      [
        {row - 1, col - 1},
        {row - 1, col},
        {row - 1, col + 1},
        {row, col + 1},
        {row + 1, col + 1},
        {row + 1, col},
        {row + 1, col - 1},
        {row, col - 1}
      ]
      |> Enum.map(&amp;{&amp;1, Map.get(grid, &amp;1)})
      |> Enum.filter(&amp;(elem(&amp;1, 1) == 0))
      |> Enum.map(&amp;incr_octo/1)

    new_grid = Map.merge(grid, Enum.into(neibs, %{}))
    spread(new_grid, get_flashers(neibs) ++ flashers)
  end

  def incr_octo({pos, 0}), do: {pos, 0}
  def incr_octo({pos, 9}), do: {pos, 0}
  def incr_octo({pos, val}), do: {pos, val + 1}
  def get_flashers(grid), do: Enum.filter(grid, fn {_, val} -> val == 0 end)
end

# 1647?
# 348

puzzle1
|> lines_to_grid.()
|> Flash.step(100)

Part 1 José

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

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

:ok
defmodule Jose2 do
  def step(grid) do
    flash(grid, Map.keys(grid), MapSet.new())
  end

  def flash(grid, [{row, col} = key | keys], flashed) do
    value = grid[key]

    cond do
      is_nil(value) or key in flashed ->
        flash(grid, keys, flashed)

      grid[key] >= 9 ->
        new_keys = [
          {row - 1, col - 1},
          {row - 1, col},
          {row - 1, col + 1},
          {row, col + 1},
          {row + 1, col + 1},
          {row + 1, col},
          {row + 1, col - 1},
          {row, col - 1}
          | keys
        ]

        flash(Map.put(grid, key, 0), new_keys, MapSet.put(flashed, key))

      value ->
        flash(Map.put(grid, key, value + 1), keys, flashed)
    end
  end

  def flash(grid, [], flashed) do
    {grid, MapSet.size(flashed)}
  end
end

1..10
|> Enum.map_reduce(grid, fn _, grid ->
  {grid, flashes} = Jose2.step(grid)
  {flashes, grid}
end)
|> elem(0)
|> Enum.sum()

Part 2 José

Stream.iterate(1, &amp;(&amp;1 + 1))
|> Enum.reduce_while(grid, fn i, grid ->
  case Jose2.step(grid) do
    {grid, flashes} when map_size(grid) == flashes -> {:halt, i}
    {grid, _flashes} -> {:cont, grid}
  end
end)