Only call Player.report (prev. Player.phase_report) as final contact
authorW. Trevor King <wking@drexel.edu>
Fri, 26 Mar 2010 00:40:26 +0000 (20:40 -0400)
committerW. Trevor King <wking@drexel.edu>
Fri, 26 Mar 2010 00:42:05 +0000 (20:42 -0400)
risk/base.py

index 8d8ef33467724fef9e3812f73dfbd72c5b52c5f1..b63e6c2540e14a0b8a3bb4b034adea2b0a73bfed 100644 (file)
@@ -251,26 +251,34 @@ class Player (ID_CmpMixin):
                 if neighbor.player != self:
                     yield t
                     break
                 if neighbor.player != self:
                     yield t
                     break
-    def phase_report(self, world, log):
+    def report(self, world, log):
+        """Send reports about death and game endings.
+
+        These events mark the end of contact and require no change in
+        player status or response, so they get a special command
+        seperate from the usual phase_* family.  The phase_* commands
+        in Player subclasses can notify the player (possibly by
+        calling report internally) if they feel so inclined.
+        """
         print 'Reporting for %s:\n  %s' \
             % (self, '\n  '.join(log[self._message_index:]))
         self._message_index = len(log)
         print 'Reporting for %s:\n  %s' \
             % (self, '\n  '.join(log[self._message_index:]))
         self._message_index = len(log)
-    def phase_select_territory(self, world):
+    def phase_select_territory(self, world, log):
         """Return the selected territory
         """
         free_territories = [t for t in world.territories() if t.player == None]
         return random.sample(free_territories, 1)[0]
         """Return the selected territory
         """
         free_territories = [t for t in world.territories() if t.player == None]
         return random.sample(free_territories, 1)[0]
-    def phase_play_cards(self, world, play_required=True):
+    def phase_play_cards(self, world, log, play_required=True):
         if play_required == True:
             return random.sample(list(self.hand.possible()), 1)[0]
         if play_required == True:
             return random.sample(list(self.hand.possible()), 1)[0]
-    def phase_place_armies(self, world, remaining=1, this_round=1):
+    def phase_place_armies(self, world, log, remaining=1, this_round=1):
         """Both during setup and before each turn.
 
         Return {territory_name: num_armies, ...}
         """
         t = random.sample(list(self.border_territories(world)), 1)[0]
         return {t.name: this_round}
         """Both during setup and before each turn.
 
         Return {territory_name: num_armies, ...}
         """
         t = random.sample(list(self.border_territories(world)), 1)[0]
         return {t.name: this_round}
-    def phase_attack(self, world):
+    def phase_attack(self, world, log):
         """Return list of (source, target, armies) tuples.  Place None
         in the list to end this phase.
         """
         """Return list of (source, target, armies) tuples.  Place None
         in the list to end this phase.
         """
@@ -284,14 +292,14 @@ class Player (ID_CmpMixin):
         if len(possible_attacks) == 0:
             return [None]
         return random.sample(possible_attacks, 1) # + [None]
         if len(possible_attacks) == 0:
             return [None]
         return random.sample(possible_attacks, 1) # + [None]
-    def phase_support_attack(self, world, source, target):
+    def phase_support_attack(self, world, log, source, target):
         return source.armies-1
         return source.armies-1
-    def phase_fortify(self, world):
+    def phase_fortify(self, world, log):
         """Return list of (source, target, armies) tuples.  Place None
         in the list to end this phase.
         """
         return [None]
         """Return list of (source, target, armies) tuples.  Place None
         in the list to end this phase.
         """
         return [None]
-    def phase_draw(self, cards=[]):
+    def phase_draw(self, world, log, cards=[]):
         """Only called if you earned a new card (or cards)"""
         self.hand.extend(cards)
 
         """Only called if you earned a new card (or cards)"""
         self.hand.extend(cards)
 
@@ -311,7 +319,7 @@ class Engine (ID_CmpMixin):
         self.play()
         self.log('Game over.')
         for p in self.players:
         self.play()
         self.log('Game over.')
         for p in self.players:
-            p.phase_report(self.world, self.log)
+            p.report(self.world, self.log)
     def setup(self):
         for p in self.players:
             p.alive = True
     def setup(self):
         for p in self.players:
             p.alive = True
@@ -332,18 +340,16 @@ class Engine (ID_CmpMixin):
         self.log("%s's turn (territory score: %s)"
                  % (player, [(p,len(list(p.territories(self.world))))
                              for p in self.players]))
         self.log("%s's turn (territory score: %s)"
                  % (player, [(p,len(list(p.territories(self.world))))
                              for p in self.players]))
-        player.phase_report(self.world, self.log)
         self.play_cards_and_place_armies(player)
         captures = self.attack_phase(player)
         if captures > 0 and len(self.deck) > 0 and len(self.living_players()) > 1:
         self.play_cards_and_place_armies(player)
         captures = self.attack_phase(player)
         if captures > 0 and len(self.deck) > 0 and len(self.living_players()) > 1:
-            player.phase_draw([self.deck.pop()])
+            player.phase_draw(self.world, self.log, [self.deck.pop()])
     def select_territories(self):
         for t in self.world.territories():
             t.player = None
         for i in range(len(list(self.world.territories()))):
             p = self.players[i % len(self.players)]
     def select_territories(self):
         for t in self.world.territories():
             t.player = None
         for i in range(len(list(self.world.territories()))):
             p = self.players[i % len(self.players)]
-            p.phase_report(self.world, self.log)
-            t = p.phase_select_territory(self.world)
+            t = p.phase_select_territory(self.world, self.log)
             if t.player != None:
                 raise PlayerError('Cannot select %s owned by %s'
                                   % (t, t.player))
             if t.player != None:
                 raise PlayerError('Cannot select %s owned by %s'
                                   % (t, t.player))
@@ -358,16 +364,14 @@ class Engine (ID_CmpMixin):
             assert min(s) == max(s)-1, 'Min %d, max %d' % (min(s), max(s))
             for p,placed in zip(self.players, already_placed):
                 if placed == min(s):
             assert min(s) == max(s)-1, 'Min %d, max %d' % (min(s), max(s))
             for p,placed in zip(self.players, already_placed):
                 if placed == min(s):
-                    p.phase_report(self.world, self.log)
                     self.player_place_armies(p, remaining, 1)
         remaining = self.world.initial_armies[len(self.players)] - max(s)
         while remaining > 0:
             for p in self.players:
                     self.player_place_armies(p, remaining, 1)
         remaining = self.world.initial_armies[len(self.players)] - max(s)
         while remaining > 0:
             for p in self.players:
-                p.phase_report(self.world, self.log)
                 self.player_place_armies(p, remaining, 1)
             remaining -= 1
     def player_place_armies(self, player, remaining=1, this_round=1):
                 self.player_place_armies(p, remaining, 1)
             remaining -= 1
     def player_place_armies(self, player, remaining=1, this_round=1):
-        placements = player.phase_place_armies(self.world, remaining, this_round)
+        placements = player.phase_place_armies(self.world, self.log, remaining, this_round)
         if sum(placements.values()) != this_round:
             raise PlayerError('Placing more than %d armies' % this_round)
         for ter_name,armies in placements.items():
         if sum(placements.values()) != this_round:
             raise PlayerError('Placing more than %d armies' % this_round)
         for ter_name,armies in placements.items():
@@ -387,12 +391,12 @@ class Engine (ID_CmpMixin):
             cards = []
             for i in range(3):
                 cards.append(self.deck.pop())
             cards = []
             for i in range(3):
                 cards.append(self.deck.pop())
-            p.phase_draw(cards)
+            p.phase_draw(self.world, self.log, cards)
         self.log('Initial hands dealt')
     def play_cards_and_place_armies(self, player, additional_armies=0):
         cards_required = len(player.hand) >= 5
         cards = player.phase_play_cards(
         self.log('Initial hands dealt')
     def play_cards_and_place_armies(self, player, additional_armies=0):
         cards_required = len(player.hand) >= 5
         cards = player.phase_play_cards(
-            self.world, play_required=cards_required)
+            self.world, self.log, play_required=cards_required)
         if cards_required == True and cards == None:
             raise PlayerError('You have %d >= 5 cards in your hand, you must play'
                               % len(player.hand))
         if cards_required == True and cards == None:
             raise PlayerError('You have %d >= 5 cards in your hand, you must play'
                               % len(player.hand))
@@ -418,7 +422,7 @@ class Engine (ID_CmpMixin):
     def attack_phase(self, player):
         captures = 0
         while True:
     def attack_phase(self, player):
         captures = 0
         while True:
-            attacks = player.phase_attack(self.world)
+            attacks = player.phase_attack(self.world, self.log)
             for attack in attacks:
                 if attack == None:
                     return captures
             for attack in attacks:
                 if attack == None:
                     return captures
@@ -470,7 +474,7 @@ class Engine (ID_CmpMixin):
         source.armies -= remaining_attackers
         target.armies += remaining_attackers
         target.player = source.player
         source.armies -= remaining_attackers
         target.armies += remaining_attackers
         target.player = source.player
-        support = source.player.phase_support_attack(self.world, source, target)
+        support = source.player.phase_support_attack(self.world, self.log, source, target)
         if support < 0 or support >= source.armies:
             raise PlayerError('Cannot support from %s to %s with %d armies, only %d available'
                               % (source, target, support, source.armies-1))
         if support < 0 or support >= source.armies:
             raise PlayerError('Cannot support from %s to %s with %d armies, only %d available'
                               % (source, target, support, source.armies-1))
@@ -484,7 +488,7 @@ class Engine (ID_CmpMixin):
                 self.play_cards_and_place_armies(killer)
         self.log('%s killed by %s' % (player, killer))
         if len(self.living_players()) > 1:
                 self.play_cards_and_place_armies(killer)
         self.log('%s killed by %s' % (player, killer))
         if len(self.living_players()) > 1:
-            player.phase_report(self.world, self.log)
+            player.report(self.world, self.log)
             # else the game is over, and killed will hear about this then.
     def living_players(self):
         return [p for p in self.players if p.alive == True]
             # else the game is over, and killed will hear about this then.
     def living_players(self):
         return [p for p in self.players if p.alive == True]