RosettaCodeData/Task/Dijkstras-algorithm/Wren/dijkstras-algorithm.wren

153 lines
4.4 KiB
Plaintext

import "./dynamic" for Tuple
import "./trait" for Comparable
import "./sort" for Cmp, Sort
import "./set" for Set
var Edge = Tuple.create("Edge", ["v1", "v2", "dist"])
// One vertex of the graph, complete with mappings to neighboring vertices
class Vertex is Comparable {
static map { __map } // maps a name to its corresponding Vertex
construct new(name) {
_name = name
_dist = Num.maxSafeInteger // assumed to be infinity
_prev = null
_neighbors = {}
if (!__map) __map = {}
__map[name] = this
}
name { _name }
dist { _dist }
dist=(d) { _dist = d }
prev { _prev }
prev=(v) { _prev = v }
neighbors { _neighbors }
printPath() {
if (this == _prev) {
System.write(_name)
} else if (!_prev) {
System.write("%(_name)(unreached)")
} else {
_prev.printPath()
System.write(" -> %(_name)(%(_dist))")
}
}
compare(other) {
if (_dist == other.dist) return Cmp.string.call(_name, other.name)
return Cmp.num.call(_dist, other.dist)
}
toString { "(%(_name), %(_dist))" }
}
class Graph {
construct new(edges, directed, showAllPaths) {
_graph = {}
// one pass to find all vertices
for (e in edges) {
if (!_graph.containsKey(e.v1)) _graph[e.v1] = Vertex.new(e.v1)
if (!_graph.containsKey(e.v2)) _graph[e.v2] = Vertex.new(e.v2)
}
// another pass to set neighboring vertices
for (e in edges) {
_graph[e.v1].neighbors[_graph[e.v2].name] = e.dist
// also do this for an undirected graph if applicable
if (!directed) _graph[e.v2].neighbors[_graph[e.v1].name] = e.dist
}
_showAllPaths = showAllPaths
_directed = directed
}
// Runs dijkstra using a specified source vertex
dijkstra(startName) {
if (!_graph.containsKey(startName)) {
System.print("Graph doesn't contain start vertex '%(startName)'")
return
}
var source = _graph[startName]
var q = Set.new()
// set-up vertices
for (v in _graph.values) {
v.prev = (v == source) ? source : null
v.dist = (v == source) ? 0 : Num.maxSafeInteger
q.add(v.name)
}
dijkstra_(q)
}
// Implementation of dijkstra's algorithm using a (simulated) tree set
dijkstra_(q) {
while (!q.isEmpty) {
var qq = q.toList
Sort.heap(qq)
// vertex with shortest distance (first iteration will return source)
var u = Vertex.map[qq[0]]
q.remove(qq[0])
// if distance is infinite we can ignore 'u'
// (and any other remaining vertices) since they are unreachable
if (u.dist == Num.maxSafeInteger) break
// look at distances to each neighbor
for (a in u.neighbors) {
var v = Vertex.map[a.key] // the neighbor in this iteration
var alternateDist = u.dist + a.value
if (alternateDist < v.dist) { // shorter path to neighbor found
v.dist = alternateDist
v.prev = u
}
}
}
}
// Prints the path from the source to every vertex
// (output order is not guaranteed)
printAllPaths_() {
for (v in _graph.values) {
v.printPath()
System.print()
}
System.print()
}
// Prints a path from the source to the specified vertex
printPath(endName) {
if (!_graph.containsKey(endName)) {
System.print("Graph doesn't contain end vertex '%(endName)'")
return
}
System.write(_directed ? "Directed : " : "Undirected : ")
_graph[endName].printPath()
System.print()
if (_showAllPaths) printAllPaths_() else System.print()
}
}
var GRAPH = [
Edge.new("a", "b", 7),
Edge.new("a", "c", 9),
Edge.new("a", "f", 14),
Edge.new("b", "c", 10),
Edge.new("b", "d", 15),
Edge.new("c", "d", 11),
Edge.new("c", "f", 2),
Edge.new("d", "e", 6),
Edge.new("e", "f", 9)
]
var START = "a"
var END = "e"
var g = Graph.new(GRAPH, true, false) // directed
g.dijkstra(START)
g.printPath(END)
g = Graph.new(GRAPH, false, false) // undirected
g.dijkstra(START)
g.printPath(END)