Code for the Advent of Code event
aoc
advent-of-code
1# frozen_string_literal: true
2
3require_relative 'pqueue'
4
5INF = Float::INFINITY
6
7module AStar
8 class << self
9 def find_path(graph, start, goal, &heuristic)
10 heuristic ||= method(:default_heuristic)
11
12 frontier = PriorityQueue.new
13 came_from = {}
14 cost_so_far = {}
15
16 if start.is_a?(Enumerable) && !start.is_a?(Vector)
17 start.each do
18 frontier.enqueue _1, 0
19 came_from[_1] = nil
20 cost_so_far[_1] = 0
21 end
22 else
23 frontier.enqueue start, 0
24 came_from[start] = nil
25 cost_so_far[start] = 0
26 end
27
28 while frontier.any?
29 current = frontier.dequeue
30 break if current == goal
31 graph.neighbors(current).each do |vertex|
32 new_cost = cost_so_far[current] + graph.cost(current, vertex)
33 next unless !cost_so_far.key?(vertex) || new_cost < cost_so_far[vertex]
34 cost_so_far[vertex] = new_cost
35 priority = new_cost + heuristic.call(vertex, goal)
36 frontier.enqueue vertex, priority
37 came_from[vertex] = current
38 end
39 end
40
41 [came_from, cost_so_far]
42 end
43
44 def reconstruct_path(came_from, start, goal)
45 current = goal
46 path = []
47 while current != start
48 path << current
49 current = came_from[current]
50 end
51 path << start
52 path.reverse
53 end
54
55 private
56
57 def default_heuristic(a, b)
58 x1, y1 = a.to_a
59 x2, y2 = b.to_a
60 (x1 - x2).abs + (y1 - y2).abs
61 end
62 end
63end