From: W. Trevor King Date: Sat, 27 Mar 2010 01:56:41 +0000 (-0400) Subject: Added fortification to the basic Player AI. X-Git-Tag: 0.1~17 X-Git-Url: http://git.tremily.us/?p=pyrisk.git;a=commitdiff_plain;h=efb81a5579292a08de0bf157994cb61681d7f8b1 Added fortification to the basic Player AI. This will excercise the fortification code during random_game()s. Also moved Player.border_territories functionality into a combo of Player.territories and a new Territory.border. This makes it easy to iterate through non-border territories looking for out-of-the-way armies for fortification. Finally, limit the players to one fortification per turn ;). --- diff --git a/pyrisk/base.py b/pyrisk/base.py index 7f9fcef..8229f60 100644 --- a/pyrisk/base.py +++ b/pyrisk/base.py @@ -20,7 +20,8 @@ import random from .log import Logger, BeginGame, EndGame, Killed, StartTurn, DealtCards, \ - EarnsArmies, SelectTerritory, PlaceArmies, PlayCards, Attack, Conquer + EarnsArmies, SelectTerritory, PlaceArmies, PlayCards, Attack, Conquer, \ + Fortify class PlayerError (Exception): @@ -75,6 +76,11 @@ class Territory (NameMixin, ID_CmpMixin, list): if id(t) == id(other): return True return False + def border(self): + for t in self: + if t.player != self.player: + return True + return False class Continent (NameMixin, ID_CmpMixin, list): """A group of Territories. @@ -400,15 +406,6 @@ class Player (NameMixin, ID_CmpMixin): for t in world.territories(): if t.player == self: yield t - def border_territories(self, world): - """Iterate through all territories owned by this player which - border another player's territories. - """ - for t in self.territories(world): - for neighbor in t: - if neighbor.player != self: - yield t - break def report(self, world, log): """Send reports about death and game endings. @@ -453,8 +450,9 @@ class Player (NameMixin, ID_CmpMixin): Return {territory_name: num_armies, ...} """ - t = random.sample(list(self.border_territories(world)), 1)[0] - return {t.name: this_round} + terr = random.sample([t for t in self.territories(world) + if t.border()], 1)[0] + return {terr.name: this_round} def attack_and_fortify(self, world, log, error=None, mode='attack'): """Return list of (source, target, armies) tuples. Place None @@ -462,15 +460,29 @@ class Player (NameMixin, ID_CmpMixin): """ assert mode != 'fortify', mode possible_attacks = [] - for t in self.border_territories(world): + for t in self.territories(world): + if not t.border(): + continue if t.armies <= 3: #1: # be more conservative, only attack with 3 dice continue targets = [border_t for border_t in t if border_t.player != self] for tg in targets: - possible_attacks.append((t.name, tg.name, min(3, t.armies-1))) + possible_attacks.append( + (t.name, tg.name, min(3, t.armies-1))) if len(possible_attacks) == 0: - return [None, None] # stop attack phase, then stop fortification phase - return random.sample(possible_attacks, 1) # + [None] + fortifications = [] + for t in self.territories(world): + if t.border() or t.armies == 1: + continue + targets = list(t) + for tg in targets: + fortifications.append( + (t.name, tg.name, t.armies-1)) + if len(fortifications) > 1: + fortifications = random.sample(fortifications, 1) + # stop attack phase, fortify, stop fortification phase + return [None] + fortifications + [None] + return random.sample(possible_attacks, 1) def support_attack(self, world, log, error, source, target): """Follow up on a conquest by moving additional armies. @@ -683,6 +695,7 @@ class Engine (ID_CmpMixin): else: assert mode == 'fortify', mode self.fortify(source, target, armies) + return captures # only allow one fortification except PlayerError, error: continue def attack(self, source, target, armies):