Day 15
input =
File.read!("day15.txt")
|> String.trim()
|> String.split("\n")
|> Enum.map(&String.to_charlist/1)
|> Enum.with_index()
|> Enum.flat_map(fn {row, y} ->
row
|> Enum.with_index()
|> Enum.map(fn {v, x} -> {{x, y}, v - ?0} end)
end)
|> Map.new()
{width, height} = Enum.max(Map.keys(input))
{99, 99}
Task 1
shortest_paths =
for y <- height..0//-1,
x <- width..0//-1,
reduce: %{} do
acc ->
right = acc[{x + 1, y}]
bottom = acc[{x, y + 1}]
value =
case {right, bottom} do
{nil, nil} -> input[{x, y}]
_ -> input[{x, y}] + min(right, bottom)
end
Map.put(acc, {x, y}, value)
end
shortest_paths[{0, 0}] - input[{0, 0}]
429
Task 2
defmodule Day15.Task2 do
def expand_grid(board) do
{width, height} = Enum.max(Map.keys(board))
board
|> Enum.flat_map(fn {{x, y}, v} ->
for rx <- 0..4, ry <- 0..4 do
{{x + (width + 1) * rx, y + (height + 1) * ry}, rem(v - 1 + rx + ry, 9) + 1}
end
end)
|> Map.new()
end
def find_path(board, start, finish) do
dists = :gb_sets.singleton({0, start})
find_path(board, finish, dists, MapSet.new())
end
@surround for dx <- -1..1, dy <- -1..1, abs(dx) != abs(dy), do: {dx, dy}
def find_path(board, finish, dists, visited) do
{{dist, {x, y} = curr}, dists} = :gb_sets.take_smallest(dists)
if curr == finish do
dist
else
visited = MapSet.put(visited, curr)
dists =
for {dx, dy} <- @surround,
next = {x + dx, y + dy},
next not in visited,
is_map_key(board, next),
alt = dist + board[next],
reduce: dists do
acc ->
:gb_sets.add_element({alt, next}, acc)
end
find_path(board, finish, dists, visited)
end
end
end
{:module, Day15.Task2, <<70, 79, 82, 49, 0, 0, 16, ...>>, {:find_path, 4}}
input
|> Day15.Task2.expand_grid()
|> Day15.Task2.find_path({0, 0}, {499, 499})
2844