Exemplo n.º 1
0
    def nextActions(self, team: str, board: GameBoard, state: GameState, step: str, depth: int) -> List[Action]:
        """
        Builds the possible actions considering that the movements are possible only at the beginning of the
        exploration: this means that all the actions after the first one are Attacks.

        :param team:    find the next actions for this team
        :param board:   board of the game
        :param state:   current state of the game
        :param step:    if "response", this method will generate the possible next actions
        :param depth:   current depth of the exploration
        :return: a list of the available actions that can be applied
        """
        nextActions = []
        if step == 'response':
            nextActions += [self.gm.actionNoResponse(team)]
            for figure in state.getFiguresCanRespond(team):
                nextActions += self.gm.buildResponses(board, state, figure)

        else:
            for figure in state.getFiguresCanBeActivated(team):
                # RED team can't pass
                if team == BLUE:
                    nextActions += [self.gm.actionPassFigure(figure)]

                if self.maxDepth - depth == 1:
                    nextActions += self.gm.buildMovements(board, state, figure)
                nextActions += self.gm.buildAttacks(board, state, figure)

            # if we don't have actions available we are forced to pass with the whole team
            if not nextActions:
                nextActions += [self.gm.actionPassTeam(team)]

        return nextActions
Exemplo n.º 2
0
    def test_RequestCallsRotation(self):
        """
        This tests that requests are performed in a clockwise rotation (http://boardgamegeek.com/article/18425206#18425206).
        However, for the sake of game flow, the targetted player (if any) will be requested first.
        """
        GameState.reset()
        GameState.PlayerList = []
        
        Order = []
        
        class PlayerNumber(Player):  
            def __init__(self, position, Order):
                self.position = position
                self.Order = Order
                Player.__init__(self)
            def confirmCall(self, activePlayer, action): 
                self.Order.append(self.position)
                return False

        player1 = PlayerNumber(1, Order)
        player2 = PlayerNumber(2, Order)
        player3 = PlayerNumber(3, Order)
        player4 = PlayerNumber(4, Order)
        player5 = PlayerNumber(5, Order)
        player6 = PlayerNumber(6, Order)
        
        status, response = player4.play(action.Captain, player3)
        self.assertTrue(status, response)

        self.assertEqual(Order, [3, 5, 6, 1, 2])
Exemplo n.º 3
0
    def test_RequestCallsRotation(self):
        """
        This tests that requests are performed in a clockwise rotation (http://boardgamegeek.com/article/18425206#18425206).
        However, for the sake of game flow, the targetted player (if any) will be requested first.
        """
        GameState.reset()
        GameState.PlayerList = []

        Order = []

        class PlayerNumber(Player):
            def __init__(self, position, Order):
                self.position = position
                self.Order = Order
                Player.__init__(self)

            def confirmCall(self, activePlayer, action):
                self.Order.append(self.position)
                return False

        player1 = PlayerNumber(1, Order)
        player2 = PlayerNumber(2, Order)
        player3 = PlayerNumber(3, Order)
        player4 = PlayerNumber(4, Order)
        player5 = PlayerNumber(5, Order)
        player6 = PlayerNumber(6, Order)

        status, response = player4.play(action.Captain, player3)
        self.assertTrue(status, response)

        self.assertEqual(Order, [3, 5, 6, 1, 2])
Exemplo n.º 4
0
    def nextActions(self, team: str, board: GameBoard, state: GameState,
                    step: str, depth: int) -> List[Action]:
        """
        Generates a list of possible actions or responses.

        By overriding this method you need to use the parameter "step" to discriminate between actions and responses. It
        is mandatory to return a list of "Response" when the step value equals to "response".

        :param team:    find the next actions for this team
        :param board:   board of the game
        :param state:   current state of the game
        :param step:    if "response", this method will generate the possible next actions
        :param depth:   current depth of the exploration
        :return: a list of the available actions that can be applied
        """
        nextActions = []
        if step == 'response':
            nextActions += [self.gm.actionNoResponse(team)]
            for figure in state.getFiguresCanRespond(team):
                nextActions += self.gm.buildResponses(board, state, figure)
        else:
            for figure in state.getFiguresCanBeActivated(team):
                nextActions += [self.gm.actionPassFigure(figure)]

                # standard actions
                nextActions += self.gm.buildAttacks(board, state, figure)
                nextActions += self.gm.buildMovements(board, state, figure)
        return nextActions
Exemplo n.º 5
0
    def setUp(self):
        shape = (8, 8)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.blue_tank = buildFigure('Tank', (6, 4), BLUE)
        self.red_tank = buildFigure('Tank', (1, 4), RED)
        self.red_inf = buildFigure('Infantry', (2, 4), RED)

        self.state.addFigure(self.red_tank, self.red_inf, self.blue_tank)
Exemplo n.º 6
0
    def chooseFigureGroups(self, board: GameBoard, state: GameState) -> None:
        """
        Chooses randomly the initial color to use.

        :param board:   board of the game
        :param state:   the current state
        """
        # TODO: find a better idea? now random
        colors = list(state.choices[self.team].keys())
        color = self.rnd.choice(colors)

        state.choose(self.team, color)
Exemplo n.º 7
0
    def chooseFigureGroups(self, board: GameBoard, state: GameState) -> None:
        """
        Randomly choose the group of units to use.

        :param board:   board of the game
        :param state:   the current state
        """
        # randomly choose a color
        colors = list(state.choices[self.team].keys())
        color = np.random.choice(colors)

        state.choose(self.team, color)
Exemplo n.º 8
0
def Setup():
    # How many people are playing?
    # Generate the player list
    # Shuffle the player list
    GameState.reset()
    SetupActions()

    def GetNumberOfPlayers():
        PlayerCount = input("How many players (2-6)? ")
        if not PlayerCount.isnumeric():
            return GetNumberOfPlayers()

        PlayerCount = int(PlayerCount)
        if PlayerCount < 2 or PlayerCount > 6:
            return GetNumberOfPlayers()

        return PlayerCount

    PlayerCount = GetNumberOfPlayers()

    #PlayerCount = 2        # for testing purposes

    def CreatePlayer(Number):
        player = ConsolePlayer()

        player.name = input(
            "Player #%i: What is your name (Leave blank for a random name)? " %
            (Number + 1))

        if player.name.strip() == "":
            player.name = random.choice(defaultNames)
            defaultNames.remove(player.name)
            print(" Player %i's name is %s\n" % (Number + 1, player.name))

        if FreeMode:
            message = "Select %s's cards" % (player.name)
            player.influence = SelectCards(message, True)

            print(" Player %s is holding: %s and %s\n" %
                  (player.name, player.influence[0].name,
                   player.influence[1].name))

        return player

    print("\n")
    for i in range(PlayerCount):
        Players.append(CreatePlayer(i))

    SetupRNG()
    random.shuffle(Players)

    global PlayersAlive
    PlayersAlive = [player for player in Players if player.alive]
Exemplo n.º 9
0
    def reset(self):
        self.name = "Noname"

        self.coins = 2
        self.alive = True

        card1 = GameState.DrawCard()
        card2 = GameState.DrawCard()
        self.influence = [card1, card2]
        #self.influence = [Action, Action]  # for testing purposes

        GameState.PlayerList.append(self)
Exemplo n.º 10
0
    def test_getBlockingActions(self):
        # Foreign Aid
        blockers = GameState.getBlockingActions(action.ForeignAid)
        self.assertIn(action.Duke, blockers)

        # Captain
        blockers = GameState.getBlockingActions(action.Captain)
        self.assertIn(action.Captain, blockers)
        self.assertIn(action.Ambassador, blockers)

        # Assassin
        blockers = GameState.getBlockingActions(action.Assassin)
        self.assertIn(action.Contessa, blockers)
Exemplo n.º 11
0
    def test_getBlockingActions(self):
        # Foreign Aid
        blockers = GameState.getBlockingActions(action.ForeignAid)
        self.assertIn(action.Duke, blockers)

        # Captain
        blockers = GameState.getBlockingActions(action.Captain)
        self.assertIn(action.Captain, blockers)
        self.assertIn(action.Ambassador, blockers)
    
        # Assassin
        blockers = GameState.getBlockingActions(action.Assassin)
        self.assertIn(action.Contessa, blockers)
Exemplo n.º 12
0
    def changeCard(self, card):
        """
        change card to a new card from the player deck. This is called when a card is exposed after a call for bluff.
        """
        if not card in self.influence:
            # todo: create a Coup-specific exception
            raise BaseException(
                "%s is not found in player's influence. Something went wrong" %
                card)

        self.influence.remove(card)
        GameState.AddToDeck(card)

        newCard = GameState.DrawCard()
        self.influence.append(newCard)
Exemplo n.º 13
0
def Setup():
    # How many people are playing?
    # Generate the player list
    # Shuffle the player list    
    GameState.reset()
    SetupActions()
    
    def GetNumberOfPlayers():
        PlayerCount = input("How many players (2-6)? ")
        if not PlayerCount.isnumeric():
            return GetNumberOfPlayers()
        
        PlayerCount = int(PlayerCount)
        if PlayerCount < 2 or PlayerCount > 6:
            return GetNumberOfPlayers()
            
        return PlayerCount
        
    PlayerCount = GetNumberOfPlayers()
    #PlayerCount = 2        # for testing purposes
    
    def CreatePlayer(Number):
        player = ConsolePlayer()
        
        player.name = input("Player #%i: What is your name (Leave blank for a random name)? " % (Number + 1))
                
        if player.name.strip() == "":
            player.name = random.choice(defaultNames)
            defaultNames.remove(player.name)
            print(" Player %i's name is %s\n" % (Number + 1, player.name))
            
        if FreeMode:                
            message = "Select %s's cards" % (player.name)
            player.influence = SelectCards(message, True)
            
            print(" Player %s is holding: %s and %s\n" % (player.name, player.influence[0].name, player.influence[1].name))
                
        return player

    print("\n")
    for i in range(PlayerCount):
        Players.append(CreatePlayer(i))
        
    SetupRNG()
    random.shuffle(Players)

    global PlayersAlive
    PlayersAlive = [player for player in Players if player.alive]
Exemplo n.º 14
0
    def chooseResponse(self, board: GameBoard, state: GameState) -> Action:
        """
        Randomly choose a response between the possible ones.

        :param board:   board of the game
        :param state:   the current state
        :return: the next response to apply
        """
        # choose to respond or not
        if not np.random.choice([True, False]):
            raise ValueError('no response given')

        # choose which figures that can still respond will respond
        figures = state.getFiguresCanRespond(self.team)
        if not figures:
            raise ValueError('no figure can respond')

        f = np.random.choice(figures)

        # build possible response for the chosen unit
        responses = self.gm.buildResponses(board, state, f)

        if responses:
            response = np.random.choice(responses)
            self.store(state, response)
            return response
        else:
            raise ValueError('no response available')
Exemplo n.º 15
0
    def placeFigures(self, board: GameBoard, state: GameState) -> None:
        """
        Random choose the initial position of the figures.

        :param board:   board of the game
        :param state:   the current state
        """
        # select area
        x, y = np.where(state.placement_zone[self.team] > 0)
        figures = state.getFigures(self.team)

        # choose random positions
        indices = np.random.choice(len(x), size=len(figures), replace=False)

        for i in range(len(figures)):
            # move each unit to its position
            figure = figures[i]
            dst = Hex(x[indices[i]], y[indices[i]]).cube()
            state.moveFigure(figure, figure.position, dst)
Exemplo n.º 16
0
    def placeFigures(self, board: GameBoard, state: GameState) -> None:
        """
        Find the initial position for the figure where the state has the best value. The generation of the position is
        done randomly 100 times.

        :param board:   board of the game
        :param state:   the current state
        """
        # select area
        x, y = np.where(state.placement_zone[self.team] > 0)
        figures = state.getFigures(self.team)

        # choose groups of random positions
        indices = [
            np.random.choice(len(x), size=len(figures), replace=False)
            for _ in range(100)
        ]

        scores = []
        s = deepcopy(state)

        for i in range(len(indices)):
            # select a group of positions
            group = indices[i]
            for j in range(len(group)):
                # move each unit to its position
                figure = figures[j]
                dst = Hex(x[group[j]], y[group[j]]).cube()
                s.moveFigure(figure, figure.position, dst)

            score = stateScore(self.team, self.goal_params, board, s)
            scores.append((score, group))

        # choose the better group
        score, group = self.opt(scores)

        for j in range(len(group)):
            figure = figures[j]
            dst = Hex(x[group[j]], y[group[j]]).cube()
            state.moveFigure(figure, dst=dst)

        logger.info(f'{self.team:5}: placed his troops in {group} ({score})')
Exemplo n.º 17
0
    def test_CourtDeck(self):
        """ 
        Tests related to the court deck found in GameState class.
            Card Drawing 
            Drawing card from an empty deck (should raise MajorError)
            Returning card to deck
        """
        GameState.Deck = [action.Income]
        card = GameState.DrawCard()

        self.assertEqual(len(GameState.Deck), 0)
        self.assertEqual(action.Income, card)

        with self.assertRaises(action.MajorError):
            card = GameState.DrawCard()

        GameState.AddToDeck(action.ForeignAid)

        self.assertEqual(len(GameState.Deck), 1)
        self.assertIn(action.ForeignAid, GameState.Deck)
Exemplo n.º 18
0
    def play(self, player, target = None):
        influenceRemaining = len(player.influence)
        choices = list(player.influence)
        
        deckCards = [GameState.DrawCard(), GameState.DrawCard()]
        choices.append(deckCards[0])
        choices.append(deckCards[1])
        
        newInfluence = player.selectAmbassadorInfluence(list(choices), influenceRemaining)
        if type(newInfluence) != list:
            newInfluence = [newInfluence]
        
        def ReturnCards():
            GameState.AddToDeck(deckCards[0])
            GameState.AddToDeck(deckCards[1])
            
        if len(newInfluence) != influenceRemaining:
            # There is a missing card. Try again.
            ReturnCards()
            raise InvalidTarget("Wrong number of cards given")

        choicesCopy = list(choices) # this allow us to test for card duplicates
        for card in newInfluence:
            if not card in choicesCopy:
                # something is wrong. The player sent a card choice that is not part of the original choices.
                # try again.
                ReturnCards()
                raise InvalidTarget("Card given not part of valid choices")
            
            choicesCopy.remove(card)
        
        # give the player their new cards        
        player.influence = list(newInfluence)

        # return the unselected cards back to the Court Deck.
        for card in newInfluence:
            choices.remove(card)
            
        for card in choices:
            GameState.AddToDeck(card)
        return True, "Success"
Exemplo n.º 19
0
    def chooseFigureGroups(self, board: GameBoard, state: GameState) -> None:
        """
        Find the best color that gives the optimal score.

        :param board:   board of the game
        :param state:   the current state
        """
        colors = list(state.choices[self.team].keys())
        scores = []

        for color in colors:
            s = deepcopy(state)
            s.choose(self.team, color)

            score = stateScore(self.team, self.goal_params, board, s)
            scores.append((score, color))

        score, color = self.opt(scores)
        state.choose(self.team, color)

        logger.info(f'{self.team:5}: choose positions color {color}')
Exemplo n.º 20
0
    def setUp(self):
        shape = (16, 16)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.inf_1 = buildFigure('Infantry', (5, 11), RED)
        self.inf_2 = buildFigure('Infantry', (7, 12), RED)

        self.target_1 = buildFigure('Infantry', (3, 13), BLUE)
        self.target_2 = buildFigure('Infantry', (5, 13), BLUE)
        self.target_3 = buildFigure('Infantry', (7, 13), BLUE)
        self.target_4 = buildFigure('Infantry', (9, 13), BLUE)

        self.state.addFigure(
            self.inf_1,
            self.inf_2,
            self.target_1,
            self.target_2,
            self.target_3,
            self.target_4,
        )
Exemplo n.º 21
0
    def setUp(self):
        shape = (16, 16)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.inf_1 = buildFigure('Infantry', (4, 0), RED)
        self.inf_2 = buildFigure('Infantry', (8, 0), BLUE)

        self.state.addFigure(
            self.inf_1,
            self.inf_2,
        )

        self.red = Puppet(RED)
        self.red.action = GM.actionMove(self.board, self.state, self.inf_1, destination=self.inf_1.position)
        self.red.response = GM.actionNoResponse(RED)

        self.blue = Puppet(BLUE)
        self.blue.action = GM.actionMove(self.board, self.state, self.inf_2, destination=self.inf_2.position)
        self.blue.response = GM.actionNoResponse(BLUE)

        self.mm = MatchManager('', self.red, self.blue)
Exemplo n.º 22
0
    def chooseFigureGroups(self, board: GameBoard, state: GameState) -> None:
        """
        Plays a quick game with each color and choose the color with the best score.

        :param board:   board of the game
        :param state:   the current state
        """
        colors = list(state.choices[self.team].keys())

        max_color = None
        max_value = -math.inf

        for color in colors:
            s: GameState = deepcopy(state)
            s.choose(self.team, color)
            score, _ = self.search(board, s)

            if score > max_value:
                max_value = score
                max_color = color

        state.choose(self.team, max_color)
        logging.info(f'{self.team:5}: choose positions color {max_color}')
Exemplo n.º 23
0
    def chooseAction(self, board: GameBoard, state: GameState) -> Action:
        """
        Randomly choose an action between the possible ones.

        :param board:   board of the game
        :param state:   the current state
        :return: the next action to apply
        """
        # choose which figures that can still be activate will be activated
        figures = state.getFiguresCanBeActivated(self.team)
        if not figures:
            raise ValueError(f"no more figures for {self.team}")

        f = np.random.choice(figures)

        moves = self.gm.buildMovements(board, state, f)
        attacks = self.gm.buildAttacks(board, state, f)

        if not moves and not attacks:
            raise ValueError(f"no more moves for {f} {self.team}")

        whatDo = [ACTION_PASS]

        if moves:
            whatDo.append(ACTION_MOVE)
        if attacks:
            whatDo.append(ACTION_ATTACK)

        p = [[1], [0.1, 0.9], [0.1, 0.45, 0.45]]

        # agent chooses type of action
        toa = np.random.choice(whatDo, p=p[len(whatDo) - 1])

        actions = []

        if toa == ACTION_PASS:
            actions = [PassTeam(self.team), PassFigure(f)]

        if toa == ACTION_MOVE:
            actions = moves

        if toa == ACTION_ATTACK:
            actions = attacks
        action = np.random.choice(actions)
        self.store(state, action)

        return action
Exemplo n.º 24
0
    def chooseResponse(self, board: GameBoard, state: GameState) -> Action:
        """
        Choose the best response based on the defined heuristic and optimization function.

        :param board:   board of the game
        :param state:   the current state
        :return: the next response to apply
        """
        scores = [] + self.scorePass(board, state)

        # compute all scores for possible responses
        for figure in state.getFiguresCanBeActivated(self.team):
            scores += self.scoreResponse(board, state, figure)

        # search for action with best score
        score, action = self.opt(scores)

        self.store(state, score, action, scores)

        logger.debug(f'{self.team:5}: {action} ({score})')
        return action
Exemplo n.º 25
0
    def chooseResponse(self, board: GameBoard, state: GameState) -> Action:
        """
        Use the internal ML model to find the best next response to apply. If the randomChoice parameter is true, then
        it finds a random action between the best topn actions.

        :param board:   board of the game
        :param state:   the current state
        :return: the next response to apply
        """
        all_actions = []

        for figure in state.getFiguresCanBeActivated(self.team):
            actions = [self.gm.actionNoResponse(self.team)] + \
                self.gm.buildResponses(board, state, figure)

            all_actions += actions

        if not all_actions:
            logger.warning('No actions available: no response given')
            raise ValueError('No response given')

        scores = self.scores(board, state, all_actions)

        if self.randomChoice:
            bestScore, bestAction = self.bestActionRandom(scores)
        else:
            bestScore, bestAction = self.bestAction(scores)

        if not bestAction:
            logger.warning('No best action found: no response given')
            raise ValueError('No response given')

        self.store(state, bestScore, bestAction, scores)

        logger.debug(
            f'BEST RESPONSE {self.team:5}: {bestAction} ({bestScore})')

        return bestAction
Exemplo n.º 26
0
    def chooseAction(self, board: GameBoard, state: GameState) -> Action:
        """
        Use the internal ML model to find the best next action to apply. If the randomChoice parameter is true, then it
        finds a random action between the best tops actions.

        :param board:   board of the game
        :param state:   the current state
        :return: the next action to apply
        """
        all_actions = []

        for figure in state.getFiguresCanBeActivated(self.team):
            actions = [self.gm.actionPassFigure(figure)] + \
                self.gm.buildAttacks(board, state, figure) + \
                self.gm.buildMovements(board, state, figure)

            all_actions += actions

        if not all_actions:
            logger.warning('No actions available: no action given')
            raise ValueError('No action given')

        scores = self.scores(board, state, all_actions)

        if self.randomChoice:
            bestScore, bestAction = self.bestActionRandom(scores)
        else:
            bestScore, bestAction = self.bestAction(scores)

        self.store(state, bestScore, bestAction, scores)

        if not bestAction:
            logger.warning('No best action found: no action given')
            raise ValueError('No action given')

        return bestAction
Exemplo n.º 27
0
 def play(self, action, target = None):
     """
     1. Check if player is alive. If not, throw exception.
     2. Check if player has at least 12 coins. If they do, throw exception unless coup is played.
     3. Check if any player wants to call bluff from active player
        a. If someone wants to call bluff, do Call step
     4. Check if a player wants to block
        a. If active player wants to call bluff, do Call step (todo: official rules says any play can call bluff. implement later)
     5. Play action if successful
     Call step: If someone call the bluff, reveal card. 
                If card is the action played, remove influence from player.
                Else, remove influence from calling player        
     """        
     if not self.alive or (target != None and not target.alive):
         raise DeadPlayer
         
     if target == self:
         raise TargetRequired
         
     if self.coins < action.coinsNeeded:
         raise NotEnoughCoins(action.coinsNeeded)
     
     if self.coins >= ForceCoupCoins and action != Coup:
         raise ActionNotAllowed("Player has %i coins. Forced Coup is the only allowed action" % (self.coins))
     
     # Step 3
     callingPlayer = None
     
     if action in GameState.CardsAvailable:      # should only call bluff for cards, not common actions
         callingPlayer = GameState.requestCallForBluffs(self, action, target)
         
     if callingPlayer != None:
         # step 4.a
         if action in self.influence:
             # active player is telling the truth. Return the card back to the deck.
             index = self.influence.index(action)
             card = self.influence[index]
             self.influence.remove(card)
             GameState.AddToDeck(card)
             card = GameState.DrawCard()
             self.influence.append(card)
             
             callingPlayer.loseInfluence()
         else:
             self.loseInfluence()
             message = "Bluffing %s failed for %s" % (action.name, self.name)
             return False, message             
     
     # Step 4
     blockingPlayer = None
     
     # should only call bluff for cards, not common actions
     if len(GameState.getBlockingActions(action)):
         blockingPlayer, blockingAction = GameState.requestBlocks(self, action, target)
     
     if blockingPlayer != None:
         # Step 3.a
         if self.confirmCall(blockingPlayer, blockingAction):
             if blockingAction in blockingPlayer.influence:
                 self.loseInfluence()
                 message = "Player %s has %s. Player %s loses influence." % (blockingPlayer.name, blockingAction.name, self.name)
                 blockingPlayer.changeCard(blockingAction)
                 return False, message
             else:
                 blockingPlayer.loseInfluence()
         else:
             message = "Blocked by %s" % blockingPlayer.name
             return False, message
             
     # Step 5
     status, response = action.play(action, self, target)
     return status, response
Exemplo n.º 28
0
class TestGoals(unittest.TestCase):
    def setUp(self):
        shape = (8, 8)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.blue_tank = buildFigure('Tank', (6, 4), BLUE)
        self.red_tank = buildFigure('Tank', (1, 4), RED)
        self.red_inf = buildFigure('Infantry', (2, 4), RED)

        self.state.addFigure(self.red_tank, self.red_inf, self.blue_tank)

    def testEliminateOpponent(self):
        g = GoalEliminateOpponent(RED, BLUE)

        self.assertFalse(g.check(self.state),
                         'before attack, blue unit is still alive!')

        self.blue_tank.killed = True

        self.assertTrue(g.check(self.state),
                        'after attack, blue unit is still alive!')

    def testReachPoint(self):
        x1 = Hex(4, 4).cube()
        x2 = Hex(5, 5).cube()
        g = GoalReachPoint(RED, self.board.shape, [x1.hex()])

        GM.update(self.state)
        self.assertFalse(g.check(self.state),
                         'figure is still in starting position')

        m1 = Move(self.red_tank, [x1])
        m2 = Move(self.red_tank, [x2])

        GM.step(self.board, self.state, m1)
        self.assertFalse(g.check(self.state),
                         'figure moved to goal in this turn')

        GM.step(self.board, self.state, m2)
        self.assertFalse(g.check(self.state), 'figure moved outside of goal')

        GM.step(self.board, self.state, m1)
        self.assertFalse(g.check(self.state),
                         'figure is in position but not not long enough')
        GM.update(self.state)
        self.assertTrue(g.check(self.state),
                        'figure is in position since previous turn')

    def testEndTurn(self):
        g = GoalMaxTurn(RED, 2)

        GM.update(self.state)
        self.assertFalse(g.check(self.state), 'we are still in turn 1!')

        GM.update(self.state)
        self.assertTrue(g.check(self.state), 'we are already in turn 2!')

        GM.update(self.state)
        self.assertTrue(g.check(self.state),
                        'we are in turn 3, game should be ended!')
Exemplo n.º 29
0
def blank(shape) -> (GameBoard, GameState):
    return GameBoard(shape), GameState(shape)
Exemplo n.º 30
0
class TestExecutionFlow(unittest.TestCase):

    def setUp(self):
        shape = (16, 16)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.inf_1 = buildFigure('Infantry', (4, 0), RED)
        self.inf_2 = buildFigure('Infantry', (8, 0), BLUE)

        self.state.addFigure(
            self.inf_1,
            self.inf_2,
        )

        self.red = Puppet(RED)
        self.red.action = GM.actionMove(self.board, self.state, self.inf_1, destination=self.inf_1.position)
        self.red.response = GM.actionNoResponse(RED)

        self.blue = Puppet(BLUE)
        self.blue.action = GM.actionMove(self.board, self.state, self.inf_2, destination=self.inf_2.position)
        self.blue.response = GM.actionNoResponse(BLUE)

        self.mm = MatchManager('', self.red, self.blue)

    def testFlowFromInit(self):
        self.mm.loadState(self.board, self.state)
        step, nextPlayer, _ = self.mm.nextPlayer()
        print(step, nextPlayer)

        self.assertEqual(step, 'round')
        self.assertEqual(nextPlayer, RED)

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()
        print(step, nextPlayer)

        self.assertEqual(step, 'response')
        self.assertEqual(nextPlayer, BLUE)

    def testFlowFromResponse(self):
        response = GM.actionRespond(self.board, self.state, self.inf_2, self.inf_1, self.inf_2.weapons['AR'])
        GM.step(self.board, self.state, response)

        self.mm.loadState(self.board, self.state)
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'round')
        self.assertEqual(nextPlayer, BLUE)

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'response')
        self.assertEqual(nextPlayer, RED)

    def testFlowUpdate(self):
        self.mm.loadState(self.board, self.state)
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'round')
        self.assertEqual(nextPlayer, RED)

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'response')
        self.assertEqual(nextPlayer, BLUE)

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'round')
        self.assertEqual(nextPlayer, BLUE)

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'response')
        self.assertEqual(nextPlayer, RED)

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'update')

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'round')
        self.assertEqual(nextPlayer, RED)

        self.mm.step()
        step, nextPlayer, _ = self.mm.nextPlayer()

        self.assertEqual(step, 'response')
        self.assertEqual(nextPlayer, BLUE)
Exemplo n.º 31
0
class TestFigures(unittest.TestCase):
    def setUp(self):
        shape = (16, 16)
        self.board = GameBoard(shape)
        self.state = GameState(shape)

        self.inf_1 = buildFigure('Infantry', (5, 11), RED)
        self.inf_2 = buildFigure('Infantry', (7, 12), RED)

        self.target_1 = buildFigure('Infantry', (3, 13), BLUE)
        self.target_2 = buildFigure('Infantry', (5, 13), BLUE)
        self.target_3 = buildFigure('Infantry', (7, 13), BLUE)
        self.target_4 = buildFigure('Infantry', (9, 13), BLUE)

        self.state.addFigure(
            self.inf_1,
            self.inf_2,
            self.target_1,
            self.target_2,
            self.target_3,
            self.target_4,
        )

    def testAttackAndResponse(self):
        # check default status
        self.assertFalse(self.inf_1.activated)
        self.assertFalse(self.inf_1.responded)
        self.assertFalse(self.inf_2.activated)
        self.assertFalse(self.inf_2.responded)

        a1 = GM.actionAttack(self.board, self.state, self.inf_1, self.target_1,
                             self.inf_1.weapons['AR'])
        r1 = GM.actionRespond(self.board, self.state, self.inf_1,
                              self.target_2, self.inf_1.weapons['AR'])
        r2 = GM.actionRespond(self.board, self.state, self.inf_2,
                              self.target_3, self.inf_1.weapons['AR'])

        # check that attack activate unit
        GM.step(self.board, self.state, a1)

        self.assertTrue(self.inf_1.activated, 'unit should be activated')
        self.assertFalse(self.inf_1.responded,
                         'unit should not have responded')

        # check that unit can be both activated and responded
        GM.step(self.board, self.state, r1)

        self.assertTrue(self.inf_1.activated, 'unit should be activated')
        self.assertTrue(self.inf_1.responded, 'unit should have responded')

        # check that response does not activate the unit
        GM.step(self.board, self.state, r2)

        self.assertFalse(self.inf_2.activated, 'unit should not be activated')
        self.assertTrue(self.inf_2.responded, 'unit should have responded')

    def testMoveAndResponse(self):
        # check default status
        self.assertFalse(self.inf_1.activated)
        self.assertFalse(self.inf_1.responded)
        self.assertFalse(self.inf_2.activated)
        self.assertFalse(self.inf_2.responded)

        dst1 = Hex(5, 12).cube()
        dst2 = Hex(8, 12).cube()

        m1 = GM.actionMove(self.board,
                           self.state,
                           self.inf_1,
                           destination=dst1)
        r1 = GM.actionRespond(self.board, self.state, self.inf_1,
                              self.target_2, self.inf_1.weapons['AR'])
        m2 = GM.actionMove(self.board,
                           self.state,
                           self.inf_2,
                           destination=dst2)
        r2 = GM.actionRespond(self.board, self.state, self.inf_2,
                              self.target_3, self.inf_1.weapons['AR'])

        # check that attack activate unit
        GM.step(self.board, self.state, m1)

        self.assertTrue(self.inf_1.activated, 'unit should be activated')
        self.assertFalse(self.inf_1.responded,
                         'unit should not have responded')

        # check that unit can responded after move
        GM.step(self.board, self.state, r1)

        self.assertTrue(self.inf_1.activated, 'unit should be activated')
        self.assertTrue(self.inf_1.responded, 'unit should have responded')

        # check that response does not activate the unit
        GM.step(self.board, self.state, r2)

        self.assertFalse(self.inf_2.activated, 'unit should not be activated')
        self.assertTrue(self.inf_2.responded, 'unit should have responded')

        # check that unit can move after response
        GM.step(self.board, self.state, m2)

        self.assertTrue(self.inf_2.activated, 'unit should be activated')
        self.assertTrue(self.inf_2.responded, 'unit should have responded')

    def testPassAndResponse(self):
        # check default status
        self.assertFalse(self.inf_1.activated)
        self.assertFalse(self.inf_1.responded)
        self.assertFalse(self.inf_2.activated)
        self.assertFalse(self.inf_2.responded)

        p1 = GM.actionPassFigure(self.inf_1)
        r1 = GM.actionRespond(self.board, self.state, self.inf_1,
                              self.target_2, self.inf_1.weapons['AR'])
        p2 = GM.actionPassFigure(self.inf_2)
        r2 = GM.actionRespond(self.board, self.state, self.inf_2,
                              self.target_3, self.inf_1.weapons['AR'])

        # check that attack activate unit
        GM.step(self.board, self.state, p1)

        self.assertTrue(self.inf_1.activated, 'unit should be activated')
        self.assertFalse(self.inf_1.responded,
                         'unit should not have responded')

        # check that unit can responded after move
        GM.step(self.board, self.state, r1)

        self.assertTrue(self.inf_1.activated, 'unit should be activated')
        self.assertTrue(self.inf_1.responded, 'unit should have responded')

        # check that response does not activate the unit
        GM.step(self.board, self.state, r2)

        self.assertFalse(self.inf_2.activated, 'unit should not be activated')
        self.assertTrue(self.inf_2.responded, 'unit should have responded')

        # check that unit can move after response
        GM.step(self.board, self.state, p2)

        self.assertTrue(self.inf_2.activated, 'unit should be activated')
        self.assertTrue(self.inf_2.responded, 'unit should have responded')
Exemplo n.º 32
0
    def play(self, action, target=None):
        """
        1. Check if player is alive. If not, throw exception.
        2. Check if player has at least 12 coins. If they do, throw exception unless coup is played.
        3. Check if any player wants to call bluff from active player
           a. If someone wants to call bluff, do Call step
        4. Check if a player wants to block
           a. If active player wants to call bluff, do Call step (todo: official rules says any play can call bluff. implement later)
        5. Play action if successful
        Call step: If someone call the bluff, reveal card. 
                   If card is the action played, remove influence from player.
                   Else, remove influence from calling player        
        """
        if not self.alive or (target != None and not target.alive):
            raise DeadPlayer

        if target == self:
            raise TargetRequired

        if self.coins < action.coinsNeeded:
            raise NotEnoughCoins(action.coinsNeeded)

        if self.coins >= ForceCoupCoins and action != Coup:
            raise ActionNotAllowed(
                "Player has %i coins. Forced Coup is the only allowed action" %
                (self.coins))

        # Step 3
        callingPlayer = None

        if action in GameState.CardsAvailable:  # should only call bluff for cards, not common actions
            callingPlayer = GameState.requestCallForBluffs(
                self, action, target)

        if callingPlayer != None:
            # step 4.a
            if action in self.influence:
                # active player is telling the truth. Return the card back to the deck.
                index = self.influence.index(action)
                card = self.influence[index]
                self.influence.remove(card)
                GameState.AddToDeck(card)
                card = GameState.DrawCard()
                self.influence.append(card)

                callingPlayer.loseInfluence()
            else:
                self.loseInfluence()
                message = "Bluffing %s failed for %s" % (action.name,
                                                         self.name)
                return False, message

        # Step 4
        blockingPlayer = None

        # should only call bluff for cards, not common actions
        if len(GameState.getBlockingActions(action)):
            blockingPlayer, blockingAction = GameState.requestBlocks(
                self, action, target)

        if blockingPlayer != None:
            # Step 3.a
            if self.confirmCall(blockingPlayer, blockingAction):
                if blockingAction in blockingPlayer.influence:
                    self.loseInfluence()
                    message = "Player %s has %s. Player %s loses influence." % (
                        blockingPlayer.name, blockingAction.name, self.name)
                    blockingPlayer.changeCard(blockingAction)
                    return False, message
                else:
                    blockingPlayer.loseInfluence()
            else:
                message = "Blocked by %s" % blockingPlayer.name
                return False, message

        # Step 5
        status, response = action.play(action, self, target)
        return status, response
Exemplo n.º 33
0
 def setUp(self):
     GameState.reset()
     GameState.PlayerList = []
     self.player = Player()        
Exemplo n.º 34
0
    def nextAction(self, board: GameBoard, state: GameState,
                   data: dict) -> None:
        """
        Parse the given data structure in order to get the next action.

        :param board:       board of the game
        :param state:       current state of the game
        :param data:        data received from a human through the web interface
        """
        action = data['action']
        self._clear()

        if action == 'choose':
            self.color = data['color']
            return

        if action == 'place':
            idx = int(data['idx'])
            x = int(data['x'])
            y = int(data['y'])
            pos = Hex(x, y).cube()

            self.place[idx] = pos
            return

        if action == 'wait':
            self.next_action = self.gm.actionWait(self.team)
            return

        if action == 'pass':
            if 'idx' in data and data['team'] == self.team:
                idx = int(data['idx'])
                figure = state.getFigureByIndex(self.team, idx)
                self.next_action = self.gm.actionPassFigure(figure)
            elif data['step'] == 'respond':
                self.next_action = self.gm.actionNoResponse(self.team)
            else:
                self.next_action = self.gm.actionPassTeam(self.team)
            return

        idx = int(data['idx'])
        x = int(data['x'])
        y = int(data['y'])
        pos = Hex(x, y).cube()

        figure = state.getFigureByIndex(self.team, idx)

        if figure.responded and data['step'] == 'respond':
            raise ValueError('Unit has already responded!')

        if figure.activated and data['step'] in ('round', 'move'):
            raise ValueError('Unit has already been activated!')

        if action == 'move':
            fs = state.getFiguresByPos(self.team, pos)
            for transport in fs:
                if transport.canTransport(figure):
                    self.next_action = self.gm.actionLoadInto(
                        board, state, figure, transport)
                    return

            self.next_action = self.gm.actionMove(board,
                                                  state,
                                                  figure,
                                                  destination=pos)
            return

        if action == 'attack':
            w = data['weapon']
            weapon = figure.weapons[w]

            if 'targetTeam' in data:
                targetTeam = data['targetTeam']
                targetIdx = int(data['targetIdx'])
                target = state.getFigureByIndex(targetTeam, targetIdx)

            else:
                otherTeam = BLUE if self.team == RED else RED
                target = state.getFiguresByPos(otherTeam, pos)[
                    0]  # TODO: get unit based on index or weapon target type

            self.next_action = self.gm.actionAttack(board, state, figure,
                                                    target, weapon)
            self.next_response = self.gm.actionRespond(board, state, figure,
                                                       target, weapon)
Exemplo n.º 35
0
 def ReturnCards():
     GameState.AddToDeck(deckCards[0])
     GameState.AddToDeck(deckCards[1])