Day 09
Setup
Mix.install([{:kino, "~> 0.4.1"}])
example_input =
Kino.Input.textarea("example input:")
|> Kino.render()
real_input = Kino.Input.textarea("real input:")
Part 1
defmodule Grid do
def basins(_, [], basins), do: basins
def basins(grid, [{coord, _} | low_points], basins) do
basins(grid, low_points, [expand_basin(grid, neighbors(coord), MapSet.new([coord])) | basins])
end
defp expand_basin(_, [], set), do: set
defp expand_basin(grid, [coord | rest], set) do
case Map.get(grid, coord, 9) do
9 ->
expand_basin(grid, rest, set)
_ ->
case MapSet.member?(set, coord) do
true ->
expand_basin(grid, rest, set)
_ ->
expand_basin(grid, neighbors(coord) ++ rest, MapSet.put(set, coord))
end
end
end
def low_points(grid) do
Enum.reduce(grid, [], fn {coord, v} = point, acc ->
neighbors(coord)
|> then(&Map.take(grid, &1))
|> Map.values()
|> Enum.all?(&(&1 > v))
|> then(&if &1, do: [point | acc], else: acc)
end)
end
defp neighbors({i, j}), do: [{i - 1, j}, {i + 1, j}, {i, j - 1}, {i, j + 1}]
def parse(input) do
input
|> String.split()
|> Enum.with_index(fn line, j ->
String.split(line, "", trim: true)
|> Enum.with_index(fn node, i ->
{{i, j}, String.to_integer(node)}
end)
end)
|> List.flatten()
|> Map.new()
end
end
real_input
|> Kino.Input.read()
|> Grid.parse()
|> Grid.low_points()
|> Enum.map(&Kernel.+(elem(&1, 1), 1))
|> Enum.sum()
Part 2
real_input
|> Kino.Input.read()
|> Grid.parse()
|> then(&Grid.basins(&1, Grid.low_points(&1), []))
|> Enum.map(&MapSet.size(&1))
|> Enum.sort(:desc)
|> Enum.take(3)
|> Enum.product()