Day 11: Dumbo Octopus
Setup
Mix.install([
{:kino, "~> 0.4.1"}
])
Input
input = Kino.Input.textarea("Input")
Part 1
defmodule M1 do
def parse(input) do
input
|> String.split("\n", trim: true)
|> Enum.map(fn row ->
for <>, do: String.to_integer(<>)
end)
|> matrix_to_map()
end
def matrix_to_map(matrix) do
for {row, y} <- Enum.with_index(matrix),
{value, x} <- Enum.with_index(row),
into: %{},
do: {{x, y}, value}
end
def map_to_matrix(map) do
{{cols, rows}, _} = Enum.max(map)
for y <- 0..rows do
for x <- 0..cols, do: map[{x, y}]
end
end
def print(map) do
IO.inspect(map_to_matrix(map))
map
end
def step(map, n) do
{flashes, _} =
Enum.map_reduce(1..n, map, fn _, map ->
step(map)
|> then(fn map ->
{Enum.count(map, fn {_, v} -> v == 0 end), map}
end)
end)
Enum.sum(flashes)
end
def step(map) do
for {k, v} <- map, into: %{} do
{k, v + 1}
end
|> flash()
|> print()
end
def flash(map) do
flash(map, MapSet.new())
end
def flash(map, flashed) do
flashing =
for {k, v} <- map, v > 9 do
k
end
{map, flashed} =
Enum.reduce(
flashing,
{map, flashed},
fn {x, y}, {map, flashed} -> {flash(map, x, y), MapSet.put(flashed, {x, y})} end
)
map
|> Enum.map(fn {k, v} -> {k, if(MapSet.member?(flashed, k), do: 0, else: v)} end)
|> Map.new()
|> then(fn map -> if length(flashing) > 0, do: flash(map, flashed), else: map end)
end
def flash(map, x, y) do
Map.merge(
map,
for {ox, oy} <- [{1, 1}, {1, 0}, {1, -1}, {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}, {0, 1}],
x + ox >= 0 and y + oy >= 0 and map[{x + ox, y + oy}] <= 9,
into: %{} do
{{x + ox, y + oy}, map[{x + ox, y + oy}] + 1}
end
)
end
end
Kino.Input.read(input)
|> M1.parse()
|> M1.step(100)
Part 2
defmodule M2 do
def step(map) do
step(map, 0)
end
def step(map, step) do
if synchronized?(map) do
step
else
step(M1.step(map), step + 1)
end
end
def synchronized?(map) do
[first | rest] = Map.values(map)
Enum.all?(rest, fn x -> x == first end)
end
end
Kino.Input.read(input)
|> M1.parse()
|> M2.step()