def test_apply_gravity(): b = Board(9, 3, 2) b._board = [[ Position.PLAYER1, Position.PLAYER2, Position.PLAYER1, Position.PLAYER2, Position.PLAYER1, Position.PLAYER2, Position.FILLED, Position.FILLED, Position.FILLED ], [ Position.EMPTY, Position.EMPTY, Position.EMPTY, Position.EMPTY, Position.FILLED, Position.FILLED, Position.FILLED, Position.FILLED, Position.FILLED ], [ Position.EMPTY, Position.EMPTY, Position.FILLED, Position.FILLED, Position.FILLED, Position.FILLED, Position.PLAYER1, Position.PLAYER2, Position.FILLED ]] b._apply_gravity() assert b._board == [[ Position.EMPTY, Position.EMPTY, Position.EMPTY, Position.EMPTY, Position.PLAYER1, Position.PLAYER2, Position.FILLED, Position.FILLED, Position.FILLED ], [ Position.EMPTY, Position.EMPTY, Position.PLAYER1, Position.PLAYER2, Position.FILLED, Position.FILLED, Position.FILLED, Position.FILLED, Position.FILLED ], [ Position.PLAYER1, Position.PLAYER2, Position.FILLED, Position.FILLED, Position.FILLED, Position.FILLED, Position.PLAYER1, Position.PLAYER2, Position.FILLED ]]
def __init__(self, width, height, units_per_side): self._board = Board(width, height, units_per_side) self._player1_score = 0 self._player2_score = 0 self._p1_columns = deque([], self.MAX_TURNS_FOR_COLUMN) self._p2_columns = deque([], self.MAX_TURNS_FOR_COLUMN) self._turn = Match._decide_first_turn()
def sample_board_small(): b = Board(3, 3, 3) b._board = [[Position.FILLED, Position.EMPTY, Position.FILLED], [Position.FILLED, Position.EMPTY, Position.EMPTY], [Position.FILLED, Position.EMPTY, Position.FILLED], [Position.FILLED, Position.EMPTY, Position.EMPTY], [Position.FILLED, Position.EMPTY, Position.FILLED]] return b
def sample_board_small_score(): b = Board(3, 5, 3) b._board = [[Position.PLAYER1, Position.EMPTY, Position.EMPTY], [Position.FILLED, Position.FILLED, Position.FILLED], [Position.PLAYER1, Position.EMPTY, Position.EMPTY], [Position.FILLED, Position.EMPTY, Position.EMPTY], [Position.FILLED, Position.FILLED, Position.FILLED]] return b
def test_find_winners(): b = Board(3, 1, 1) b._board = [[Position.PLAYER1, Position.EMPTY, Position.PLAYER2]] assert b.find_winners() == [] b._board = [[Position.EMPTY, Position.PLAYER2, Position.EMPTY]] assert b.find_winners() == [Position.PLAYER1] b._board = [[Position.PLAYER1, Position.EMPTY, Position.EMPTY]] assert b.find_winners() == [Position.PLAYER2] b._board = [[Position.FILLED, Position.EMPTY, Position.EMPTY]] assert b.find_winners() == [Position.PLAYER1, Position.PLAYER2]
def sample_board_medium(): b = Board(5, 5, 3) b._board = [[ Position.EMPTY, Position.FILLED, Position.FILLED, Position.PLAYER2, Position.EMPTY ], [ Position.PLAYER1, Position.FILLED, Position.EMPTY, Position.EMPTY, Position.PLAYER2 ], [ Position.EMPTY, Position.FILLED, Position.FILLED, Position.PLAYER2, Position.EMPTY ], [ Position.FILLED, Position.PLAYER1, Position.EMPTY, Position.EMPTY, Position.FILLED ], [ Position.EMPTY, Position.PLAYER1, Position.FILLED, Position.FILLED, Position.FILLED ]] return b
class Match(object): # A column can only be moved this many times in a row before being disabled MAX_TURNS_FOR_COLUMN = 6 def __init__(self, width, height, units_per_side): self._board = Board(width, height, units_per_side) self._player1_score = 0 self._player2_score = 0 self._p1_columns = deque([], self.MAX_TURNS_FOR_COLUMN) self._p2_columns = deque([], self.MAX_TURNS_FOR_COLUMN) self._turn = Match._decide_first_turn() def get_valid_columns(self): """ Determine the available moves that the current-turn player can make :return: List of movable columns (starting at 0) """ cols = self._board.player_columns(self._turn) # remove a column if it has been picked the last X times if self._reached_column_max(): if self._turn == Position.PLAYER1: cols.remove(self._p1_columns[0]) else: cols.remove(self._p2_columns[0]) return cols def _reached_column_max(self): """ Determine if a player has moved the same column too many times in a row. :return: """ if self._turn == Position.PLAYER1: return (len(self._p1_columns) == Match.MAX_TURNS_FOR_COLUMN and all(e == self._p1_columns[0] for e in self._p1_columns)) elif self._turn == Position.PLAYER2: return (len(self._p2_columns) == Match.MAX_TURNS_FOR_COLUMN and all(e == self._p2_columns[0] for e in self._p2_columns)) def do_turn(self, column, direction): """ Perform the current player's turn :param column: column to move :param direction: direction to move :return: """ if not isinstance(direction, PlayerInput): raise Exception("Invalid type of direction") if column < 0 or column >= self._board.width: raise Exception("Invalid column") if direction == PlayerInput.UP: self._board.player_move(column, direction, self._turn) elif direction == PlayerInput.DOWN: self._board.player_move(column, direction, self._turn) @staticmethod def _decide_first_turn(): """ Decide and return which player gets the first turn. :param self: :return: """ return Position.PLAYER1 if random.randint(0, 1) == 0 else Position.PLAYER2 def print(self): print( f'[ P1: {self._player1_score: <2} | P2: {self._player2_score: <2} | Turn: PLAYER {self._turn.value}]' ) print(f'') self._board.print() col_state = [' '] * self._board.width for valid_turn in self.get_valid_columns(): col_state[valid_turn] = '^' xv = [f'{x: ^3}' for x in col_state] print('|'.join(xv))
def test_can_move_down(): board = [[Position.PLAYER1, Position.PLAYER1, Position.EMPTY], [Position.FILLED, Position.EMPTY, Position.PLAYER1]] assert Board.can_move_down(board, 0, 0) == False assert Board.can_move_down(board, 1, 0) == True assert Board.can_move_down(board, 2, 1) == False
def test_can_move_right(): board = [[ Position.PLAYER1, Position.FILLED, Position.PLAYER1, Position.EMPTY ]] assert Board.can_move_right(board, 0, 0) == False assert Board.can_move_right(board, 2, 0) == True
def test_can_move_left(): board = [[ Position.EMPTY, Position.PLAYER1, Position.FILLED, Position.PLAYER1 ]] assert Board.can_move_left(board, 1, 0) == True assert Board.can_move_left(board, 3, 0) == False