This commit is contained in:
bluepython508
2023-12-18 15:57:01 +00:00
parent a9519aebbf
commit aa1d6f5ca0
7 changed files with 190 additions and 1 deletions

167
lib/day17.ex Normal file
View File

@@ -0,0 +1,167 @@
defmodule Aoc2023.Day17 do
use Aoc2023
defmodule PriorityQueue do
defstruct [:set]
def new(contents \\ []), do: %__MODULE__{set: :gb_sets.from_list(contents)}
def add(%__MODULE__{set: set}, elem, prio) do
%__MODULE__{set: :gb_sets.add({prio, elem}, set)}
end
def size(%__MODULE__{set: set}) do
:gb_sets.size(set)
end
def pop_min(%__MODULE__{set: set}) do
case :gb_sets.size(set) do
0 ->
{nil, new()}
_ ->
{res, set} = :gb_sets.take_smallest(set)
{res, %__MODULE__{set: set}}
end
end
defimpl Inspect do
import Inspect.Algebra
def inspect(%PriorityQueue{set: set}, opts) do
concat(["#PriorityQueue.new(", to_doc(:gb_sets.to_list(set), opts), ")"])
end
end
end
def parse(input) do
lines = input |> lines
{
{lines |> length() |> Kernel.-(1), lines |> head |> String.length() |> Kernel.-(1)},
lines
|> Enum.with_index()
|> Enum.flat_map(fn {row, y} ->
row
|> String.to_charlist()
|> Enum.with_index()
|> Enum.map(fn {cost, x} -> {{y, x}, String.to_integer(<<cost>>)} end)
end)
|> Enum.into(%{})
}
end
defp a_star(starts, neighbors, heuristic, is_goal) do
loop = fn recur, explored, frontier ->
{explored, frontier}
{{_, current}, frontier} = PriorityQueue.pop_min(frontier)
if is_goal.(current) do
{explored, current}
else
cost_to_here = Map.get(explored, current) |> elem(1)
{explored, frontier} =
for {neighbor, cost} <- neighbors.(current), reduce: {explored, frontier} do
{explored, frontier} ->
cost_ = cost_to_here + cost
if Map.get(explored, neighbor, {nil, cost_}) |> elem(1) < cost_ do
{explored, frontier}
else
{
Map.put(explored, neighbor, {current, cost_}),
PriorityQueue.add(frontier, neighbor, cost_ + heuristic.(neighbor))
}
end
end
recur.(recur, explored, frontier)
end
end
{explored, goal} =
loop.(
loop,
starts |> Enum.map(&{&1, {nil, 0}}) |> Enum.into(%{}),
starts |> Enum.map(&{0, &1}) |> PriorityQueue.new()
)
# This doesn't include the starting point
path_find = fn recur, point, path ->
case Map.get(explored, point) do
nil -> path
{nil, _} -> path
{prev, _} -> recur.(recur, prev, [point | path])
end
end
path_find.(path_find, goal, [])
end
def part1({{my, mx}, grid}) do
# Nodes are y, x, dir, straight length
a_star(
[{0, 0, :d, 0}, {0, 0, :r, 0}],
fn {y, x, dir, len} ->
case dir do
:u ->
[{y, x - 1, :l, 0}, {y, x + 1, :r, 0}] ++
if len < 2, do: [{y + 1, x, dir, len + 1}], else: []
:d ->
[{y, x - 1, :l, 0}, {y, x + 1, :r, 0}] ++
if len < 2, do: [{y - 1, x, dir, len + 1}], else: []
:l ->
[{y + 1, x, :u, 0}, {y - 1, x, :d, 0}] ++
if len < 2, do: [{y, x - 1, dir, len + 1}], else: []
:r ->
[{y + 1, x, :u, 0}, {y - 1, x, :d, 0}] ++
if len < 2, do: [{y, x + 1, dir, len + 1}], else: []
end
|> Enum.filter(fn {y, x, _, _} -> y in 0..my and x in 0..mx end)
|> Enum.map(fn {y, x, _, _} = pos -> {pos, Map.get(grid, {y, x})} end)
end,
fn {y, x, _, _} -> abs(y - my) + abs(x - mx) end,
fn {y, x, _, _} -> {y, x} == {my, mx} end
)
|> Enum.map(fn {y, x, _, _} -> Map.get(grid, {y, x}) end)
|> Enum.sum()
end
def part2({{my, mx}, grid}) do
# Nodes are y, x, dir, straight length
a_star(
[{0, 0, :r, 0}, {0, 0, :d, 0}, {0, 0, :u, 0}, {0, 0, :l, 0}],
fn {y, x, dir, len} ->
(if(len < 9,
do:
case dir do
:u -> [{y + 1, x, :u, len + 1}]
:d -> [{y - 1, x, :d, len + 1}]
:l -> [{y, x - 1, :l, len + 1}]
:r -> [{y, x + 1, :r, len + 1}]
end,
else: []
) ++
if(len > 2,
do:
case dir do
:u -> [{y, x - 1, :l, 0}, {y, x + 1, :r, 0}]
:d -> [{y, x - 1, :l, 0}, {y, x + 1, :r, 0}]
:l -> [{y + 1, x, :u, 0}, {y - 1, x, :d, 0}]
:r -> [{y + 1, x, :u, 0}, {y - 1, x, :d, 0}]
end,
else: []
))
|> Enum.filter(fn {y, x, _, _} -> y in 0..my and x in 0..mx end)
|> Enum.map(fn {y, x, _, _} = pos -> {pos, Map.get(grid, {y, x})} end)
end,
fn {y, x, _, _} -> abs(y - my) + abs(x - mx) end,
fn {y, x, _, len} -> {y, x} == {my, mx} and len > 2 end
)
|> Enum.map(fn {y, x, _, _} -> Map.get(grid, {y, x}) end)
|> Enum.sum()
end
end

View File

@@ -18,6 +18,7 @@ defmodule Mix.Tasks.Aoc do
defp module(14), do: Aoc2023.Day14 defp module(14), do: Aoc2023.Day14
defp module(15), do: Aoc2023.Day15 defp module(15), do: Aoc2023.Day15
defp module(16), do: Aoc2023.Day16 defp module(16), do: Aoc2023.Day16
defp module(17), do: Aoc2023.Day17
defp module(18), do: Aoc2023.Day18 defp module(18), do: Aoc2023.Day18
# [MODULE INSERTION POINT] # [MODULE INSERTION POINT]

13
tests/day17/1 Normal file
View File

@@ -0,0 +1,13 @@
2413432311323
3215453535623
3255245654254
3446585845452
4546657867536
1438598798454
4457876987766
3637877979653
4654967986887
4564679986453
1224686865563
2546548887735
4322674655533

1
tests/day17/1.1 Normal file
View File

@@ -0,0 +1 @@
102

1
tests/day17/1.2 Normal file
View File

@@ -0,0 +1 @@
94

5
tests/day17/2 Normal file
View File

@@ -0,0 +1,5 @@
111111111111
999999999991
999999999991
999999999991
999999999991

1
tests/day17/2.2 Normal file
View File

@@ -0,0 +1 @@
71