def play_against(self, opponent: Player, game: Connect4Game = Connect4Game()): """ Make the agent play against another player on the given game or a new game. If both player have the same game turn id, self will change its game turn id Returns the winner :param opponent: another player :param game: The current game, if nothing specified then a new game :return: the winner (0 for draw, 1 for player 1, 2 for player 2 """ if self.player_turn_id == opponent.player_turn_id: self.player_turn_id = 3 - self.player_turn_id yellow_goes_first = game.get_turn() == 1 winner = game.get_win() while winner is None: if game.get_turn() == self.player_turn_id: game.place(self.choose_action(game)) else: game.place(opponent.choose_action(game)) winner = game.get_win() if winner != 0 and not yellow_goes_first: winner = 3 - winner return winner
def choose_action(self, game: Connect4Game): board = game.transform_board()[0] # Get the prediction prediction = self.forward_pass(board) # Remove full column prediction = [ 0 if game.board[i][-1] != 0 else prediction[0][i] for i in range(len(game.board)) ] return np.argmax(prediction)
async def play(self, ctx, *, player2: discord.Member): """ Play connect4 with another player """ player1 = ctx.message.author game = Connect4Game( player1.display_name, player2.display_name ) message = await ctx.send(str(game)) for digit in self.DIGITS: await message.add_reaction(digit) def check(reaction, user): return ( user == (player1, player2)[game.whomst_turn()-1] and str(reaction) in self.VALID_REACTIONS and reaction.message.id == message.id ) while game.whomst_won() == game.NO_WINNER: try: reaction, user = await self.bot.wait_for( 'reaction_add', check=check, timeout=self.GAME_TIMEOUT_THRESHOLD ) except asyncio.TimeoutError: game.forfeit() break await asyncio.sleep(0.2) try: await message.remove_reaction(reaction, user) except discord.errors.Forbidden: pass if str(reaction) == self.CANCEL_GAME_EMOJI: game.forfeit() break try: # convert the reaction to a 0-indexed int and move in that column game.move(self.DIGITS.index(str(reaction))) except ValueError: pass # the column may be full await message.edit(content=str(game)) await self.end_game(game, message)
def get_random_hypothetical_game_history(): """ Constructs a game by making an agent play against himself (since he is random, his turn id doesn't matter) :return: """ game = Connect4Game() player = RandomPlayer.RandomPlayer(3 - game.get_turn()) while game.get_win() is None: placement = player.choose_action(game) if placement is not None: game.place(placement) return game.history
def compute_fitness(self): """ The fitness of one player is computed by making him play 10 times against a MinMaxPlayer :return: """ player_score = 1 # Since this will be used for probabilities, no one should have a score of 0 for i in range(10): game = Connect4Game() opponent = MinMaxPlayer(player_turn_id=3 - game.get_turn()) winner = self.play_against(opponent, game) if winner == 0: # Tie player_score += 50 elif winner == self.player_turn_id: # Won player_score += 100 return player_score
def get_minmax_game_history(difficulty=2): """ Constructs a game by making a minmax agent play against another minmax agent :param difficulty: :return: """ game = Connect4Game() player_a = MinMaxPlayer.MinMaxPlayer(3 - game.get_turn()) player_b = MinMaxPlayer.MinMaxPlayer(3 - player_a.player_turn_id) while game.get_win() is None: placement = player_a.choose_action(game, difficulty) game.place(placement) if game.get_win() is not None: break placement = player_b.choose_action(game, difficulty) game.place(placement) return game.history
def compute_fitness(player: Player.Player): """ Compute the fitness of the agent. This is done by playing 10 times against a minmax player followed by 10 other games against a random player to differentiate agents with low but better than random reasoning :return: the score """ game = Connect4Game() score = 1 for _ in range(10): adversary = MinMaxPlayer.MinMaxPlayer(random.randint(1, 2)) winner = player.play_against(adversary, game) if winner == player.player_turn_id: score += 1 for _ in range(10): adversary = RandomPlayer.RandomPlayer(random.randint(1, 2)) winner = player.play_against(adversary, game) if winner == player.player_turn_id: score += 1 return score
def choose_action(self, game: Connect4Game) -> int: best_substring = "" letter = None for gh_i in range(len(game.history)): for chromo in self.chromosomes: if chromo[-1] != str(game.get_turn()): continue substring = game.history[gh_i:-2] index = chromo.rfind(substring) # Search from the end # If we found the substring and is longer than the previous best # and that it is not the game outcome if index != -1 and len(substring) > len(best_substring): best_substring = substring letter = chromo[index + len(best_substring)].lower() # If nothing was found if letter is None or game.history.count( letter.lower()) + game.history.count(letter.upper()) >= 6: action = random.randint(0, 6) else: action = ord(letter) - ord("a") return action
scores = scores + scores_2 return scores / sum(scores) # makes the total equals to 1 if __name__ == '__main__': MinMaxPlayer.MinMaxPlayer.difficulty = 2 gen = Generation(20, 100, 1) best_player = None max_fitness = 0 for player in gen.players: fitness = compute_fitness(player) if fitness > max_fitness: max_fitness = fitness best_player = player player = best_player game = Connect4Game() game.reset_game() view = Connect4Viewer(game=game) view.initialize() running = True while running: for i, event in enumerate(pygame.event.get()): if event.type == pygame.QUIT: running = False if event.type == pygame.MOUSEBUTTONUP and event.button == 1: if game.get_win() is None: placement = game.place(pygame.mouse.get_pos()[0] // SQUARE_SIZE) if placement is None: # Still player's turn if placement fails continue if game.get_win() is not None: game.reset_game()
else: action = ord(letter) - ord("a") return action if __name__ == '__main__': # for h in [CombinatorialPlayer.get_random_hypothetical_game_history() for _ in range(10)]: # print(h) # board = Connect4Game.from_history(h) # for col in board.board: # print(col) # print(board.get_win(), board.history) # # player = [CombinatorialPlayer(5), CombinatorialPlayer(5)] # board = Connect4Game.from_history("dAgDeAfFeBaDdCeBeAaAcDbFb") # player[0].choose_action(board) # new_player = CombinatorialPlayer.reproduce(player) # for p in player: # print(p.chromosomes) # print(new_player.chromosomes) player_a = CombinatorialPlayer(24) player_b = CombinatorialPlayer(24) player_c = CombinatorialPlayer.reproduce((player_a, player_b))[0] history = "BfFaEdBeAgGaDbFgDdEcFaCaGcFcBcBaGgBdDfCeEe" board = Connect4Game.from_history(history) player_a.choose_action(board) player_b.choose_action(board) player_c.choose_action(board)