Day 15:
Intro
https://adventofcode.com/2021/day/15
Input
Mix.install([
{:priority_queue, "~> 1.0"}
])
input_test =
"""
1163751742
1381373672
2136511328
3694931569
7463417111
1319128137
1359912421
3125421639
1293138521
2311944581
"""
|> String.split("\n", trim: true)
|> Enum.map(fn r -> String.graphemes(r) |> Enum.map(&String.to_integer(&1)) end)
input =
File.read!("input15.txt")
|> String.split("\n", trim: true)
|> Enum.map(fn r -> String.graphemes(r) |> Enum.map(&String.to_integer(&1)) end)
Part 1
defmodule Aoc2021.Day15 do
def load(lol, r) do
# lol = Enum.map(args, fn l -> String.graphemes(l) |> Enum.map(&String.to_integer/1) end)
map =
Stream.with_index(lol)
|> Enum.map(fn {x, i} ->
Stream.with_index(x) |> Enum.map(&{{i, elem(&1, 1)}, elem(&1, 0)})
end)
|> List.flatten()
|> Map.new()
{map, length(lol) * r - 1, length(hd(lol)) * r - 1, length(lol), length(hd(lol))}
end
def update(pq, {map, ly, lx, my, mx}, cost, dist, p = {y, x})
when y >= 0 and y <= ly and x >= 0 and x <= lx do
oldd = if is_map_key(cost, p), do: cost[p], else: 999_999_999
newd = dist + rem(map[{rem(y, my), rem(x, mx)}] + div(y, my) + div(x, mx) - 1, 9) + 1
if newd < oldd, do: PriorityQueue.put(pq, {newd, p}), else: pq
end
def update(pq, _map, _cost, _dist, _pos), do: pq
def explore({_map, ly, lx, _, _}, _cost, _pq, {dist, {ly, lx}}), do: dist
def explore(mp, cost, pq, {dist, {y, x}}) do
pq = PriorityQueue.delete_min!(pq)
if not is_map_key(cost, {y, x}) or cost[{y, x}] > dist do
cost = Map.put(cost, {y, x}, dist)
ms = Enum.map([{-1, 0}, {1, 0}, {0, -1}, {0, 1}], fn {a, b} -> {y + a, x + b} end)
pq = Enum.reduce(ms, pq, &update(&2, mp, cost, dist, &1))
explore(mp, cost, pq, PriorityQueue.min!(pq))
else
explore(mp, cost, pq, PriorityQueue.min!(pq))
end
end
def startq(), do: PriorityQueue.new() |> PriorityQueue.put({0, {0, 0}})
def part1(args), do: load(args, 1) |> explore(%{}, startq(), {0, {0, 0}})
def part2(args), do: load(args, 5) |> explore(%{}, startq(), {0, {0, 0}})
end
# TODO: Does not work
i = input_test
xmax = (Enum.at(i, 0) |> length) - 1
ymax = length(i) - 1
goal = {xmax, ymax}
start = {0, 0}
risk =
for y <- 0..ymax do
for x <- 0..xmax do
{{x, y}, Enum.at(i, y) |> Enum.at(x)}
end
end
|> List.flatten()
|> Map.new()
defmodule M1 do
def solve(start, goal, risk) do
solve(start, goal, risk, [], 0, 0)
end
def solve(goal, goal, risk, _seen, score, _deep) do
score + risk[goal]
end
def solve({x, y} = pos, goal, risk, seen, score, deep) do
if deep >= 20 do
IO.puts("LOOP!")
:invalid
else
candidates =
[{x - 1, y}, {x + 1, y}, {x, y - 1}, {x, y + 1}]
|> Enum.filter(fn p -> p not in seen end)
|> Enum.filter(fn p -> Map.has_key?(risk, p) end)
|> Enum.map(fn p -> solve(p, goal, risk, seen ++ [pos], score + risk[goal], deep + 1) end)
|> IO.inspect()
|> Enum.filter(fn r -> r != :invalid end)
if length(candidates) == 0 do
:invalid
else
IO.puts("MIN")
Enum.min(candidates)
end
end
end
end
# M1.solve(start, goal, risk)
# M1.solve({3,0}, {3,0}, risk, [{0,0},{1,0},{1,1},{1,0},{2,0}],2)
# risk[{9,9}]
Aoc2021.Day15.part1(input)
Correct: 602
Part 2
Aoc2021.Day15.part2(input)
Correct: 2935