Day 11
Setup
Mix.install([
{:kino, "~> 0.5.0"},
{:vega_lite, "~> 0.1.1"}
])
input = Kino.Input.textarea("Input:")
lines = input |> Kino.Input.read() |> String.split("\n", trim: true)
grid =
for {line, row} <- Enum.with_index(lines),
{energy, col} <- Enum.with_index(String.to_charlist(line)),
into: %{},
do: {{row, col}, energy - ?0}
defmodule Recursion do
def step(grid) do
flash(Map.keys(grid), grid, MapSet.new())
end
defp flash([{row, col} = key | keys], grid, flashed) do
value = grid[key]
cond do
is_nil(value) or key in flashed ->
flash(keys, grid, flashed)
grid[key] >= 9 ->
keys = [
{row - 1, col - 1},
{row - 1, col},
{row - 1, col + 1},
{row, col - 1},
{row, col + 1},
{row + 1, col - 1},
{row + 1, col},
{row + 1, col + 1}
| keys
]
flash(keys, Map.put(grid, key, 0), MapSet.put(flashed, key))
true ->
flash(keys, Map.put(grid, key, value + 1), flashed)
end
end
defp flash([], grid, flashed) do
{grid, MapSet.size(flashed)}
end
end
Part 1
1..100
|> Enum.map_reduce(grid, fn _, grid ->
{grid, flashes} = Recursion.step(grid)
{flashes, grid}
end)
|> elem(0)
|> Enum.sum()
Part 2
Stream.iterate(1, &(&1 + 1))
|> Enum.reduce_while(grid, fn i, grid ->
case Recursion.step(grid) do
{grid, flashes} when map_size(grid) == flashes -> {:halt, i}
{grid, _flashes} -> {:cont, grid}
end
end)
VegaLite
alias VegaLite, as: Vl
graph =
Vl.new(height: 300, width: 300)
|> Vl.mark(:circle, opacity: 0.8)
|> Vl.encode_field(:x, "x", type: :quantitative, axis: false)
|> Vl.encode_field(:y, "y", type: :quantitative, axis: false)
|> Vl.encode_field(:color, "h",
type: :quantitative,
scale: [domain: [0, 9], range: ["brown", "red", "yellow"]]
)
|> Vl.encode_field(:size, "h",
type: :quantitative,
scale: [domain: [0, 9], range: [20, 100]]
)
|> Kino.VegaLite.new()
|> Kino.render()
Kino.VegaLite.periodically(
graph,
100,
grid,
fn grid ->
{grid, flashes} = Recursion.step(grid)
data =
Enum.map(grid, fn {{x, y}, h} ->
%{"x" => x, "y" => y, "h" => if(h == 0, do: 9, else: h - 1)}
end)
Kino.VegaLite.clear(graph)
Kino.VegaLite.push_many(graph, data)
if map_size(grid) == flashes do
:halt
else
{:cont, grid}
end
end
)