Top

risktools module

This file contains the RISK simulator that consitutes the backbone of the RISK AI Assignment

"""
This file contains the RISK simulator that consitutes the backbone of the RISK AI Assignment
"""
import gui.riskengine as riskengine
import random
import zipfile
import xml.dom.minidom
import math
import json

class RiskBoard():
    """
    Stores all of the information about the current Risk game that doesn't change
    over the course of the game, things like:
        
        Which territories make up the map
        
        Which territories are connected to which
        
        What the continents are and which territories they are composed of
        
        What the sequence of card turn-in values is
        
        What players are in the game
        
        What pictures are on the cards 
        
        What the set of all cards is
    """
    def __init__(self):
        """
        Initialize a Risk Board.
        All of the variables are initially empty.  
        They should be filled in through other function calls
        """
        
        self.players = []               
        """ An array of RiskPlayer objects """
        
        self.player_to_id = dict()
        """ A dictionary which is indexed by player name and stores the id number of that player """

        self.id_to_player = dict()
        """ A dictionary which is indexed by player id and stores the player name of that player """
        
        self.territories = []           
        """ An array of RiskTerritory objects """
        self.territory_to_id = dict()
        """ A dictionary which is indexed by territory name and stores the id number of that territory """        

        self.cards = []                 
        """ An array of RiskCard objects """ 

        self.card_to_id = dict()
        """ A dictionary which is indexed by card name (territory name of pictured territory, or wildcard) Stores the id of that card """

        self.pictures = []
        """ An array of string descriptions of the different card pictures """
        
        self.continents = dict()        
        """ A dictionary of RiskContinent objects indexed by continent name, stores corresponding RiskContinent object """
        
        self.turn_in_values = []
        """ 
         An array of the card turn-in-values 
         turn_in_values[i] gives the number of troops
         received for the i-th card turn-in
        """

        self.increment_value = 0
        """ A number specifying the incremental gain in received troops for card turn-ins beyond the length of turn-in-values array """
        
        
    def from_string(self, s):
        """
        Load RiskBoard information from a string.  
        We assume the string was created by the to_string 
        function.
        """
        ss = s.split('|')
        #Players
        ssp = ss[1].split(';')
        for p in ssp:
            if len(p) > 0:
                np = RiskPlayer(None,None,None,None)
                np.from_string(p)
                self.add_player(np)
        #Territories
        sst = ss[2].split(';')
        for t in sst:
            if t:
                nt = RiskTerritory(None,None)
                nt.from_string(t)
                self.add_territory(nt)
        #Continents
        ssc = ss[3].split(';')
        for c in ssc:
            if c:
            
                nc = RiskContinent(None,None)
                nc.from_string(c)
                self.add_continent(nc)
        #Cards
        ssd = ss[4].split(';')
        for d in ssd:
            if d:
                nd = RiskCard(None,None,None)
                nd.from_string(d)
                self.add_card(nd)
        #Turn in values
        self.turn_in_values = json.loads(ss[5])
        #Increment value
        self.increment_value = json.loads(ss[6])
        #Pictures
        self.pictures = json.loads(ss[7])
    
    def to_string(self):
        """Save the current RiskBoard to a string.  This is used to save games."""
        output_string = 'RISKBOARD|'
        #Players
        for p in self.players:
            output_string = output_string + p.to_string()
            output_string = output_string + ';'
        output_string = output_string + '|'
        #Territories
        for t in self.territories:
            output_string = output_string + t.to_string()
            output_string = output_string + ';'
        output_string = output_string + '|'
        #Continents
        for n,c in self.continents.iteritems():
            output_string = output_string + c.to_string() + ';'
        output_string = output_string + '|'
        #Cards 
        for c in self.cards:
            output_string = output_string + c.to_string()
            output_string = output_string + ';'
        output_string = output_string + '|'
        #Turn In Values
        output_string = output_string + json.dumps(self.turn_in_values)
        output_string = output_string + '|'
        #Increment value
        output_string = output_string + json.dumps(self.increment_value)
        output_string = output_string + '|'
        #Pictures
        output_string = output_string + json.dumps(self.pictures)
        
        return output_string
        
        
    # def shuffle_players(self):
    #     """
    #     Randomize the player order.  Make sure everything is right after that
    #     """
    #     player_order = range(len(self.players))
    #     random.shuffle(player_order)
        
    #     shuffled_players = []
    #     player_counter = 0
    #     for i in player_order:
    #         p = self.players[i]
    #         p.id = player_counter
    #         shuffled_players.append(p)
    #         self.player_to_id[p.name] = p.id
    #         self.id_to_player[p.id] = p.name
    #         player_counter += 1
            
    #     self.players = shuffled_players
        
        
    def add_player(self, player):
        """
        Add a player object to the list of players.
        Modify player_to_id and id_to_player to include new player
        """
        self.players.append(player)
        self.player_to_id[player.name] = player.id
        self.id_to_player[player.id] = player.name
        
    def add_territory(self, territory):
        """
        Add a territory object to the list of territories.
        Modify territory_to_id to include new territory
        """
        self.territories.append(territory)
        self.territory_to_id[territory.name] = territory.id
        
    def add_card(self, card):
        """
        Add a card object to the list of cards
        Modify card_to_id to include the new card
        """
        self.cards.append(card)
        self.card_to_id[self.territories[card.territory].name] = card.id
        
    def shuffle_cards(self):
        """Randomly shuffle the array of cards and reassign the card ids to be consistent"""
        random.shuffle(self.cards)
        for i in range(len(self.cards)):
            self.cards[i].id = i
            self.card_to_id[self.territories[self.cards[i].territory].name] = i
        
    def add_continent(self, continent):
        """Add a continent object to the list of continents"""
        if continent.name not in self.continents:
            self.continents[continent.name] = continent
            
    def set_turn_in_values(self, tiv):
        """Set the array of turn-in values (for card turn-ins)"""
        self.turn_in_values = tiv
        
    def set_increment_value(self, iv):
        """Set the increment value for card turn-ins beyond the end of turn_in_values"""
        self.increment_value = iv    
            
    def print_board(self):
        """Display the Risk Board to the output."""
        print 'RISK BOARD'
        #PRINT TERRITORIES BY CONTINENT
        print 'CONTINENTS'
        for c in self.continents.values():
            c.print_continent(self)
        
        #PRINT CARDS
        print 'CARDS'
        for c in self.cards:
            c.print_card(self)
            
        #PRINT PLAYERS
        print 'PLAYERS'
        for p in self.players:
            p.print_player(self)
            
class RiskTerritory():
    """Stores all of the information for a territory"""
    def __init__(self, name, id):
        self.name = name
        """ The name of the territory (a string) """
        
        self.id = id
        """ The id number of the territory (an integer) """

        self.neighbors = []
        """ An list of the id numbers of all territories neighboring this one """

    
    def add_neighbor(self, neighbor):
        """Add a neighbor id to the neighbor list"""
        self.neighbors.append(neighbor)
    
    def print_territory(self, board, indent=0):
        """Display information about this territory to the output"""
        for i in range(indent):
            print ' ',
        print '[', self.name, '] (', self.id, ')'
        for i in range(indent+2):
            print ' ',
        print 'Neighbors:'
        for n in self.neighbors:
            for i in range(indent+3):
                print ' ',
            print board.territories[n].name
    
    def to_string(self):
        """Save the current Territory information to a string"""
        s = json.dumps(self.name) + '&' + json.dumps(self.id) + '&' + json.dumps(self.neighbors) 
        return s
        
    def from_string(self, s):
        """Load information about this territory from a string"""
        ss = s.split('&')
        self.name = json.loads(ss[0])
        self.id = json.loads(ss[1])
        self.neighbors = json.loads(ss[2])
    
class RiskPlayer():
    """Stores all information about a player in the game"""
    def __init__(self, name, id, free_armies, conquered_territory):
        """Initializes the various components of this RiskPlayer object"""
        self.name = name
        """ The Player's name (string) """
        
        self.id = id
        """ The Player's id (integer) """

        self.cards = []
        """ A list of card id numbers that this player holds (integers) """

        self.free_armies = free_armies
        """ The number of armies this player has in hand, waiting to be placed on the board """

        self.conquered_territory = conquered_territory
        """ A boolean stating whether or not this player conquered a territory on their current turn """
    
    def add_card(self, card):
        """Adds a card (card id number) to the player's list of card ids"""
        self.cards.append(card)
    
    def add_armies(self, n):
        """Adds a number (n) of armies to the player's free_armies count"""
        self.free_armies += n
    
    def print_player(self, board, indent=0):
        """Displays information about this player to the output"""
        for i in range(indent):
            print ' ',
        print '<', self.name, '[', self.id, ']> (', self.free_armies, ' free armies )'
        for i in range(indent+2):
            print ' ',
        print 'Cards:'
        for c in self.cards:
            board.cards[c].print_card(board, indent+3)
        
    def copy_player(self):
        """Creates a copy of this player and returns it"""
        np = RiskPlayer(self.name, self.id, self.free_armies, self.conquered_territory)
        np.cards = self.cards[:]
        return np
        
    def to_string(self):
        """Saves this player to a string"""
        s = json.dumps(self.name) + '.' + json.dumps(self.id) + '.' + json.dumps(self.cards) + '.' + json.dumps(self.free_armies) + '.' + json.dumps(self.conquered_territory)
        return s
        
    def from_string(self, s):
        """Loads player information from a string"""
        ss = s.split('.')
        self.name = json.loads(ss[0])
        self.id = json.loads(ss[1])
        self.cards = json.loads(ss[2])
        self.free_armies = json.loads(ss[3])
        self.conquered_territory = json.loads(ss[4])
    
class RiskCard():
    """Stores all the information for a risk card"""
    def __init__(self, territory, picture, id):
        """Initializes card information"""

        self.territory = territory
        """ The territory id number of the territory pictured on the card """
        
        self.picture = picture
        """ The picture on the card """

        self.id = id
        """ The id number of this card """

    
    def print_card(self, board, indent=0):
        """Displays information about this card to the output"""
        for i in range(indent):
            print ' ',
        print board.territories[self.territory].name, ' : ', self.picture
        
    def to_string(self):
        """Saves card information to a string"""
        s = str(self.territory) + '.' + str(self.picture) + '.' + str(self.id)
        return s
        
    def from_string(self, s):
        """Loads card information from a string"""
        ss = s.split('.')
        self.territory = json.loads(ss[0])
        self.picture = json.loads(ss[1])
        self.id = json.loads(ss[2])
        
class RiskContinent():
    """Stores all information related to a continent"""
    def __init__(self, name, reward):
        """Initializes the continent information"""
        self.name = name
        """The name of this continent (string) """
        
        self.reward = reward
        """
         The reward for this continent 
         This is the number of troops bonus that a player gets if the player 
         owns all of the territories in this continent
        """
        self.territories = []
        """ A list of the territory id numbers of the territories in this continent"""        

    def add_territory(self, territory):
        """Adds a territory to this continent"""
        if territory not in self.territories:
            self.territories.append(territory)
    
    def print_continent(self,board,indent=0):
        """Displays information about continent to output"""
        for i in range(indent):
            print ' ',
        print '{', self.name, '} : ', self.reward
        for t in self.territories:
            board.territories[t].print_territory(board, indent+2)
    
    def to_string(self):
        """Save continent information to string"""
        s = json.dumps(self.name) + '&' + json.dumps(self.reward) + '&' + json.dumps(self.territories)
        return s
    
    def from_string(self, s):
        """Load continent information from string"""
        ss = s.split('&')
        self.name = json.loads(ss[0])
        self.reward = json.loads(ss[1])
        self.territories = json.loads(ss[2])
    
def nextPlayer(state):
    """
    Moves the state's current_player to the next player in the order
    Also ensures that when it exits, the new state.current_player is still in the game
    Input: RiskState object
    """
    incrementPlayer(state)
    while state.current_player not in state.owners and None not in state.owners:
        incrementPlayer(state)
    
def incrementPlayer(state):
    """
    Increments the current_player of the input state
    Input: RiskState object
    """
    state.current_player = state.current_player + 1
    if state.current_player >= len(state.players):
        state.current_player = 0
    
class RiskState():
    """Stores all the information about a state of a Risk game"""
    
    def __init__(self, players, armies, owners, current_player, turn_type, turn_in_number, last_attacker, last_defender, cards, board):
        """Initializes a RiskState object"""
    
        self.players = players
        """An array of RiskPlayer objects (the players in the game)"""
        
        self.armies = armies
        """
         An array of integers, indexed by territory id number, that 
         stores the number of armies on that territory
        """
        self.owners = owners
        """
         An array of integers, indexed by territory id number, that 
         stores the player id number of the player who owns that territory
        """
        self.current_player = current_player
        """ The player id number of the current player (player whose turn it is) """
        
        self.turn_type = turn_type
        """
         What kind of turn is it currently 
         Choices = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify, GameOver)
        """
        self.cards = cards
        """ A list of all the card id numbers of the cards still in the deck """

        self.turn_in_number = turn_in_number
        """ How many card sets have been turned in? """
        
        self.last_attacker = last_attacker
        """
         What is the territory id of the last territory that was attacking 
         Important to determine troop movements after territory is conquered
        """
        self.last_defender = last_defender
        """
         What is the territory id of the last territory that was defending 
         Important to determine troop movements after territory is conquered
        """
        
        self.board = board
        """
         A RiskBoard object that stores all the non-changing information about
         this risk game
        """

    def to_string(self):
        """Saves this state to a string"""
        s = 'RISKSTATE|'
        #players
        for p in self.players:
            s = s + p.to_string()
            s = s + ';'
        s = s + '|' + json.dumps(self.armies) + '|' + json.dumps(self.owners) + '|'
        s = s + json.dumps(self.current_player) + '|' + json.dumps(self.turn_type) + '|'
        s = s + json.dumps(self.cards) + '|' + json.dumps(self.turn_in_number) + '|'
        s = s + json.dumps(self.last_attacker) + '|' + json.dumps(self.last_defender)
        return s
        
    def from_string(self, s, board):
        """Loads this state from a string"""
        ss = s.split('|')
        if ss[0] != 'RISKSTATE':
            print 'THIS IS AN INVALID RISKSTATE'
        ps = ss[1].split(';')
        self.players = []
        for p in ps:
            if p:#len(p) > 0:
                np = RiskPlayer(None, None, None, None)
                np.from_string(p)
                self.players.append(np)
                
        self.armies = json.loads(ss[2])
        self.owners = json.loads(ss[3])
        self.current_player = json.loads(ss[4])
        self.turn_type = json.loads(ss[5])
        self.cards = json.loads(ss[6])
        self.turn_in_number = json.loads(ss[7])
        self.last_attacker = json.loads(ss[8])
        self.last_defender = json.loads(ss[9])
        self.board = board
        
    def print_state(self):
        """Displays information about this state to the output"""
        print 'PLAYERS'
        for p in self.players:
            p.print_player(self.board)
        
        print 'OWNERS/ARMIES'
        for i in range(len(self.armies)):
            if self.owners[i] in self.board.id_to_player:
                print self.board.territories[i].name, '[', self.board.id_to_player[self.owners[i]], '] : ', self.armies[i]
            else:
                print self.board.territories[i].name, '[', self.owners[i], '] : ', self.armies[i]
        
        if self.current_player < len(self.players):
            print 'CURRENT PLAYER: ', self.players[self.current_player].name, '[', self.current_player, ']'
        else:
            print 'CURRENT PLAYER: ??? [', self.current_player, ']'
        print len(self.cards), ' CARDS LEFT'
        
    def copy_state(self):
        """
        Creates a (deep) copy of this state and return it. Modifications to new state won't change original, except for the risk board, of which there is only one (it shouldn't be modified!)
        """
        copy_players = []
        for p in self.players:
            copy_players.append(p.copy_player())
        return RiskState(copy_players,self.armies[:],self.owners[:],self.current_player,self.turn_type,self.turn_in_number, self.last_attacker, self.last_defender, self.cards[:],self.board)

class RiskAction():
    """Stores the information about an action in a risk game"""
    
    def __init__(self, type, to_territory, from_territory, troops):
        """Initializes a RiskAction"""
        
        self.type = type
        """
         What kind of action this is? Should be a string
         possible types = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify)
        """
        
        self.to_territory = to_territory
        """
         This stores the territory id of the place the action is going
         For Each type it contains:
               
                PreAssign: The territory id being chosen by player
               
                PrePlace:  The territory id of the territory where troop is being placed
               
                Place: The territory id of the territory where troop is being placed
                
                TurnInCards: The card id of first of the cards being turned in, or None, if there are no cards to turn in
               
                Attack: The territory id of the territory being attacked
               
                Occupy: The territory id of the territory into which troops are moving
               
                Fortify: The territory id of the territory into which troops are moving
        """

        self.from_territory = from_territory
        """
         This stores the territory id of the place the action is coming from
         For Each type it contains:

                PreAssign: None
         
                PrePlace:  None
         
                Place: None
         
                TurnInCards: The card id of second of the cards being turned in, or None, if there are no cards to turn in
         
                Attack: The territory id of the territory doing the attacking
         
                Occupy: The territory id of the territory from which troops are moving
         
                Fortify: The territory id of the territory from which troops are moving
        """
        
        self.troops = troops
        """
         This stores the number of troops involved in the action
         For Each type it contains:
               
                PreAssign: None
               
                PrePlace:  None
               
                Place: None
               
                TurnInCards: The card id of third of the cards being turned in, or None, if there are no cards to turn in
               
                Attack: None
               
                Occupy: Number of troops moving into conquered territory
               
                Fortify: Number of troops moving to other territory
        """

    def print_action(self):
        """Displays information about this action to the output"""
        print self.description()
        
    def description(self, newline=False):
        """returns string description of this action, useful for display"""
        d = ""
        d = d + str(self.type) 
        if newline:
            d = d + "\n"
        if self.type == 'TurnInCards':
            d = d + ' CARD 1: ' + str(self.from_territory)
        elif self.type == 'Attack' or self.type == 'Occupy' or self.type == 'Fortify':
            d = d + ' FROM: ' + str(self.from_territory) 
        if newline:
            d = d + "\n"
        if self.type == 'TurnInCards':
            d = d + ' CARD 2: ' + str(self.to_territory) 
        elif self.type == 'Place' or self.type == 'PrePlace':
            d = d + ' IN: ' + str(self.to_territory) 
        else:
            d = d + ' TO: ' + str(self.to_territory) 
        if newline:
            d = d + "\n"
        if self.type == 'TurnInCards':
            d = d + ' CARD 3: ' + str(self.troops)
        elif self.type == 'Occupy' or self.type == 'Fortify':
            d = d + ' NUM: ' + str(self.troops)
        return d
        
    def to_string(self):
        """Saves this action to a string"""
        s = 'RISKACTION|' + json.dumps(self.type) + '|' + json.dumps(self.from_territory) + '|' + json.dumps(self.to_territory) + '|' + json.dumps(self.troops)
        return s
        
    def from_string(self, s):
        """Loads this action from a string"""
        ss = s.split('|')
        if ss[0] != 'RISKACTION':
            print 'THIS IS NOT A RISK ACTION STRING!'
        self.type = json.loads(ss[1])
        self.from_territory = json.loads(ss[2])
        self.to_territory = json.loads(ss[3])
        self.troops = json.loads(ss[4])
        
def translateAction(state, action):
    """
    Takes a RiskAction and converts it into what needs to be returned by the AI to compete in the interactive risk game.
    Don't modify
    """
    
    if action.type == 'PreAssign' or action.type == 'PrePlace' or action.type == 'Place':
        return filter(lambda x:x.name == action.to_territory, riskengine.territories.values())[0]
    elif action.type == 'TurnInCards':
        if action.to_territory is None:
            return None,None,None
        else:
            return filter(lambda x:x.territory == state.board.territories[state.board.cards[action.to_territory].territory].name, riskengine.currentplayer.cards)[0],filter(lambda x:x.territory == state.board.territories[state.board.cards[action.from_territory].territory].name, riskengine.currentplayer.cards)[0],filter(lambda x:x.territory == state.board.territories[state.board.cards[action.troops].territory].name, riskengine.currentplayer.cards)[0]
    elif action.type == 'Attack':
        if action.to_territory is None:
            return None,None
        return filter(lambda x:x.name == action.from_territory, riskengine.territories.values())[0], filter(lambda x:x.name == action.to_territory, riskengine.territories.values())[0]
    elif action.type == 'Occupy':
        return action.troops
    elif action.type == 'Fortify':
        if action.to_territory is None:
            return None,None,0
        return filter(lambda x:x.name == action.from_territory, riskengine.territories.values())[0], filter(lambda x:x.name == action.to_territory, riskengine.territories.values())[0], action.troops
    else:
        print 'ILLEGAL ACTION TYPE!' 
        
def simulateAction(input_state, action):
    """
    Returns a list of all possible future states that this action could lead to, along with the probability of each.  For all but attack actions, there is only a single possibility.  
    This function makes a copy of the input_state, so it is not modified
    Returns: [state0, state1, ....], [probability0, probability1]
    """
    
    advance_player = False
    #Handle attacks differently, because there are multiple possible outcomes
    rstates = []
    rsprobs = []
    if action.type == 'Attack':
        rstates,rsprobs = simulateAttack(input_state, action)
    else:
        s = input_state.copy_state()
    
        if action.type == 'PreAssign':
            simulatePreAssignAction(s, action)
            advance_player = True
        elif action.type == 'PrePlace':
            simulatePrePlaceAction(s, action)
            advance_player = True
        elif action.type == 'TurnInCards':
            simulateTurnInCardsAction(s, action)
        elif action.type == 'Place':
            simulatePlaceAction(s, action)
        elif action.type == 'Occupy':
            simulateOccupyAction(s, action)
        elif action.type == 'Fortify':
            simulateFortifyAction(s, action)
            advance_player = True
        else:
            print 'ILLEGAL ACTION TYPE!' 
        
        rstates = [s]
        rsprobs = [1]
    
    for state in rstates:
        nextType(state, action)
        if advance_player:
            nextPlayer(state)
    
        #If it is the beginning of the turn, do the beginning of the turn stuff for the next player
        if advance_player and (state.turn_type == 'Place' or state.turn_type == 'TurnInCards'):
            beginTurn(state)    
        
    return rstates, rsprobs
        
        
def getReinforcementNum(state, player_id):
    """
    Determine how many troop reinforcements the indicated player should get in the given state.
    This is calculated from the number of territories and continents they occupy
    """
    #Count territories owned by the current player
    territory_num = state.owners.count(player_id)
    #Get that divided by three (with a min of three)
    territory_troops = int(max(3, math.floor(territory_num / 3.0)))
    
    #See if they own all of any continents
    continent_troops = 0
    for c in state.board.continents.itervalues():
        owned = True
        for t in c.territories:
            if state.owners[t] != player_id:
                owned = False
                break
        if owned:
            continent_troops = continent_troops + c.reward
        
    return territory_troops + continent_troops
        
def beginTurn(state):
    """
    Takes care of beginning-of-turn stuff (cards handled separately)
    Calculates new free armies from territories and continents
    """
    #Update the player's free armies count
    state.players[state.current_player].free_armies = getReinforcementNum(state, state.current_player)
    
def nextType(state, action):
    """Sets a state's turn type after an action is performed"""
    
    if action.type == 'PreAssign':
        #Move to PrePlace if all countries are owned
        if not None in state.owners:
            state.turn_type = 'PrePlace'
    elif action.type == 'PrePlace':
        #Move to Place if no one has any free armies left
        done = True
        for p in state.players:
            if p.free_armies > 0:
                done = False
        if done: 
            state.turn_type = 'Place'
    elif action.type == 'Place':
        if state.players[state.current_player].free_armies == 0:
            state.turn_type = 'Attack'
    elif action.type == 'TurnInCards':
        if len(state.players[state.current_player].cards) <= 3 or action.to_territory is None:
            state.turn_type = 'Place'
        if state.players[state.current_player].conquered_territory and len(state.players[state.current_player].cards) < 5:
            state.turn_type = 'Place'
    elif action.type == 'Attack':
        #If attack is over, change to Fortify
        if action.to_territory is None:
            state.turn_type = 'Fortify'
        elif state.armies[state.board.territory_to_id[action.to_territory]] == 0:
            #The attack was successful
            state.turn_type = 'Occupy'
            state.players[state.current_player].conquered_territory = True
        if max(state.owners) == min(state.owners):
            #GAME OVER IN THIS STATE
            state.turn_type = 'GameOver'

    elif action.type == 'Occupy':
        #Moved troops in, still attacking
        state.turn_type = 'Attack'
        if len(state.players[state.current_player].cards) > 5:
            #If this player has too many cards from defeating someone, must turn them in now (THIS Needs to happen after occupy)
            state.turn_type = 'TurnInCards'
        
    elif action.type == 'Fortify':
        #Done with turn, now next players turn
        state.turn_type = 'TurnInCards'
    else:
        print 'ILLEGAL ACTION TYPE!'
        
def getAllowedActions(state):
    """
    Returns a list of allowed actions in this current state.  
    An AI Agent simply has to select one of these
    """
      
    if state.turn_type == 'PreAssign':
        return getPreAssignActions(state)
    elif state.turn_type == 'PrePlace':
        return getPrePlaceActions(state)
    elif state.turn_type == 'Place':
        return getPlaceActions(state)
    elif state.turn_type == 'TurnInCards':
        return getTurnInCardsActions(state)
    elif state.turn_type == 'Attack':
        return getAttackActions(state)
    elif state.turn_type == 'Occupy':
        return getOccupyActions(state)
    elif state.turn_type == 'Fortify':
        return getFortifyActions(state)
    else:
        print 'THE STATE\'S TURN PHASE OF > ', state.turn_type, '< IS NOT VALID'

def getPreAssignActions(state):
    """Returns a list of all the PreAssign actions possible in this state"""
    
    #An Action is to select an unoccupied territory
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] is None:
            to_territory = state.board.territories[i].name
            a = RiskAction('PreAssign', to_territory, None, None)
            actions.append(a)
            
    return actions

def simulatePreAssignAction(state, action):
    """Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state."""

    idx = state.board.territory_to_id[action.to_territory]
    
    if state.owners[idx] != None or state.armies[idx] != 0 or state.players[state.current_player].free_armies < 1:
        print 'INVALID PREASSIGN ACTION!'
        
    state.owners[idx] = state.current_player
    state.armies[idx] = 1
    state.players[state.current_player].free_armies -= 1
    
def getPrePlaceActions(state):
    """Returns a list of all the PrePlace actions possible in this state"""
    
    #An action is to place a troop in a territory occupied by the current player
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player:
            to_territory = state.board.territories[i].name
            a = RiskAction('PrePlace', to_territory, None, None)
            actions.append(a)
            
    return actions

def simulatePrePlaceAction(state, action):
    """Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state."""
    
    idx = state.board.territory_to_id[action.to_territory]
    if state.owners[idx] == state.current_player and state.players[state.current_player].free_armies > 0:
        state.armies[idx] = state.armies[idx] + 1
        state.players[state.current_player].free_armies -= 1
    else:
        print 'INVALID PREPLACE ACTION:'
        print 'NO PREPLACE ACTION WILL OCCUR'
    
def getTurnInCardsActions(state):
    """Returns a list of all the TurnInCards actions possible in this state"""
    actions = []

    if len(state.players[state.current_player].cards) >= 3:
        for i1 in range(len(state.players[state.current_player].cards)-2):
            c1 = state.players[state.current_player].cards[i1]
            for i2 in range(i1+1, len(state.players[state.current_player].cards)-1):
                c2 = state.players[state.current_player].cards[i2]
                for i3 in range(i2+1, len(state.players[state.current_player].cards)):
                    c3 = state.players[state.current_player].cards[i3]
                    if isCardSet(state, c1, c2, c3):
                        a = RiskAction('TurnInCards', c1, c2, c3)
                        actions.append(a)
    
    if len(state.players[state.current_player].cards) < 5:
        #Don't have to turn in yet, so make a Non-Action
        a = RiskAction('TurnInCards', None, None, None)
        actions.append(a)
    
    return actions

def isCardSet(state, c1, c2, c3):
    """See if this trio of cards can be turned in (is it a set?)"""
    
    #Get the pictures on the cards
    p1 = state.board.cards[c1].picture
    p2 = state.board.cards[c2].picture
    p3 = state.board.cards[c3].picture
    
    #If there is one wildcard in the set then it must be a set
    if 'Wildcard' in [p1,p2,p3]:
        return True
    #No wildcards, so are they all the same kind?
    if p1 == p2 and p2 == p3:
        return True
    else:
        #Not all the same, so they have to all be different
        #i.e. if any are the same, then they aren't a set
        if p1==p2 or p1==p3 or p2==p3:
            return False
    #The only case that gets here is when they are all different, so a set
    return True

def pause():
    """Utility if you ever want to pause to see output at some point. For debugging"""
    i = raw_input('Paused. Press a key to continue . . . ')
    
def getTurnInValue(state):
    """See what the current card turn-in-value is"""
    
    value = 0
    if state.turn_in_number >= len(state.board.turn_in_values):
        #Calculate turn in, more than scripted values
        value = state.board.turn_in_values[-1] + state.board.increment_value * (state.turn_in_number - len(state.board.turn_in_values) + 1)
    else:
        #Just grab scripted value
        value = state.board.turn_in_values[state.turn_in_number]
        
    state.turn_in_number = state.turn_in_number + 1
    return value
    
def simulateTurnInCardsAction(state, action):
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the action.
    """
    #See if they want to turn in cards
    if action.to_territory is None:
        return
        
    if (not isCardSet(state, action.to_territory, action.from_territory, action.troops)) or action.to_territory not in state.players[state.current_player].cards or action.from_territory not in state.players[state.current_player].cards or action.troops not in state.players[state.current_player].cards:
        print 'INVALID TURN-IN-CARDS ACTION!'
        action.print_action()
        print 'NO TURN-IN-CARDS ACTION WILL BE TAKEN'
        
    #Modify cards appropriately (cards indices are stored in to_territory, from_territory, and troops
    #Add turn in value to players free_armies
    turn_in_troops = getTurnInValue(state)
    state.players[state.current_player].free_armies  += turn_in_troops
    
    #Add two troops to any territory that appears on one of the cards owned by this player
    for i in [action.from_territory, action.to_territory, action.troops]:
        t = state.board.cards[i].territory
        if state.owners[t] == state.current_player:
            state.armies[t] = state.armies[t] + 2
        #Remove these cards from the player's hand
        state.players[state.current_player].cards.remove(i)
    
def getPlaceActions(state):
    """
     Returns a list of all the Place actions possible in this state
     An action is to place a troop in a territory occupied by the current player
    """
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player:
            to_territory = state.board.territories[i].name
            a = RiskAction('Place', to_territory, None, None)
            actions.append(a)
            
    return actions

def simulatePlaceAction(state, action):
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state.
    """
    idx = state.board.territory_to_id[action.to_territory]
    if state.owners[idx] == state.current_player and state.players[state.current_player].free_armies >= 1:
        state.armies[idx] = state.armies[idx] + 1
        state.players[state.current_player].free_armies -= 1
    else:
        print 'INVALID PLACE ACTION: '
        action.print_action()
        print 'NO PLACE ACTION WILL OCCUR'
    
def getAttackActions(state):
    """
     Returns a list of all the Attack actions possible in this state
     An action is to attack another territory from a territory owned by the current_player where 2 or more troops are
    """
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player and state.armies[i] >= 2:
            from_territory = state.board.territories[i].name
            for n in state.board.territories[i].neighbors:
                if state.owners[n] != state.current_player:
                    to_territory = state.board.territories[n].name
                    a = RiskAction('Attack', to_territory, from_territory, None)
                    actions.append(a)
    
    no_action = RiskAction('Attack', None, None, None)
    actions.append(no_action)
    
    return actions

def getNumAttackSuccessors(state, action):
    """
    Determines how many possible states could result from this attack action
    This will determine how many successor states we create for the attack action
    """
    
    #Get indices of involved territories
    a_idx = state.board.territory_to_id[action.from_territory]
    d_idx = state.board.territory_to_id[action.to_territory]
  
    #Get number of dice that will be involved (This assumes attacker always attacks with all dice)
    a_num_dice = min(3, state.armies[a_idx]-1)
    d_num_dice = min(2, state.armies[d_idx])
    
    #The number of possible future states will be the minimum of the dice amounts + 1
    return min(a_num_dice, d_num_dice) + 1
    
    
def getAttackOutcome(a_num_dice, d_num_dice, outcome_index):
    """
    This will compute the probability of the outcome_index'th possible 
    result of a battle between the given number of dice.
    It will return the attacker_loss, defender_loss, outcome_probability
    """
    
    #Index by attacker dice, defender dice, outcome number
    outcome_probabilities = [[[0.4167, 0.5833], [0.2546, 0.7454]],[[0.5787, 0.4213],[0.2276, 0.3241, 0.4483]],[[0.6597, 0.3404],[0.3717, 0.3358, 0.2926]]]
    
    #print 'Getting attack outcome for : ', a_num_dice, ' : ', d_num_dice, ' : ', outcome_index
    
    attacker_loss = 0
    defender_loss = 0
    outcome_probability = outcome_probabilities[a_num_dice-1][d_num_dice-1][outcome_index]
    total_loss = min(a_num_dice, d_num_dice)
    
    if total_loss == 1:
        if outcome_index == 0:
            defender_loss = 1
        elif outcome_index == 1:
            attacker_loss = 1
        else:
            print 'Attack Outcome Index invalid'
        
    elif total_loss == 2:
        if outcome_index == 0:
            defender_loss = 2
        elif outcome_index == 1:
            defender_loss = 1
            attacker_loss = 1
        elif outcome_index == 2:
            attacker_loss = 2
        else:
            print 'Attack Outcome index invalid'
    else:
        print 'Total Loss is invalid.  It is: ', total_loss, ' A Num Dice: ', a_num_dice, 'D Num Dice: ', d_num_dice, ' Outcome Index: ', outcome_index
   
    return attacker_loss, defender_loss, outcome_probability
   
def simulateAttack(input_state, action):
    """
    Simulates attack action.  Returns a list of possible successor states and a 
    list of their probabilities.  This copies the input_state, so it is not modified.
    """
    
    if action.from_territory is None:
        #This is the end of attack action.  Give the player a card if they earned it
        cur_state = input_state.copy_state()
        
        if cur_state.players[cur_state.current_player].conquered_territory:
            not_duplicate = False
            card = random.choice(cur_state.cards)
            while not_duplicate:
                #Randomly choose a card and give it to this player
                card = random.choice(cur_state.cards)
                if card not in cur_state.players[cur_state.current_player].cards:
                    not_duplicate = True
            cur_state.players[cur_state.current_player].cards.append(card)
            #Reset the players conquered_territory flag
            cur_state.players[cur_state.current_player].conquered_territory = False
            
        return [cur_state], [1]
    
    #How many possible attack outcomes are there
    num_successors = getNumAttackSuccessors(input_state, action)
    
    successor_states = []
    successor_probs = []
    
    for i in range(num_successors):
        cur_state = input_state.copy_state()
        cur_prob = 0
        if action.type == 'Attack':
            cur_prob = simulateAttackAction(cur_state, action, i)
        else:
            print 'ILLEGAL ACTION TYPE'
        
        nextType(cur_state, action)
        successor_states.append(cur_state)
        successor_probs.append(cur_prob)
        
    return successor_states, successor_probs
   
def simulateAttackAction(state, action, outcome_index):
    """
    Execute the given action in the given state, assuming that the outcome of the battle is given by outcome_index.  This will modify the state to 
    reflect the outcome of the state.
    """            
    #a is attacker and d is defender
    
    #Get indices of involved territories
    a_idx = state.board.territory_to_id[action.from_territory]
    d_idx = state.board.territory_to_id[action.to_territory]
  
    #MAKE SURE THIS IS VALID
    if state.owners[a_idx] != state.current_player or state.owners[d_idx] == state.current_player or state.armies[a_idx] <= 1: 
        print 'INVALID ATTACK ACTION: '
        action.print_action()
        print 'NO ATTACK ACTION WILL BE TAKEN'
        return 
  
    #Set last attacker and defender variables in the state
    state.last_attacker = a_idx
    state.last_defender = d_idx
  
    #Player id of defender
    defender = state.owners[d_idx]
  
    #Get number of dice that will be involved (This assumes attacker always attacks with all dice)
    a_num_dice = min(3, state.armies[a_idx]-1)
    d_num_dice = min(2, state.armies[d_idx])

    if state.armies[d_idx] == 0:
        print 'THERE ARE NO ARMIES IN TERRITORY: ', state.board.territories[d_idx].name
        print 'ACTION: ', action.print_action()
        print 'State: ', state.print_state()
        
    #Get the outcome and probability for the input outcome index
    a_loss, d_loss, outcome_probability = getAttackOutcome(a_num_dice, d_num_dice, outcome_index)
    
    state.armies[d_idx] = max(state.armies[d_idx] - d_loss, 0)
    state.armies[a_idx] = state.armies[a_idx] - a_loss
    
    #Check if the defender is at zero, then change owner (armies will be moved in with the next action (Occupy)
    if state.armies[d_idx] == 0:
        state.owners[d_idx] = state.current_player
        
    #Check to see if the defender is now done completely, in which case we need to give her cards to the attacker.
    if defender not in state.owners:
        #The defender is done
        state.players[state.current_player].cards.extend(state.players[defender].cards)
        state.players[defender].cards = []
    
    return outcome_probability
    
def getOccupyActions(state):
    """
     Returns a list of all the Occupy actions possible in this state
     An action is to move an amount of troops into the newly conquered country (must leave at least 1 behind, and must move at least min(3,number_there -1))
    """
    actions = []
    
    if state.last_defender is None or state.last_attacker is None:
        return actions
    
    to_territory = state.board.territories[state.last_defender].name
    from_territory = state.board.territories[state.last_attacker].name
        
    for k in range(min(state.armies[state.last_attacker]-1,3), state.armies[state.last_attacker]):
        a = RiskAction('Occupy', to_territory, from_territory, k)
        actions.append(a)
        
    return actions
    
def simulateOccupyAction(state, action):    
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state.
    """
    to_idx = state.board.territory_to_id[action.to_territory]
    from_idx = state.board.territory_to_id[action.from_territory]
    #Make sure that the occupy action is correctly constructed
    if to_idx != state.last_defender or from_idx != state.last_attacker or state.armies[from_idx] - action.troops < 1 or state.owners[from_idx] != state.current_player or state.owners[to_idx] != state.current_player:
        #This move is invalid
        print 'INVALID OCCUPY ACTION: '
        action.print_action()
        print 'To index = ', to_idx
        print 'Last defender = ', state.last_defender
        print 'From index = ', from_idx
        print 'Last attacker = ', state.last_attacker
        
        print 'NO OCCUPY ACTION WILL BE TAKEN'
        pause()
        return 

    state.armies[to_idx] = state.armies[to_idx] + action.troops
    state.armies[from_idx] = state.armies[from_idx] - action.troops
    
def getFortifyActions(state):
    """
     Returns a list of all the Fortify actions possible in this state
     An action is to move troops from one territory to a neighboring territory (both owned by current_player), leaving at least 1 troop in the from_territory
    """
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player and state.armies[i] >= 2:
            from_territory = state.board.territories[i].name
            for n in state.board.territories[i].neighbors:
                if state.owners[n] == state.current_player:
                    to_territory = state.board.territories[n].name
                    for k in range(1, state.armies[i]):
                        a = RiskAction('Fortify', to_territory, from_territory, k)
                        actions.append(a)
                        
    no_action = RiskAction('Fortify', None, None, 0)
    actions.append(no_action)
    
    return actions    
    
def simulateFortifyAction(state, action):
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state.
    """
    if action.to_territory is None:
        return
        
    to_idx = state.board.territory_to_id[action.to_territory]
    from_idx = state.board.territory_to_id[action.from_territory]
    
    #Make sure that the fortify action is correctly constructed
    if state.armies[from_idx] - action.troops < 1 or state.owners[from_idx] != state.current_player or state.owners[to_idx] != state.current_player or to_idx not in state.board.territories[from_idx].neighbors:
        #This move is invalid
        print 'INVALID FORTIFY ACTION: '
        action.print_action()
        print 'NO FORTIFY ACTION WILL BE TAKEN'
        return 
        
    state.armies[to_idx] = state.armies[to_idx] + action.troops
    state.armies[from_idx] = state.armies[from_idx] - action.troops
    
def createRiskBoard():
    """
     Creates a RiskBoard from the current riskengine state.  
     Used to interface with the GUI that allows humans to play the AIs
    """
    
    board = RiskBoard()
    
    #Create Continents
    for c in riskengine.continents:
        rc = RiskContinent(c[0],c[1])
        board.add_continent(rc)
        
    #Create Territories
    id_counter = 0
    for t in riskengine.territories.values():
        rt = RiskTerritory(t.name, id_counter)    
        board.add_territory(rt)
        tc = board.continents[t.continent]
        tc.add_territory(rt.id)
        id_counter += 1
    
    #Add in neighbors of each territory
    for t in riskengine.territories.values():
        rt = board.territories[board.territory_to_id[t.name]]
        for n in t.neighbors:
            rt.add_neighbor(board.territory_to_id[n.name])
    
    #Create cards
    for c in riskengine.allcards:
        rc = RiskCard(board.territory_to_id[c.territory], c.picture, len(board.cards))
        board.add_card(rc)
        
    #Create and add players
    id_counter = 0
    for p in riskengine.playerorder:
        rp = RiskPlayer(p.name, id_counter, p.freeArmies, p.conqueredTerritory)
        id_counter += 1
        for c in p.cards:
            rc = RiskCard(board.territory_to_id[c.territory], c.picture, len(board.cards))
            board.add_card(rc)
            rp.add_card(board.card_to_id[board.territories[board.territory_to_id[c.territory]].name])
        board.add_player(rp)
        
    board.set_turn_in_values(riskengine.cardvals)
    board.set_increment_value(riskengine.incrementval)
        
    return board
    
def createRiskState(board, function_name, occupying=None):
    """
     Creates a RiskState from the current riskengine state.  
     Used to interface with the GUI that allows humans to play the AIs
    """

    #players, armies, owners, current_player, turn_type
    #Create players
    players = []
    id_counter = 0
    for p in riskengine.playerorder:
        rp = RiskPlayer(p.name, id_counter, p.freeArmies, p.conqueredTerritory)
        for c in p.cards:
            rp.add_card(board.card_to_id[c.territory])
        players.append(rp)
        id_counter += 1
    
    #Create armies and owners
    armies = [0]*len(board.territories)
    owners = [None]*len(board.territories)
    for t in riskengine.territories.values():
        idx = board.territory_to_id[t.name]
        if t.player is not None:
            armies[idx] = t.armies
            owners[idx] = board.player_to_id[t.player.name]
    
    #Determine the current player
    current_player_obj = filter(lambda x:x.name == riskengine.currentplayer.name, players)[0]
    current_player = current_player_obj.id

    turn_type = None
    if riskengine.phase == 'Preposition' and function_name == 'Assignment':
        turn_type = 'PreAssign'
    elif riskengine.phase == 'Preposition' and function_name == 'Placement':
        turn_type = 'PrePlace'
    elif riskengine.phase == 'Place' and function_name == 'Placement':
        turn_type = 'Place'
    elif riskengine.phase == 'Place' and function_name == 'TurnInCards':
        turn_type = 'TurnInCards'
    elif riskengine.phase == 'Attack' and function_name == 'Attack':
        turn_type = 'Attack'
    elif riskengine.phase == 'Attack' and function_name == 'Occupation':
        turn_type = 'Occupy'
    elif riskengine.phase == 'Attack' and function_name == 'Fortification':
        turn_type = 'Fortify'
            
    #current card turn in index
    turn_in_number = riskengine.currentcard
            
    #Determine last attacker and defender
    last_attacker = None
    last_defender = None
    if occupying is not None:
        last_attacker = board.territory_to_id[occupying[0]]
        last_defender = board.territory_to_id[occupying[1]]
        
    #Create Cards
    cards = []
    for c in riskengine.allcards:
        cards.append(board.card_to_id[c.territory])
       
    state = RiskState(players,armies,owners,current_player,turn_type,turn_in_number, last_attacker, last_defender, cards, board)

    return state
    
def getInitialState(board):
    """Get the initial state for this board."""
    
    #Initialize the state with the information in the board

    free_armies = 45 - 5*(len(board.players)-1)

    state_players = []
    for p in board.players:
        new_player = p.copy_player()
        state_players.append(new_player)
        new_player.free_armies = free_armies
             
    #Initialize other state elements
    armies = [0]*len(board.territories)
    owners = [None]*len(board.territories)
    current_player = 0
    turn_type = 'PreAssign'
    turn_in_number = 0
    last_attacker = None
    last_defender = None
    
    #Cards
    cards = [0]*len(board.cards)
    for i in range(len(cards)):
        cards[i] = board.cards[i].id
    
    state = RiskState(state_players, armies, owners, current_player, turn_type, turn_in_number, last_attacker, last_defender, cards, board)
    return state
    
    
def loadBoard(filename):
    """Loads a RiskBoard from the given filename"""
    
    #Open the zip file to get map data
    zfile = zipfile.ZipFile(filename)
    board = RiskBoard()
    loadTerritories(zfile, board)
    
    #Close the zip file
    zfile.close()

    return board
    
def loadTerritories(zfile, board):
    """Load territory (and other) information from a file."""
   
    terr = xml.dom.minidom.parseString(zfile.read("territory.xml"))
    
    terr_structs = terr.getElementsByTagName("territory")
    
    #Create and add territories
    for t in terr_structs:
        name = t.getAttribute("name")
        nt = RiskTerritory(name, len(board.territories))
        board.add_territory(nt)
    
    #Create continents, add in neighbors
    for terrs in terr_structs:
        name = terrs.getAttribute("name")
        cname = terrs.getAttribute("continent")
        tidx = board.territory_to_id[name]
        ncon = RiskContinent(cname, 0)
        board.add_continent(ncon)
        continent = board.continents[cname]
        continent.add_territory(tidx)
        
        neighbors = terrs.getElementsByTagName("neighbor")
        for neigh in neighbors:
            nidx = board.territory_to_id[neigh.childNodes[0].data]
            board.territories[tidx].add_neighbor(nidx)
        
    cont_structs = terr.getElementsByTagName("continent")
    for con in cont_structs:
        continent = board.continents[con.getAttribute("name")] 
        continent.reward = int(con.getAttribute("value"))
        
    loadCards(terr, board)
    
def loadCards(xmlFile, board):
    """Load the data for the cards from the file."""

    cardvals = []
    card = xmlFile.getElementsByTagName("cards")[0]
    for pic in card.getElementsByTagName("picture"):
        board.pictures.append(pic.childNodes[0].data)
    for cvalue in card.getElementsByTagName("card"):
        cardvals.append(int(cvalue.childNodes[0].data))
        
    incremtag = card.getElementsByTagName("increase")[0]
    incrementval = int(incremtag.childNodes[0].data)
    
    board.set_turn_in_values(cardvals)
    board.set_increment_value(incrementval)
    
    createCards(board)
    
def createCards(board):
    """Create the set of cards."""
    
    wildcard = "Wildcard"
    for terr in range(2):
        car = RiskCard(terr, wildcard, terr)
        board.add_card(car)
    for terr in range(2, len(board.territories)):
        car = RiskCard(terr, random.choice(board.pictures), terr)
        board.add_card(car)
        
    board.shuffle_cards()
    

Functions

def beginTurn(

state)

Takes care of beginning-of-turn stuff (cards handled separately) Calculates new free armies from territories and continents

def beginTurn(state):
    """
    Takes care of beginning-of-turn stuff (cards handled separately)
    Calculates new free armies from territories and continents
    """
    #Update the player's free armies count
    state.players[state.current_player].free_armies = getReinforcementNum(state, state.current_player)

def createCards(

board)

Create the set of cards.

def createCards(board):
    """Create the set of cards."""
    
    wildcard = "Wildcard"
    for terr in range(2):
        car = RiskCard(terr, wildcard, terr)
        board.add_card(car)
    for terr in range(2, len(board.territories)):
        car = RiskCard(terr, random.choice(board.pictures), terr)
        board.add_card(car)
        
    board.shuffle_cards()

def createRiskBoard(

)

Creates a RiskBoard from the current riskengine state.
Used to interface with the GUI that allows humans to play the AIs

def createRiskBoard():
    """
     Creates a RiskBoard from the current riskengine state.  
     Used to interface with the GUI that allows humans to play the AIs
    """
    
    board = RiskBoard()
    
    #Create Continents
    for c in riskengine.continents:
        rc = RiskContinent(c[0],c[1])
        board.add_continent(rc)
        
    #Create Territories
    id_counter = 0
    for t in riskengine.territories.values():
        rt = RiskTerritory(t.name, id_counter)    
        board.add_territory(rt)
        tc = board.continents[t.continent]
        tc.add_territory(rt.id)
        id_counter += 1
    
    #Add in neighbors of each territory
    for t in riskengine.territories.values():
        rt = board.territories[board.territory_to_id[t.name]]
        for n in t.neighbors:
            rt.add_neighbor(board.territory_to_id[n.name])
    
    #Create cards
    for c in riskengine.allcards:
        rc = RiskCard(board.territory_to_id[c.territory], c.picture, len(board.cards))
        board.add_card(rc)
        
    #Create and add players
    id_counter = 0
    for p in riskengine.playerorder:
        rp = RiskPlayer(p.name, id_counter, p.freeArmies, p.conqueredTerritory)
        id_counter += 1
        for c in p.cards:
            rc = RiskCard(board.territory_to_id[c.territory], c.picture, len(board.cards))
            board.add_card(rc)
            rp.add_card(board.card_to_id[board.territories[board.territory_to_id[c.territory]].name])
        board.add_player(rp)
        
    board.set_turn_in_values(riskengine.cardvals)
    board.set_increment_value(riskengine.incrementval)
        
    return board

def createRiskState(

board, function_name, occupying=None)

Creates a RiskState from the current riskengine state.
Used to interface with the GUI that allows humans to play the AIs

def createRiskState(board, function_name, occupying=None):
    """
     Creates a RiskState from the current riskengine state.  
     Used to interface with the GUI that allows humans to play the AIs
    """

    #players, armies, owners, current_player, turn_type
    #Create players
    players = []
    id_counter = 0
    for p in riskengine.playerorder:
        rp = RiskPlayer(p.name, id_counter, p.freeArmies, p.conqueredTerritory)
        for c in p.cards:
            rp.add_card(board.card_to_id[c.territory])
        players.append(rp)
        id_counter += 1
    
    #Create armies and owners
    armies = [0]*len(board.territories)
    owners = [None]*len(board.territories)
    for t in riskengine.territories.values():
        idx = board.territory_to_id[t.name]
        if t.player is not None:
            armies[idx] = t.armies
            owners[idx] = board.player_to_id[t.player.name]
    
    #Determine the current player
    current_player_obj = filter(lambda x:x.name == riskengine.currentplayer.name, players)[0]
    current_player = current_player_obj.id

    turn_type = None
    if riskengine.phase == 'Preposition' and function_name == 'Assignment':
        turn_type = 'PreAssign'
    elif riskengine.phase == 'Preposition' and function_name == 'Placement':
        turn_type = 'PrePlace'
    elif riskengine.phase == 'Place' and function_name == 'Placement':
        turn_type = 'Place'
    elif riskengine.phase == 'Place' and function_name == 'TurnInCards':
        turn_type = 'TurnInCards'
    elif riskengine.phase == 'Attack' and function_name == 'Attack':
        turn_type = 'Attack'
    elif riskengine.phase == 'Attack' and function_name == 'Occupation':
        turn_type = 'Occupy'
    elif riskengine.phase == 'Attack' and function_name == 'Fortification':
        turn_type = 'Fortify'
            
    #current card turn in index
    turn_in_number = riskengine.currentcard
            
    #Determine last attacker and defender
    last_attacker = None
    last_defender = None
    if occupying is not None:
        last_attacker = board.territory_to_id[occupying[0]]
        last_defender = board.territory_to_id[occupying[1]]
        
    #Create Cards
    cards = []
    for c in riskengine.allcards:
        cards.append(board.card_to_id[c.territory])
       
    state = RiskState(players,armies,owners,current_player,turn_type,turn_in_number, last_attacker, last_defender, cards, board)

    return state

def getAllowedActions(

state)

Returns a list of allowed actions in this current state.
An AI Agent simply has to select one of these

def getAllowedActions(state):
    """
    Returns a list of allowed actions in this current state.  
    An AI Agent simply has to select one of these
    """
      
    if state.turn_type == 'PreAssign':
        return getPreAssignActions(state)
    elif state.turn_type == 'PrePlace':
        return getPrePlaceActions(state)
    elif state.turn_type == 'Place':
        return getPlaceActions(state)
    elif state.turn_type == 'TurnInCards':
        return getTurnInCardsActions(state)
    elif state.turn_type == 'Attack':
        return getAttackActions(state)
    elif state.turn_type == 'Occupy':
        return getOccupyActions(state)
    elif state.turn_type == 'Fortify':
        return getFortifyActions(state)
    else:
        print 'THE STATE\'S TURN PHASE OF > ', state.turn_type, '< IS NOT VALID'

def getAttackActions(

state)

Returns a list of all the Attack actions possible in this state An action is to attack another territory from a territory owned by the current_player where 2 or more troops are

def getAttackActions(state):
    """
     Returns a list of all the Attack actions possible in this state
     An action is to attack another territory from a territory owned by the current_player where 2 or more troops are
    """
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player and state.armies[i] >= 2:
            from_territory = state.board.territories[i].name
            for n in state.board.territories[i].neighbors:
                if state.owners[n] != state.current_player:
                    to_territory = state.board.territories[n].name
                    a = RiskAction('Attack', to_territory, from_territory, None)
                    actions.append(a)
    
    no_action = RiskAction('Attack', None, None, None)
    actions.append(no_action)
    
    return actions

def getAttackOutcome(

a_num_dice, d_num_dice, outcome_index)

This will compute the probability of the outcome_index'th possible result of a battle between the given number of dice. It will return the attacker_loss, defender_loss, outcome_probability

def getAttackOutcome(a_num_dice, d_num_dice, outcome_index):
    """
    This will compute the probability of the outcome_index'th possible 
    result of a battle between the given number of dice.
    It will return the attacker_loss, defender_loss, outcome_probability
    """
    
    #Index by attacker dice, defender dice, outcome number
    outcome_probabilities = [[[0.4167, 0.5833], [0.2546, 0.7454]],[[0.5787, 0.4213],[0.2276, 0.3241, 0.4483]],[[0.6597, 0.3404],[0.3717, 0.3358, 0.2926]]]
    
    #print 'Getting attack outcome for : ', a_num_dice, ' : ', d_num_dice, ' : ', outcome_index
    
    attacker_loss = 0
    defender_loss = 0
    outcome_probability = outcome_probabilities[a_num_dice-1][d_num_dice-1][outcome_index]
    total_loss = min(a_num_dice, d_num_dice)
    
    if total_loss == 1:
        if outcome_index == 0:
            defender_loss = 1
        elif outcome_index == 1:
            attacker_loss = 1
        else:
            print 'Attack Outcome Index invalid'
        
    elif total_loss == 2:
        if outcome_index == 0:
            defender_loss = 2
        elif outcome_index == 1:
            defender_loss = 1
            attacker_loss = 1
        elif outcome_index == 2:
            attacker_loss = 2
        else:
            print 'Attack Outcome index invalid'
    else:
        print 'Total Loss is invalid.  It is: ', total_loss, ' A Num Dice: ', a_num_dice, 'D Num Dice: ', d_num_dice, ' Outcome Index: ', outcome_index
   
    return attacker_loss, defender_loss, outcome_probability

def getFortifyActions(

state)

Returns a list of all the Fortify actions possible in this state An action is to move troops from one territory to a neighboring territory (both owned by current_player), leaving at least 1 troop in the from_territory

def getFortifyActions(state):
    """
     Returns a list of all the Fortify actions possible in this state
     An action is to move troops from one territory to a neighboring territory (both owned by current_player), leaving at least 1 troop in the from_territory
    """
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player and state.armies[i] >= 2:
            from_territory = state.board.territories[i].name
            for n in state.board.territories[i].neighbors:
                if state.owners[n] == state.current_player:
                    to_territory = state.board.territories[n].name
                    for k in range(1, state.armies[i]):
                        a = RiskAction('Fortify', to_territory, from_territory, k)
                        actions.append(a)
                        
    no_action = RiskAction('Fortify', None, None, 0)
    actions.append(no_action)
    
    return actions    

def getInitialState(

board)

Get the initial state for this board.

def getInitialState(board):
    """Get the initial state for this board."""
    
    #Initialize the state with the information in the board

    free_armies = 45 - 5*(len(board.players)-1)

    state_players = []
    for p in board.players:
        new_player = p.copy_player()
        state_players.append(new_player)
        new_player.free_armies = free_armies
             
    #Initialize other state elements
    armies = [0]*len(board.territories)
    owners = [None]*len(board.territories)
    current_player = 0
    turn_type = 'PreAssign'
    turn_in_number = 0
    last_attacker = None
    last_defender = None
    
    #Cards
    cards = [0]*len(board.cards)
    for i in range(len(cards)):
        cards[i] = board.cards[i].id
    
    state = RiskState(state_players, armies, owners, current_player, turn_type, turn_in_number, last_attacker, last_defender, cards, board)
    return state

def getNumAttackSuccessors(

state, action)

Determines how many possible states could result from this attack action This will determine how many successor states we create for the attack action

def getNumAttackSuccessors(state, action):
    """
    Determines how many possible states could result from this attack action
    This will determine how many successor states we create for the attack action
    """
    
    #Get indices of involved territories
    a_idx = state.board.territory_to_id[action.from_territory]
    d_idx = state.board.territory_to_id[action.to_territory]
  
    #Get number of dice that will be involved (This assumes attacker always attacks with all dice)
    a_num_dice = min(3, state.armies[a_idx]-1)
    d_num_dice = min(2, state.armies[d_idx])
    
    #The number of possible future states will be the minimum of the dice amounts + 1
    return min(a_num_dice, d_num_dice) + 1

def getOccupyActions(

state)

Returns a list of all the Occupy actions possible in this state An action is to move an amount of troops into the newly conquered country (must leave at least 1 behind, and must move at least min(3,number_there -1))

def getOccupyActions(state):
    """
     Returns a list of all the Occupy actions possible in this state
     An action is to move an amount of troops into the newly conquered country (must leave at least 1 behind, and must move at least min(3,number_there -1))
    """
    actions = []
    
    if state.last_defender is None or state.last_attacker is None:
        return actions
    
    to_territory = state.board.territories[state.last_defender].name
    from_territory = state.board.territories[state.last_attacker].name
        
    for k in range(min(state.armies[state.last_attacker]-1,3), state.armies[state.last_attacker]):
        a = RiskAction('Occupy', to_territory, from_territory, k)
        actions.append(a)
        
    return actions

def getPlaceActions(

state)

Returns a list of all the Place actions possible in this state An action is to place a troop in a territory occupied by the current player

def getPlaceActions(state):
    """
     Returns a list of all the Place actions possible in this state
     An action is to place a troop in a territory occupied by the current player
    """
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player:
            to_territory = state.board.territories[i].name
            a = RiskAction('Place', to_territory, None, None)
            actions.append(a)
            
    return actions

def getPreAssignActions(

state)

Returns a list of all the PreAssign actions possible in this state

def getPreAssignActions(state):
    """Returns a list of all the PreAssign actions possible in this state"""
    
    #An Action is to select an unoccupied territory
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] is None:
            to_territory = state.board.territories[i].name
            a = RiskAction('PreAssign', to_territory, None, None)
            actions.append(a)
            
    return actions

def getPrePlaceActions(

state)

Returns a list of all the PrePlace actions possible in this state

def getPrePlaceActions(state):
    """Returns a list of all the PrePlace actions possible in this state"""
    
    #An action is to place a troop in a territory occupied by the current player
    actions = []
    
    for i in range(len(state.owners)):
        if state.owners[i] == state.current_player:
            to_territory = state.board.territories[i].name
            a = RiskAction('PrePlace', to_territory, None, None)
            actions.append(a)
            
    return actions

def getReinforcementNum(

state, player_id)

Determine how many troop reinforcements the indicated player should get in the given state. This is calculated from the number of territories and continents they occupy

def getReinforcementNum(state, player_id):
    """
    Determine how many troop reinforcements the indicated player should get in the given state.
    This is calculated from the number of territories and continents they occupy
    """
    #Count territories owned by the current player
    territory_num = state.owners.count(player_id)
    #Get that divided by three (with a min of three)
    territory_troops = int(max(3, math.floor(territory_num / 3.0)))
    
    #See if they own all of any continents
    continent_troops = 0
    for c in state.board.continents.itervalues():
        owned = True
        for t in c.territories:
            if state.owners[t] != player_id:
                owned = False
                break
        if owned:
            continent_troops = continent_troops + c.reward
        
    return territory_troops + continent_troops

def getTurnInCardsActions(

state)

Returns a list of all the TurnInCards actions possible in this state

def getTurnInCardsActions(state):
    """Returns a list of all the TurnInCards actions possible in this state"""
    actions = []

    if len(state.players[state.current_player].cards) >= 3:
        for i1 in range(len(state.players[state.current_player].cards)-2):
            c1 = state.players[state.current_player].cards[i1]
            for i2 in range(i1+1, len(state.players[state.current_player].cards)-1):
                c2 = state.players[state.current_player].cards[i2]
                for i3 in range(i2+1, len(state.players[state.current_player].cards)):
                    c3 = state.players[state.current_player].cards[i3]
                    if isCardSet(state, c1, c2, c3):
                        a = RiskAction('TurnInCards', c1, c2, c3)
                        actions.append(a)
    
    if len(state.players[state.current_player].cards) < 5:
        #Don't have to turn in yet, so make a Non-Action
        a = RiskAction('TurnInCards', None, None, None)
        actions.append(a)
    
    return actions

def getTurnInValue(

state)

See what the current card turn-in-value is

def getTurnInValue(state):
    """See what the current card turn-in-value is"""
    
    value = 0
    if state.turn_in_number >= len(state.board.turn_in_values):
        #Calculate turn in, more than scripted values
        value = state.board.turn_in_values[-1] + state.board.increment_value * (state.turn_in_number - len(state.board.turn_in_values) + 1)
    else:
        #Just grab scripted value
        value = state.board.turn_in_values[state.turn_in_number]
        
    state.turn_in_number = state.turn_in_number + 1
    return value

def incrementPlayer(

state)

Increments the current_player of the input state Input: RiskState object

def incrementPlayer(state):
    """
    Increments the current_player of the input state
    Input: RiskState object
    """
    state.current_player = state.current_player + 1
    if state.current_player >= len(state.players):
        state.current_player = 0

def isCardSet(

state, c1, c2, c3)

See if this trio of cards can be turned in (is it a set?)

def isCardSet(state, c1, c2, c3):
    """See if this trio of cards can be turned in (is it a set?)"""
    
    #Get the pictures on the cards
    p1 = state.board.cards[c1].picture
    p2 = state.board.cards[c2].picture
    p3 = state.board.cards[c3].picture
    
    #If there is one wildcard in the set then it must be a set
    if 'Wildcard' in [p1,p2,p3]:
        return True
    #No wildcards, so are they all the same kind?
    if p1 == p2 and p2 == p3:
        return True
    else:
        #Not all the same, so they have to all be different
        #i.e. if any are the same, then they aren't a set
        if p1==p2 or p1==p3 or p2==p3:
            return False
    #The only case that gets here is when they are all different, so a set
    return True

def loadBoard(

filename)

Loads a RiskBoard from the given filename

def loadBoard(filename):
    """Loads a RiskBoard from the given filename"""
    
    #Open the zip file to get map data
    zfile = zipfile.ZipFile(filename)
    board = RiskBoard()
    loadTerritories(zfile, board)
    
    #Close the zip file
    zfile.close()

    return board

def loadCards(

xmlFile, board)

Load the data for the cards from the file.

def loadCards(xmlFile, board):
    """Load the data for the cards from the file."""

    cardvals = []
    card = xmlFile.getElementsByTagName("cards")[0]
    for pic in card.getElementsByTagName("picture"):
        board.pictures.append(pic.childNodes[0].data)
    for cvalue in card.getElementsByTagName("card"):
        cardvals.append(int(cvalue.childNodes[0].data))
        
    incremtag = card.getElementsByTagName("increase")[0]
    incrementval = int(incremtag.childNodes[0].data)
    
    board.set_turn_in_values(cardvals)
    board.set_increment_value(incrementval)
    
    createCards(board)

def loadTerritories(

zfile, board)

Load territory (and other) information from a file.

def loadTerritories(zfile, board):
    """Load territory (and other) information from a file."""
   
    terr = xml.dom.minidom.parseString(zfile.read("territory.xml"))
    
    terr_structs = terr.getElementsByTagName("territory")
    
    #Create and add territories
    for t in terr_structs:
        name = t.getAttribute("name")
        nt = RiskTerritory(name, len(board.territories))
        board.add_territory(nt)
    
    #Create continents, add in neighbors
    for terrs in terr_structs:
        name = terrs.getAttribute("name")
        cname = terrs.getAttribute("continent")
        tidx = board.territory_to_id[name]
        ncon = RiskContinent(cname, 0)
        board.add_continent(ncon)
        continent = board.continents[cname]
        continent.add_territory(tidx)
        
        neighbors = terrs.getElementsByTagName("neighbor")
        for neigh in neighbors:
            nidx = board.territory_to_id[neigh.childNodes[0].data]
            board.territories[tidx].add_neighbor(nidx)
        
    cont_structs = terr.getElementsByTagName("continent")
    for con in cont_structs:
        continent = board.continents[con.getAttribute("name")] 
        continent.reward = int(con.getAttribute("value"))
        
    loadCards(terr, board)

def nextPlayer(

state)

Moves the state's current_player to the next player in the order Also ensures that when it exits, the new state.current_player is still in the game Input: RiskState object

def nextPlayer(state):
    """
    Moves the state's current_player to the next player in the order
    Also ensures that when it exits, the new state.current_player is still in the game
    Input: RiskState object
    """
    incrementPlayer(state)
    while state.current_player not in state.owners and None not in state.owners:
        incrementPlayer(state)

def nextType(

state, action)

Sets a state's turn type after an action is performed

def nextType(state, action):
    """Sets a state's turn type after an action is performed"""
    
    if action.type == 'PreAssign':
        #Move to PrePlace if all countries are owned
        if not None in state.owners:
            state.turn_type = 'PrePlace'
    elif action.type == 'PrePlace':
        #Move to Place if no one has any free armies left
        done = True
        for p in state.players:
            if p.free_armies > 0:
                done = False
        if done: 
            state.turn_type = 'Place'
    elif action.type == 'Place':
        if state.players[state.current_player].free_armies == 0:
            state.turn_type = 'Attack'
    elif action.type == 'TurnInCards':
        if len(state.players[state.current_player].cards) <= 3 or action.to_territory is None:
            state.turn_type = 'Place'
        if state.players[state.current_player].conquered_territory and len(state.players[state.current_player].cards) < 5:
            state.turn_type = 'Place'
    elif action.type == 'Attack':
        #If attack is over, change to Fortify
        if action.to_territory is None:
            state.turn_type = 'Fortify'
        elif state.armies[state.board.territory_to_id[action.to_territory]] == 0:
            #The attack was successful
            state.turn_type = 'Occupy'
            state.players[state.current_player].conquered_territory = True
        if max(state.owners) == min(state.owners):
            #GAME OVER IN THIS STATE
            state.turn_type = 'GameOver'

    elif action.type == 'Occupy':
        #Moved troops in, still attacking
        state.turn_type = 'Attack'
        if len(state.players[state.current_player].cards) > 5:
            #If this player has too many cards from defeating someone, must turn them in now (THIS Needs to happen after occupy)
            state.turn_type = 'TurnInCards'
        
    elif action.type == 'Fortify':
        #Done with turn, now next players turn
        state.turn_type = 'TurnInCards'
    else:
        print 'ILLEGAL ACTION TYPE!'

def pause(

)

Utility if you ever want to pause to see output at some point. For debugging

def pause():
    """Utility if you ever want to pause to see output at some point. For debugging"""
    i = raw_input('Paused. Press a key to continue . . . ')

def simulateAction(

input_state, action)

Returns a list of all possible future states that this action could lead to, along with the probability of each. For all but attack actions, there is only a single possibility.
This function makes a copy of the input_state, so it is not modified Returns: [state0, state1, ....], [probability0, probability1]

def simulateAction(input_state, action):
    """
    Returns a list of all possible future states that this action could lead to, along with the probability of each.  For all but attack actions, there is only a single possibility.  
    This function makes a copy of the input_state, so it is not modified
    Returns: [state0, state1, ....], [probability0, probability1]
    """
    
    advance_player = False
    #Handle attacks differently, because there are multiple possible outcomes
    rstates = []
    rsprobs = []
    if action.type == 'Attack':
        rstates,rsprobs = simulateAttack(input_state, action)
    else:
        s = input_state.copy_state()
    
        if action.type == 'PreAssign':
            simulatePreAssignAction(s, action)
            advance_player = True
        elif action.type == 'PrePlace':
            simulatePrePlaceAction(s, action)
            advance_player = True
        elif action.type == 'TurnInCards':
            simulateTurnInCardsAction(s, action)
        elif action.type == 'Place':
            simulatePlaceAction(s, action)
        elif action.type == 'Occupy':
            simulateOccupyAction(s, action)
        elif action.type == 'Fortify':
            simulateFortifyAction(s, action)
            advance_player = True
        else:
            print 'ILLEGAL ACTION TYPE!' 
        
        rstates = [s]
        rsprobs = [1]
    
    for state in rstates:
        nextType(state, action)
        if advance_player:
            nextPlayer(state)
    
        #If it is the beginning of the turn, do the beginning of the turn stuff for the next player
        if advance_player and (state.turn_type == 'Place' or state.turn_type == 'TurnInCards'):
            beginTurn(state)    
        
    return rstates, rsprobs

def simulateAttack(

input_state, action)

Simulates attack action. Returns a list of possible successor states and a list of their probabilities. This copies the input_state, so it is not modified.

def simulateAttack(input_state, action):
    """
    Simulates attack action.  Returns a list of possible successor states and a 
    list of their probabilities.  This copies the input_state, so it is not modified.
    """
    
    if action.from_territory is None:
        #This is the end of attack action.  Give the player a card if they earned it
        cur_state = input_state.copy_state()
        
        if cur_state.players[cur_state.current_player].conquered_territory:
            not_duplicate = False
            card = random.choice(cur_state.cards)
            while not_duplicate:
                #Randomly choose a card and give it to this player
                card = random.choice(cur_state.cards)
                if card not in cur_state.players[cur_state.current_player].cards:
                    not_duplicate = True
            cur_state.players[cur_state.current_player].cards.append(card)
            #Reset the players conquered_territory flag
            cur_state.players[cur_state.current_player].conquered_territory = False
            
        return [cur_state], [1]
    
    #How many possible attack outcomes are there
    num_successors = getNumAttackSuccessors(input_state, action)
    
    successor_states = []
    successor_probs = []
    
    for i in range(num_successors):
        cur_state = input_state.copy_state()
        cur_prob = 0
        if action.type == 'Attack':
            cur_prob = simulateAttackAction(cur_state, action, i)
        else:
            print 'ILLEGAL ACTION TYPE'
        
        nextType(cur_state, action)
        successor_states.append(cur_state)
        successor_probs.append(cur_prob)
        
    return successor_states, successor_probs

def simulateAttackAction(

state, action, outcome_index)

Execute the given action in the given state, assuming that the outcome of the battle is given by outcome_index. This will modify the state to reflect the outcome of the state.

def simulateAttackAction(state, action, outcome_index):
    """
    Execute the given action in the given state, assuming that the outcome of the battle is given by outcome_index.  This will modify the state to 
    reflect the outcome of the state.
    """            
    #a is attacker and d is defender
    
    #Get indices of involved territories
    a_idx = state.board.territory_to_id[action.from_territory]
    d_idx = state.board.territory_to_id[action.to_territory]
  
    #MAKE SURE THIS IS VALID
    if state.owners[a_idx] != state.current_player or state.owners[d_idx] == state.current_player or state.armies[a_idx] <= 1: 
        print 'INVALID ATTACK ACTION: '
        action.print_action()
        print 'NO ATTACK ACTION WILL BE TAKEN'
        return 
  
    #Set last attacker and defender variables in the state
    state.last_attacker = a_idx
    state.last_defender = d_idx
  
    #Player id of defender
    defender = state.owners[d_idx]
  
    #Get number of dice that will be involved (This assumes attacker always attacks with all dice)
    a_num_dice = min(3, state.armies[a_idx]-1)
    d_num_dice = min(2, state.armies[d_idx])

    if state.armies[d_idx] == 0:
        print 'THERE ARE NO ARMIES IN TERRITORY: ', state.board.territories[d_idx].name
        print 'ACTION: ', action.print_action()
        print 'State: ', state.print_state()
        
    #Get the outcome and probability for the input outcome index
    a_loss, d_loss, outcome_probability = getAttackOutcome(a_num_dice, d_num_dice, outcome_index)
    
    state.armies[d_idx] = max(state.armies[d_idx] - d_loss, 0)
    state.armies[a_idx] = state.armies[a_idx] - a_loss
    
    #Check if the defender is at zero, then change owner (armies will be moved in with the next action (Occupy)
    if state.armies[d_idx] == 0:
        state.owners[d_idx] = state.current_player
        
    #Check to see if the defender is now done completely, in which case we need to give her cards to the attacker.
    if defender not in state.owners:
        #The defender is done
        state.players[state.current_player].cards.extend(state.players[defender].cards)
        state.players[defender].cards = []
    
    return outcome_probability

def simulateFortifyAction(

state, action)

Execute the given action in the given state. This will modify the state to reflect the outcome of the state.

def simulateFortifyAction(state, action):
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state.
    """
    if action.to_territory is None:
        return
        
    to_idx = state.board.territory_to_id[action.to_territory]
    from_idx = state.board.territory_to_id[action.from_territory]
    
    #Make sure that the fortify action is correctly constructed
    if state.armies[from_idx] - action.troops < 1 or state.owners[from_idx] != state.current_player or state.owners[to_idx] != state.current_player or to_idx not in state.board.territories[from_idx].neighbors:
        #This move is invalid
        print 'INVALID FORTIFY ACTION: '
        action.print_action()
        print 'NO FORTIFY ACTION WILL BE TAKEN'
        return 
        
    state.armies[to_idx] = state.armies[to_idx] + action.troops
    state.armies[from_idx] = state.armies[from_idx] - action.troops

def simulateOccupyAction(

state, action)

Execute the given action in the given state. This will modify the state to reflect the outcome of the state.

def simulateOccupyAction(state, action):    
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state.
    """
    to_idx = state.board.territory_to_id[action.to_territory]
    from_idx = state.board.territory_to_id[action.from_territory]
    #Make sure that the occupy action is correctly constructed
    if to_idx != state.last_defender or from_idx != state.last_attacker or state.armies[from_idx] - action.troops < 1 or state.owners[from_idx] != state.current_player or state.owners[to_idx] != state.current_player:
        #This move is invalid
        print 'INVALID OCCUPY ACTION: '
        action.print_action()
        print 'To index = ', to_idx
        print 'Last defender = ', state.last_defender
        print 'From index = ', from_idx
        print 'Last attacker = ', state.last_attacker
        
        print 'NO OCCUPY ACTION WILL BE TAKEN'
        pause()
        return 

    state.armies[to_idx] = state.armies[to_idx] + action.troops
    state.armies[from_idx] = state.armies[from_idx] - action.troops

def simulatePlaceAction(

state, action)

Execute the given action in the given state. This will modify the state to reflect the outcome of the state.

def simulatePlaceAction(state, action):
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state.
    """
    idx = state.board.territory_to_id[action.to_territory]
    if state.owners[idx] == state.current_player and state.players[state.current_player].free_armies >= 1:
        state.armies[idx] = state.armies[idx] + 1
        state.players[state.current_player].free_armies -= 1
    else:
        print 'INVALID PLACE ACTION: '
        action.print_action()
        print 'NO PLACE ACTION WILL OCCUR'

def simulatePreAssignAction(

state, action)

Execute the given action in the given state. This will modify the state to reflect the outcome of the state.

def simulatePreAssignAction(state, action):
    """Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state."""

    idx = state.board.territory_to_id[action.to_territory]
    
    if state.owners[idx] != None or state.armies[idx] != 0 or state.players[state.current_player].free_armies < 1:
        print 'INVALID PREASSIGN ACTION!'
        
    state.owners[idx] = state.current_player
    state.armies[idx] = 1
    state.players[state.current_player].free_armies -= 1

def simulatePrePlaceAction(

state, action)

Execute the given action in the given state. This will modify the state to reflect the outcome of the state.

def simulatePrePlaceAction(state, action):
    """Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the state."""
    
    idx = state.board.territory_to_id[action.to_territory]
    if state.owners[idx] == state.current_player and state.players[state.current_player].free_armies > 0:
        state.armies[idx] = state.armies[idx] + 1
        state.players[state.current_player].free_armies -= 1
    else:
        print 'INVALID PREPLACE ACTION:'
        print 'NO PREPLACE ACTION WILL OCCUR'

def simulateTurnInCardsAction(

state, action)

Execute the given action in the given state. This will modify the state to reflect the outcome of the action.

def simulateTurnInCardsAction(state, action):
    """
    Execute the given action in the given state.  This will modify the state to 
    reflect the outcome of the action.
    """
    #See if they want to turn in cards
    if action.to_territory is None:
        return
        
    if (not isCardSet(state, action.to_territory, action.from_territory, action.troops)) or action.to_territory not in state.players[state.current_player].cards or action.from_territory not in state.players[state.current_player].cards or action.troops not in state.players[state.current_player].cards:
        print 'INVALID TURN-IN-CARDS ACTION!'
        action.print_action()
        print 'NO TURN-IN-CARDS ACTION WILL BE TAKEN'
        
    #Modify cards appropriately (cards indices are stored in to_territory, from_territory, and troops
    #Add turn in value to players free_armies
    turn_in_troops = getTurnInValue(state)
    state.players[state.current_player].free_armies  += turn_in_troops
    
    #Add two troops to any territory that appears on one of the cards owned by this player
    for i in [action.from_territory, action.to_territory, action.troops]:
        t = state.board.cards[i].territory
        if state.owners[t] == state.current_player:
            state.armies[t] = state.armies[t] + 2
        #Remove these cards from the player's hand
        state.players[state.current_player].cards.remove(i)

def translateAction(

state, action)

Takes a RiskAction and converts it into what needs to be returned by the AI to compete in the interactive risk game. Don't modify

def translateAction(state, action):
    """
    Takes a RiskAction and converts it into what needs to be returned by the AI to compete in the interactive risk game.
    Don't modify
    """
    
    if action.type == 'PreAssign' or action.type == 'PrePlace' or action.type == 'Place':
        return filter(lambda x:x.name == action.to_territory, riskengine.territories.values())[0]
    elif action.type == 'TurnInCards':
        if action.to_territory is None:
            return None,None,None
        else:
            return filter(lambda x:x.territory == state.board.territories[state.board.cards[action.to_territory].territory].name, riskengine.currentplayer.cards)[0],filter(lambda x:x.territory == state.board.territories[state.board.cards[action.from_territory].territory].name, riskengine.currentplayer.cards)[0],filter(lambda x:x.territory == state.board.territories[state.board.cards[action.troops].territory].name, riskengine.currentplayer.cards)[0]
    elif action.type == 'Attack':
        if action.to_territory is None:
            return None,None
        return filter(lambda x:x.name == action.from_territory, riskengine.territories.values())[0], filter(lambda x:x.name == action.to_territory, riskengine.territories.values())[0]
    elif action.type == 'Occupy':
        return action.troops
    elif action.type == 'Fortify':
        if action.to_territory is None:
            return None,None,0
        return filter(lambda x:x.name == action.from_territory, riskengine.territories.values())[0], filter(lambda x:x.name == action.to_territory, riskengine.territories.values())[0], action.troops
    else:
        print 'ILLEGAL ACTION TYPE!' 

Classes

class RiskAction

Stores the information about an action in a risk game

class RiskAction():
    """Stores the information about an action in a risk game"""
    
    def __init__(self, type, to_territory, from_territory, troops):
        """Initializes a RiskAction"""
        
        self.type = type
        """
         What kind of action this is? Should be a string
         possible types = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify)
        """
        
        self.to_territory = to_territory
        """
         This stores the territory id of the place the action is going
         For Each type it contains:
               
                PreAssign: The territory id being chosen by player
               
                PrePlace:  The territory id of the territory where troop is being placed
               
                Place: The territory id of the territory where troop is being placed
                
                TurnInCards: The card id of first of the cards being turned in, or None, if there are no cards to turn in
               
                Attack: The territory id of the territory being attacked
               
                Occupy: The territory id of the territory into which troops are moving
               
                Fortify: The territory id of the territory into which troops are moving
        """

        self.from_territory = from_territory
        """
         This stores the territory id of the place the action is coming from
         For Each type it contains:

                PreAssign: None
         
                PrePlace:  None
         
                Place: None
         
                TurnInCards: The card id of second of the cards being turned in, or None, if there are no cards to turn in
         
                Attack: The territory id of the territory doing the attacking
         
                Occupy: The territory id of the territory from which troops are moving
         
                Fortify: The territory id of the territory from which troops are moving
        """
        
        self.troops = troops
        """
         This stores the number of troops involved in the action
         For Each type it contains:
               
                PreAssign: None
               
                PrePlace:  None
               
                Place: None
               
                TurnInCards: The card id of third of the cards being turned in, or None, if there are no cards to turn in
               
                Attack: None
               
                Occupy: Number of troops moving into conquered territory
               
                Fortify: Number of troops moving to other territory
        """

    def print_action(self):
        """Displays information about this action to the output"""
        print self.description()
        
    def description(self, newline=False):
        """returns string description of this action, useful for display"""
        d = ""
        d = d + str(self.type) 
        if newline:
            d = d + "\n"
        if self.type == 'TurnInCards':
            d = d + ' CARD 1: ' + str(self.from_territory)
        elif self.type == 'Attack' or self.type == 'Occupy' or self.type == 'Fortify':
            d = d + ' FROM: ' + str(self.from_territory) 
        if newline:
            d = d + "\n"
        if self.type == 'TurnInCards':
            d = d + ' CARD 2: ' + str(self.to_territory) 
        elif self.type == 'Place' or self.type == 'PrePlace':
            d = d + ' IN: ' + str(self.to_territory) 
        else:
            d = d + ' TO: ' + str(self.to_territory) 
        if newline:
            d = d + "\n"
        if self.type == 'TurnInCards':
            d = d + ' CARD 3: ' + str(self.troops)
        elif self.type == 'Occupy' or self.type == 'Fortify':
            d = d + ' NUM: ' + str(self.troops)
        return d
        
    def to_string(self):
        """Saves this action to a string"""
        s = 'RISKACTION|' + json.dumps(self.type) + '|' + json.dumps(self.from_territory) + '|' + json.dumps(self.to_territory) + '|' + json.dumps(self.troops)
        return s
        
    def from_string(self, s):
        """Loads this action from a string"""
        ss = s.split('|')
        if ss[0] != 'RISKACTION':
            print 'THIS IS NOT A RISK ACTION STRING!'
        self.type = json.loads(ss[1])
        self.from_territory = json.loads(ss[2])
        self.to_territory = json.loads(ss[3])
        self.troops = json.loads(ss[4])

Ancestors (in MRO)

Instance variables

var from_territory

This stores the territory id of the place the action is coming from For Each type it contains:

   PreAssign: None

   PrePlace:  None

   Place: None

   TurnInCards: The card id of second of the cards being turned in, or None, if there are no cards to turn in

   Attack: The territory id of the territory doing the attacking

   Occupy: The territory id of the territory from which troops are moving

   Fortify: The territory id of the territory from which troops are moving

var to_territory

This stores the territory id of the place the action is going For Each type it contains:

   PreAssign: The territory id being chosen by player

   PrePlace:  The territory id of the territory where troop is being placed

   Place: The territory id of the territory where troop is being placed

   TurnInCards: The card id of first of the cards being turned in, or None, if there are no cards to turn in

   Attack: The territory id of the territory being attacked

   Occupy: The territory id of the territory into which troops are moving

   Fortify: The territory id of the territory into which troops are moving

var troops

This stores the number of troops involved in the action For Each type it contains:

   PreAssign: None

   PrePlace:  None

   Place: None

   TurnInCards: The card id of third of the cards being turned in, or None, if there are no cards to turn in

   Attack: None

   Occupy: Number of troops moving into conquered territory

   Fortify: Number of troops moving to other territory

var type

What kind of action this is? Should be a string possible types = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify)

Methods

def __init__(

self, type, to_territory, from_territory, troops)

Initializes a RiskAction

def __init__(self, type, to_territory, from_territory, troops):
    """Initializes a RiskAction"""
    
    self.type = type
    """
     What kind of action this is? Should be a string
     possible types = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify)
    """
    
    self.to_territory = to_territory
    """
     This stores the territory id of the place the action is going
     For Each type it contains:
           
            PreAssign: The territory id being chosen by player
           
            PrePlace:  The territory id of the territory where troop is being placed
           
            Place: The territory id of the territory where troop is being placed
            
            TurnInCards: The card id of first of the cards being turned in, or None, if there are no cards to turn in
           
            Attack: The territory id of the territory being attacked
           
            Occupy: The territory id of the territory into which troops are moving
           
            Fortify: The territory id of the territory into which troops are moving
    """
    self.from_territory = from_territory
    """
     This stores the territory id of the place the action is coming from
     For Each type it contains:
            PreAssign: None
     
            PrePlace:  None
     
            Place: None
     
            TurnInCards: The card id of second of the cards being turned in, or None, if there are no cards to turn in
     
            Attack: The territory id of the territory doing the attacking
     
            Occupy: The territory id of the territory from which troops are moving
     
            Fortify: The territory id of the territory from which troops are moving
    """
    
    self.troops = troops
    """
     This stores the number of troops involved in the action
     For Each type it contains:
           
            PreAssign: None
           
            PrePlace:  None
           
            Place: None
           
            TurnInCards: The card id of third of the cards being turned in, or None, if there are no cards to turn in
           
            Attack: None
           
            Occupy: Number of troops moving into conquered territory
           
            Fortify: Number of troops moving to other territory
    """

def description(

self, newline=False)

returns string description of this action, useful for display

def description(self, newline=False):
    """returns string description of this action, useful for display"""
    d = ""
    d = d + str(self.type) 
    if newline:
        d = d + "\n"
    if self.type == 'TurnInCards':
        d = d + ' CARD 1: ' + str(self.from_territory)
    elif self.type == 'Attack' or self.type == 'Occupy' or self.type == 'Fortify':
        d = d + ' FROM: ' + str(self.from_territory) 
    if newline:
        d = d + "\n"
    if self.type == 'TurnInCards':
        d = d + ' CARD 2: ' + str(self.to_territory) 
    elif self.type == 'Place' or self.type == 'PrePlace':
        d = d + ' IN: ' + str(self.to_territory) 
    else:
        d = d + ' TO: ' + str(self.to_territory) 
    if newline:
        d = d + "\n"
    if self.type == 'TurnInCards':
        d = d + ' CARD 3: ' + str(self.troops)
    elif self.type == 'Occupy' or self.type == 'Fortify':
        d = d + ' NUM: ' + str(self.troops)
    return d

def from_string(

self, s)

Loads this action from a string

def from_string(self, s):
    """Loads this action from a string"""
    ss = s.split('|')
    if ss[0] != 'RISKACTION':
        print 'THIS IS NOT A RISK ACTION STRING!'
    self.type = json.loads(ss[1])
    self.from_territory = json.loads(ss[2])
    self.to_territory = json.loads(ss[3])
    self.troops = json.loads(ss[4])

def print_action(

self)

Displays information about this action to the output

def print_action(self):
    """Displays information about this action to the output"""
    print self.description()

def to_string(

self)

Saves this action to a string

def to_string(self):
    """Saves this action to a string"""
    s = 'RISKACTION|' + json.dumps(self.type) + '|' + json.dumps(self.from_territory) + '|' + json.dumps(self.to_territory) + '|' + json.dumps(self.troops)
    return s

class RiskBoard

Stores all of the information about the current Risk game that doesn't change over the course of the game, things like:

Which territories make up the map

Which territories are connected to which

What the continents are and which territories they are composed of

What the sequence of card turn-in values is

What players are in the game

What pictures are on the cards

What the set of all cards is
class RiskBoard():
    """
    Stores all of the information about the current Risk game that doesn't change
    over the course of the game, things like:
        
        Which territories make up the map
        
        Which territories are connected to which
        
        What the continents are and which territories they are composed of
        
        What the sequence of card turn-in values is
        
        What players are in the game
        
        What pictures are on the cards 
        
        What the set of all cards is
    """
    def __init__(self):
        """
        Initialize a Risk Board.
        All of the variables are initially empty.  
        They should be filled in through other function calls
        """
        
        self.players = []               
        """ An array of RiskPlayer objects """
        
        self.player_to_id = dict()
        """ A dictionary which is indexed by player name and stores the id number of that player """

        self.id_to_player = dict()
        """ A dictionary which is indexed by player id and stores the player name of that player """
        
        self.territories = []           
        """ An array of RiskTerritory objects """
        self.territory_to_id = dict()
        """ A dictionary which is indexed by territory name and stores the id number of that territory """        

        self.cards = []                 
        """ An array of RiskCard objects """ 

        self.card_to_id = dict()
        """ A dictionary which is indexed by card name (territory name of pictured territory, or wildcard) Stores the id of that card """

        self.pictures = []
        """ An array of string descriptions of the different card pictures """
        
        self.continents = dict()        
        """ A dictionary of RiskContinent objects indexed by continent name, stores corresponding RiskContinent object """
        
        self.turn_in_values = []
        """ 
         An array of the card turn-in-values 
         turn_in_values[i] gives the number of troops
         received for the i-th card turn-in
        """

        self.increment_value = 0
        """ A number specifying the incremental gain in received troops for card turn-ins beyond the length of turn-in-values array """
        
        
    def from_string(self, s):
        """
        Load RiskBoard information from a string.  
        We assume the string was created by the to_string 
        function.
        """
        ss = s.split('|')
        #Players
        ssp = ss[1].split(';')
        for p in ssp:
            if len(p) > 0:
                np = RiskPlayer(None,None,None,None)
                np.from_string(p)
                self.add_player(np)
        #Territories
        sst = ss[2].split(';')
        for t in sst:
            if t:
                nt = RiskTerritory(None,None)
                nt.from_string(t)
                self.add_territory(nt)
        #Continents
        ssc = ss[3].split(';')
        for c in ssc:
            if c:
            
                nc = RiskContinent(None,None)
                nc.from_string(c)
                self.add_continent(nc)
        #Cards
        ssd = ss[4].split(';')
        for d in ssd:
            if d:
                nd = RiskCard(None,None,None)
                nd.from_string(d)
                self.add_card(nd)
        #Turn in values
        self.turn_in_values = json.loads(ss[5])
        #Increment value
        self.increment_value = json.loads(ss[6])
        #Pictures
        self.pictures = json.loads(ss[7])
    
    def to_string(self):
        """Save the current RiskBoard to a string.  This is used to save games."""
        output_string = 'RISKBOARD|'
        #Players
        for p in self.players:
            output_string = output_string + p.to_string()
            output_string = output_string + ';'
        output_string = output_string + '|'
        #Territories
        for t in self.territories:
            output_string = output_string + t.to_string()
            output_string = output_string + ';'
        output_string = output_string + '|'
        #Continents
        for n,c in self.continents.iteritems():
            output_string = output_string + c.to_string() + ';'
        output_string = output_string + '|'
        #Cards 
        for c in self.cards:
            output_string = output_string + c.to_string()
            output_string = output_string + ';'
        output_string = output_string + '|'
        #Turn In Values
        output_string = output_string + json.dumps(self.turn_in_values)
        output_string = output_string + '|'
        #Increment value
        output_string = output_string + json.dumps(self.increment_value)
        output_string = output_string + '|'
        #Pictures
        output_string = output_string + json.dumps(self.pictures)
        
        return output_string
        
        
    # def shuffle_players(self):
    #     """
    #     Randomize the player order.  Make sure everything is right after that
    #     """
    #     player_order = range(len(self.players))
    #     random.shuffle(player_order)
        
    #     shuffled_players = []
    #     player_counter = 0
    #     for i in player_order:
    #         p = self.players[i]
    #         p.id = player_counter
    #         shuffled_players.append(p)
    #         self.player_to_id[p.name] = p.id
    #         self.id_to_player[p.id] = p.name
    #         player_counter += 1
            
    #     self.players = shuffled_players
        
        
    def add_player(self, player):
        """
        Add a player object to the list of players.
        Modify player_to_id and id_to_player to include new player
        """
        self.players.append(player)
        self.player_to_id[player.name] = player.id
        self.id_to_player[player.id] = player.name
        
    def add_territory(self, territory):
        """
        Add a territory object to the list of territories.
        Modify territory_to_id to include new territory
        """
        self.territories.append(territory)
        self.territory_to_id[territory.name] = territory.id
        
    def add_card(self, card):
        """
        Add a card object to the list of cards
        Modify card_to_id to include the new card
        """
        self.cards.append(card)
        self.card_to_id[self.territories[card.territory].name] = card.id
        
    def shuffle_cards(self):
        """Randomly shuffle the array of cards and reassign the card ids to be consistent"""
        random.shuffle(self.cards)
        for i in range(len(self.cards)):
            self.cards[i].id = i
            self.card_to_id[self.territories[self.cards[i].territory].name] = i
        
    def add_continent(self, continent):
        """Add a continent object to the list of continents"""
        if continent.name not in self.continents:
            self.continents[continent.name] = continent
            
    def set_turn_in_values(self, tiv):
        """Set the array of turn-in values (for card turn-ins)"""
        self.turn_in_values = tiv
        
    def set_increment_value(self, iv):
        """Set the increment value for card turn-ins beyond the end of turn_in_values"""
        self.increment_value = iv    
            
    def print_board(self):
        """Display the Risk Board to the output."""
        print 'RISK BOARD'
        #PRINT TERRITORIES BY CONTINENT
        print 'CONTINENTS'
        for c in self.continents.values():
            c.print_continent(self)
        
        #PRINT CARDS
        print 'CARDS'
        for c in self.cards:
            c.print_card(self)
            
        #PRINT PLAYERS
        print 'PLAYERS'
        for p in self.players:
            p.print_player(self)

Ancestors (in MRO)

Instance variables

var card_to_id

A dictionary which is indexed by card name (territory name of pictured territory, or wildcard) Stores the id of that card

var cards

An array of RiskCard objects

var continents

A dictionary of RiskContinent objects indexed by continent name, stores corresponding RiskContinent object

var id_to_player

A dictionary which is indexed by player id and stores the player name of that player

var increment_value

A number specifying the incremental gain in received troops for card turn-ins beyond the length of turn-in-values array

var pictures

An array of string descriptions of the different card pictures

var player_to_id

A dictionary which is indexed by player name and stores the id number of that player

var players

An array of RiskPlayer objects

var territories

An array of RiskTerritory objects

var territory_to_id

A dictionary which is indexed by territory name and stores the id number of that territory

var turn_in_values

An array of the card turn-in-values turn_in_values[i] gives the number of troops received for the i-th card turn-in

Methods

def __init__(

self)

Initialize a Risk Board. All of the variables are initially empty.
They should be filled in through other function calls

def __init__(self):
    """
    Initialize a Risk Board.
    All of the variables are initially empty.  
    They should be filled in through other function calls
    """
    
    self.players = []               
    """ An array of RiskPlayer objects """
    
    self.player_to_id = dict()
    """ A dictionary which is indexed by player name and stores the id number of that player """
    self.id_to_player = dict()
    """ A dictionary which is indexed by player id and stores the player name of that player """
    
    self.territories = []           
    """ An array of RiskTerritory objects """
    self.territory_to_id = dict()
    """ A dictionary which is indexed by territory name and stores the id number of that territory """        
    self.cards = []                 
    """ An array of RiskCard objects """ 
    self.card_to_id = dict()
    """ A dictionary which is indexed by card name (territory name of pictured territory, or wildcard) Stores the id of that card """
    self.pictures = []
    """ An array of string descriptions of the different card pictures """
    
    self.continents = dict()        
    """ A dictionary of RiskContinent objects indexed by continent name, stores corresponding RiskContinent object """
    
    self.turn_in_values = []
    """ 
     An array of the card turn-in-values 
     turn_in_values[i] gives the number of troops
     received for the i-th card turn-in
    """
    self.increment_value = 0
    """ A number specifying the incremental gain in received troops for card turn-ins beyond the length of turn-in-values array """

def add_card(

self, card)

Add a card object to the list of cards Modify card_to_id to include the new card

def add_card(self, card):
    """
    Add a card object to the list of cards
    Modify card_to_id to include the new card
    """
    self.cards.append(card)
    self.card_to_id[self.territories[card.territory].name] = card.id

def add_continent(

self, continent)

Add a continent object to the list of continents

def add_continent(self, continent):
    """Add a continent object to the list of continents"""
    if continent.name not in self.continents:
        self.continents[continent.name] = continent

def add_player(

self, player)

Add a player object to the list of players. Modify player_to_id and id_to_player to include new player

def add_player(self, player):
    """
    Add a player object to the list of players.
    Modify player_to_id and id_to_player to include new player
    """
    self.players.append(player)
    self.player_to_id[player.name] = player.id
    self.id_to_player[player.id] = player.name

def add_territory(

self, territory)

Add a territory object to the list of territories. Modify territory_to_id to include new territory

def add_territory(self, territory):
    """
    Add a territory object to the list of territories.
    Modify territory_to_id to include new territory
    """
    self.territories.append(territory)
    self.territory_to_id[territory.name] = territory.id

def from_string(

self, s)

Load RiskBoard information from a string.
We assume the string was created by the to_string function.

def from_string(self, s):
    """
    Load RiskBoard information from a string.  
    We assume the string was created by the to_string 
    function.
    """
    ss = s.split('|')
    #Players
    ssp = ss[1].split(';')
    for p in ssp:
        if len(p) > 0:
            np = RiskPlayer(None,None,None,None)
            np.from_string(p)
            self.add_player(np)
    #Territories
    sst = ss[2].split(';')
    for t in sst:
        if t:
            nt = RiskTerritory(None,None)
            nt.from_string(t)
            self.add_territory(nt)
    #Continents
    ssc = ss[3].split(';')
    for c in ssc:
        if c:
        
            nc = RiskContinent(None,None)
            nc.from_string(c)
            self.add_continent(nc)
    #Cards
    ssd = ss[4].split(';')
    for d in ssd:
        if d:
            nd = RiskCard(None,None,None)
            nd.from_string(d)
            self.add_card(nd)
    #Turn in values
    self.turn_in_values = json.loads(ss[5])
    #Increment value
    self.increment_value = json.loads(ss[6])
    #Pictures
    self.pictures = json.loads(ss[7])

def print_board(

self)

Display the Risk Board to the output.

def print_board(self):
    """Display the Risk Board to the output."""
    print 'RISK BOARD'
    #PRINT TERRITORIES BY CONTINENT
    print 'CONTINENTS'
    for c in self.continents.values():
        c.print_continent(self)
    
    #PRINT CARDS
    print 'CARDS'
    for c in self.cards:
        c.print_card(self)
        
    #PRINT PLAYERS
    print 'PLAYERS'
    for p in self.players:
        p.print_player(self)

def set_increment_value(

self, iv)

Set the increment value for card turn-ins beyond the end of turn_in_values

def set_increment_value(self, iv):
    """Set the increment value for card turn-ins beyond the end of turn_in_values"""
    self.increment_value = iv    

def set_turn_in_values(

self, tiv)

Set the array of turn-in values (for card turn-ins)

def set_turn_in_values(self, tiv):
    """Set the array of turn-in values (for card turn-ins)"""
    self.turn_in_values = tiv

def shuffle_cards(

self)

Randomly shuffle the array of cards and reassign the card ids to be consistent

def shuffle_cards(self):
    """Randomly shuffle the array of cards and reassign the card ids to be consistent"""
    random.shuffle(self.cards)
    for i in range(len(self.cards)):
        self.cards[i].id = i
        self.card_to_id[self.territories[self.cards[i].territory].name] = i

def to_string(

self)

Save the current RiskBoard to a string. This is used to save games.

def to_string(self):
    """Save the current RiskBoard to a string.  This is used to save games."""
    output_string = 'RISKBOARD|'
    #Players
    for p in self.players:
        output_string = output_string + p.to_string()
        output_string = output_string + ';'
    output_string = output_string + '|'
    #Territories
    for t in self.territories:
        output_string = output_string + t.to_string()
        output_string = output_string + ';'
    output_string = output_string + '|'
    #Continents
    for n,c in self.continents.iteritems():
        output_string = output_string + c.to_string() + ';'
    output_string = output_string + '|'
    #Cards 
    for c in self.cards:
        output_string = output_string + c.to_string()
        output_string = output_string + ';'
    output_string = output_string + '|'
    #Turn In Values
    output_string = output_string + json.dumps(self.turn_in_values)
    output_string = output_string + '|'
    #Increment value
    output_string = output_string + json.dumps(self.increment_value)
    output_string = output_string + '|'
    #Pictures
    output_string = output_string + json.dumps(self.pictures)
    
    return output_string

class RiskCard

Stores all the information for a risk card

class RiskCard():
    """Stores all the information for a risk card"""
    def __init__(self, territory, picture, id):
        """Initializes card information"""

        self.territory = territory
        """ The territory id number of the territory pictured on the card """
        
        self.picture = picture
        """ The picture on the card """

        self.id = id
        """ The id number of this card """

    
    def print_card(self, board, indent=0):
        """Displays information about this card to the output"""
        for i in range(indent):
            print ' ',
        print board.territories[self.territory].name, ' : ', self.picture
        
    def to_string(self):
        """Saves card information to a string"""
        s = str(self.territory) + '.' + str(self.picture) + '.' + str(self.id)
        return s
        
    def from_string(self, s):
        """Loads card information from a string"""
        ss = s.split('.')
        self.territory = json.loads(ss[0])
        self.picture = json.loads(ss[1])
        self.id = json.loads(ss[2])

Ancestors (in MRO)

Instance variables

var id

The id number of this card

var picture

The picture on the card

var territory

The territory id number of the territory pictured on the card

Methods

def __init__(

self, territory, picture, id)

Initializes card information

def __init__(self, territory, picture, id):
    """Initializes card information"""
    self.territory = territory
    """ The territory id number of the territory pictured on the card """
    
    self.picture = picture
    """ The picture on the card """
    self.id = id
    """ The id number of this card """

def from_string(

self, s)

Loads card information from a string

def from_string(self, s):
    """Loads card information from a string"""
    ss = s.split('.')
    self.territory = json.loads(ss[0])
    self.picture = json.loads(ss[1])
    self.id = json.loads(ss[2])

def print_card(

self, board, indent=0)

Displays information about this card to the output

def print_card(self, board, indent=0):
    """Displays information about this card to the output"""
    for i in range(indent):
        print ' ',
    print board.territories[self.territory].name, ' : ', self.picture

def to_string(

self)

Saves card information to a string

def to_string(self):
    """Saves card information to a string"""
    s = str(self.territory) + '.' + str(self.picture) + '.' + str(self.id)
    return s

class RiskContinent

Stores all information related to a continent

class RiskContinent():
    """Stores all information related to a continent"""
    def __init__(self, name, reward):
        """Initializes the continent information"""
        self.name = name
        """The name of this continent (string) """
        
        self.reward = reward
        """
         The reward for this continent 
         This is the number of troops bonus that a player gets if the player 
         owns all of the territories in this continent
        """
        self.territories = []
        """ A list of the territory id numbers of the territories in this continent"""        

    def add_territory(self, territory):
        """Adds a territory to this continent"""
        if territory not in self.territories:
            self.territories.append(territory)
    
    def print_continent(self,board,indent=0):
        """Displays information about continent to output"""
        for i in range(indent):
            print ' ',
        print '{', self.name, '} : ', self.reward
        for t in self.territories:
            board.territories[t].print_territory(board, indent+2)
    
    def to_string(self):
        """Save continent information to string"""
        s = json.dumps(self.name) + '&' + json.dumps(self.reward) + '&' + json.dumps(self.territories)
        return s
    
    def from_string(self, s):
        """Load continent information from string"""
        ss = s.split('&')
        self.name = json.loads(ss[0])
        self.reward = json.loads(ss[1])
        self.territories = json.loads(ss[2])

Ancestors (in MRO)

Instance variables

var name

The name of this continent (string)

var reward

The reward for this continent This is the number of troops bonus that a player gets if the player owns all of the territories in this continent

var territories

A list of the territory id numbers of the territories in this continent

Methods

def __init__(

self, name, reward)

Initializes the continent information

def __init__(self, name, reward):
    """Initializes the continent information"""
    self.name = name
    """The name of this continent (string) """
    
    self.reward = reward
    """
     The reward for this continent 
     This is the number of troops bonus that a player gets if the player 
     owns all of the territories in this continent
    """
    self.territories = []
    """ A list of the territory id numbers of the territories in this continent"""        

def add_territory(

self, territory)

Adds a territory to this continent

def add_territory(self, territory):
    """Adds a territory to this continent"""
    if territory not in self.territories:
        self.territories.append(territory)

def from_string(

self, s)

Load continent information from string

def from_string(self, s):
    """Load continent information from string"""
    ss = s.split('&')
    self.name = json.loads(ss[0])
    self.reward = json.loads(ss[1])
    self.territories = json.loads(ss[2])

def print_continent(

self, board, indent=0)

Displays information about continent to output

def print_continent(self,board,indent=0):
    """Displays information about continent to output"""
    for i in range(indent):
        print ' ',
    print '{', self.name, '} : ', self.reward
    for t in self.territories:
        board.territories[t].print_territory(board, indent+2)

def to_string(

self)

Save continent information to string

def to_string(self):
    """Save continent information to string"""
    s = json.dumps(self.name) + '&' + json.dumps(self.reward) + '&' + json.dumps(self.territories)
    return s

class RiskPlayer

Stores all information about a player in the game

class RiskPlayer():
    """Stores all information about a player in the game"""
    def __init__(self, name, id, free_armies, conquered_territory):
        """Initializes the various components of this RiskPlayer object"""
        self.name = name
        """ The Player's name (string) """
        
        self.id = id
        """ The Player's id (integer) """

        self.cards = []
        """ A list of card id numbers that this player holds (integers) """

        self.free_armies = free_armies
        """ The number of armies this player has in hand, waiting to be placed on the board """

        self.conquered_territory = conquered_territory
        """ A boolean stating whether or not this player conquered a territory on their current turn """
    
    def add_card(self, card):
        """Adds a card (card id number) to the player's list of card ids"""
        self.cards.append(card)
    
    def add_armies(self, n):
        """Adds a number (n) of armies to the player's free_armies count"""
        self.free_armies += n
    
    def print_player(self, board, indent=0):
        """Displays information about this player to the output"""
        for i in range(indent):
            print ' ',
        print '<', self.name, '[', self.id, ']> (', self.free_armies, ' free armies )'
        for i in range(indent+2):
            print ' ',
        print 'Cards:'
        for c in self.cards:
            board.cards[c].print_card(board, indent+3)
        
    def copy_player(self):
        """Creates a copy of this player and returns it"""
        np = RiskPlayer(self.name, self.id, self.free_armies, self.conquered_territory)
        np.cards = self.cards[:]
        return np
        
    def to_string(self):
        """Saves this player to a string"""
        s = json.dumps(self.name) + '.' + json.dumps(self.id) + '.' + json.dumps(self.cards) + '.' + json.dumps(self.free_armies) + '.' + json.dumps(self.conquered_territory)
        return s
        
    def from_string(self, s):
        """Loads player information from a string"""
        ss = s.split('.')
        self.name = json.loads(ss[0])
        self.id = json.loads(ss[1])
        self.cards = json.loads(ss[2])
        self.free_armies = json.loads(ss[3])
        self.conquered_territory = json.loads(ss[4])

Ancestors (in MRO)

Instance variables

var cards

A list of card id numbers that this player holds (integers)

var conquered_territory

A boolean stating whether or not this player conquered a territory on their current turn

var free_armies

The number of armies this player has in hand, waiting to be placed on the board

var id

The Player's id (integer)

var name

The Player's name (string)

Methods

def __init__(

self, name, id, free_armies, conquered_territory)

Initializes the various components of this RiskPlayer object

def __init__(self, name, id, free_armies, conquered_territory):
    """Initializes the various components of this RiskPlayer object"""
    self.name = name
    """ The Player's name (string) """
    
    self.id = id
    """ The Player's id (integer) """
    self.cards = []
    """ A list of card id numbers that this player holds (integers) """
    self.free_armies = free_armies
    """ The number of armies this player has in hand, waiting to be placed on the board """
    self.conquered_territory = conquered_territory
    """ A boolean stating whether or not this player conquered a territory on their current turn """

def add_armies(

self, n)

Adds a number (n) of armies to the player's free_armies count

def add_armies(self, n):
    """Adds a number (n) of armies to the player's free_armies count"""
    self.free_armies += n

def add_card(

self, card)

Adds a card (card id number) to the player's list of card ids

def add_card(self, card):
    """Adds a card (card id number) to the player's list of card ids"""
    self.cards.append(card)

def copy_player(

self)

Creates a copy of this player and returns it

def copy_player(self):
    """Creates a copy of this player and returns it"""
    np = RiskPlayer(self.name, self.id, self.free_armies, self.conquered_territory)
    np.cards = self.cards[:]
    return np

def from_string(

self, s)

Loads player information from a string

def from_string(self, s):
    """Loads player information from a string"""
    ss = s.split('.')
    self.name = json.loads(ss[0])
    self.id = json.loads(ss[1])
    self.cards = json.loads(ss[2])
    self.free_armies = json.loads(ss[3])
    self.conquered_territory = json.loads(ss[4])

def print_player(

self, board, indent=0)

Displays information about this player to the output

def print_player(self, board, indent=0):
    """Displays information about this player to the output"""
    for i in range(indent):
        print ' ',
    print '<', self.name, '[', self.id, ']> (', self.free_armies, ' free armies )'
    for i in range(indent+2):
        print ' ',
    print 'Cards:'
    for c in self.cards:
        board.cards[c].print_card(board, indent+3)

def to_string(

self)

Saves this player to a string

def to_string(self):
    """Saves this player to a string"""
    s = json.dumps(self.name) + '.' + json.dumps(self.id) + '.' + json.dumps(self.cards) + '.' + json.dumps(self.free_armies) + '.' + json.dumps(self.conquered_territory)
    return s

class RiskState

Stores all the information about a state of a Risk game

class RiskState():
    """Stores all the information about a state of a Risk game"""
    
    def __init__(self, players, armies, owners, current_player, turn_type, turn_in_number, last_attacker, last_defender, cards, board):
        """Initializes a RiskState object"""
    
        self.players = players
        """An array of RiskPlayer objects (the players in the game)"""
        
        self.armies = armies
        """
         An array of integers, indexed by territory id number, that 
         stores the number of armies on that territory
        """
        self.owners = owners
        """
         An array of integers, indexed by territory id number, that 
         stores the player id number of the player who owns that territory
        """
        self.current_player = current_player
        """ The player id number of the current player (player whose turn it is) """
        
        self.turn_type = turn_type
        """
         What kind of turn is it currently 
         Choices = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify, GameOver)
        """
        self.cards = cards
        """ A list of all the card id numbers of the cards still in the deck """

        self.turn_in_number = turn_in_number
        """ How many card sets have been turned in? """
        
        self.last_attacker = last_attacker
        """
         What is the territory id of the last territory that was attacking 
         Important to determine troop movements after territory is conquered
        """
        self.last_defender = last_defender
        """
         What is the territory id of the last territory that was defending 
         Important to determine troop movements after territory is conquered
        """
        
        self.board = board
        """
         A RiskBoard object that stores all the non-changing information about
         this risk game
        """

    def to_string(self):
        """Saves this state to a string"""
        s = 'RISKSTATE|'
        #players
        for p in self.players:
            s = s + p.to_string()
            s = s + ';'
        s = s + '|' + json.dumps(self.armies) + '|' + json.dumps(self.owners) + '|'
        s = s + json.dumps(self.current_player) + '|' + json.dumps(self.turn_type) + '|'
        s = s + json.dumps(self.cards) + '|' + json.dumps(self.turn_in_number) + '|'
        s = s + json.dumps(self.last_attacker) + '|' + json.dumps(self.last_defender)
        return s
        
    def from_string(self, s, board):
        """Loads this state from a string"""
        ss = s.split('|')
        if ss[0] != 'RISKSTATE':
            print 'THIS IS AN INVALID RISKSTATE'
        ps = ss[1].split(';')
        self.players = []
        for p in ps:
            if p:#len(p) > 0:
                np = RiskPlayer(None, None, None, None)
                np.from_string(p)
                self.players.append(np)
                
        self.armies = json.loads(ss[2])
        self.owners = json.loads(ss[3])
        self.current_player = json.loads(ss[4])
        self.turn_type = json.loads(ss[5])
        self.cards = json.loads(ss[6])
        self.turn_in_number = json.loads(ss[7])
        self.last_attacker = json.loads(ss[8])
        self.last_defender = json.loads(ss[9])
        self.board = board
        
    def print_state(self):
        """Displays information about this state to the output"""
        print 'PLAYERS'
        for p in self.players:
            p.print_player(self.board)
        
        print 'OWNERS/ARMIES'
        for i in range(len(self.armies)):
            if self.owners[i] in self.board.id_to_player:
                print self.board.territories[i].name, '[', self.board.id_to_player[self.owners[i]], '] : ', self.armies[i]
            else:
                print self.board.territories[i].name, '[', self.owners[i], '] : ', self.armies[i]
        
        if self.current_player < len(self.players):
            print 'CURRENT PLAYER: ', self.players[self.current_player].name, '[', self.current_player, ']'
        else:
            print 'CURRENT PLAYER: ??? [', self.current_player, ']'
        print len(self.cards), ' CARDS LEFT'
        
    def copy_state(self):
        """
        Creates a (deep) copy of this state and return it. Modifications to new state won't change original, except for the risk board, of which there is only one (it shouldn't be modified!)
        """
        copy_players = []
        for p in self.players:
            copy_players.append(p.copy_player())
        return RiskState(copy_players,self.armies[:],self.owners[:],self.current_player,self.turn_type,self.turn_in_number, self.last_attacker, self.last_defender, self.cards[:],self.board)

Ancestors (in MRO)

Instance variables

var armies

An array of integers, indexed by territory id number, that stores the number of armies on that territory

var board

A RiskBoard object that stores all the non-changing information about this risk game

var cards

A list of all the card id numbers of the cards still in the deck

var current_player

The player id number of the current player (player whose turn it is)

var last_attacker

What is the territory id of the last territory that was attacking Important to determine troop movements after territory is conquered

var last_defender

What is the territory id of the last territory that was defending Important to determine troop movements after territory is conquered

var owners

An array of integers, indexed by territory id number, that stores the player id number of the player who owns that territory

var players

An array of RiskPlayer objects (the players in the game)

var turn_in_number

How many card sets have been turned in?

var turn_type

What kind of turn is it currently Choices = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify, GameOver)

Methods

def __init__(

self, players, armies, owners, current_player, turn_type, turn_in_number, last_attacker, last_defender, cards, board)

Initializes a RiskState object

def __init__(self, players, armies, owners, current_player, turn_type, turn_in_number, last_attacker, last_defender, cards, board):
    """Initializes a RiskState object"""

    self.players = players
    """An array of RiskPlayer objects (the players in the game)"""
    
    self.armies = armies
    """
     An array of integers, indexed by territory id number, that 
     stores the number of armies on that territory
    """
    self.owners = owners
    """
     An array of integers, indexed by territory id number, that 
     stores the player id number of the player who owns that territory
    """
    self.current_player = current_player
    """ The player id number of the current player (player whose turn it is) """
    
    self.turn_type = turn_type
    """
     What kind of turn is it currently 
     Choices = (PreAssign, PrePlace, Place, TurnInCards, Attack, Occupy, Fortify, GameOver)
    """
    self.cards = cards
    """ A list of all the card id numbers of the cards still in the deck """
    self.turn_in_number = turn_in_number
    """ How many card sets have been turned in? """
    
    self.last_attacker = last_attacker
    """
     What is the territory id of the last territory that was attacking 
     Important to determine troop movements after territory is conquered
    """
    self.last_defender = last_defender
    """
     What is the territory id of the last territory that was defending 
     Important to determine troop movements after territory is conquered
    """
    
    self.board = board
    """
     A RiskBoard object that stores all the non-changing information about
     this risk game
    """

def copy_state(

self)

Creates a (deep) copy of this state and return it. Modifications to new state won't change original, except for the risk board, of which there is only one (it shouldn't be modified!)

def copy_state(self):
    """
    Creates a (deep) copy of this state and return it. Modifications to new state won't change original, except for the risk board, of which there is only one (it shouldn't be modified!)
    """
    copy_players = []
    for p in self.players:
        copy_players.append(p.copy_player())
    return RiskState(copy_players,self.armies[:],self.owners[:],self.current_player,self.turn_type,self.turn_in_number, self.last_attacker, self.last_defender, self.cards[:],self.board)

def from_string(

self, s, board)

Loads this state from a string

def from_string(self, s, board):
    """Loads this state from a string"""
    ss = s.split('|')
    if ss[0] != 'RISKSTATE':
        print 'THIS IS AN INVALID RISKSTATE'
    ps = ss[1].split(';')
    self.players = []
    for p in ps:
        if p:#len(p) > 0:
            np = RiskPlayer(None, None, None, None)
            np.from_string(p)
            self.players.append(np)
            
    self.armies = json.loads(ss[2])
    self.owners = json.loads(ss[3])
    self.current_player = json.loads(ss[4])
    self.turn_type = json.loads(ss[5])
    self.cards = json.loads(ss[6])
    self.turn_in_number = json.loads(ss[7])
    self.last_attacker = json.loads(ss[8])
    self.last_defender = json.loads(ss[9])
    self.board = board

def print_state(

self)

Displays information about this state to the output

def print_state(self):
    """Displays information about this state to the output"""
    print 'PLAYERS'
    for p in self.players:
        p.print_player(self.board)
    
    print 'OWNERS/ARMIES'
    for i in range(len(self.armies)):
        if self.owners[i] in self.board.id_to_player:
            print self.board.territories[i].name, '[', self.board.id_to_player[self.owners[i]], '] : ', self.armies[i]
        else:
            print self.board.territories[i].name, '[', self.owners[i], '] : ', self.armies[i]
    
    if self.current_player < len(self.players):
        print 'CURRENT PLAYER: ', self.players[self.current_player].name, '[', self.current_player, ']'
    else:
        print 'CURRENT PLAYER: ??? [', self.current_player, ']'
    print len(self.cards), ' CARDS LEFT'

def to_string(

self)

Saves this state to a string

def to_string(self):
    """Saves this state to a string"""
    s = 'RISKSTATE|'
    #players
    for p in self.players:
        s = s + p.to_string()
        s = s + ';'
    s = s + '|' + json.dumps(self.armies) + '|' + json.dumps(self.owners) + '|'
    s = s + json.dumps(self.current_player) + '|' + json.dumps(self.turn_type) + '|'
    s = s + json.dumps(self.cards) + '|' + json.dumps(self.turn_in_number) + '|'
    s = s + json.dumps(self.last_attacker) + '|' + json.dumps(self.last_defender)
    return s

class RiskTerritory

Stores all of the information for a territory

class RiskTerritory():
    """Stores all of the information for a territory"""
    def __init__(self, name, id):
        self.name = name
        """ The name of the territory (a string) """
        
        self.id = id
        """ The id number of the territory (an integer) """

        self.neighbors = []
        """ An list of the id numbers of all territories neighboring this one """

    
    def add_neighbor(self, neighbor):
        """Add a neighbor id to the neighbor list"""
        self.neighbors.append(neighbor)
    
    def print_territory(self, board, indent=0):
        """Display information about this territory to the output"""
        for i in range(indent):
            print ' ',
        print '[', self.name, '] (', self.id, ')'
        for i in range(indent+2):
            print ' ',
        print 'Neighbors:'
        for n in self.neighbors:
            for i in range(indent+3):
                print ' ',
            print board.territories[n].name
    
    def to_string(self):
        """Save the current Territory information to a string"""
        s = json.dumps(self.name) + '&' + json.dumps(self.id) + '&' + json.dumps(self.neighbors) 
        return s
        
    def from_string(self, s):
        """Load information about this territory from a string"""
        ss = s.split('&')
        self.name = json.loads(ss[0])
        self.id = json.loads(ss[1])
        self.neighbors = json.loads(ss[2])

Ancestors (in MRO)

Instance variables

var id

The id number of the territory (an integer)

var name

The name of the territory (a string)

var neighbors

An list of the id numbers of all territories neighboring this one

Methods

def __init__(

self, name, id)

def __init__(self, name, id):
    self.name = name
    """ The name of the territory (a string) """
    
    self.id = id
    """ The id number of the territory (an integer) """
    self.neighbors = []
    """ An list of the id numbers of all territories neighboring this one """

def add_neighbor(

self, neighbor)

Add a neighbor id to the neighbor list

def add_neighbor(self, neighbor):
    """Add a neighbor id to the neighbor list"""
    self.neighbors.append(neighbor)

def from_string(

self, s)

Load information about this territory from a string

def from_string(self, s):
    """Load information about this territory from a string"""
    ss = s.split('&')
    self.name = json.loads(ss[0])
    self.id = json.loads(ss[1])
    self.neighbors = json.loads(ss[2])

def print_territory(

self, board, indent=0)

Display information about this territory to the output

def print_territory(self, board, indent=0):
    """Display information about this territory to the output"""
    for i in range(indent):
        print ' ',
    print '[', self.name, '] (', self.id, ')'
    for i in range(indent+2):
        print ' ',
    print 'Neighbors:'
    for n in self.neighbors:
        for i in range(indent+3):
            print ' ',
        print board.territories[n].name

def to_string(

self)

Save the current Territory information to a string

def to_string(self):
    """Save the current Territory information to a string"""
    s = json.dumps(self.name) + '&' + json.dumps(self.id) + '&' + json.dumps(self.neighbors) 
    return s