1
0
Fork 0

2021 day 15 pt 1

This commit is contained in:
Sloane Perrault 2022-09-21 09:19:53 -04:00
parent b82ec31fe3
commit 32bd49675f
2 changed files with 104 additions and 1 deletions

View file

@ -16,7 +16,7 @@
| :-: | :-: | :-: | :-: | :-: | :-: | :-: |
| | | | [1] | [2] | [3] | [4] |
| [5] | [6] | [7] | [8] | [9] | [10] | [11]|
| [12]| [13]| [14]| 15 | 16 | 17 | 18 |
| [12]| [13]| [14]| [15] | 16 | 17 | 18 |
| 19 | 20 | 21 | 22 | 23 | 24 | 25 |
<!-- links -->
@ -35,3 +35,4 @@
[12]: ./lib/2021/12.ex
[13]: ./lib/2021/13.ex
[14]: ./lib/2021/14.ex
[15]: ./lib/2021/15.ex

102
2021/lib/2021/15.ex Normal file
View file

@ -0,0 +1,102 @@
import AOC
aoc 2021, 15 do
def input(input_string \\ input_string()) do
lists =
input_string
|> String.split("\n", trim: true)
|> Enum.map(fn line ->
line
|> String.graphemes()
|> Enum.map(&String.to_integer/1)
end)
for {row, i} <- Enum.with_index(lists), {cell, j} <- Enum.with_index(row), into: %{} do
{{i, j}, cell}
end
end
def move({i, j}, {g, h}), do: {g.(i), h.(j)}
def neighbors(map, pos) do
[
{&(&1 + 1), & &1},
{& &1, &(&1 + 1)},
{&(&1 - 1), & &1},
{& &1, &(&1 - 1)}
]
|> Enum.map(&move(pos, &1))
|> Enum.filter(&Map.has_key?(map, &1))
end
def manhattan_dist({x1, y1}, {x2, y2}), do: abs(x1 - x2) + abs(y1 - y2)
def a_star(map, start, goal) do
open =
PriorityQueue.new()
|> PriorityQueue.push(start, 0)
g_scores = %{start => 0}
f_scores = %{start => manhattan_dist(start, goal)}
a_star(map, goal, open, g_scores, f_scores)
end
# Gets into PriorityQueue implementation details and is slow...
# https://github.com/bitwalker/libgraph/blob/46c435f507f8b99f3f14c96d380eda28e5e9c7de/lib/priority_queue.ex#L129-L132
def p_queue_member?(%PriorityQueue{priorities: tree}, v) do
v in (:gb_trees.to_list(tree) |> Enum.flat_map(fn {_, q} -> :queue.to_list(q) end))
end
def a_star(map, goal, open, g_scores, f_scores) do
case PriorityQueue.pop(open) do
{{:value, curr}, open} ->
if curr == goal do
f_scores[curr]
else
{open, g_scores, f_scores} =
for neighbor <- neighbors(map, curr), reduce: {open, g_scores, f_scores} do
{open, g_scores, f_scores} ->
tentative_g_score = g_scores[curr] + Map.get(map, neighbor)
if tentative_g_score < g_scores[neighbor] do
g_scores = Map.put(g_scores, neighbor, tentative_g_score)
f_scores =
Map.put(
f_scores,
neighbor,
tentative_g_score + manhattan_dist(neighbor, goal)
)
open =
if p_queue_member?(open, neighbor),
do: open,
else: PriorityQueue.push(open, neighbor, f_scores[neighbor])
{open, g_scores, f_scores}
else
{open, g_scores, f_scores}
end
end
a_star(map, goal, open, g_scores, f_scores)
end
{:empty, _} ->
:error
end
end
def p1 do
map = input()
start = {0, 0}
goal = map |> Map.keys() |> Enum.max()
a_star(map, start, goal)
end
def p2 do
end
end