private List <double[]> Evaluate(List <double[]> pop) { foreach (var item in pop) { item[item.Length - 1] = 0; } foreach (var player1 in pop) { AbstractAgent agent1 = new GreedyAgent(); AbstractAgent agent2 = new KISSBot(); Random rnd = new Random(Guid.NewGuid().GetHashCode()); var gameHandler1 = new POGameHandler(gameConfig1, agent1, agent2, repeatDraws: false); var gameHandler2 = new POGameHandler(gameConfig2, agent1, agent2, repeatDraws: false); var gameHandler3 = new POGameHandler(gameConfig3, agent1, agent2, repeatDraws: false); //gameHandler.PlayGame(debug: true); gameHandler1.PlayGames(nr_of_games: _numGames, addResultToGameStats: true, debug: false); gameHandler2.PlayGames(nr_of_games: _numGames, addResultToGameStats: true, debug: false); gameHandler3.PlayGames(nr_of_games: _numGames, addResultToGameStats: true, debug: false); player1[player1.Length - 1] += gameHandler1.getGameStats().PlayerB_Wins; player1[player1.Length - 1] += gameHandler2.getGameStats().PlayerB_Wins; player1[player1.Length - 1] += gameHandler3.getGameStats().PlayerB_Wins; } return(pop.OrderByDescending(x => x[x.Length - 1]).ToList()); }
public static void TestPOGame() { Console.WriteLine("Setup gameConfig"); var gameConfig = new GameConfig() { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player2HeroClass = CardClass.MAGE, Player1Deck = Decks.RenoKazakusMage, Player2Deck = Decks.RenoKazakusMage, FillDecks = false, Shuffle = true, Logging = false }; Console.WriteLine("Setup POGameHandler"); AbstractAgent player1 = new GreedyAgent(); AbstractAgent player2 = new GreedyAgent(); var gameHandler = new POGameHandler(gameConfig, player1, player2, repeatDraws: false); Console.WriteLine("Simulate Games"); //gameHandler.PlayGame(); gameHandler.PlayGames(nr_of_games: 1000, addResultToGameStats: true, debug: false); GameStats gameStats = gameHandler.getGameStats(); gameStats.printResults(); Console.WriteLine("Test successful"); Console.ReadLine(); }
private static void Main() { Console.WriteLine("Setup gameConfig"); var gameConfig = new GameConfig() { StartPlayer = 1, // line for deck selection in here Player1HeroClass = CardClass.WARRIOR, Player2HeroClass = CardClass.WARRIOR, FillDecks = true, Shuffle = true, Logging = false }; Console.WriteLine("Setup POGameHandler"); AbstractAgent player1 = new GreedyAgent(); AbstractAgent player2 = new MyAgent(); var gameHandler = new POGameHandler(gameConfig, player1, player2, repeatDraws: false); Console.WriteLine("Simulate Games"); //gameHandler.PlayGame(); gameHandler.PlayGames(nr_of_games: 100, addResultToGameStats: true, debug: false); GameStats gameStats = gameHandler.getGameStats(); gameStats.printResults(); Console.WriteLine("Test successful"); Console.ReadLine(); }
public void PlayRandomGreedy(Game game) { RandomAgent player1 = new RandomAgent(1); GreedyAgent player2 = new GreedyAgent(2); PlayGame(game, player1, player2); }
public void ShouldPlayCardOnOnlyOwlThatGoesFurthest() { var player = new GreedyAgent(); var state = TestUtilities.GenerateTestState(2, 1); var play = player.FormulatePlay(state); Assert.AreEqual(CardType.Red, play.Card); Assert.AreEqual(0, play.Position); }
public void ShouldPlayCardOnOwlThatGoesFurthestWithHootingIntoNest() { var player = new GreedyAgent(); var state = TestUtilities.GenerateTestState(2); state.Board.Owls.Move(0, 6); var play = player.FormulatePlay(state); Assert.AreEqual(CardType.Red, play.Card); Assert.AreEqual(1, play.Position); }
public void ShouldPlayCardOnOnlyOwlThatGoesFurthestWhenUsingGreedyStrategy() { var player = new EpsilonGreedyAgent(0); var greedyPlayer = new GreedyAgent(); var state = TestUtilities.GenerateTestState(2, 1); var play = player.FormulatePlay(state); var greedyPlay = greedyPlayer.FormulatePlay(state); Assert.AreEqual(play.Card, greedyPlay.Card); Assert.AreEqual(play.Position, greedyPlay.Position); }
private static void testWeights(Dictionary <string, CardClass> classMap, Dictionary <string, List <Card> > deckMap, List <string> deckList, List <double> weights) { Console.WriteLine("Simulate Games"); Random r = new Random(); double wins = 0.0; double losses = 0.0; double numGames = 3000; for (int i = 0; i < numGames; i++) { string p1Deck = deckList[r.Next(deckList.Count)]; string p2Deck = deckList[r.Next(deckList.Count)]; var gameConfig = new GameConfig() { StartPlayer = r.Next(2) + 1, Player1HeroClass = classMap.GetValueOrDefault(p1Deck, CardClass.MAGE), Player2HeroClass = classMap.GetValueOrDefault(p2Deck, CardClass.ROGUE), Player1Deck = deckMap.GetValueOrDefault(p1Deck, Decks.RenoKazakusMage), Player2Deck = deckMap.GetValueOrDefault(p2Deck, Decks.MiraclePirateRogue), FillDecks = true, Shuffle = true, Logging = false }; AbstractAgent player1 = new GreedyAgent(); AbstractAgent player2 = new NNAgent(weights); Console.WriteLine("Game " + i + " " + p1Deck + " " + p2Deck); var gameHandler = new POGameHandler(gameConfig, player1, player2, repeatDraws: false); gameHandler.PlayGames(nr_of_games: 1, addResultToGameStats: true, debug: false); GameStats gameStats = gameHandler.getGameStats(); wins += gameStats.PlayerB_Wins; losses += gameStats.PlayerA_Wins; } Console.WriteLine("Bot winrate: " + (wins / (wins + losses))); Console.WriteLine("Wins: " + wins); Console.WriteLine("Losses: " + losses); Console.WriteLine("Draws: " + (numGames - (wins + losses))); }
//? To score a game we set up three kinds of matchup, condense each one into a score, //? add the scores together and then normalise them between 0 and 1. public IEnumerator ScoreGame(Game game) { //? Reset playerBiasScore = 0f; greedIsGoodScore = 0f; skillIsBetterScore = 0f; drawsAreBadScore = 0f; highSkillBalanceScore = 0f; string scoresSoFar = ""; if (interfaceEnabled) { currentRulesText.text = game.GameToString(); scoresSoFar = "First Play Bias: " + ToScore(playerBiasScore) + "\n"; currentScoresText.text = scoresSoFar; yield return(0); } //? Random vs. Random: These games can go either way, the only thing we're interested //? is if there's a clear bias towards playing first or second. This is a good indicator. //? Score is therefore proportional to the amount one agent won over the other. RandomAgent randomAgent1 = new RandomAgent(1); RandomAgent randomAgent2 = new RandomAgent(2); int firstWon = 0; int secondWon = 0; for (int i = 0; i < randomRandomMatches; i++) { if (interfaceEnabled) { currentScoresText.text = "First Play Bias: Playing (" + i + "/" + randomRandomMatches + ")\n"; } //NOTE MJ: Playing the games could be coroutines, so they don't block UI. //res is redundant game.endStatus already has info. yield return(GameEvaluation.instance.PlayGame(game, randomAgent1, randomAgent2)); if (game.endStatus == 1) { firstWon++; } if (game.endStatus == 2) { secondWon++; } //? Yield after each playout - we could yield more frequently, this is OK though. yield return(0); } playerBiasScore = 1 - (Mathf.Abs(firstWon - secondWon) / randomRandomMatches); if (interfaceEnabled) { scoresSoFar = "First Play Bias: " + ToScore(playerBiasScore) + "\n"; currentScoresText.text = scoresSoFar; yield return(0); } //? We could also add in a measure of 'decisiveness' - i.e. games shouldn't end in draws. //? However for random agents this might happen just because they aren't very good. //? Random vs. Greedy: Greedy may not always win the game, but we expect it to //? win more than random. Score is proportion to the number of games greedy won or tied. int randomAgentWon = 0; for (int i = 0; i < greedyRandomMatches; i++) { if (interfaceEnabled) { currentScoresText.text = scoresSoFar + "Simple Beats Random: Playing (" + i + "/" + greedyRandomMatches + ")\n"; yield return(0); } //? Small detail: note that we swap who plays first, to compensate //? for first-player advantage RandomAgent randomAgent = new RandomAgent(1 + (i % 2)); GreedyAgent greedyAgent = new GreedyAgent(2 - (i % 2)); //NOTE MJ: Playing the games could be coroutines, so they don't block UI. res could be an out parameter. yield return(GameEvaluation.instance.PlayGame(game, randomAgent, greedyAgent)); if (game.endStatus == 1 + (i % 2)) { randomAgentWon++; } yield return(0); } greedIsGoodScore = 1 - ((float)randomAgentWon / greedyRandomMatches); if (interfaceEnabled) { scoresSoFar += "Simple Beats Random: " + ToScore(greedIsGoodScore) + "\n"; currentScoresText.text = scoresSoFar; yield return(0); } //? Greedy vs. MCTS: We know that greedy players will avoid causing their own loss, and //? win if given the opportunity, but MCTS players can look ahead and plan. As a result, //? a more strategic game should be won by MCTS agents. Score is proportion of games MCTS //? agent won. Note that we might need to give the MCTS agent more computational resources //? for some games to ensure it is performing better. int mctsAgentWon = 0; for (int i = 0; i < greedySkilledMatches; i++) { if (interfaceEnabled) { currentScoresText.text = scoresSoFar + "Clever Beats Simple: Playing (" + i + "/" + greedySkilledMatches + ")\n"; yield return(0); } MCTSAgent skilledAgent = new MCTSAgent(1 + (i % 2)); GreedyAgent greedyAgent = new GreedyAgent(2 - (i % 2)); //NOTE MJ: Playing the games could be coroutines, so they don't block UI. res could be an out parameter. yield return(GameEvaluation.instance.PlayGame(game, skilledAgent, greedyAgent)); if (game.endStatus == 1 + (i % 2)) { mctsAgentWon++; } yield return(0); } skillIsBetterScore = (float)mctsAgentWon / greedySkilledMatches; if (interfaceEnabled) { scoresSoFar += "Clever Beats Simple: " + ToScore(skillIsBetterScore) + "\n"; currentScoresText.text = scoresSoFar; yield return(0); } //? Finally, MCTS vs MCTS. If we wanted more depth, we could do two version of this, //? one with MCTS agents that are given different amounts of computation, to really //? test to see if more thinking time = better play. However, here we're just going to //? test a good old fashioned mirror matchup. For two good equal players, we want //? a) not too much imbalance in favour of either player and b) not too many draws. int drawnGames = 0; int firstPlayerWon = 0; int secondPlayerWon = 0; MCTSAgent skilledAgent1 = new MCTSAgent(1); MCTSAgent skilledAgent2 = new MCTSAgent(2); for (int i = 0; i < skilledMirrorMatches; i++) { if (interfaceEnabled) { currentScoresText.text = scoresSoFar + "Avoid Draws: Playing (" + i + "/" + skilledMirrorMatches + ")\n" + "High Skill Mirror Matchup: Playing (" + i + "/" + skilledMirrorMatches + ")\n"; yield return(0); } //NOTE MJ: Playing the games could be coroutines, so they don't block UI. res could be an out parameter. yield return(GameEvaluation.instance.PlayGame(game, skilledAgent1, skilledAgent2)); if (game.endStatus == 1) { firstPlayerWon++; } if (game.endStatus == 2) { secondPlayerWon++; } if (game.endStatus == 3 || game.endStatus == 0) { drawnGames++; } yield return(0); } drawsAreBadScore = 1 - ((float)drawnGames / skilledMirrorMatches); highSkillBalanceScore = Mathf.Abs(firstPlayerWon - secondPlayerWon) / skilledMirrorMatches; if (interfaceEnabled) { currentScoresText.text = scoresSoFar + "Avoid Draws: " + ToScore(drawsAreBadScore) + "\n" + "High Skill Mirror Matchup: " + ToScore(highSkillBalanceScore) + "\n"; yield return(0); } //? Now we can add up the scores and return them. If we wanted we could balance them so //? some scores are more important than others, or we could partition them into "must-haves" //? and "nice-to-haves". I discuss this in the tutorial video. // Debug.Log("Random vs. Random: "+playerBiasScore); // Debug.Log("Greedy vs. Random: "+greedIsGoodScore); // Debug.Log("MCTS vs. Greedy: "+skillIsBetterScore); // Debug.Log("MCTS vs. MCTS (draws): "+drawsAreBadScore); // Debug.Log("MCTS vs. MCTS (win balance): "+highSkillBalanceScore); game.evaluatedScore = (playerBiasScore + greedIsGoodScore + skillIsBetterScore + drawsAreBadScore + highSkillBalanceScore) / 5f; }
private static void Main() { Console.WriteLine("Setup gameConfig"); double[] values = new double[] { 41.9584023938321, 20.9314780959075, 42.5709950325876, 29.2160915509873, 3.02713018633757, 39.1902154319408, 16.5569344163206, 41.7280641359873, 25.5307942824582, 44.74108665634, 26.4395090874469, 34.6203779911717 }; //var gameConfig = new GameConfig() //{ // StartPlayer = 1, // Player1HeroClass = CardClass.SHAMAN, // Player2HeroClass = CardClass.SHAMAN, // Player1Deck = Decks.MidrangeJadeShaman, // Player2Deck = Decks.MidrangeJadeShaman, // FillDecks = true, // Shuffle = true, // Logging = false, // History = true //}; //EA ea = new EA(100, 0.1f, 6, 10, 4, 12); //var result = ea.StartEA(); //Console.WriteLine("Values"); //foreach (var item in result) //{ // Console.WriteLine(String.Join(',', item)); //} Console.WriteLine("Setup POGameHandler"); AbstractAgent player1 = new GreedyAgent(); AbstractAgent player2 = new KISSBot(); Random rnd = new Random(Guid.NewGuid().GetHashCode()); GameConfig gameConfig1 = new GameConfig() { StartPlayer = 1, Player1HeroClass = CardClass.SHAMAN, Player2HeroClass = CardClass.SHAMAN, Player1Deck = Decks.MidrangeJadeShaman, Player2Deck = Decks.MidrangeJadeShaman, FillDecks = true, Shuffle = true, Logging = false, History = true }; GameConfig gameConfig2 = new GameConfig() { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player2HeroClass = CardClass.MAGE, Player1Deck = Decks.RenoKazakusMage, Player2Deck = Decks.RenoKazakusMage, FillDecks = true, Shuffle = true, Logging = false, History = true }; GameConfig gameConfig3 = new GameConfig() { StartPlayer = 1, Player1HeroClass = CardClass.WARRIOR, Player2HeroClass = CardClass.WARRIOR, Player1Deck = Decks.AggroPirateWarrior, Player2Deck = Decks.AggroPirateWarrior, FillDecks = true, Shuffle = true, Logging = false, History = true }; Console.WriteLine("Simulate Games"); var gameHandler1 = new POGameHandler(gameConfig1, player2, player1, repeatDraws: false); var gameHandler11 = new POGameHandler(gameConfig1, player1, player2, repeatDraws: false); var gameHandler2 = new POGameHandler(gameConfig2, player2, player1, repeatDraws: false); var gameHandler21 = new POGameHandler(gameConfig2, player1, player2, repeatDraws: false); var gameHandler3 = new POGameHandler(gameConfig3, player2, player1, repeatDraws: false); var gameHandler31 = new POGameHandler(gameConfig3, player1, player2, repeatDraws: false); //gameHandler11.PlayGame(debug: true); //gameHandler11.getGameStats().printResults(); gameHandler1.PlayGames(nr_of_games: 100, addResultToGameStats: true, debug: false); gameHandler1.getGameStats().printResults(); gameHandler11.PlayGames(nr_of_games: 100, addResultToGameStats: true, debug: false); gameHandler11.getGameStats().printResults(); gameHandler2.PlayGames(nr_of_games: 100, addResultToGameStats: true, debug: false); gameHandler2.getGameStats().printResults(); gameHandler21.PlayGames(nr_of_games: 100, addResultToGameStats: true, debug: false); gameHandler21.getGameStats().printResults(); gameHandler3.PlayGames(nr_of_games: 100, addResultToGameStats: true, debug: false); gameHandler3.getGameStats().printResults(); gameHandler31.PlayGames(nr_of_games: 100, addResultToGameStats: true, debug: false); gameHandler31.getGameStats().printResults(); Console.ReadLine(); }