Merge: Various fixes and improvements from We Broke The World
authorJean Privat <jean@pryen.org>
Thu, 25 Sep 2014 21:41:25 +0000 (17:41 -0400)
committerJean Privat <jean@pryen.org>
Thu, 25 Sep 2014 21:41:37 +0000 (17:41 -0400)
Pull-Request: #778
Reviewed-by: Jean Privat <jean@pryen.org>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>

contrib/inkscape_tools/src/svg_to_png_and_nit.nit
lib/a_star.nit
lib/ai/search.nit
lib/bucketed_game.nit

index 1a2d7b3..2a94089 100644 (file)
@@ -183,8 +183,8 @@ for drawing in drawings do
 
                        var x = words[1].to_f.floor.to_i
                        var y = words[2].to_f.floor.to_i
-                       var w = words[3].to_f.ceil.to_i
-                       var h = words[4].to_f.ceil.to_i
+                       var w = words[3].to_f.ceil.to_i+1
+                       var h = words[4].to_f.ceil.to_i+1
 
                        if id.has_prefix("0") then
                                var nit_name = id.substring_from(1)
index c6f6329..125b053 100644 (file)
@@ -96,6 +96,13 @@ class Node
        # Main functionnality, returns path from `self` to `dest`
        fun path_to(dest: N, max_cost: Int, context: PathContext): nullable Path[N]
        do
+               return path_to_alts(dest, max_cost, context, null)
+       end
+
+       # Find a path to a possible `destination` or a node accepted by `alt_targets`
+       fun path_to_alts(destination: nullable N, max_cost: Int, context: PathContext,
+               alt_targets: nullable TargetCondition[N]): nullable Path[N]
+       do
                var cost = 0
 
                var nbr_buckets = context.worst_cost + context.worst_heuristic_cost + 1
@@ -142,7 +149,8 @@ class Node
                                return null
 
                        # at destination
-                       else if frontier_node == dest then
+                       else if frontier_node == destination or
+                            (alt_targets != null and alt_targets.accept(frontier_node)) then
                                debug "picked {frontier_node}, is destination"
 
                                var path = new Path[N](cost)
@@ -168,13 +176,18 @@ class Node
                                           (peek_node.open and
                                             peek_node.best_cost_up_to > cost + context.cost(link)))
                                        then
-
                                                peek_node.open = true
                                                peek_node.last_pathfinding_evocation = graph.pathfinding_current_evocation
                                                peek_node.best_cost_up_to = cost + context.cost(link)
                                                peek_node.best_source = frontier_node
 
-                                               var est_cost = peek_node.best_cost_up_to+context.heuristic_cost(link.from, peek_node)
+                                               var est_cost
+                                               if destination != null then
+                                                       est_cost = peek_node.best_cost_up_to + context.heuristic_cost(peek_node, destination)
+                                               else if alt_targets != null then
+                                                       est_cost = peek_node.best_cost_up_to + alt_targets.heuristic_cost(peek_node, link)
+                                               else est_cost = 0
+
                                                var at_bucket = buckets[est_cost % nbr_buckets]
                                                at_bucket.add(peek_node)
 
@@ -333,3 +346,12 @@ class WeightedLink
                self.weight = weight
        end
 end
+
+# Advanced path conditions with customizable accept states
+class TargetCondition[N: Node]
+       # Should the pathfinding accept `node` as a goal?
+       fun accept(node: N): Bool is abstract
+
+       # Approximate cost from `node` to an accept state
+       fun heuristic_cost(node: N, link: Link): Int is abstract
+end
index 248ab7c..f279d4f 100644 (file)
@@ -99,7 +99,7 @@ interface SearchProblem[S: Object, A]
        # An heuristic of the estimated `cost` going from `state` to a goal state.
        #
        # Is is expected that the heuristic is *admissible*, it means its is an
-       # optimistic estimation that never an over-estimate, thus is cannot be#
+       # optimistic estimation and never an over-estimate, thus is cannot be
        # higher than the lowest possible remaining cost.
        # See `SearchSolver::do_revisit` for details.
        #
index b680079..45a439c 100644 (file)
@@ -30,7 +30,13 @@ end
 # Something acting on the game from time to time
 class Bucketable[G: Game]
        super Turnable[G]
-       private var act_at: Int = 0
+       private var act_at: nullable Int = null
+
+       # Cancel the previously registered acting turn
+       #
+       # Once called, `self.do_turn` will not be invoked until `GameTurn::act_next`
+       # or `GameTurn::act_in` are called again.
+       fun cancel_act do act_at = null
 end
 
 # Optiomized organization of `Bucketable` instances
@@ -76,19 +82,23 @@ class Buckets[G: Game]
                current_bucket_key = key_for_tick(turn.tick)
                var current_bucket = buckets[current_bucket_key]
 
-               next_bucket = new HashSet[Bucketable[G]]
+               var next_bucket = new HashSet[Bucketable[G]]
 
                for e in current_bucket do
-                       if e.act_at == turn.tick then
-                               e.do_turn(turn)
-                       else if e.act_at > turn.tick and
-                               key_for_tick(e.act_at) == current_bucket_key
-                       then
-                               next_bucket.as(not null).add(e)
+                       var act_at = e.act_at
+                       if act_at != null then
+                               if turn.tick == act_at then
+                                       e.do_turn(turn)
+                               else if act_at > turn.tick and
+                                       key_for_tick(act_at) == current_bucket_key
+                               then
+                                       next_bucket.add(e)
+                               end
                        end
                end
 
-               buckets[current_bucket_key] = next_bucket.as(not null)
+               self.next_bucket = next_bucket
+               buckets[current_bucket_key] = next_bucket
        end
 end