2021 day 15 pt 1
This commit is contained in:
parent
b82ec31fe3
commit
32bd49675f
2 changed files with 104 additions and 1 deletions
|
@ -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
102
2021/lib/2021/15.ex
Normal 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
|
Loading…
Reference in a new issue