예제 #1
0
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
예제 #2
0
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
예제 #3
0
 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 = []
예제 #4
0
 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)
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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)
예제 #8
0
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
예제 #9
0
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)
예제 #10
0
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)
예제 #11
0
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)
예제 #12
0
def test_find_top_empty_board(boardsize, col):
    b = Board(*boardsize)
    row = b.find_top(col)
    expected = b.height - 1
    assert row == expected
예제 #13
0
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
예제 #14
0
 def __init__(self):
     self.turn = 0
     self.board = Board()