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
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())
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], })
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
def test_is_valid_empty_column(self): board = Connect4() game = Game(board) result = game.is_valid(4) self.assertEqual(result, True)
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'))
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')
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]
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)
def test_is_valid_negative_column(self): board = Connect4() game = Game(board) result = game.is_valid(-4) self.assertEqual(result, False)
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)
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)
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()
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)
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'))
def test_get_move_user(self, input): board = Connect4() game = Game(board) game.get_move() self.assertEqual(game.board.board[5][0], 'X')
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)
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}
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)
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
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)
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)
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)
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)
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)
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()
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)
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)
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)
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)