Day 11: Dumbo Octopus
Mix.install([:kino])
input = Kino.Input.textarea("Please paste your input:")
Setup
inputs =
input
|> Kino.Input.read()
|> String.split("\n", trim: true)
|> Enum.map(fn line -> line |> String.graphemes() |> Enum.map(&String.to_integer/1) end)
|> Enum.with_index()
|> Enum.reduce(%{}, fn {line, y}, grid ->
line
|> Enum.with_index()
|> Enum.reduce(grid, fn {value, x}, grid ->
grid |> Map.put({x, y}, value)
end)
end)
Part 1
https://adventofcode.com/2021/day/11
Solve: Part 1
defmodule Day11.Part1 do
def run(grid, step) do
size = size(grid)
do_run(grid, step, size, 0)
end
def size(grid) do
grid
|> Enum.reduce({0, 0}, fn {{x, y}, _energy_level}, {max_x, max_y} ->
max_x = max(max_x, x)
max_y = max(max_y, y)
{max_x, max_y}
end)
|> then(fn {max_x, max_y} -> {max_x + 1, max_y + 1} end)
end
defp do_run(_grid, 0, _size, total_flash_count) do
total_flash_count
end
defp do_run(grid, remain_step, size, total_flash_count) do
new_grid =
grid
|> increase_energy_level()
|> flash(size)
flash_count = new_grid |> count_flash()
do_run(new_grid, remain_step - 1, size, total_flash_count + flash_count)
end
defp increase_energy_level(grid) do
grid
|> Enum.map(fn {position, energy_level} -> {position, energy_level + 1} end)
|> Map.new()
end
defp flash(grid, size) do
case get_flash_positions(grid) do
[] ->
grid
flash_positions ->
grid
|> reset_energy_level()
|> increase_energy_level_of_adjacent_points(flash_positions, size)
|> flash(size)
end
end
defp get_flash_positions(grid) do
grid
|> Enum.filter(fn {_position, energy_level} -> energy_level >= 10 end)
|> Enum.map(fn {position, _energy_level} -> position end)
end
defp reset_energy_level(grid) do
grid
|> Enum.map(fn
{position, energy_level} when energy_level >= 10 -> {position, 0}
{position, energy_level} -> {position, energy_level}
end)
|> Map.new()
end
defp increase_energy_level_of_adjacent_points(grid, flash_positions, {width, height}) do
flash_positions
|> Enum.reduce(grid, fn {x, y}, grid ->
for dx <- -1..1,
dy <- -1..1,
adjacent_x = x + dx,
adjacent_y = y + dy,
adjacent_x > -1,
adjacent_x < width,
adjacent_y > -1,
adjacent_y < height,
reduce: grid do
grid ->
grid
|> Map.update!({x + dx, y + dy}, fn
0 -> 0
energy_level -> energy_level + 1
end)
end
end)
end
defp count_flash(grid) do
grid
|> Enum.map(fn
{_position, 0} -> 1
_ -> 0
end)
|> Enum.sum()
end
end
inputs
|> Day11.Part1.run(100)
Part 2
https://adventofcode.com/2021/day/11#part2
Solve: Part 2
defmodule Day11.Part2 do
def run(grid) do
size = size(grid)
do_run(grid, size, 1)
end
def size(grid) do
grid
|> Enum.reduce({0, 0}, fn {{x, y}, _energy_level}, {max_x, max_y} ->
max_x = max(max_x, x)
max_y = max(max_y, y)
{max_x, max_y}
end)
|> then(fn {max_x, max_y} -> {max_x + 1, max_y + 1} end)
end
defp do_run(grid, {width, height} = size, step) do
new_grid =
grid
|> increase_energy_level()
|> flash(size)
flash_count = new_grid |> count_flash()
case flash_count == width * height do
true -> step
false -> do_run(new_grid, size, step + 1)
end
end
defp increase_energy_level(grid) do
grid
|> Enum.map(fn {position, energy_level} -> {position, energy_level + 1} end)
|> Map.new()
end
defp flash(grid, size) do
case get_flash_positions(grid) do
[] ->
grid
flash_positions ->
grid
|> reset_energy_level()
|> increase_energy_level_of_adjacent_points(flash_positions, size)
|> flash(size)
end
end
defp get_flash_positions(grid) do
grid
|> Enum.filter(fn {_position, energy_level} -> energy_level >= 10 end)
|> Enum.map(fn {position, _energy_level} -> position end)
end
defp reset_energy_level(grid) do
grid
|> Enum.map(fn
{position, energy_level} when energy_level >= 10 -> {position, 0}
{position, energy_level} -> {position, energy_level}
end)
|> Map.new()
end
defp increase_energy_level_of_adjacent_points(grid, flash_positions, {width, height}) do
flash_positions
|> Enum.reduce(grid, fn {x, y}, grid ->
for dx <- -1..1,
dy <- -1..1,
adjacent_x = x + dx,
adjacent_y = y + dy,
adjacent_x > -1,
adjacent_x < width,
adjacent_y > -1,
adjacent_y < height,
reduce: grid do
grid ->
grid
|> Map.update!({x + dx, y + dy}, fn
0 -> 0
energy_level -> energy_level + 1
end)
end
end)
end
defp count_flash(grid) do
grid
|> Enum.map(fn
{_position, 0} -> 1
_ -> 0
end)
|> Enum.sum()
end
end
step = inputs |> Day11.Part2.run()