Exemple #1
0
    def __init__(self,
                 width=600,
                 height=600,
                 time_limit=30000,
                 bg_color=BG_COLOR,
                 font=FONT):
        screen_dim = (width, height)
        self.side_length = min(width, height)
        if width >= height:
            self.top_left = (0.5 * (width - height), 0)
        else:
            self.top_left = (0, 0.5 * (height - width))

        pygame.font.init()
        self.board = ReversiBoard(self.side_length, self.top_left)

        actions = self._init_action_set()
        super().__init__(width, height, actions=actions)

        self.bg_color = bg_color
        self.font = font
        self.last_label = '1A'
        self.cur_player = -1
        self.prev_action_time = 0
        self.time_limit = time_limit
        self.time_left = {-1: time_limit, 1: time_limit}
Exemple #2
0
 def __init__(self, player1, player2, show_status=True, board_size=8, board_filename=None):
     self.player1 = player1
     self.player2 = player2
     self.show_status = show_status
     if board_filename is None:
         self.board = ReversiBoard(board_size)
     else:
         self.board = ReversiBoard(board_filename=board_filename)
     self.decision_times = {self.player1.symbol: 0, self.player2.symbol: 0}
     self.moves_made = {self.player1.symbol: 0, self.player2.symbol: 0}
     self.max_decision_time = {self.player1.symbol: 0, self.player2.symbol: 0}
     self.play_game()
class ReversiGame(object):

    def __init__(self, display=False):
        self.display = display
        self.board = ReversiBoard(self.display)

    def reset(self):
        self.board.reset()

    def play(self, player1, player2):
        players = {ReversiBoard.PLAYER_X: player1,
                   ReversiBoard.PLAYER_O: player2}

        if self.display:
            print(f'X: {players[ReversiBoard.PLAYER_X].name}, '
                  f'O: {players[ReversiBoard.PLAYER_O].name}')

        for player in (ReversiBoard.PLAYER_X, ReversiBoard.PLAYER_O):
            players[player].on_game_started(player)

        player = ReversiBoard.PLAYER_X
        while self.board.state == ReversiBoard.ACTIVE:
            pos = players[player].on_next_move_required(player)
            self.board.make_next_move(pos, player)

            if player == ReversiBoard.PLAYER_X:
                if len(self.board.available_places[ReversiBoard.PLAYER_O]) > 0:
                    player = ReversiBoard.PLAYER_O
            else:
                if len(self.board.available_places[ReversiBoard.PLAYER_X]) > 0:
                    player = ReversiBoard.PLAYER_X

        for player in (ReversiBoard.PLAYER_X, ReversiBoard.PLAYER_O):
            pos = players[player].on_next_move_required(player)
            assert pos is None
            players[player].on_game_finished(player)

        if self.display:
            print(f'X: {players[ReversiBoard.PLAYER_X].name}, '
                  f'O: {players[ReversiBoard.PLAYER_O].name}')

        return self.board.state
Exemple #4
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('player1', nargs='?', default='greedy')
    parser.add_argument('player2', nargs='?', default='human')
    parser.add_argument('--load1', metavar='FILE')
    parser.add_argument('--load2', metavar='FILE')
    args = parser.parse_args()

    board = ReversiBoard(display=False)
    player1 = PLAYERS[args.player1](board, train=False)
    player2 = PLAYERS[args.player2](board, train=False)

    if args.load1:
        player1.load_params(args.load1)
    if args.load2:
        player2.load_params(args.load2)

    pygame.init()
    GUIGame(board, player1, player2).play()
    pygame.quit()
Exemple #5
0
class Reversi(PyGameWrapper):
    """
        game_state:
            -1: dark side
            0: no piece
            1: light side
    """
    BG_COLOR = (255, 255, 255)
    FONT = 'font/OpenSans-Regular.ttf'
    def __init__(self, width=600, height=600, time_limit=30000, bg_color=BG_COLOR, font=FONT):
        screen_dim = (width, height)
        self.side_length = min(width, height)
        if width >= height:
            self.top_left = (0.5 * (width - height), 0)
        else:
            self.top_left = (0, 0.5 * (height - width))

        pygame.font.init()
        self.board = ReversiBoard(self.side_length, self.top_left)

        actions = self._init_action_set()
        super().__init__(width, height, actions=actions)

        self.bg_color = bg_color
        self.font = font
        self.last_label = '1A'
        self.cur_player = -1
        self.prev_action_time = 0
        self.time_limit = time_limit
        self.time_left = {-1: time_limit, 1: time_limit}

    def _init_action_set(self):
        actions = {}
        for i, row in enumerate(self.board.rows):
            for j , col in enumerate(self.board.cols):
                x = 0.1 * self.side_length + 0.8 * (j+0.5) / len(self.board.cols) * self.side_length
                y = 0.1 * self.side_length + 0.8 * (i+0.5) / len(self.board.rows) * self.side_length
                actions[row+col] = utils.element_wise_addition(self.top_left, (x, y))
        return actions

    def _handle_player_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            elif event.type == pygame.MOUSEMOTION:
                try:
                    if self.get_game_state()[self.board.enum[self.last_label]] == 2:
                        self.board.update(self.last_label, 0)
                    label = self.pos2label(event.pos)
                    if self._is_available(label):
                        self.last_label = label
                        self.board.update(label, 2)

                except utils.ValueOutOfRange:
                    pass

            elif (event.type == pygame.MOUSEBUTTONDOWN or
                  event.type == pygame.USEREVENT):
                try:
                    label = self.pos2label(event.pos)
                    if self._is_available(label, flip=True):
                        cur_time = pygame.time.get_ticks()
                        self.time_left[self.cur_player] -= cur_time - self.prev_action_time
                        self.prev_action_time = cur_time

                        self.board.update(label, self.cur_player)
                        self.cur_player *= -1

                        if len(self._get_available_actions()) <= 0:
                            self.cur_player *= -1
                            raise utils.NoAvailableAction()
                    else:
                        raise utils.InvalidAction()

                except utils.ValueOutOfRange:
                    raise utils.ValueOutOfRange()

    def _update_scores(self):
        x, y = 0, 0
        for r in self.board.rows:
            for c in self.board.cols:
                status = self.get_game_state()[self.board.enum[r+c]]
                if status == -1:
                    x += 1
                elif status == 1:
                    y += 1
        
        self.scores[-1] = x
        self.scores[1] = y

    def pos2label(self, pos):
        """
        Change the screen position to the label on the board.
        """
        pos = tuple([p - tl for p, tl in zip(pos, self.top_left)])

        if (pos[0] < 0 or pos[0] > self.side_length or
            pos[1] < 0 or pos[1] > self.side_length):
            raise utils.ValueOutOfRange()

        return self.board.pos2label(pos)

    def _is_available(self, label, flip=False):
        """
        Check if is able to place a piece on the label.

        Parameters
        ----------
        label: str
            The reference position
        flip: bool
            Flip the pieces or not

        Return
        ------
        bool
            Whether able to place the piece or not
        """
        status = self.get_game_state()
        if status[self.board.enum[label]] == 2 and flip == False:
            return True

        if status[self.board.enum[label]] == 0 or status[self.board.enum[label]] == 2:
            return self._check_around(label, flip=flip)

        return False

    def _check_around(self, label, flip):
        """
        Check the 3x3 blocks centered by label are occupied by the opponent or not.
        Run through that direction if the block on that direction is occupied by the opponent.

        Parameters
        ----------
        label: str
            The reference position
        flip: bool
            Flip the pieces or not

        Return
        ------
        bool
            Whether able to flip or not

        """
        is_avail = False
        status = self.get_game_state()
        row = int(self.board.enum[label] // len(self.board.rows))
        col = int(self.board.enum[label] % len(self.board.rows))
        for i in range(-1, 2):
            if row+i < 0 or row+i >= len(self.board.rows): continue

            for j in range(-1, 2):
                if col+j < 0 or col+j >= len(self.board.cols): continue

                label = self.board.rows[row+i] + self.board.cols[col+j]
                if status[self.board.enum[label]] == -1 * self.cur_player:
                    if self._check_direction(row, col, i, j, flip=flip):
                        is_avail = True
                    
        return is_avail

    def _check_direction(self, row, col, dx, dy, flip):
        """
        Check each direction whether is able to flip pieces or not.

        Parameters
        ----------
        row, col: int
            The position to start from
        dx, dy: int
            The direction to go through
        flip: bool
            Flip the pieces or not

        Return
        ------
        bool
            Whether able to flip or not

        """
        is_avail = False
        status = self.get_game_state()
        x, y = [dx], [dy]
        while 0 <= row+x[-1] < len(self.board.rows) and 0 <= col+y[-1] < len(self.board.cols):
            label = self.board.rows[row+x[-1]] + self.board.cols[col+y[-1]]
            if status[self.board.enum[label]] == 0:
                break
            if status[self.board.enum[label]] == self.cur_player:
                if flip:
                    for r, c in zip(x, y):
                        self.board.update(self.board.rows[row+r]+self.board.cols[col+c], self.cur_player)
                    is_avail = True
                    break
                else:
                    return True

            x.append(x[-1] + dx)
            y.append(y[-1] + dy)

        return is_avail

    def _get_available_actions(self):
        avail = []
        for row in self.board.rows:
            for col in self.board.cols:
                if self._is_available(row+col):
                    avail.append(row+col)
                
        return avail

    def get_game_state(self):
        return self.board.status

    def get_actions(self):
        return self.actions

    def init(self):
        self.board.reset_status()

        self.time_left = {-1: self.time_limit, 1: self.time_limit}

        init_status = [('4D', 1), ('4E', -1), ('5D', -1), ('5E', 1)]
        for s in init_status:
            self.board.update(*s)

        self._update_scores()

        self.screen.fill(self.bg_color)
        self.board.draw_board(self.screen)
        self.board.draw_pieces(self.screen)

    def game_over(self):
        if self._time_out():
            self.winner = -1 * self.cur_player
            self._display_game_over()
            return True

        elif len(self._get_available_actions()) > 0:
            return False

        else:
            if self.scores[1] > self.scores[-1]:
                self.winner = 1
            elif self.scores[-1] > self.scores[1]:
                self.winner = -1

            self._display_game_over()
            return True

    def _display_game_over(self):
        """
        Display 'GAME OVER' on the screen 
        """
        font = pygame.font.Font(self.font, 72)
        text = font.render('GAME OVER', True, (255, 255, 255))
        text_rect = text.get_rect()
        text_rect.center = utils.element_wise_addition(self.top_left, (0.5 * self.side_length, 0.5 * self.side_length))
        self.screen.blit(text, text_rect)

    def step(self, dt):
        self._update_time_left()
        self._display_scores_and_time_left()

        try:
            self._handle_player_events()
            self._update_scores()
            self.board.draw_board(self.screen)
            self.board.draw_pieces(self.screen)
            self._display_scores_and_time_left()
            self._display_current_player()

        except utils.ValueOutOfRange:
            raise utils.ValueOutOfRange()

        except utils.InvalidAction:
            raise utils.InvalidAction()

        except utils.NoAvailableAction:
            self._update_scores()
            self.board.draw_board(self.screen)
            self.board.draw_pieces(self.screen)
            self._display_scores_and_time_left()
            self._display_current_player()
            raise utils.NoAvailableAction()

    def _time_out(self):
        """
        Gets the time left, return true if no time left.
        """
        if pygame.time.get_ticks() - self.prev_action_time > self.time_left[self.cur_player]:
            return True
        return False

    def _update_time_left(self):
        """
        Update the time left to the time left on the screen on date.
        """
        if pygame.time.get_ticks() - self.prev_action_time > self.time_left[self.cur_player] % 1000:
            self.time_left[self.cur_player] -= pygame.time.get_ticks() - self.prev_action_time
            self.prev_action_time = pygame.time.get_ticks()

    def _display_scores_and_time_left(self):
        """
        Dispaly scores and time left for both players.
        """
        text_colors = [[(255,160,122), (255,160,122)], [(0, 0, 0), (255, 255, 255)]]
        time_left = {key: max(0, int(self.time_left[key] // 1000)) for key in self.time_left}
        for i, display_dict in enumerate((time_left, self.scores)):
            for j, (player, text_color) in enumerate(zip(display_dict, text_colors[i])):
                font = pygame.font.Font(self.font, 24)
                text = font.render(str(display_dict[player]), True, text_color)
                text_rect = text.get_rect()
                text_rect.center = utils.element_wise_addition(self.top_left, (abs(0.1*(i+1)-j) * self.side_length, 0.95 * self.side_length))
                self.screen.blit(text, text_rect)

    def _display_current_player(self):
        """
        Display who's turn to play.
        """
        content = {-1: 'Black\'s turn.', 1: 'White\'s turn.'}
        text_color = {-1: (0, 0, 0), 1: (255, 255, 255)}
        font = pygame.font.Font(self.font, 24)
        text = font.render(content[self.cur_player], True, text_color[self.cur_player])
        text_rect = text.get_rect()
        text_rect.center = utils.element_wise_addition(self.top_left, (0.5 * self.side_length, 0.95 * self.side_length))
        self.screen.blit(text, text_rect)
 def __init__(self, display=False):
     self.display = display
     self.board = ReversiBoard(self.display)
Exemple #7
0
    parser.add_argument('--height', default=600, type=int)
    parser.add_argument('--rounds', default=10, type=int)
    parser.add_argument('--time_limit', default=30000, type=int)
    parser.add_argument('--headless', action='store_true')
    args = parser.parse_args()

    if args.headless:
        import os
        os.putenv('SDL_VIDEODRIVER', 'fbcon')
        os.environ["SDL_VIDEODRIVER"] = "dummy"

    game = Reversi(width=args.width,
                   height=args.height,
                   time_limit=args.time_limit)
    play_ground = Environment(game, force_fps=False)
    rev_board = ReversiBoard()

    # init agent and game.
    play_ground.init()
    play_ground.display_screen = True

    agent1_module = importlib.import_module("agent." +
                                            args.agent1.split('.')[0])
    agent2_module = importlib.import_module("agent." +
                                            args.agent2.split('.')[0])

    agent1 = getattr(agent1_module,
                     args.agent1.split('.')[1])(color="black",
                                                rows_n=len(rev_board.rows),
                                                cols_n=len(rev_board.cols),
                                                width=args.width,
Exemple #8
0
class ReversiGame:

    def __init__(self, player1, player2, show_status=True, board_size=8, board_filename=None):
        self.player1 = player1
        self.player2 = player2
        self.show_status = show_status
        if board_filename is None:
            self.board = ReversiBoard(board_size)
        else:
            self.board = ReversiBoard(board_filename=board_filename)
        self.decision_times = {self.player1.symbol: 0, self.player2.symbol: 0}
        self.moves_made = {self.player1.symbol: 0, self.player2.symbol: 0}
        self.max_decision_time = {self.player1.symbol: 0, self.player2.symbol: 0}
        self.play_game()

    def play_game(self):
        if self.show_status:
            self.board.draw_board()
        while self.board.game_continues():
            self.play_round()
        if self.show_status:
            print("Game over, Final Scores:")
            print_scores(self.board.calc_scores())

    def play_round(self):
        start = datetime.now()
        self.play_move(self.player1)
        self.decision_times[self.player1.symbol] += (datetime.now()-start).total_seconds()
        move_time = (datetime.now()-start).total_seconds()
        if move_time > 2.7:
            print("BEEG MOVE",move_time)
        self.max_decision_time[self.player1.symbol] = move_time if move_time > self.max_decision_time[self.player1.symbol] else self.max_decision_time[self.player1.symbol]
        start = datetime.now()
        self.play_move(self.player2)
        self.decision_times[self.player2.symbol] += (datetime.now()-start).total_seconds()
        move_time = (datetime.now()-start).total_seconds()
        if move_time > 2.7:
            print("BEEG MOVE",move_time)
        self.max_decision_time[self.player2.symbol] = move_time if move_time > self.max_decision_time[self.player2.symbol] else self.max_decision_time[self.player2.symbol]



    def play_move(self, player):
        if self.board.calc_valid_moves(player.symbol):
            self.moves_made[player.symbol] += 1
            chosen_move = player.get_move(copy.deepcopy(self.board))
            if not self.board.make_move(player.symbol, chosen_move):
                print("Error: invalid move made")
            elif self.show_status:
                self.board.draw_board()
                print_scores(self.board.calc_scores())
        elif self.show_status:
            print(player.symbol, "can't move.")

    def calc_winner(self):
        scores = self.board.calc_scores()
        if scores[self.player1.symbol] > scores[self.player2.symbol]:
            return self.player1.symbol
        if scores[self.player1.symbol] < scores[self.player2.symbol]:
            return self.player2.symbol
        else:
            return "TIE"

    def get_decision_times(self):
        return self.decision_times