Merge: serialization: safe formal types, fix warnings in generated code and more
[nit.git] / lib / a_star.nit
index 9780e12..9ea68e8 100644 (file)
@@ -14,9 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Services related to pathfinding of graphs using A*
-# A single graph may have different properties according to the `PathContext` used
+# A* pathfinding in graphs
 #
+# A single graph may have different properties according to the `PathContext` used
 #
 # Usage:
 #
@@ -90,7 +90,7 @@ class Node
        # lifetime limited to evocation of `path_to`
        private var open: Bool = false
 
-       # Main functionnality, returns path from `self` to `dest`
+       # Main functionality, returns path from `self` to `dest`
        fun path_to(dest: N, max_cost: Int, context: PathContext): nullable AStarPath[N]
        do
                return path_to_alts(dest, max_cost, context, null)
@@ -188,13 +188,21 @@ class Node
                end
        end
 
+       # Find the closest node accepted by `cond` under `max_cost`
+       fun find_closest(max_cost: Int, context: PathContext, cond: nullable TargetCondition[N]): nullable N
+       do
+               var path = path_to_alts(null, max_cost, context, cond)
+               if path == null then return null
+               return path.nodes.last
+       end
+
        # We customize the serialization process to avoid problems with recursive
        # serialization engines. These engines, such as `JsonSerializer`,
        # are at danger to serialize the graph as a very deep tree.
        # With a large graph it can cause a stack overflow.
        #
        # Instead, we serialize the nodes first and then the links.
-       redef fun core_serialize_to(serializer: Serializer)
+       redef fun core_serialize_to(serializer)
        do
                serializer.serialize_attribute("graph", graph)
        end
@@ -203,8 +211,8 @@ class Node
        do
                deserializer.notify_of_creation self
 
-               var graph = deserializer.deserialize_attribute("graph")
-               assert graph isa Graph[N, Link]
+               var graph = deserializer.deserialize_attribute("graph", (new GetName[Graph[N, Link]]).to_s)
+               if not graph isa Graph[N, Link] then graph = new Graph[N, Link]
                self.graph = graph
        end
 end
@@ -239,10 +247,10 @@ class Graph[N: Node, L: Link]
        super Serializable
 
        # Nodes in this graph
-       var nodes: Set[N] = new HashSet[N]
+       var nodes = new Set[N]
 
        # Links in this graph
-       var links: Set[L] = new HashSet[L]
+       var links = new Set[L]
 
        # Add a `node` to this graph
        fun add_node(node: N): N
@@ -265,7 +273,7 @@ class Graph[N: Node, L: Link]
        # Used to check if nodes have been searched in one pathfinding
        private var pathfinding_current_evocation: Int = 0
 
-       redef fun core_serialize_to(serializer: Serializer)
+       redef fun core_serialize_to(serializer)
        do
                serializer.serialize_attribute("nodes", nodes)
                serializer.serialize_attribute("links", links)
@@ -275,13 +283,17 @@ class Graph[N: Node, L: Link]
        do
                deserializer.notify_of_creation self
 
-               var nodes = deserializer.deserialize_attribute("nodes")
-               assert nodes isa HashSet[N]
-               self.nodes = nodes
+               var nodes = deserializer.deserialize_attribute("nodes", (new GetName[Set[N]]).to_s)
+               if deserializer.deserialize_attribute_missing then
+                       deserializer.errors.add new AttributeMissingError(self, "nodes")
+               end
+               if nodes isa Set[N] then self.nodes = nodes
 
-               var links = deserializer.deserialize_attribute("links")
-               assert links isa HashSet[L]
-               for link in links do add_link link
+               var links = deserializer.deserialize_attribute("links", (new GetName[Set[L]]).to_s)
+               if deserializer.deserialize_attribute_missing then
+                       deserializer.errors.add new AttributeMissingError(self, "links")
+               end
+               if links isa Set[L] then for link in links do add_link link
        end
 end
 
@@ -316,7 +328,7 @@ class AStarPath[N]
 end
 
 # Context related to an evocation of pathfinding
-class PathContext
+abstract class PathContext
        serialize
 
        # Type of the nodes in `graph`
@@ -380,7 +392,7 @@ class WeightedPathContext
                self.worst_cost = worst_cost
        end
 
-       redef var worst_cost: Int is noinit
+       redef var worst_cost is noinit
 
        redef fun cost(l) do
                return l.weight
@@ -400,7 +412,7 @@ class WeightedLink
 end
 
 # Advanced path conditions with customizable accept states
-class TargetCondition[N: Node]
+abstract class TargetCondition[N: Node]
        serialize
 
        # Should the pathfinding accept `node` as a goal?