pep8analysis: print CFG as dot graph to OStream
[nit.git] / lib / a_star.nit
index 1f25f00..c6f6329 100644 (file)
 # Services related to pathfinding of graphs using A*
 # A single graph may have different properties according to the `PathContext` used
 #
+#
 # Usage:
 #
-#    # Weighted graph (letters are nodes, digits are weights):
-#    #
-#    #     a -2- b
-#    #    /     /
-#    #   3     1
-#    #  /     /
-#    # c -3- d -8- e
-#    #
-#    var graph = new Graph[Node,WeigthedLink[Node]]
+# ~~~
+# # Weighted graph (letters are nodes, digits are weights):
+# #
+# #     a -2- b
+# #    /     /
+# #   3     1
+# #  /     /
+# # c -3- d -8- e
+# #
+# var graph = new Graph[Node,WeightedLink]
 #
-#    var na = new Node(graph)
-#    var nb = new Node(graph)
-#    var nc = new Node(graph)
-#    var nd = new Node(graph)
-#    var ne = new Node(graph)
+# var na = new Node(graph)
+# var nb = new Node(graph)
+# var nc = new Node(graph)
+# var nd = new Node(graph)
+# var ne = new Node(graph)
 #
-#    var lab = new WeightedLink(graph, na, nb, 2)
-#    var lac = new WeightedLink(graph, na, nc, 3)
-#    var lbd = new WeightedLink(graph, nb, nd, 1)
-#    var lcd = new WeightedLink(graph, nc, nd, 3)
-#    var lde = new WeightedLink(graph, nd, ne, 8)
+# var lab = new WeightedLink(graph, na, nb, 2)
+# var lac = new WeightedLink(graph, na, nc, 3)
+# var lbd = new WeightedLink(graph, nb, nd, 1)
+# var lcd = new WeightedLink(graph, nc, nd, 3)
+# var lde = new WeightedLink(graph, nd, ne, 8)
 #
-#    var context = new WeightedPathContext(graph)
+# var context = new WeightedPathContext(graph)
 #
-#    var path = na.path_to(ne, 100, context)
-#    assert path != null else print "No possible path"
+# var path = na.path_to(ne, 100, context)
+# assert path != null else print "No possible path"
 #
-#    while not path.at_end_of_path do
-#        print path.step
-#    end
+# assert path.step == nb
+# assert path.step == nd
+# assert path.step == ne
+# assert path.at_end_of_path
+# ~~~
 module a_star
 
 redef class Object
        protected fun debug_a_star: Bool do return false
        private fun debug(msg: String) do if debug_a_star then
-               stderr.write "a_star debug: {msg}\n"
+               sys.stderr.write "a_star debug: {msg}\n"
        end
 end
 
@@ -78,28 +82,27 @@ class Node
        private var last_pathfinding_evocation: Int = 0
 
        # cost up to in current evocation
-       # lifetime limited to evocation of path_to
+       # lifetime limited to evocation of `path_to`
        private var best_cost_up_to: Int = 0
 
        # source node
-       # lifetime limited to evocation of path_to
+       # lifetime limited to evocation of `path_to`
        private var best_source: nullable N = null
 
        # is in frontier or buckets
-       # lifetime limited to evocation of path_to
+       # lifetime limited to evocation of `path_to`
        private var open: Bool = false
 
-
        # Main functionnality, returns path from `self` to `dest`
-       fun path_to(dest: Node, max_cost: Int, context: PathContext): nullable Path[N]
+       fun path_to(dest: N, max_cost: Int, context: PathContext): nullable Path[N]
        do
-               var cost: Int = 0
+               var cost = 0
 
                var nbr_buckets = context.worst_cost + context.worst_heuristic_cost + 1
-               var buckets = new Array[List[Node]].with_capacity(nbr_buckets)
+               var buckets = new Array[List[N]].with_capacity(nbr_buckets)
 
                for i in [0 .. nbr_buckets[ do
-                       buckets.add(new List[Node])
+                       buckets.add(new List[N])
                end
 
                graph.pathfinding_current_evocation += 1
@@ -110,8 +113,8 @@ class Node
                self.last_pathfinding_evocation = graph.pathfinding_current_evocation
                self.best_cost_up_to = 0
 
-               while cost < max_cost do
-                       var frontier_node: nullable Node = null
+               loop
+                       var frontier_node: nullable N = null
 
                        var bucket_searched: Int = 0
 
@@ -122,6 +125,7 @@ class Node
                                if current_bucket.is_empty then # move to next bucket
                                        debug "b {cost} {cost % nbr_buckets} {buckets[cost % nbr_buckets].hash}"
                                        cost += 1
+                                       if cost > max_cost then return null
                                        bucket_searched += 1
 
                                        if bucket_searched > nbr_buckets then break
@@ -179,46 +183,10 @@ class Node
                                end
                        end
                end
-
-               # costs over max
-               return null
-       end
-
-       # Find closes node with matching caracteristic
-       # TODO remove closures
-       fun find_closest(max_to_search: Int): nullable N !with(n: N): Bool
-       do
-               if with(self) then return self
-
-               var frontier = new List[N]
-               graph.pathfinding_current_evocation += 1
-               var current_evocation = graph.pathfinding_current_evocation
-
-               frontier.add(self)
-               self.last_pathfinding_evocation = current_evocation
-
-               var i = 0
-               while not frontier.is_empty do
-                       var node = frontier.shift
-
-                       for link in node.links do
-                               var to = link.to
-                               if to.last_pathfinding_evocation != current_evocation then
-                                       if with(to) then return to
-
-                                       frontier.add(to)
-                                       to.last_pathfinding_evocation = current_evocation
-                               end
-                       end
-
-                       i += 1
-                       if i > max_to_search then return null
-               end
-
-               return null
        end
 end
 
+# Link between two nodes and associated to a graph
 class Link
        type N: Node
        type L: Link