comparison gamelib/gameboard.py @ 456:96dbf2c8506e

Factor position cache out into its own class, make Position more useful.
author Jeremy Thurgood <firxen@gmail.com>
date Mon, 23 Nov 2009 10:30:22 +0000
parents 4bce845fbe6c
children fc648da2334c
comparison
equal deleted inserted replaced
455:fef4b1686d6c 456:96dbf2c8506e
38 if e.type == MOUSEBUTTONDOWN: 38 if e.type == MOUSEBUTTONDOWN:
39 self.gameboard.use_tool(e) 39 self.gameboard.use_tool(e)
40 elif e.type == MOUSEMOTION and self.gameboard.sprite_cursor: 40 elif e.type == MOUSEMOTION and self.gameboard.sprite_cursor:
41 self.gameboard.update_sprite_cursor(e) 41 self.gameboard.update_sprite_cursor(e)
42 42
43
44 class AnimalPositionCache(object):
45 def __init__(self, gameboard):
46 self.gameboard = gameboard
47 self.clear()
48
49 def clear(self):
50 self._cache = {'chicken': {}, 'fox': {}}
51
52 def _in_bounds(self, pos):
53 return self.gameboard.in_bounds(pos)
54
55 def add(self, animal, animal_type):
56 if animal and self._in_bounds(animal.pos):
57 self._cache[animal_type][animal.pos] = animal
58
59 def remove(self, pos, animal_type):
60 if pos in self._cache:
61 del self._cache[animal_type][pos]
62
63 def update(self, old_pos, animal, animal_type):
64 self.remove(old_pos, animal_type)
65 self.add(animal, animal_type)
66
67 def get(self, pos, animal_type):
68 return self._cache[animal_type].get(pos, None)
69
70
43 class GameBoard(serializer.Simplifiable): 71 class GameBoard(serializer.Simplifiable):
44 72
45 GRASSLAND = tiles.REVERSE_TILE_MAP['grassland'] 73 GRASSLAND = tiles.REVERSE_TILE_MAP['grassland']
46 FENCE = tiles.REVERSE_TILE_MAP['fence'] 74 FENCE = tiles.REVERSE_TILE_MAP['fence']
47 WOODLAND = tiles.REVERSE_TILE_MAP['woodland'] 75 WOODLAND = tiles.REVERSE_TILE_MAP['woodland']
73 self.animal_to_place = None 101 self.animal_to_place = None
74 self.sprite_cursor = None 102 self.sprite_cursor = None
75 self.chickens = set() 103 self.chickens = set()
76 self.foxes = set() 104 self.foxes = set()
77 self.buildings = set() 105 self.buildings = set()
78 self._pos_cache = { 'fox' : [], 'chicken' : []} 106 self._pos_cache = AnimalPositionCache(self)
79 self.cash = 0 107 self.cash = 0
80 self.wood = 0 108 self.wood = 0
81 self.eggs = 0 109 self.eggs = 0
82 self.days = 0 110 self.days = 0
83 self.killed_foxes = 0 111 self.killed_foxes = 0
186 def start_day(self): 214 def start_day(self):
187 self.day, self.night = True, False 215 self.day, self.night = True, False
188 self.tv.sun(True) 216 self.tv.sun(True)
189 self.reset_states() 217 self.reset_states()
190 self.toolbar.start_day() 218 self.toolbar.start_day()
191 self._pos_cache = { 'fox' : [], 'chicken' : []} 219 self._pos_cache.clear()
192 self.advance_day() 220 self.advance_day()
193 self.clear_foxes() 221 self.clear_foxes()
194 for chicken in self.chickens.copy(): 222 for chicken in self.chickens.copy():
195 chicken.start_day(self) 223 chicken.start_day(self)
196 self.toolbar.update_egg_counter(self.eggs) 224 self.toolbar.update_egg_counter(self.eggs)
619 self.chickens_attack() 647 self.chickens_attack()
620 return over 648 return over
621 649
622 def _cache_animal_positions(self): 650 def _cache_animal_positions(self):
623 """Cache the current set of fox positions for the avoiding checks""" 651 """Cache the current set of fox positions for the avoiding checks"""
624 w, h = self.tv.size 652 self._pos_cache.clear()
625 self._pos_cache['fox'] = [[[None for z in range(5)] for y in range(h)]
626 for x in range(w)] # NB: Assumes z in [0, 4]
627 self._pos_cache['chicken'] = [[[None for z in range(5)] for y in range(h)]
628 for x in range(w)]
629 for fox in self.foxes: 653 for fox in self.foxes:
630 self._add_to_pos_cache(fox, 'fox') 654 self._pos_cache.add(fox, 'fox')
631 for chick in self.chickens: 655 for chick in self.chickens:
632 self._add_to_pos_cache(chick, 'chicken') 656 self._pos_cache.add(chick, 'chicken')
633 657
634 def _add_to_pos_cache(self, animal, cache_type): 658 def get_animal_at_pos(self, pos, animal_type):
635 if self.in_bounds(animal.pos): 659 return self._pos_cache.get(pos, animal_type)
636 self._pos_cache[cache_type][animal.pos.x][animal.pos.y][animal.pos.z] = animal
637
638 def _update_pos_cache(self, old_pos, animal, cache_type):
639 if self.in_bounds(old_pos) and self._pos_cache[cache_type]:
640 self._pos_cache[cache_type][old_pos.x][old_pos.y][old_pos.z] = None
641 if animal:
642 pos = animal.pos
643 if self.in_bounds(pos):
644 self._pos_cache[cache_type][pos.x][pos.y][pos.z] = animal
645
646 def get_animal_at_pos(self, pos, cache_type):
647 if not self._pos_cache[cache_type]:
648 return None # We don't maintain the cache during the day
649 if self.in_bounds(pos):
650 return self._pos_cache[cache_type][pos.x][pos.y][pos.z]
651 return None
652 660
653 def chickens_scatter(self): 661 def chickens_scatter(self):
654 """Chickens outside move around randomly a bit""" 662 """Chickens outside move around randomly a bit"""
655 for chicken in [chick for chick in self.chickens if chick.outside()]: 663 for chicken in [chick for chick in self.chickens if chick.outside()]:
656 old_pos = chicken.pos 664 old_pos = chicken.pos
657 chicken.move(self) 665 chicken.move(self)
658 if chicken.pos != old_pos: 666 self._pos_cache.update(old_pos, chicken, 'chicken')
659 self._update_pos_cache(old_pos, chicken, 'chicken')
660 667
661 def chickens_chop_wood(self): 668 def chickens_chop_wood(self):
662 """Chickens with axes chop down trees near them""" 669 """Chickens with axes chop down trees near them"""
663 for chicken in [chick for chick in self.chickens if chick.outside()]: 670 for chicken in [chick for chick in self.chickens if chick.outside()]:
664 chicken.chop(self) 671 chicken.chop(self)
668 for fox in self.foxes: 675 for fox in self.foxes:
669 old_pos = fox.pos 676 old_pos = fox.pos
670 fox.move(self) 677 fox.move(self)
671 if not fox.safe: 678 if not fox.safe:
672 over = False 679 over = False
673 if fox.pos != old_pos: 680 self._pos_cache.update(old_pos, fox, 'fox')
674 self._update_pos_cache(old_pos, fox, 'fox')
675 return over 681 return over
676 682
677 def foxes_attack(self): 683 def foxes_attack(self):
678 for fox in self.foxes: 684 for fox in self.foxes:
679 fox.attack(self) 685 fox.attack(self)
717 723
718 def kill_fox(self, fox): 724 def kill_fox(self, fox):
719 self.killed_foxes += 1 725 self.killed_foxes += 1
720 self.toolbar.update_fox_counter(self.killed_foxes) 726 self.toolbar.update_fox_counter(self.killed_foxes)
721 self.add_cash(self.level.sell_price_dead_fox) 727 self.add_cash(self.level.sell_price_dead_fox)
722 self._update_pos_cache(fox.pos, None, 'fox')
723 self.remove_fox(fox) 728 self.remove_fox(fox)
724 729
725 def remove_fox(self, fox): 730 def remove_fox(self, fox):
731 self._pos_cache.remove(fox.pos, 'fox')
726 self.foxes.discard(fox) 732 self.foxes.discard(fox)
727 if fox.building: 733 if fox.building:
728 fox.building.remove_predator(fox) 734 fox.building.remove_predator(fox)
729 if fox in self.tv.sprites: 735 if fox in self.tv.sprites:
730 self.tv.sprites.remove(fox) 736 self.tv.sprites.remove(fox)
738 if chick.abode: 744 if chick.abode:
739 chick.abode.clear_occupant() 745 chick.abode.clear_occupant()
740 self.toolbar.update_chicken_counter(len(self.chickens)) 746 self.toolbar.update_chicken_counter(len(self.chickens))
741 if chick in self.tv.sprites and chick.outside(): 747 if chick in self.tv.sprites and chick.outside():
742 self.tv.sprites.remove(chick) 748 self.tv.sprites.remove(chick)
743 self._update_pos_cache(chick.pos, None, 'chicken') 749 self._pos_cache.remove(chick.pos, 'chicken')
744 750
745 def remove_building(self, building): 751 def remove_building(self, building):
746 if building in self.buildings: 752 if building in self.buildings:
747 self.buildings.discard(building) 753 self.buildings.discard(building)
748 self.tv.sprites.remove(building, layer='buildings') 754 self.tv.sprites.remove(building, layer='buildings')