— Day 9: Smoke Basin —
Setup
defmodule Setup do
def get_input(prompt) do
case IO.gets(prompt) do
:eof -> ""
line -> line <> get_input(prompt)
end
end
def parse_input(binary) do
binary
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.split("", trim: true)
|> Enum.map(&String.to_integer/1)
end)
|> then(fn input ->
{height, width} = {length(input), length(hd(input))}
for x <- 0..(height - 1), y <- 0..(width - 1), into: %{} do
{{x, y}, get_in(input, [Access.at(x), Access.at(y)])}
end
end)
end
end
map =
Setup.get_input("input")
|> Setup.parse_input()
defmodule LavaTubes do
def lowpoints(map) do
map
|> Enum.filter(fn {{x, y}, h} ->
map
|> Map.take([{x + 1, y}, {x - 1, y}, {x, y - 1}, {x, y + 1}])
|> Map.values()
|> Enum.all?(&(&1 > h))
end)
|> Map.new()
end
def explore(point, map, basin \\ MapSet.new())
def explore({x, y} = point, map, basin) do
if map[point] && point not in basin do
[{x, y + 1}, {x, y - 1}, {x + 1, y}, {x - 1, y}]
|> Enum.reduce(MapSet.put(basin, point), fn point, basin ->
next = map[point]
if next < 9 do
MapSet.union(basin, explore(point, map, basin))
else
basin
end
end)
else
MapSet.new()
end
end
end
Part1
map
|> LavaTubes.lowpoints()
|> Map.values()
|> then(fn values -> Enum.count(values) + Enum.sum(values) end)
Part2
map
|> LavaTubes.lowpoints()
|> Map.keys()
|> Enum.map(&LavaTubes.explore(&1, map))
|> Enum.uniq()
|> Enum.map(&MapSet.size/1)
|> Enum.sort(:desc)
|> Enum.take(3)
|> Enum.product()
ASCII MAP
Setup.get_input("input")
|> String.split("\n", trim: true)
|> then(fn [l | ls] ->
border = String.duplicate("9", String.length(l))
[border, l | ls] ++ [border]
end)
|> Enum.map(fn line ->
line
|> then(&("9" <> &1 <> "9"))
|> String.split("", trim: true)
|> Enum.map(fn
"9" -> "#"
_ -> " "
end)
|> Enum.join()
end)
|> Enum.join("\n")
|> IO.puts()