示例#1
0
 def test_is_playable_discard(self):
     """move.is_playable returns true so long as there's a card in that player's hand at that index."""
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.player_hands = [['card0', 'card1', 'card2', 'card3'],
                                    ['card4', 'card5', 'card6']]
     move = Move(move_type='discard', player_index=0, card_index=3)
     assert move.is_playable(mock_gamestate) is True
示例#2
0
 def test_is_playable_discard_bad_index_fails(self):
     """move.is_playable returns false when there's no card in that player's hand at that index."""
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.player_hands = [['card0', 'card1', 'card2'],
                                    ['card3', 'card4', 'card5', 'card6']]
     move = Move(move_type='discard', player_index=0, card_index=-1)
     assert move.is_playable(mock_gamestate) is False
示例#3
0
def construct_all_legal_moves(game_state):
    moves = []
    my_hand = game_state.get_my_hand()
    # all discards and all plays
    for card_index in range(len(my_hand)):
        moves.append(Move('discard', game_state.player_id, card_index=card_index))
        moves.append(Move('play', game_state.player_id, card_index=card_index))

    # all information that could be given
    # Ensure info tokens exist before we bother constructing info moves
    if game_state.board.clock_tokens > 0:
        for pid in range(len(game_state.player_hands)):
            if pid != game_state.player_id:
                card_colors = set([])
                card_numbers = set([])
                hand = game_state.player_hands[pid]
                for card_index in range(len(hand)):
                    card_colors.add(hand[card_index].color)
                    card_numbers.add(hand[card_index].number)
                for color in card_colors:
                    moves.append(Move('give_information',
                                      game_state.player_id,
                                      information={'player_id': pid,
                                                   'information_type': 'color',
                                                   'information': color}))
                for number in card_numbers:
                    moves.append(Move('give_information',
                                      game_state.player_id,
                                      information={'player_id': pid,
                                                   'information_type': 'number',
                                                   'information': number}))

    return moves
示例#4
0
 def test_apply_give_information_number_multiple_cards(self):
     """Give information (number) should:
         call make_public('number') on all cards with that number in a hand
         call board.use_clock_token()
     """
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_gamestate.board.clock_tokens = 1
     mock_card = create_autospec(Card)
     mock_card.number = 2
     mock_card_other_number = create_autospec(Card)
     mock_card_other_number.number = 4
     mock_gamestate.player_hands = [[
         mock_card_other_number, mock_card, mock_card_other_number
     ], [mock_card, mock_card_other_number, mock_card]]
     info_dict = {
         'player_id': 1,
         'information_type': 'number',
         'information': 2
     }
     move = Move(move_type='give_information',
                 player_index=0,
                 information=info_dict)
     mock_gamestate = move.apply(game_state=mock_gamestate)
     mock_card.make_public.assert_called_with('number')
     assert mock_card.make_public.call_count == 2
     mock_gamestate.board.use_clock_token.assert_called_once()
示例#5
0
 def test_apply_give_information_color_once(self):
     """Give information (color) should:
         call make_public('color') on all cards with that color in a hand
         call board.use_clock_token()
     """
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_gamestate.board.clock_tokens = 2
     mock_card = create_autospec(Card)
     mock_card.color = 'blue'
     mock_card_other_colors = create_autospec(Card)
     mock_card_other_colors.color = 'red'
     mock_gamestate.player_hands = [[
         mock_card_other_colors, mock_card_other_colors, mock_card,
         mock_card
     ], [mock_card, mock_card_other_colors]]
     info_dict = {
         'player_id': 1,
         'information_type': 'color',
         'information': 'blue'
     }
     move = Move(move_type='give_information',
                 player_index=0,
                 information=info_dict)
     mock_gamestate = move.apply(game_state=mock_gamestate)
     mock_card.make_public.assert_called_once_with('color')
     mock_gamestate.board.use_clock_token.assert_called_once()
示例#6
0
    def construct_move(self, game_state):
        move_type = None
        while move_type not in ('play', 'discard', 'give_information'):
            move_type = raw_input(
                "Please enter 'play', 'discard', or 'give_information':")
        if move_type in ('play', 'discard'):
            card_index = None
            while card_index not in [
                    str(i) for i in range(
                        len(game_state.player_hands[game_state.get_my_id()]))
            ]:
                print("Your current hand: " +
                      str(game_state.player_hands[game_state.get_my_id()]))
                card_index = raw_input(
                    "Please specify the index of the card you'd like to " +
                    move_type + ":")
            return Move(move_type,
                        game_state.get_my_id(),
                        card_index=int(card_index))
        else:
            player_id = False
            information_type = False
            information = False
            while player_id not in [
                    str(i) for i in range(len(game_state.player_hands))
            ] or player_id == str(game_state.get_my_id()):
                player_id = raw_input(
                    "Which player would you like to give information?")
            print("Player {pid}'s hand: {hand}".format(
                pid=player_id,
                hand=str(game_state.player_hands[int(player_id)])))

            while information_type not in ('number', 'color'):
                information_type = raw_input(
                    "Would you like to share a number or a color?")

            if information_type == 'number':
                while information not in ['1', '2', '3', '4', '5']:
                    information = raw_input(
                        "Enter the number you would like to reveal.")
                return Move(move_type,
                            game_state.get_my_id(),
                            information={
                                'player_id': int(player_id),
                                'information_type': information_type,
                                'information': int(information)
                            })
            else:
                while information not in game_state.board.deck_colors:
                    information = raw_input("Enter a color from {c}".format(
                        c=game_state.board.deck_colors))
                return Move(move_type,
                            game_state.get_my_id(),
                            information={
                                'player_id': int(player_id),
                                'information_type': information_type,
                                'information': information
                            })
示例#7
0
 def test_apply_bad_move_fails(self):
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.player_hands = [['card0', 'card1', 'card2'],
                                    ['card3', 'card4', 'card5', 'card6']]
     move = Move(move_type='discard', player_index=0, card_index=-1)
     with pytest.raises(AssertionError) as excinfo:
         move.apply(mock_gamestate)
     assert str(
         excinfo.value
     ) == 'Cannot apply move discard card index -1 in their hand, not playable.'
示例#8
0
 def get_valid_moves(self, board):
     # Prevents future calls appending to the same array
     self.valid_moves = []
     m = self._magnitude()
     if (board.get_piece_at(self.x, self.y + m) == None):
         self._append_valid_move(board, Move(self, T(0, m, 1)))
     if (not self.has_moved):
         self._append_valid_move(board, Move(self, T(0, m, 2)))
     if (board.get_piece_at(self.x + 1, self.y + m) != None):
         self._append_valid_move(board, Move(self, T(1, m, 1)))
     if (board.get_piece_at(self.x - 1, self.y + m) != None):
         self._append_valid_move(board, Move(self, T(-1, m, 1)))
     return self.valid_moves
示例#9
0
 def test_apply_discard(self):
     """Discard should remove a card from the player's hand, add it to the discard pile and add back a clock token."""
     mock_gamestate = create_autospec(GameState)
     mock_card = create_autospec(Card)
     mock_card_for_discard = create_autospec(Card)
     mock_gamestate.player_hands = [[mock_card],
                                    [mock_card, mock_card_for_discard]]
     mock_gamestate.board = create_autospec(Board)
     move = Move(move_type='discard', player_index=1, card_index=1)
     mock_gamestate = move.apply(game_state=mock_gamestate)
     assert len(mock_gamestate.player_hands[1]) == 1
     mock_gamestate.board.discard_card.assert_called_with(
         mock_card_for_discard)
     mock_gamestate.board.add_clock_token.assert_called_once()
示例#10
0
 def test_is_playable_information_give_self_information_fails(self):
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_gamestate.board.clock_tokens = 1
     mock_card = create_autospec(Card)
     mock_card.number = 2
     mock_gamestate.player_hands = [[mock_card, mock_card, mock_card],
                                    [mock_card, mock_card, mock_card]]
     info_dict = {
         'player_id': 0,
         'information_type': 'number',
         'information': 2
     }
     move = Move(move_type='give_information',
                 player_index=0,
                 information=info_dict)
     assert move.is_playable(mock_gamestate) is False
示例#11
0
 def test_is_playable_information_bad_information_type_fails(self):
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_gamestate.board.clock_tokens = 1
     mock_card = create_autospec(Card)
     mock_card.number = 2
     mock_gamestate.player_hands = [[
         'is_playable should', 'not look at players cards'
     ], [mock_card, mock_card, mock_card]]
     info_dict = {
         'player_id': 1,
         'information_type': 'board talk is for cheaters',
         'information': 2
     }
     move = Move(move_type='give_information',
                 player_index=0,
                 information=info_dict)
     assert move.is_playable(mock_gamestate) is False
示例#12
0
 def test_is_playable_information_no_clock_tokens(self):
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_card = create_autospec(Card)
     mock_card.number = 2
     mock_gamestate.player_hands = [[
         'is_playable should', 'not look at players cards'
     ], [mock_card, mock_card, mock_card]]
     mock_gamestate.board.clock_tokens = 0
     info_dict = {
         'player_id': 0,
         'information_type': 'number',
         'information': 2
     }
     move = Move(move_type='give_information',
                 player_index=1,
                 information=info_dict)
     assert move.is_playable(mock_gamestate) is False
示例#13
0
 def test_apply_play_blow_fuse(self):
     """Play (blow fuse) should discard the card marked for play and call board.use_fuse_token"""
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_card = create_autospec(Card)
     mock_card_for_play = create_autospec(Card)
     mock_card_for_play.color = 'red'
     mock_gamestate.player_hands = [[mock_card],
                                    [mock_card_for_play, mock_card]]
     mock_stack = create_autospec(CardStack)
     mock_stack.is_legal_play.return_value = False
     mock_gamestate.board.get_card_stack.return_value = mock_stack
     move = Move(move_type='play', player_index=1, card_index=0)
     mock_gamestate = move.apply(game_state=mock_gamestate)
     mock_gamestate.board.get_card_stack.assert_called_with('red')
     assert len(mock_gamestate.player_hands[1]) == 1
     mock_gamestate.board.use_fuse_token.assert_called_once()
     mock_gamestate.board.discard_card.assert_called_with(
         mock_card_for_play)
示例#14
0
 def test_is_playable_information_number_subset_of_cards(self):
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_gamestate.board.clock_tokens = 1
     mock_card = create_autospec(Card)
     mock_card.number = 2
     mock_card_not_two = create_autospec(Card)
     mock_card_not_two.number = 4
     mock_gamestate.player_hands = [[
         'is_playable should', 'not look at players cards'
     ], [mock_card_not_two, mock_card, mock_card_not_two, mock_card]]
     info_dict = {
         'player_id': 1,
         'information_type': 'number',
         'information': 2
     }
     move = Move(move_type='give_information',
                 player_index=0,
                 information=info_dict)
     assert move.is_playable(mock_gamestate)
示例#15
0
    def test_hash(self):
        a = Move()
        a.positions = ['A', 'B', 'C']

        b = Move()
        b.positions = ['A', 'B', 'C']

        self.assert_(hash(a) == hash(b))

        b.horizontal = False
        self.assert_(not hash(a) == hash(b))

        b.positions = ['A', 'B', 'D']
        self.assert_(not hash(a) == hash(b))

        b.horizontal = True
        self.assert_(not hash(a) == hash(b))

        b.positions = ['B', 'C', 'A']
        self.assert_(hash(a) == hash(b))
示例#16
0
 def test_is_playable_information_color(self):
     mock_gamestate = create_autospec(GameState)
     mock_gamestate.board = create_autospec(Board)
     mock_gamestate.board.clock_tokens = 1
     mock_card = create_autospec(Card)
     mock_card.color = 'blue'
     mock_gamestate.player_hands = [[mock_card, mock_card],
                                    [
                                        'is_playable should',
                                        'not look at players cards'
                                    ]]
     info_dict = {
         'player_id': 0,
         'information_type': 'color',
         'information': 'blue'
     }
     move = Move(move_type='give_information',
                 player_index=1,
                 information=info_dict)
     assert move.is_playable(mock_gamestate)
示例#17
0
    def test_equality(self):
        a = Move()
        a.positions = ['A', (1, 2, 3)]

        b = Move()
        b.positions = ['A', (1, 2, 3)]

        self.assert_(a == b)

        b.positions = [(1, 2, 3), 'A']
        self.assert_(a == b)

        b.horizontal = False
        self.assert_(not a == b)

        b.positions = ['A', (1, 2)]
        self.assert_(not a == b)

        b.horizontal = True
        self.assert_(not a == b)
示例#18
0
    def test_apply_play_successful_play_complete_stack(self):
        """Play (successful) should 
                  remove the card from hand, 
                  add it to the stack of the right color, 
                  call board.add_clock_token
          """
        mock_gamestate = create_autospec(GameState)
        mock_gamestate.board = create_autospec(Board)
        mock_card = create_autospec(Card)
        mock_card_for_play = create_autospec(Card)
        mock_card_for_play.color = 'green'
        mock_gamestate.player_hands = [[mock_card],
                                       [mock_card_for_play, mock_card]]
        mock_stack = create_autospec(CardStack)
        mock_stack.is_legal_play.return_value = True
        mock_stack.is_complete.return_value = True
        mock_gamestate.board.get_card_stack.return_value = mock_stack
        move = Move(move_type='play', player_index=1, card_index=0)
        mock_gamestate = move.apply(game_state=mock_gamestate)

        mock_gamestate.board.get_card_stack.assert_called_with('green')
        mock_stack.play.assert_called_with(mock_card_for_play)
        assert len(mock_gamestate.player_hands[1]) == 1
        mock_gamestate.board.add_clock_token.assert_called_once()
示例#19
0
 def get_valid_moves(self, board):
     # Prevents future calls appending to the same array
     self.valid_moves = []
     transforms = [
         T(1, 2, 1),
         T(2, 1, 1),
         T(2, -1, 1),
         T(1, -2, 1),
         T(-1, -2, 1),
         T(-2, -1, 1),
         T(-2, 1, 1),
         T(-1, 2, 1)
     ]
     for t in transforms:
         self._append_valid_move(board, Move(self, t))
     return self.valid_moves
示例#20
0
    def test_add_letter(self):
        m = Move()
        m.add_letter('a', (0, 0))

        self.assertEqual(m.positions[0].letter, 'a')
        self.assertEqual(m.positions[0].pos, (0, 0))

        m.add_letter('b', (1, 1))

        self.assertEqual(m.positions[1].letter, 'b')
        self.assertEqual(m.positions[1].pos, (1, 1))
示例#21
0
    def test_deepcopy(self):
        m = Move()

        m.add_letter('A', (0, 1))
        m.add_letter('B', (0, 0))

        m.drawn = ['A', 'B', 'C']

        exp_pos = deepcopy(m.positions)
        exp_drawn = deepcopy(m.drawn)

        m2 = deepcopy(m)

        m.drawn[2] = 'D'
        m.positions[0] = ('D', (7, 7))

        self.assertEqual(exp_pos, m2.positions)
        self.assertEqual(exp_drawn, m2.drawn)
示例#22
0
def parse_cross_set(filename):
    with open(filename, 'r') as f:
        lines = map(lambda s: s.rstrip(), f.readlines())

    lines = filter(lambda s: len(s) > 0 and not s.startswith('!:'), lines)
    i = 0
    while i < len(lines):
        line = lines[i]
        board = []
        if line != 'BEGIN BOARD':
            raise IOError('Improperly formatted scenario file, line %d: expected BEGIN BOARD.' % i)

        i += 1
        line = lines[i]
        while line != 'END BOARD':
            board.append(list(line))
            i += 1
            line = lines[i]

        if len(board) == 0:
            board = deepcopy(default_board)

        i += 1
        candidate_letters = lines[i]

        i += 1
        r_match = re.match(r'^(\d+), (\d+)$', lines[i])
        if not r_match:
            raise IOError('Improperly formatted scenario file, line %d: candidate position.' % i)
        candidate_pos = tuple(map(int, r_match.groups()))

        i += 1
        if lines[i] == 'H':
            candidate_dir = True
        elif lines[i] == 'V':
            candidate_dir = False
        else:
            raise IOError('Improperly formatted scenario file, line %d: candidate direction.' % i)

        i += 1  # Increment before beginning of next iteration
        line = lines[i]
        if line != 'BEGIN CROSSES':
            raise IOError('Improperly formatted scenario file, line %d: expected BEGIN CROSSES.' % i)

        i += 1
        line = lines[i]
        crosses = []
        while line != 'END CROSSES':
            cross = {}

            r_match = re.match(r'^(\d+), (\d+)$', line)
            if not r_match:
                raise IOError('Improperly formatted scenario file, line %d: cross position.' % i)

            cross['x'], cross['y'] = tuple(map(int, r_match.groups()))

            i += 1
            line = lines[i]
            if line[0] == '-':
                cross['horizontal'] = True
            elif line[0] == '|':
                cross['horizontal'] = False
            else:
                raise IOError('Improperly formatted scenario file, line %d: cross direction.' % i)

            i += 1
            line = lines[i]
            if line == '/':
                cross['letters'] = set()
            else:
                cross['letters'] = set(line)

            crosses.append(cross)
            i += 1
            line = lines[i]

        candidate = Move()

        offset = 0
        for j, letter in enumerate(candidate_letters):
            if candidate_dir:
                x, y = candidate_pos[0], candidate_pos[1] + j + offset
                while y < len(board[x]) and board[x][y] not in empty_locations:
                    offset += 1
                    y += 1
                candidate.positions.append(BoardPosition(letter, (x, y)))
            else:
                x, y = candidate_pos[0] + j + offset, candidate_pos[1]
                while x < len(board) and board[x][y] not in empty_locations:
                    offset += 1
                    x += 1
                candidate.positions.append(BoardPosition(letter, (x, y)))
        candidate.horizontal = candidate_dir

        yield {'board': board, 'candidate': candidate, 'crosses': crosses}
        i += 1
示例#23
0
    def test_sort_letters(self):
        m = Move()
        m.add_letter('a', (0, 1))
        m.add_letter('b', (0, 0))

        m.sort_letters()

        self.assertEqual('b', m.positions[0].letter)
        self.assertEqual((0, 0), m.positions[0].pos)

        self.assertEqual('a', m.positions[1].letter)
        self.assertEqual((0, 1), m.positions[1].pos)

        m = Move()
        m.horizontal = False
        m.add_letter('a', (1, 0))
        m.add_letter('b', (0, 0))

        m.sort_letters()

        self.assertEqual('b', m.positions[0].letter)
        self.assertEqual((0, 0), m.positions[0].pos)

        self.assertEqual('a', m.positions[1].letter)
        self.assertEqual((1, 0), m.positions[1].pos)
示例#24
0
    def test_constructor(self):
        m = Move()

        self.assertEqual(m.score, 0)
        self.assert_(not m.positions)
        self.assert_(not m.drawn)
示例#25
0
def parse_scenario(filename):
    with open(filename, 'r') as f:
        lines = map(lambda s: s.rstrip(), f.readlines())

    lines = filter(lambda s: len(s) > 0 and not s.startswith('!:'), lines)
    i = 0
    while i < len(lines):
        line = lines[i]
        board = []
        if line != 'BEGIN BOARD':
            raise IOError(
                'Improperly formatted scenario file, line %d: expected BEGIN BOARD.'
                % i)

        i += 1
        line = lines[i]
        while line != 'END BOARD':
            board.append(list(line))
            i += 1
            line = lines[i]

        if len(board) == 0:
            board = deepcopy(default_board)

        i += 1
        candidate_letters = lines[i]

        i += 1
        r_match = re.match(r'^(\d+), (\d+)$', lines[i])
        if not r_match:
            raise IOError(
                'Improperly formatted scenario file, line %d: candidate position.'
                % i)
        candidate_pos = tuple(map(int, r_match.groups()))

        i += 1
        if lines[i] == 'H':
            candidate_dir = True
        elif lines[i] == 'V':
            candidate_dir = False
        else:
            raise IOError(
                'Improperly formatted scenario file, line %d: candidate direction.'
                % i)

        i += 1
        j = int(lines[i])
        if j == 1:
            exp_result = True
        elif j == 0:
            exp_result = False
        else:
            raise IOError(
                'Improperly formatted scenario file, line %d: expected result.'
                % i)

        exp_score = -1
        if exp_result:
            i += 1
            exp_score = int(lines[i])

        i += 1  # Increment before beginning of next iteration
        candidate = Move()

        offset = 0
        for j, letter in enumerate(candidate_letters):
            if candidate_dir:
                x, y = candidate_pos[0], candidate_pos[1] + j + offset
                while y < len(board[x]) and board[x][y] not in empty_locations:
                    offset += 1
                    y += 1
                candidate.positions.append(BoardPosition(letter, (x, y)))
            else:
                x, y = candidate_pos[0] + j + offset, candidate_pos[1]
                while x < len(board) and board[x][y] not in empty_locations:
                    offset += 1
                    x += 1
                candidate.positions.append(BoardPosition(letter, (x, y)))
        candidate.horizontal = candidate_dir

        yield {
            'board': board,
            'candidate': candidate,
            'result': exp_result,
            'score': exp_score
        }
示例#26
0
 def _moves_in_direction(self, board, direction):
     moves = []
     for i in range(8):
         moves.append(Move(self, T(direction[0], direction[1], i + 1)))
     return moves
示例#27
0
 def test_create_bad_move_type(self):
     with pytest.raises(ValueError) as exinfo:
         Move(move_type='cheat', player_index=0)
     assert str(
         exinfo.value
     ) == 'Moves must either play, discard, or share information.'
示例#28
0
 def test_create_bad_move_info(self):
     with pytest.raises(AssertionError):
         info_dict = {'has_no_useful_keys': 'or values!'}
         Move(move_type='give_information',
              player_index=0,
              information=info_dict)
示例#29
0
def parse_scenario(filename):
    with open(filename, 'r') as f:
        lines = map(lambda s: s.rstrip(), f.readlines())

    lines = filter(lambda s: len(s) > 0 and not s.startswith('!:'), lines)
    i = 0
    while i < len(lines):
        line = lines[i]
        board = []
        if line != 'BEGIN BOARD':
            raise IOError('Improperly formatted scenario file, line %d: expected BEGIN BOARD.' % i)

        i += 1
        line = lines[i]
        while line != 'END BOARD':
            board.append(list(line))
            i += 1
            line = lines[i]

        if len(board) == 0:
            board = deepcopy(default_board)

        i += 1
        candidate_letters = lines[i]

        i += 1
        r_match = re.match(r'^(\d+), (\d+)$', lines[i])
        if not r_match:
            raise IOError('Improperly formatted scenario file, line %d: candidate position.' % i)
        candidate_pos = tuple(map(int, r_match.groups()))

        i += 1
        if lines[i] == 'H':
            candidate_dir = True
        elif lines[i] == 'V':
            candidate_dir = False
        else:
            raise IOError('Improperly formatted scenario file, line %d: candidate direction.' % i)

        i += 1
        j = int(lines[i])
        if j == 1:
            exp_result = True
        elif j == 0:
            exp_result = False
        else:
            raise IOError('Improperly formatted scenario file, line %d: expected result.' % i)

        exp_score = -1
        if exp_result:
            i += 1
            exp_score = int(lines[i])

        i += 1  # Increment before beginning of next iteration
        candidate = Move()

        offset = 0
        for j, letter in enumerate(candidate_letters):
            if candidate_dir:
                x, y = candidate_pos[0], candidate_pos[1] + j + offset
                while y < len(board[x]) and board[x][y] not in empty_locations:
                    offset += 1
                    y += 1
                candidate.positions.append(BoardPosition(letter, (x, y)))
            else:
                x, y = candidate_pos[0] + j + offset, candidate_pos[1]
                while x < len(board) and board[x][y] not in empty_locations:
                    offset += 1
                    x += 1
                candidate.positions.append(BoardPosition(letter, (x, y)))
        candidate.horizontal = candidate_dir

        yield {'board': board, 'candidate': candidate, 'result': exp_result, 'score': exp_score}