예제 #1
0
    def play_game(self, on_move=None, verbose=False):
        """
        explore another round of the game
            verbose: bool
                show the process of this game
            returns: list[np.array], list[int]
                the state of the playing field before the move and the move
        """
        c4 = Game(
            self.height,
            self.width,
            on_move=np.random.choice([-1, 1]) if on_move is None else on_move)

        state_list = []
        move_list = []
        # generate training data through two AIs playing against each other
        while c4.winner is None:  # and len(c4.possibleMoves()) > 0:
            color = c4.on_move
            move, meta = self.ais[color].next_exploring_move(
                c4, epsilon=self.epsilon)
            state_list.append(np.copy(c4.field) * color)
            print_cond(c4.field, cond=verbose)
            c4.play(move)
            print_cond("move:",
                       move,
                       " (explore=",
                       meta["explore"],
                       ") ends=",
                       c4.winner,
                       cond=verbose)
            move_list.append(move)

            if c4.winner in (-1, 0, 1):
                break
        return state_list, move_list
예제 #2
0
 def next_move(self, c4: Game):
     if c4.lastMove is not None:
         vicinty = list(
             set(c4.possible_moves()).intersection(
                 range(c4.lastMove - 1, c4.lastMove + 2)))
         if len(vicinty) > 0:
             return np.random.choice(vicinty)
     return np.random.choice(c4.possible_moves())
예제 #3
0
def move():
    content = request.get_json()
    board = content['board']
    player = content['player']
    other_player = 2 if player == 1 else 1
    available_columns = content['available_columns']

    # Check for win
    for avail_col in available_columns:
        new_board = transform_board(board)
        b = Connect4()
        b.set_board(new_board)
        b.move(avail_col, player)
        if b.winner(player):
            return jsonify({
                'column': avail_col,
            })

    # Block opponent
    for avail_col in available_columns:
        new_board = transform_board(board)
        b = Connect4()
        b.set_board(new_board)
        b.move(avail_col, other_player)
        if b.winner(other_player):
            return jsonify({
                'column': avail_col,
            })

    # Block opponent + 1
    bad_cols = set()
    for avail_col in available_columns:
        new_board = transform_board(board)
        b = Connect4()
        for opp_avail_col in b.get_available_columns():
            b.set_board(deepcopy(new_board))
            b.move(avail_col, player)
            b.move(opp_avail_col, other_player)

            if b.winner(other_player):
                bad_cols.add(avail_col)

    # First column that won't let other player win
    non_winning_avail_columns = [
        a for a in available_columns if a not in bad_cols
    ]

    if len(non_winning_avail_columns) > 0:
        return jsonify({
            'column': non_winning_avail_columns[0],
        })

    # Losing is better than crashing
    return jsonify({
        'column': available_columns[0],
    })
예제 #4
0
    def test_game(self, enemy="opp", verbose=False, player1_starts=True):
        c4 = Game(self.height, self.width, on_move=1 if player1_starts else -1)
        while c4.winner is None:
            if player1_starts:
                move, q_max = c4.best_next_move(self.qnet)
                c4.play(move)
                print_cond(c4.field,
                           "\nplayer 1 (qnet) played",
                           move,
                           cond=verbose)
            player1_starts = True

            if c4.winner is None:
                if enemy == "qnet":
                    move, q_max = c4.best_next_move(self.qnet)
                elif enemy == "opp":
                    move = self.ais[-1].next_move(c4)
                elif enemy == "rand":
                    move = np.random.choice(c4.possible_moves())
                elif enemy == "human":
                    print("Current Field state:\n", c4.field)
                    move = int(input("Your move: " + str(c4.possible_moves())))

                print_cond("player -1", enemy, "played", move, cond=verbose)
                c4.play(move)
        return c4.winner
예제 #5
0
    def test_is_valid_empty_column(self):
        board = Connect4()
        game = Game(board)

        result = game.is_valid(4)

        self.assertEqual(result, True)
예제 #6
0
 def testWinnerDiagonalForwardSlashTopRight(self):
     b = Connect4()
     b.move(6, '3')
     b.move(5, '3')
     b.move(4, '3')
     b.move(3, '3')
     b.move(6, '3')
     b.move(5, '3')
     b.move(4, '3')
     b.move(3, '3')
     self.assertFalse(b.winner('1'))
     b.move(6, '2')
     b.move(6, '2')
     b.move(6, '2')
     b.move(6, '1')
     self.assertFalse(b.winner('1'))
     b.move(5, '2')
     b.move(5, '2')
     b.move(5, '1')
     self.assertFalse(b.winner('1'))
     b.move(4, '2')
     b.move(4, '1')
     self.assertFalse(b.winner('1'))
     b.move(3, '1')
     print(b)
     self.assertTrue(b.winner('1'))
예제 #7
0
 def test_get_move_bot(self, random):
     board = Connect4()
     game = Game(board)
     game.turn = 1
     game.cpu_game = True
     game.get_move()
     self.assertEqual(game.board.board[3][0], 'O')
예제 #8
0
async def start(websocket):
    """
    Handle a connection from the first player: start a new game.

    """
    # Initialize a Connect Four game, the set of WebSocket connections
    # receiving moves from this game, and secret access tokens.
    game = Connect4()
    connected = {websocket}

    join_key = secrets.token_urlsafe(12)
    JOIN[join_key] = game, connected

    watch_key = secrets.token_urlsafe(12)
    WATCH[watch_key] = game, connected

    try:
        # Send the secret access tokens to the browser of the first player,
        # where they'll be used for building "join" and "watch" links.
        event = {
            "type": "init",
            "join": join_key,
            "watch": watch_key,
        }
        await websocket.send(json.dumps(event))
        # Receive and process moves from the first player.
        await play(websocket, game, PLAYER1, connected)
    finally:
        del JOIN[join_key]
        del WATCH[watch_key]
예제 #9
0
def test():
    sim = Connect4()
    brain = Brain(sim.width,
                  sim.height,
                  sim.actions_count,
                  load_path=eval_model)
    opponent = QLearn(sim,
                      brain,
                      "AI",
                      exploration_period=0,
                      discount_factor=0.9)

    display = False
    scorer = Scorer(stats_frequency)
    if eval_mode == "human":
        player = HumanPlayer("Player")
        display = True
    elif eval_mode == "random":
        player = RandomPlayer()
    elif eval_mode == "minmax":
        player = MinMax(max_level=minmax_level)
    else:
        raise ValueError, ("Invalid eval_mode. Got %s expected "
                           "(human|random|minmax)") % eval_mode

    while True:
        play_game_with_opponent([opponent, player],
                                sim,
                                scorer,
                                display_board=display)
예제 #10
0
    def test_is_valid_negative_column(self):
        board = Connect4()
        game = Game(board)

        result = game.is_valid(-4)

        self.assertEqual(result, False)
예제 #11
0
def runPVE():
    x = input(
        "would you like to play a game against our minimax ai? yes or no\n")
    if x == 'yes':
        print("playing game")

        c = Connect4()
        c.new_print_board()

        # human is always blue
        human = "B"

        while c.turn != "B_WINS" and c.turn != "R_WINS" and c.turn != "TIE":

            if c.turn == human:
                # if it is the humans turn: manage the humans input
                # TODO: bug here
                if not manage_input(c): continue

            else:
                #         manage the ai's input
                manage_minimax_input(c)

        print("GAME IS OVER")
        print(c.turn)
예제 #12
0
def run_game():
    game = Connect4()
    ab_obj1 = AlphaBeta(2, heuristic5, 'B')
    ab_obj2 = AlphaBeta(2, heuristic5, 'R')

    stop_conditions = ('B_WINS', 'R_WINS', 'TIE')

    while game.turn not in stop_conditions:

        # force random column on first move
        if game.total_moves == 0:
            random_column = randint(0, 6)
            game.drop_chip(random_column)

        elif game.turn == 'R':

            score, move = ab_obj2.find_move(game)
            game.drop_chip(move)

        elif game.turn == 'B':
            score, move = ab_obj1.find_move(game)
            game.drop_chip(move)

    game.new_print_board()
    print(game.turn)
예제 #13
0
 def __init__(self, args):
     self._game = Connect4(args)
     self.tokenSize = 100
     self._running = True
     self._screenWidth = self._game.getBoard().numCols() * self.tokenSize + self.BUFFER
     self._screenHeight = (self._game.getBoard().numRows() + 1) * self.tokenSize + self.BUFFER
     self.screen = self.initializeGraphics()
예제 #14
0
    def __init__(self, player1='Human', player2='AI'):
        self.board_colour = (0, 0, 255)
        self.bg_colour = (0, 0, 0)
        self.p1_piece_colour = (255, 0, 0)
        self.p2_piece_colour = (255, 255, 0)
        self.piece_colour = self.p1_piece_colour
        self.num_rows = 6
        self.num_columns = 7
        self.win_cond = 4
        self.square_size = 100
        self.width = self.num_columns * self.square_size
        self.height = (self.num_rows + 1) * self.square_size
        self.piece_size = int(self.square_size / 2 - 5)

        self.original_game = Connect4((self.num_columns, self.num_rows),
                                      self.win_cond)
        self.game = copy(self.original_game)
        self.player1 = player1
        self.player2 = player2
        self.cur_player = player1
        self.player = self.game.player
        self.agent = Connect4Zero()
        self.last_dropped = 0
        self.end = False

        self.screen = pygame.display.set_mode((self.width, self.height))
        self.draw_board()
        pygame.display.update()
        pygame.init()
        self.game_font = pygame.font.SysFont('Candara', 75)
예제 #15
0
 def testWinnerDiagonalForwardSlashTopLeft(self):
     b = Connect4()
     b.move(0, '3')
     b.move(1, '3')
     b.move(2, '3')
     b.move(3, '3')
     b.move(0, '3')
     b.move(1, '3')
     b.move(2, '3')
     b.move(3, '3')
     self.assertFalse(b.winner('1'))
     b.move(3, '2')
     b.move(3, '2')
     b.move(3, '2')
     b.move(3, '1')
     self.assertFalse(b.winner('1'))
     b.move(2, '2')
     b.move(2, '2')
     b.move(2, '1')
     self.assertFalse(b.winner('1'))
     b.move(1, '2')
     b.move(1, '1')
     self.assertFalse(b.winner('1'))
     b.move(0, '1')
     self.assertTrue(b.winner('1'))
예제 #16
0
    def test_get_move_user(self, input):
        board = Connect4()
        game = Game(board)

        game.get_move()

        self.assertEqual(game.board.board[5][0], 'X')
예제 #17
0
def train_with_opponent():
    sim = Connect4()
    if train_mode == "mixt":
        opponents = [RandomPlayer("Rand")]
        for idx, model_path in enumerate(os.listdir(models_root)):
            full_path = os.path.join(models_root, model_path)
            prev_brain = Brain(sim.width,
                               sim.height,
                               sim.actions_count,
                               load_path=full_path)
            opponents.append(QLearn(sim, prev_brain, "v" + str(idx)))
    elif train_mode == "random":
        opponents = [RandomPlayer("Rand")]
    elif train_mode == "minmax":
        opponents = [MinMax(max_level=minmax_level)]
    else:
        raise ValueError, ("Invalid train_mode. Got %s expected "
                           "(mixt|random|minmax)") % train_mode

    scorer = Scorer(stats_frequency)
    for step in xrange(new_models):
        brain = Brain(sim.width, sim.height, sim.actions_count)
        player = QLearn(sim, brain, "AI")

        w = [0.1 * i for i in xrange(1, len(opponents) + 1)]
        p = [wi / sum(w) for wi in w]

        for games in xrange(1, 100000):
            if games % win_threshold_games == 0:
                # If the new model wins more than 90% of the games of the last 300
                win_statistics = scorer.get_statistics(win_threshold_games)[0]
                if win_statistics > win_threshold_percentage:
                    # Save the model to disk and load it as an inference only model
                    model_path = brain.save(models_root)
                    prev_brain = Brain(sim.width,
                                       sim.height,
                                       sim.actions_count,
                                       load_path=model_path)
                    opponents.append(
                        QLearn(sim,
                               prev_brain,
                               "V" + str(step),
                               exploration_period=0,
                               discount_factor=0.9))
                    print "-" * 70
                    print(
                        "New model wins %d%s against previous models after "
                        "%d games") % (win_statistics, "%", games)
                    print "-" * 70
                    print ''
                    break

            opponent = np.random.choice(opponents, 1, p)[0]
            players = [player, opponent]
            play_game_with_opponent(players, sim, scorer)

    human_player = HumanPlayer("Player")
    while True:
        play_game_with_opponent([opponents[-1], human_player], sim, scorer)
예제 #18
0
 def next_exploring_move(self, c4: Game, epsilon=0.2):
     assert c4.on_move == self.color
     explore = np.random.rand() < epsilon
     if explore:
         move = np.random.choice(c4.possible_moves())
     else:
         move = self.next_move(c4)
     return move, {"explore": explore}
예제 #19
0
    def test_win_horizontal(self):
        board = Connect4()
        for i in range(0, 4):
            board.add_to_board(0, i)
        game = Game(board)

        result = game.check_win(1)
        self.assertEqual(result, True)
예제 #20
0
    def minimax(self, game, depth, maximizingPlayer):
        # print('calling minimax')

        # if the node is a terminal node (depth is at zero or the state of the game is gameover
        if depth == 0 or game.turn == 'B_WINS' or game.turn == 'R_WINS':

            if game.turn == self.win_string:
                return 999999999999, None

            elif game.turn == self.lose_string:
                return -999999999999, None

            else:

                board_score = self.heuristic_function(game, self.player_chip)

                return board_score, None
        if maximizingPlayer:
            value = -999999999999
            best_move = 0
            for valid_move in game.available_moves():
                child_game = Connect4(deepcopy(game.board), deepcopy(game.turn), deepcopy(game.last_move), deepcopy(game.total_moves))

                last_move = child_game.drop_chip(valid_move)
                value_this_move = self.minimax(child_game, depth - 1, not maximizingPlayer)[0]

                if value_this_move > value:
                    value = value_this_move
                    best_move = valid_move

            return value, best_move

        else:
            value = 999999999999
            best_move = 0
            for valid_move in game.available_moves():
                # print(valid_move)
                child_game = Connect4(deepcopy(game.board), deepcopy(game.turn), deepcopy(game.last_move), deepcopy(game.total_moves))

                last_move = child_game.drop_chip(valid_move)
                value_this_move = self.minimax(child_game, depth - 1, not maximizingPlayer)[0]

                if value_this_move < value:
                    value = value_this_move
                    best_move = valid_move
            return value, best_move
예제 #21
0
 def test_win_diagonal(self):
     board = Connect4()
     board.board = [['X', 'O'], ['O', 'X', 'X'], ['X'], ['O', 'X', 'X'],
                    ['X', 'O', 'X'], ['O', 'X', 'X', 'X'], ['X', 'O', 'O']]
     game = Game(board)
     board.print_board()
     result = game.check_win(2)
     self.assertEqual(result, True)
예제 #22
0
def test_check_if_game_finished_horizontal_end_of_row():
    c4 = Connect4()
    c4.board = [[0, 0, 0, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]
    assert c4.check_if_game_finished(0, 3)
    assert c4.check_if_game_finished(0, 4)
    assert c4.check_if_game_finished(0, 5)
    assert c4.check_if_game_finished(0, 6)
예제 #23
0
def test_check_if_game_finished_diagonal_right_end():
    c4 = Connect4()
    c4.board = [[0, 0, 0, 1, -1, -1, -1], [0, 0, 0, 0, 1, -1, -1],
                [0, 0, 0, 0, 0, 1, -1], [0, 0, 0, 0, 0, 0, 1],
                [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]
    assert c4.check_if_game_finished(0, 3)
    assert c4.check_if_game_finished(1, 4)
    assert c4.check_if_game_finished(2, 5)
    assert c4.check_if_game_finished(3, 6)
예제 #24
0
    def test_less_than_4_pieces(self):
        board = Connect4()
        for i in range(0, 3):
            board.add_to_board(0, 1)
        game = Game(board)

        result = game.check_vertical_win(1)

        self.assertEqual(result, False)
예제 #25
0
    def test_more_than_4_in_a_column_win(self):
        board = Connect4()
        for i in range(0, 6):
            board.add_to_board(i < 2, 1)
        game = Game(board)

        result = game.check_vertical_win(1)

        self.assertEqual(result, True)
예제 #26
0
    def init_game_connect4(self):
        """Initialize Connect4 game and assign player identifier"""
        self.connect4 = Connect4()

        self.connect4.player_a = ':red_circle:'
        self.connect4.player_b = ':black_circle:'
        self.connect4.empty_block = ':white_square:'

        self.connect4.build_new_board()
예제 #27
0
    def test_is_valid_full_column(self):
        board = Connect4()
        for i in range(0, 6):
            board.add_to_board(0, 2)
        game = Game(board)

        result = game.is_valid(2)

        self.assertEqual(result, False)
예제 #28
0
def test_check_if_game_finished_horizontal_beginning_of_row():
    c4 = Connect4()
    c4.board = [[1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0],
                [0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0]]
    assert c4.check_if_game_finished(0, 0)
    assert c4.check_if_game_finished(0, 1)
    assert c4.check_if_game_finished(0, 2)
    assert c4.check_if_game_finished(0, 3)
예제 #29
0
def run_game():
    # Create a board
    game = Connect4()

    # Initialize the game and create a screen object
    pygame.init()
    screen = pygame.display.set_mode(game.size)
    pygame.display.set_caption("Connect4 Game")
    my_font = pygame.font.SysFont("monospace", 75)

    # Creat methods
    methods = Methods()

    # Print game board
    game.print_board()
    game.draw_board(screen)

    game.turn = 0

    # Start the main loop of the game
    while not game.game_over:
        pygame.display.update()

################################## Connect 4 ###########################################################################
        turn = game.check_event(screen)
        if turn == game.PLAYER:
            col = int(math.floor(game.pos_x / game.SQUARESIZE))
            if game.is_valid_location(col):
                row = game.get_next_open_row(col)
                h = game.ij2h(row, col)
                game.get_move(screen, h, game.PLAYER_PIECE)

        elif turn == game.AI:
            # best_loc, score = methods.mini_max(game, 0, True)
            best_loc, score = methods.alpha_beta_pruning(game, 7, -math.inf, math.inf, True)
            # best_loc, score = methods.monte_carlo(game, 4)
            game.get_move(screen, best_loc, game.AI_PIECE)
            print(best_loc, score)

########################################################################################################################

        if game.game_over:
            if game.winning_move(game.PLAYER_PIECE):
                label = my_font.render("Human wins!!", 1, game.RED)
                screen.blit(label, (120, 50))
                print("Human wins!!")
            elif game.winning_move(game.AI_PIECE):
                label = my_font.render("AI wins!!", 2, game.YELLOW)
                screen.blit(label, (120, 50))
                print("AI wins!!")
            else:
                label = my_font.render("It's a draw!!", 2, game.BLACK)
                screen.blit(label, (120, 50))
                print("It's a draw!!")

            pygame.display.update()
            pygame.time.wait(10000)
예제 #30
0
    def test_win_horizontal_not_0_row(self):
        board = Connect4()
        board.board = [['X', 'O'], ['O', 'X', 'X'], ['X', 'O'],
                       ['O', 'X', 'X'], ['X', 'O', 'X'], ['O', 'X', 'X'],
                       ['X', 'O', 'O']]
        game = Game(board)

        result = game.check_horizontal_win(5)

        self.assertEqual(result, False)