Skip to content

Instantly share code, notes, and snippets.

@samueltardieu
Created December 17, 2023 15:12
Show Gist options
  • Save samueltardieu/8fa2e45cc5b84af13a2326b0b7d9e563 to your computer and use it in GitHub Desktop.
Save samueltardieu/8fa2e45cc5b84af13a2326b0b7d9e563 to your computer and use it in GitHub Desktop.
defmodule AdventOfCode.Day17 do
def part1(input), do: part(input, 1, 3)
def part2(input), do: part(input, 4, 10)
def part(input, lmin, lmax) do
grid =
input
|> String.split("\n", trim: true)
|> Enum.map(fn l -> String.graphemes(l) |> Enum.map(&String.to_integer/1) end)
at = fn {r, c} -> grid |> Enum.at(r) |> Enum.at(c) end
gl = {glr, glc} = {length(grid) - 1, length(hd(grid)) - 1}
reduce(
{[
{at.({0, 1}), {0, 1}, {0, 1}, 1},
{at.({1, 0}), {1, 0}, {1, 0}, 1}
]
|> Enum.into(Heap.min()), MapSet.new()},
fn {queue, seen} ->
{{w, pos = {r, c}, dir = {dr, dc}, l}, queue} = Heap.split(queue)
cond do
{pos, dir, l} in seen ->
{:cont, {queue, seen}}
pos == gl and l >= lmin ->
{:halt, w}
true ->
{:cont,
{
List.flatten([
if(l < lmax, do: {{r + dr, c + dc}, dir, l + 1}, else: []),
if(l >= lmin,
do: [{{r + dc, c + dr}, {dc, dr}, 1}, {{r - dc, c - dr}, {-dc, -dr}, 1}],
else: []
)
])
|> Stream.filter(fn cr = {{r, c}, _, _} ->
r in 0..glr && c in 0..glc && cr not in seen
end)
|> Stream.map(fn {pos, dir, l} -> {w + at.(pos), pos, dir, l} end)
|> Enum.reduce(queue, fn e, q -> Heap.push(q, e) end),
seen |> MapSet.put({pos, dir, l})
}}
end
end
)
end
def reduce(init, fun) do
case fun.(init) do
{:halt, result} -> result
{:cont, value} -> reduce(value, fun)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment