def test_move_one_square(board_size, num_moves): b = Board(*board_size) for i in range(num_moves): row = b.move(0, Cell.BLACK) expected_row = b.height - i - 1 assert row == expected_row assert b.cells[0, expected_row] == Cell.BLACK
class Game: def __init__(self): self.turn = 0 self.board = Board() def move(self, column): if self.turn == 0: piece = Piece.RED else: piece = Piece.BLACK coords = self.board.addPiece(column, piece) # Invalid move if not coords: return -1 # Someone won if self.board.checkWin(coords[0], coords[1], piece): return 1 self.turn = (self.turn + 1) % 2 # Next turn return 0 def __repr__(self): return self.board.__repr__() def __str__(self): return self.__repr__() def generateImageBoard(self, color1="red", color2="black"): im = Image.new("RGB", (256, 220), "white") draw = ImageDraw.Draw(im) diameter = 32 padding = 4 margin = 4 for i in range(self.board.width): for j in range(self.board.height): if self.board.getPiece(i, j) == Piece.RED: color = color1 outline = 'red' elif self.board.getPiece(i, j) == Piece.BLACK: color = color2 outline = 'black' else: color = 'grey' outline = "black" draw.ellipse((margin + (diameter + padding) * i, margin + (diameter + padding) * j, margin + (diameter + padding) * i + diameter, margin + (diameter + padding) * j + diameter), fill=color, outline=outline) return im
def reset(self) -> None: h, w, ntw = self.b.height, self.b.width, self.b.num_to_win self.b = Board(width=w, height=h, num_to_win=ntw) self.cur_player = Cell.RED self.is_game_over = False self.num_moves = 0 self.last_move = None self.history = []
def __init__(self, board_w=7, board_h=7, num_to_win=4): self.b = Board(board_w, board_h, num_to_win=num_to_win) self.cur_player = Cell.RED self.num_actions = board_w self.is_game_over = False self.num_moves: int = 0 self.last_move = None # last move in game (col, row) self.history = [ ] # history will be a list of tuples (state, action, reward)
def test_find_top_with_col_filled(board_size, up_to): b = Board(*board_size) for i in range(up_to): row_to_populate = b.height - i - 1 b.cells[0, row_to_populate] = Cell.BLACK row = b.find_top(0) expected = b.height - up_to - 1 assert row == expected
def test_string_representation_complex_case(): b = Board(2, 2, 2) b.move(0, Cell.BLACK) b.move(1, Cell.RED) b.move(0, Cell.BLACK) b_str = str(b) expected = str(Cell.BLACK.value) + str(Cell.BLACK.value) + str( Cell.EMPTY.value) + str(Cell.RED.value) assert b_str == expected
def test_move_too_tall_move_raises_exception(): b = Board(2, 2) b.move(0, Cell.BLACK) b.move(0, Cell.BLACK) with pytest.raises(ValueError) as excinfo: b.move(0, Cell.BLACK) assert 'Illegal move' in str(excinfo.value)
class Environment(object): ''' Class that serves as an interface that Players use to interact with the Board Environment manages which player is currently active, manages when the game is over, manages hwo the board state is represented to players, etc. ''' def __init__(self, board_w=7, board_h=7, num_to_win=4): self.b = Board(board_w, board_h, num_to_win=num_to_win) self.cur_player = Cell.RED self.num_actions = board_w self.is_game_over = False self.num_moves: int = 0 self.last_move = None # last move in game (col, row) self.history = [ ] # history will be a list of tuples (state, action, reward) def get_num_cells(self) -> int: return self.b.get_num_cells() def reset(self) -> None: h, w, ntw = self.b.height, self.b.width, self.b.num_to_win self.b = Board(width=w, height=h, num_to_win=ntw) self.cur_player = Cell.RED self.is_game_over = False self.num_moves = 0 self.last_move = None self.history = [] def _actually_take_action(self, col: int) -> float: ''' Moves the current player into the column specified by 'col' Returns the score of the last move: -1 if illegal, 1 if winning, 0 otherwise ''' state = self.get_state() try: row = self.b.move(col, self.cur_player) except ValueError: # illegal moves cause game over self.is_game_over = True return -1 self.last_move = (col, row) # change current player self.cur_player = Cell.RED if self.cur_player == Cell.BLACK else Cell.BLACK self.num_moves += 1 # check if any legal moves remain if self.num_moves >= self.get_num_cells(): self.is_game_over = True if self.b.check_winning_move(col, row): self.is_game_over = True return 1 return 0 def take_action(self, col: int) -> float: ''' Moves the current player into the specified column. Also records history for the move Returns the reward for making such a move ''' state = self.get_state() reward = self._actually_take_action(col) self.history.append((state, col, reward)) return reward def get_state(self) -> str: ''' Board's __str__ method returns a string of 0s 1s and 2s (for empty, red, black cells as per the Cell enum) This method converts such a string to Es, Ms, and Ys which stand for Empty, My cells, and Your cells ''' board_str = str(self.b) if self.cur_player == Cell.BLACK: board_str = board_str.replace(str(Cell.BLACK.value), 'M') # Mine board_str = board_str.replace(str(Cell.RED.value), 'Y') # Yours board_str = board_str.replace(str(Cell.EMPTY.value), 'E') # Empty else: board_str = board_str.replace(str(Cell.RED.value), 'M') # Mine board_str = board_str.replace(str(Cell.BLACK.value), 'Y') # Yours board_str = board_str.replace(str(Cell.EMPTY.value), 'E') # Empty return board_str
def test_check_winning_off_main_diagonal_win(): b = Board(3, 3, 2) b.cells[0, 1] = Cell.BLACK b.cells[1, 2] = Cell.BLACK assert b.check_winning_move(0, 1) assert b.check_winning_move(1, 2)
def test_check_winning_off_second_diagonal_win(): b = Board(3, 3, 2) b.cells[1, 0] = Cell.BLACK b.cells[2, 1] = Cell.BLACK assert b.check_winning_move(1, 0) assert b.check_winning_move(2, 1)
def test_check_winning_move_second_diagonal_win(): b = Board(2, 2, 2) b.cells[0, 0] = Cell.BLACK b.cells[1, 1] = Cell.BLACK assert b.check_winning_move(1, 1) assert b.check_winning_move(0, 0)
def test_find_top_empty_board(boardsize, col): b = Board(*boardsize) row = b.find_top(col) expected = b.height - 1 assert row == expected
def test_check_for_n_in_row(arr, color, num, expected): b = Board(2, 2, num) res = b.check_for_connect(arr, color) assert res == expected
def __init__(self): self.turn = 0 self.board = Board()