changeset 399:3294929223bd

Cache fox positions to avoid a repeated loop
author Neil Muller <drnlmuller@gmail.com>
date Tue, 17 Nov 2009 15:43:30 +0000
parents 082b1ea5f98d
children d146b7bb9b99
files gamelib/animal.py gamelib/gameboard.py
diffstat 2 files changed, 43 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/gamelib/animal.py	Mon Nov 16 15:27:36 2009 +0000
+++ b/gamelib/animal.py	Tue Nov 17 15:43:30 2009 +0000
@@ -403,28 +403,28 @@
         if new_pos == self.pos:
             # We're not moving, so we can skip all the checks
             return new_pos
+        blocked = gameboard.is_fox_at_pos(new_pos)
+        if not blocked and new_pos.z == self.pos.z:
+            # We're only worried about loops when not on a ladder
+            blocked = new_pos in self.last_steps
         final_pos = new_pos
-        blocked = False # We don't worry about loops on ladders
-        if new_pos.z != self.pos.z:
-            # We can only move up and down a ladder
-            moves = [Position(self.pos.x, self.pos.y, z) for z
-                    in range(self.pos.z-1, self.pos.z + 2) if z >= 0]
-        else:
-            blocked = final_pos in self.last_steps
-            moves = [Position(x, y) for x in range(self.pos.x-1, self.pos.x + 2)
-                    for y in range(self.pos.y-1, self.pos.y + 2)
-                    if Position(x,y) != self.pos and
-                    Position(x, y) not in self.last_steps and self.pos.z == 0]
-        for fox in gameboard.foxes:
-            if fox is not self and fox.pos == final_pos:
-                blocked = True
-            if fox.pos in moves:
-                moves.remove(fox.pos)
         if blocked:
-            # find the cheapest point in moves to new_pos that's not blocked
+            if new_pos.z != self.pos.z:
+                # We can only move up and down a ladder
+                moves = [Position(self.pos.x, self.pos.y, z) for z
+                        in range(self.pos.z-1, self.pos.z + 2) if z >= 0]
+            else:
+                moves = [Position(x, y) for x in range(self.pos.x-1, self.pos.x + 2)
+                        for y in range(self.pos.y-1, self.pos.y + 2)
+                        if Position(x,y) != self.pos and
+                        Position(x, y) not in self.last_steps and
+                        self.pos.z == 0]
+            # find the cheapest point in moves that's not blocked
             final_pos = None
             min_cost = 1000
             for poss in moves:
+                if gameboard.is_fox_at_pos(poss):
+                    continue # blocked
                 cost = self._cost_tile(poss, gameboard)
                 if cost < min_cost:
                     min_cost = cost
--- a/gamelib/gameboard.py	Mon Nov 16 15:27:36 2009 +0000
+++ b/gamelib/gameboard.py	Tue Nov 17 15:43:30 2009 +0000
@@ -292,6 +292,7 @@
         self.chickens = set()
         self.foxes = set()
         self.buildings = []
+        self._fox_pos_cache = []
         self.cash = 0
         self.eggs = 0
         self.days = 0
@@ -366,6 +367,7 @@
         self.tv.sun(False)
         self.reset_states()
         self.toolbar.update_fin_tool(self.day)
+        self._cache_fox_positions()
 
     def start_day(self):
         self.day, self.night = True, False
@@ -802,12 +804,35 @@
             self.chickens_attack()
         return over
 
+    def _cache_fox_positions(self):
+        """Cache the current set of fox positions for the avoiding checks"""
+        w, h = self.tv.size
+        self._fox_pos_cache = [[[False for z in range(5)] for y in range(h)]
+                for x in range(w)] # NB: Assumes z in [0, 4]
+        for fox in self.foxes:
+            if self.in_bounds(fox.pos):
+                self._fox_pos_cache[pos.x][pos.y][pos.z] = True
+
+    def _update_fox_pos_cache(self, old_pos, new_pos):
+        if self.is_fox_at_pos(old_pos):
+            self._fox_pos_cache[old_pos.x][old_pos.y][old_pos.z] = False
+        if new_pos and self.in_bounds(new_pos):
+            self._fox_pos_cache[new_pos.x][new_pos.y][new_pos.z] = True
+
+    def is_fox_at_pos(self, pos):
+        if self.in_bounds(pos):
+            return self._fox_pos_cache[pos.x][pos.y][pos.z]
+        return False
+
     def foxes_move(self):
         over = True
         for fox in self.foxes:
+            old_pos = fox.pos
             fox.move(self)
             if not fox.safe:
                 over = False
+            if fox.pos != old_pos:
+                self._update_fox_pos_cache(old_pos, fox.pos)
         return over
 
     def foxes_attack(self):
@@ -869,6 +894,7 @@
         self.killed_foxes += 1
         self.toolbar.update_fox_counter(self.killed_foxes)
         self.add_cash(self.level.sell_price_dead_fox)
+        self._update_fox_pos_cache(fox.pos, None)
         self.remove_fox(fox)
 
     def remove_fox(self, fox):