Add a pathfinding algorithm - why not?
This commit is contained in:
parent
b91819c4cf
commit
598c970a46
48
graph.cr
Normal file
48
graph.cr
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
class Graph(A)
|
||||||
|
def initialize
|
||||||
|
@edges = {} of A => Set({A, Int32})
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_edge(f, t, c = 1)
|
||||||
|
@edges[f] ||= Set({A, Int32}).new
|
||||||
|
@edges[f] << {t, c}
|
||||||
|
end
|
||||||
|
|
||||||
|
def add_biedge(f, t, c = 1)
|
||||||
|
add_edge(f, t, c)
|
||||||
|
add_edge(t, f, c)
|
||||||
|
end
|
||||||
|
|
||||||
|
def find_path(f, t)
|
||||||
|
visited = Set(A).new
|
||||||
|
candidates = Set { f }
|
||||||
|
distances = {f => 0}
|
||||||
|
prev = {} of A => A
|
||||||
|
|
||||||
|
while !candidates.empty?
|
||||||
|
candidate = candidates.min_by { |c| distances[c] }
|
||||||
|
break if candidate == t
|
||||||
|
visited << candidate
|
||||||
|
candidates.delete candidate
|
||||||
|
dist = distances[candidate]
|
||||||
|
|
||||||
|
@edges.fetch(candidate, Set({A, Int32}).new).each do |e|
|
||||||
|
node, cost = e
|
||||||
|
new_dist = dist + cost
|
||||||
|
candidates << node unless visited.includes? node
|
||||||
|
next if (old_dist = distances[node]?) && old_dist < new_dist
|
||||||
|
distances[node] = new_dist
|
||||||
|
prev[node] = candidate
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
backtrack = t
|
||||||
|
path = [t] of A
|
||||||
|
while backtrack != f
|
||||||
|
return nil unless prev_bt = prev[backtrack]?
|
||||||
|
path << prev_bt
|
||||||
|
backtrack = prev_bt
|
||||||
|
end
|
||||||
|
{path.reverse!, distances[t]}
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user