public static int OneRoundAOE(List <string> AICards, List <Card> combo, string comboClass) { if (!CARDCLASS.ContainsKey(comboClass)) { return(-1); } var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player2HeroClass = (CardClass)CARDCLASS[comboClass], Shuffle = false, FillDecks = true, FillDecksPredictably = false }); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.StartGame(); foreach (string cardname in AICards) //draw all cards due to mana cost limit to 10/round { //Console.WriteLine(cardname); game.Process(PlayCardTask.Any(game.CurrentPlayer, Entity.FromCard(game.CurrentPlayer, Cards.FromName(cardname), zone: game.CurrentPlayer.HandZone))); game.Process(EndTurnTask.Any(game.CurrentPlayer)); //end round switch to our side game.Process(EndTurnTask.Any(game.CurrentPlayer)); //end round skip our side, back to opponent } game.Process(EndTurnTask.Any(game.CurrentPlayer)); //end round switch to our side if (combo[0].Type.ToString() != "MINION") //minion card use first { combo.Reverse(); } foreach (Card card in combo) //use card one by one { if (card.Type.ToString() != "MINION") { IPlayable SpellTest = Generic.DrawCard(game.CurrentPlayer, card); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, SpellTest, game.CurrentOpponent.BoardZone[0])); } else //spell or weapon { game.Process(PlayCardTask.Any(game.CurrentPlayer, Entity.FromCard(game.CurrentPlayer, card, zone: game.CurrentPlayer.HandZone))); } } /*Program.ShowLog(game, LogLevel.VERBOSE); * Console.WriteLine(game.CurrentOpponent.BoardZone.FullPrint()); * Console.WriteLine(game.CurrentPlayer.BoardZone.FullPrint());*/ int health = game.CurrentOpponent.BoardZone.Health(); return(health); }
public void BasicHealthAuraTest1() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PALADIN, Player2HeroClass = CardClass.MAGE, FillDecks = true, FillDecksPredictably = true }); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.StartGame(); IPlayable minion1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Stormwind Champion")); IPlayable minion2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Stormwind Champion")); IPlayable minion3 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Shattered Sun Cleric")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion1)); game.CurrentPlayer.UsedMana = 0; game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion2)); game.CurrentPlayer.UsedMana = 0; game.Process(PlayCardTask.MinionTarget(game.CurrentPlayer, minion3, minion2)); game.CurrentPlayer.UsedMana = 0; game.Process(EndTurnTask.Any(game.CurrentPlayer)); IPlayable spell1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Flamestrike")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, spell1)); game.CurrentPlayer.UsedMana = 0; IPlayable spell2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Arcane Explosion")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, spell2)); IPlayable spell3 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Arcane Explosion")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, spell3)); Assert.Equal(2, ((ICharacter)minion2).Health); IPlayable spell4 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Arcane Explosion")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, spell4)); Assert.Equal(1, ((ICharacter)minion2).Health); Assert.Equal(Zone.PLAY, ((ICharacter)minion2).Zone.Type); }
/// <inheritdoc /> public SabberStoneAction Act(SabberStoneState state) { var timer = System.Diagnostics.Stopwatch.StartNew(); var gameState = (SabberStoneState)state.Copy(); if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine(Name()); } if (_debug) { Console.WriteLine($"Starting a NMCTS search in turn {(gameState.Game.Turn + 1) / 2}"); } // Setup and start the ensemble-search EnsembleSolutions = new List <SabberStoneAction>(); var search = (NMCTS <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction>)Builder.Build(); var context = SearchContext <List <SabberStoneAction>, SabberStoneState, SabberStoneAction, object, SabberStoneAction> .GameSearchSetup(GameLogic, EnsembleSolutions, gameState, null, search); Ensemble.EnsembleSearch(context, Searcher.Search, EnsembleSize); IterationsSpent = EnsembleSolutions.Sum(i => i.BudgetUsed); // Determine the best tasks to play based on the ensemble search, or just take the one in case of a single search. var solution = EnsembleSize > 1 ? Searcher.VoteForSolution(EnsembleSolutions, state) : EnsembleSolutions.First(); if (_debug) { Console.WriteLine(); } if (_debug) { Console.WriteLine($"NMCTS returned with solution: {solution}"); } if (_debug) { Console.WriteLine($"My total calculation time was: {timer.ElapsedMilliseconds} ms."); } // Check if the solution is a complete action. if (!solution.IsComplete()) { // Otherwise add an End-Turn task before returning. if (_debug) { Console.WriteLine("Solution was an incomplete action; adding End-Turn task."); } solution.Tasks.Add((SabberStonePlayerTask)EndTurnTask.Any(Player)); } if (_debug) { Console.WriteLine(); } return(solution); }
public static PlayerTask CreatePlayerTaskOption(Game game, PowerOption powerOption, int sendOptionTarget, int sendOptionPosition, int sendOptionSubOption) { //var allOptions = _game.AllOptionsMap[sendOptionId]; //var tasks = allOptions.PlayerTaskList; //var powerOption = allOptions.PowerOptionList[sendOptionMainOption]; var optionType = powerOption.OptionType; PlayerTask task = null; switch (optionType) { case OptionType.END_TURN: task = EndTurnTask.Any(game.CurrentPlayer); break; case OptionType.POWER: var mainOption = powerOption.MainOption; var source = game.IdEntityDic[mainOption.EntityId]; var target = sendOptionTarget > 0 ? (ICharacter)game.IdEntityDic[sendOptionTarget] : null; var subObtions = powerOption.SubOptions; if (source.Zone?.Type == Zone.PLAY) { task = MinionAttackTask.Any(game.CurrentPlayer, source, target); } else { switch (source.Card.Type) { case CardType.HERO: task = target != null ? (PlayerTask)HeroAttackTask.Any(game.CurrentPlayer, target) : PlayCardTask.Any(game.CurrentPlayer, source); break; case CardType.HERO_POWER: task = HeroPowerTask.Any(game.CurrentPlayer, target); break; default: task = PlayCardTask.Any(game.CurrentPlayer, source, target, sendOptionPosition, sendOptionSubOption); break; } } break; case OptionType.PASS: break; default: throw new NotImplementedException(); } //Log.Info($"{task?.FullPrint()}"); return(task); }
public static PlayerTask KettleOptionToPlayerTask(Game Game, int sendOptionId, int sendOptionMainOption, int sendOptionTarget, int sendOptionPosition, int sendOptionSubOption) { SabberStoneCore.Kettle.PowerAllOptions allOptions = Game.AllOptionsMap[sendOptionId]; Console.WriteLine(allOptions.Print()); List <PlayerTask> tasks = allOptions.PlayerTaskList; SabberStoneCore.Kettle.PowerOption powerOption = allOptions.PowerOptionList[sendOptionMainOption]; OptionType optionType = powerOption.OptionType; PlayerTask task = null; switch (optionType) { case OptionType.END_TURN: task = EndTurnTask.Any(Game.CurrentPlayer); break; case OptionType.POWER: SabberStoneCore.Kettle.PowerSubOption mainOption = powerOption.MainOption; IPlayable source = Game.IdEntityDic[mainOption.EntityId]; IPlayable target = sendOptionTarget > 0 ? Game.IdEntityDic[sendOptionTarget] : null; List <SabberStoneCore.Kettle.PowerSubOption> subObtions = powerOption.SubOptions; if (source.Zone?.Type == Zone.PLAY) { task = MinionAttackTask.Any(Game.CurrentPlayer, source, target); } else { switch (source.Card.Type) { case CardType.HERO: task = HeroAttackTask.Any(Game.CurrentPlayer, target); break; case CardType.HERO_POWER: task = HeroPowerTask.Any(Game.CurrentPlayer, target); break; default: task = PlayCardTask.Any(Game.CurrentPlayer, source, target, sendOptionPosition, sendOptionSubOption); break; } } break; case OptionType.PASS: break; default: throw new NotImplementedException(); } return(task); }
/// <summary> /// Plays out a player's turn. /// Note: this method continuously asks the bot to Act and stops when 'null' is returned. /// </summary> /// <param name="game">The current game state.</param> /// <param name="bot">The bot that should play the turn.</param> private void PlayPlayerTurn(SabberStoneState game, ISabberStoneBot bot) { var currentPlayerName = game.Game.CurrentPlayer.Name; if (_printToConsole) { Console.WriteLine($"- <{currentPlayerName}> ---------------------------"); } var timer = Stopwatch.StartNew(); // Ask the bot to act. var action = bot.Act(game); timer.Stop(); // In the case where an incomplete action was returned, add end-turn if (!action.IsComplete()) { Console.WriteLine("WARNING: Incomplete action received. Adding EndTurn."); action.AddTask((SabberStonePlayerTask)EndTurnTask.Any(game.Game.CurrentPlayer)); } // Process the tasks in the action var executedTasks = new List <SabberStonePlayerTask>(); foreach (var item in action.Tasks) { if (_printToConsole) { Console.WriteLine(item.Task.FullPrint()); } try { // Process the task game.Game.Process(item.Task); executedTasks.Add(item); } catch (Exception e) { Console.WriteLine($"ERROR: Exception thrown while processing a task for {game.Game.CurrentPlayer.Name} in turn {game.Game.Turn}."); WriteExceptionToFile(e); // If the game is still running and the current player is still active, pass the turn if (game.Game.CurrentPlayer.Id == bot.PlayerID()) { game.Game.Process(EndTurnTask.Any(game.Game.CurrentPlayer)); } // Do not continue with any other tasks in this action break; } } // Store the action in the match-statistics MatchStatistics.ProcessAction(currentPlayerName, executedTasks, timer.Elapsed, bot.BudgetSpent(), bot.MaxDepth()); if (_printToConsole) { Console.WriteLine($"*Action computation time: {timer.Elapsed:g}"); } }
/// <summary> /// Creates a SabberStoneAction from a collection of possible solutions by voting for separate tasks. /// </summary> /// <param name="solutions">The available solutions.</param> /// <param name="state">The game state.</param> /// <returns>SabberStoneAction.</returns> public SabberStoneAction VoteForSolution(List <SabberStoneAction> solutions, SabberStoneState state) { // Clone game so that we can process the selected tasks and get an updated options list. var clonedGame = state.Game.Clone(); var action = new SabberStoneAction(); // Have all solutions vote on tasks var taskVotes = new Dictionary <int, int>(); foreach (var solution in solutions) { foreach (var task in solution.Tasks) { var taskHash = task.GetHashCode(); if (!taskVotes.ContainsKey(taskHash)) { taskVotes.Add(taskHash, 0); } taskVotes[taskHash]++; } } // Keep selecting tasks until the action is complete or the game has ended while (!action.IsComplete() && clonedGame.State != State.COMPLETE) { // Make a dictionary of available tasks, indexed by their hashcode, but ignore the END-TURN task for now var availableTasks = clonedGame.CurrentPlayer.Options().Where(i => i.PlayerTaskType != PlayerTaskType.END_TURN).Select(i => (SabberStonePlayerTask)i).ToList(); // Pick the one with most votes var votedOnTasks = availableTasks.Where(i => taskVotes.ContainsKey(i.GetHashCode())).ToList(); var mostVoted = votedOnTasks.OrderByDescending(i => taskVotes[i.GetHashCode()]).FirstOrDefault(); // If this is null, it means none of the tasks that are available appear in any of the solutions if (mostVoted == null) { // End the turn action.AddTask((SabberStonePlayerTask)EndTurnTask.Any(clonedGame.CurrentPlayer)); break; } // Find any tasks tied for most votes var mostVotes = taskVotes[mostVoted.GetHashCode()]; var ties = votedOnTasks.Where(i => taskVotes[i.GetHashCode()] == mostVotes); // Add one of the tasks with the most votes to the action //TODO Ties during voting can be handled differently than random, but handling ties based on visit count would require extra information from the separate searches' solutions. var chosenTask = ties.RandomElementOrDefault(); action.AddTask(chosenTask); // Process the task so we have an updated options list next iteration clonedGame.Process(chosenTask.Task); } return(action); }
public void CloneAura() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player2HeroClass = CardClass.MAGE, Player2Deck = new List <Card> { Cards.FromName("Mana Wyrm"), Cards.FromName("Kirin Tor Mage"), Cards.FromName("Vaporize") }, Shuffle = false, FillDecks = false, History = false, }); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.StartGame(); game.Process(EndTurnTask.Any(game.CurrentPlayer)); PlayCardTask task1 = PlayCardTask.Any(game.CurrentPlayer, "Mana Wyrm"); PlayCardTask task2 = PlayCardTask.Any(game.CurrentPlayer, "The Coin"); game.Process(task1); Game clone = game.Clone(); clone.Process(task1); game.Process(task2); clone.Process(task2); Game clone2 = clone.Clone(); var minion = game.CurrentPlayer.BoardZone[0]; var cloneMinion = clone.CurrentPlayer.BoardZone[0]; var clone2Minion = clone2.CurrentPlayer.BoardZone[0]; Assert.Equal(2, minion.AttackDamage); Assert.Equal(2, cloneMinion.AttackDamage); Assert.Equal(2, clone2Minion.AttackDamage); clone2.Process(PlayCardTask.Any(game.CurrentPlayer, "Kirin Tor Mage")); Assert.Equal(2, clone2.Auras.Count); Game clone3 = clone2.Clone(); var task3 = PlayCardTask.Any(game.CurrentPlayer, "Vaporize"); clone3.Process(task3); clone2.Process(task3); Assert.Single(clone2.Auras); Assert.Single(clone3.Auras); Assert.Equal(3, clone2Minion.AttackDamage); }
public void SummonFailTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PALADIN, Player2HeroClass = CardClass.MAGE, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); Assert.Equal(6, game.CurrentPlayer.BoardZone.Count); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); Assert.Equal(7, game.CurrentPlayer.BoardZone.Count); game.Process(HeroPowerTask.Any(game.CurrentPlayer)); Assert.Equal(7, game.CurrentPlayer.BoardZone.Count); }
public void CloneAura2() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player1Deck = new List <Card> { Cards.FromName("Sorcerer's Apprentice"), Cards.FromName("Counterspell") }, Player2HeroClass = CardClass.MAGE, Player2Deck = new List <Card> { Cards.FromName("Sorcerer's Apprentice"), Cards.FromName("Counterspell"), Cards.FromName("Vaporize") }, Shuffle = false, FillDecks = false, History = false, }); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.StartGame(); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Sorcerer's Apprentice")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Sorcerer's Apprentice")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); Assert.Equal(2, game.Auras.Count); Assert.Equal(2, game.CurrentPlayer.HandZone[0].Cost); Assert.Equal(2, game.CurrentOpponent.HandZone[0].Cost); Assert.Equal(2, game.CurrentOpponent.HandZone[1].Cost); Game clone = game.Clone(); Assert.Equal(2, clone.Auras.Count); Assert.Equal(2, clone.CurrentPlayer.HandZone[0].Cost); Assert.Equal(2, clone.CurrentOpponent.HandZone[0].Cost); Assert.Equal(2, clone.CurrentOpponent.HandZone[1].Cost); clone.Process(MinionAttackTask.Any(clone.CurrentPlayer, clone.CurrentPlayer.BoardZone[0], clone.CurrentOpponent.BoardZone[0])); Assert.Empty(clone.Auras); Assert.Equal(3, clone.CurrentPlayer.HandZone[0].Cost); Assert.Equal(3, clone.CurrentOpponent.HandZone[0].Cost); Assert.Equal(3, clone.CurrentOpponent.HandZone[1].Cost); }
public void BasicHealthAuraTest3() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PRIEST, Player2HeroClass = CardClass.WARLOCK, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; var minion1 = (ICharacter)Generic.DrawCard(game.Player1, Cards.FromName("Murloc Raider")); var minion2 = (ICharacter)Generic.DrawCard(game.Player1, Cards.FromName("Murloc Warleader")); IPlayable minion3 = Generic.DrawCard(game.Player1, Cards.FromName("Stormwind Champion")); IPlayable minion4 = Generic.DrawCard(game.Player1, Cards.FromName("Ironbeak Owl")); IPlayable spell1 = Generic.DrawCard(game.Player1, Cards.FromName("Power Word: Shield")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion1)); game.Player1.UsedMana = 0; game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion2)); game.Player1.UsedMana = 0; game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion3)); game.Player1.UsedMana = 0; game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell1, minion1)); Assert.Equal(4, minion1.Health); Assert.Equal(4, minion2.Health); Assert.Equal(6, ((ICharacter)minion3).Health); game.Process(PlayCardTask.MinionTarget(game.CurrentPlayer, minion4, minion2)); Assert.Equal(4, minion1.Health); Assert.Equal(4, minion2.Health); Assert.Equal(6, ((ICharacter)minion3).Health); Assert.Equal(2, ((ICharacter)minion4).Health); game.Process(EndTurnTask.Any(game.CurrentPlayer)); IPlayable spell2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Hellfire")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, spell2)); Assert.Equal(1, minion1.Health); Assert.Equal(1, minion2.Health); Assert.Equal(3, ((ICharacter)minion3).Health); Assert.True(((ICharacter)minion4).IsDead); }
private static void ChooseOneTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.DRUID, Player1Deck = new List <Card>() { Cards.FromName("Stonetusk Boar"), Cards.FromName("Bloodfen Raptor"), Cards.FromName("Raven Idol"), Cards.FromName("Living Roots"), Cards.FromName("Druid of the Saber"), Cards.FromName("Wrath"), Cards.FromName("Power of the Wild"), }, Player2HeroClass = CardClass.DRUID, Player2Deck = new List <Card>() { Cards.FromName("Stonetusk Boar"), Cards.FromName("Bloodfen Raptor"), Cards.FromName("Raven Idol"), Cards.FromName("Living Roots"), Cards.FromName("Druid of the Saber"), Cards.FromName("Wrath"), Cards.FromName("Power of the Wild"), }, SkipMulligan = true, Shuffle = false, FillDecks = true }); game.StartGame(); game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); game.Process(EndTurnTask.Any(game.CurrentPlayer)); var options = game.CurrentPlayer.Options(); Console.WriteLine($" *** - {game.CurrentPlayer.Name} options on {game.Turn}. - ***"); options.ForEach(p => Console.WriteLine(p.FullPrint())); Console.WriteLine($" *** - PowerOptions - ***"); Console.WriteLine(PowerOptionsBuilder.AllOptions(game, options)?.Print()); //ShowLog(game, LogLevel.VERBOSE); }
public static void AuraTimingTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PALADIN, Player2HeroClass = CardClass.HUNTER, Player1Deck = new List <Card> { Cards.FromName("Stormwind Champion") }, Player2Deck = new List <Card> { Cards.FromName("Fiery Bat") }, FillDecks = false, Shuffle = false }); game.Player1.BaseMana = 10; game.StartGame(); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Stormwind Champion")); game.CurrentPlayer.BoardZone[0].Damage = 4; game.Process(HeroPowerTask.Any(game.CurrentPlayer)); Assert.Equal(2, game.CurrentPlayer.BoardZone[1].Health); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Fiery Bat")); game.CurrentPlayer.BoardZone[0].IsExhausted = false; while (true) { Game clone = game.Clone(); Assert.Equal(2, clone.CurrentOpponent.BoardZone[1].Health); clone.Process(MinionAttackTask.Any(clone.CurrentPlayer, clone.CurrentPlayer.BoardZone[0], clone.CurrentOpponent.BoardZone[0])); if (clone.CurrentOpponent.Hero.Damage == 7) { continue; } Assert.Equal(1, clone.CurrentOpponent.BoardZone.Count); Assert.Equal(1, clone.CurrentOpponent.BoardZone[0].AttackDamage); Assert.Equal(1, clone.CurrentOpponent.BoardZone[0].Health); break; } }
public void FatigueTest() { var game = new Game(new GameConfig { StartPlayer = 1, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); while (game.State != State.COMPLETE) { game.Process(EndTurnTask.Any(game.CurrentPlayer)); } Assert.Equal(PlayState.WON, game.Player1.PlayState); // Fatigue test didn't worked as it should for player 1 Assert.Equal(PlayState.LOST, game.Player2.PlayState); // Fatigue test didn't worked as it should for player 2 }
public override PlayerTask GetMove(POGame poGame) { int myPlayerId = poGame.CurrentPlayer.PlayerId; List <PlayerTask> options = poGame.CurrentPlayer.Options(); // Implement a simple Mulligan Rule if (poGame.CurrentPlayer.MulliganState == Mulligan.INPUT) { List <int> mulligan = new AggroScore().MulliganRule().Invoke(poGame.CurrentPlayer.Choice.Choices.Select(p => poGame.getGame().IdEntityDic[p]).ToList()); //all mulligan handlers are the same for each score return(ChooseTask.Mulligan(poGame.CurrentPlayer, mulligan)); } var simulationResults = poGame.Simulate(options); double bestWorth = getWorth(poGame, myPlayerId); //best worth starts with the current field PlayerTask bestTask = null; foreach (PlayerTask t in options) { double resultingWorth = Double.NegativeInfinity; if (simulationResults.ContainsKey(t) && t.PlayerTaskType != PlayerTaskType.END_TURN) { POGame resultingGameState = simulationResults[t]; resultingWorth = getWorth(resultingGameState, myPlayerId); } else //TODO: think of something to do if the key is unvalid //for now, do nothing if the resulting value is negative { } if (bestWorth < resultingWorth) { bestWorth = resultingWorth; bestTask = t; } } if (bestTask == null) { return(EndTurnTask.Any(poGame.CurrentPlayer)); } return(bestTask); }
public void SecretActivation() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.HUNTER, Player2HeroClass = CardClass.ROGUE, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; IPlayable minion1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Knife Juggler")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion1)); IPlayable testCard = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Snake Trap")); // Spawns 3 game.Process(PlayCardTask.Spell(game.CurrentPlayer, testCard)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); IPlayable minion2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Stonetusk Boar")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion2)); game.Process(MinionAttackTask.Any(game.CurrentPlayer, minion2, minion1)); Assert.Equal(4, game.CurrentOpponent.BoardZone.Count); if (game.CurrentPlayer.BoardZone.Count == 0) { // Minion was destroyed, so it's moved to graveyard with tags reset. Assert.Equal(1, game.CurrentPlayer.GraveyardZone.Count); Assert.Equal(game.CurrentOpponent.Hero.BaseHealth, game.CurrentOpponent.Hero.Health); Assert.Equal(game.CurrentPlayer.Hero.BaseHealth - 2, game.CurrentPlayer.Hero.Health); } else { // Minion was NOT destroyed, so it continued it's attack. Assert.Equal(0, game.CurrentPlayer.GraveyardZone.Count); Assert.Equal(game.CurrentOpponent.Hero.BaseHealth - 1, game.CurrentOpponent.Hero.Health); Assert.Equal(game.CurrentPlayer.Hero.BaseHealth - 3, game.CurrentPlayer.Hero.Health); } }
public void BasicHealthAuraTest2() { var game = new Game(new GameConfig { StartPlayer = 1, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; var minion1 = (ICharacter)Generic.DrawCard(game.Player1, Cards.FromName("Murloc Raider")); IPlayable minion2 = Generic.DrawCard(game.Player1, Cards.FromName("Ironbeak Owl")); IPlayable spell1 = Generic.DrawCard(game.Player1, Cards.FromName("Power Word: Shield")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion1)); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell1, minion1)); Assert.Equal(3, minion1.Health); game.Process(PlayCardTask.MinionTarget(game.CurrentPlayer, minion2, minion1)); Assert.Equal(1, minion1.Health); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); var minion3 = (ICharacter)Generic.DrawCard(game.Player1, Cards.FromName("Bloodfen Raptor")); IPlayable minion4 = Generic.DrawCard(game.Player1, Cards.FromName("Ironbeak Owl")); IPlayable spell2 = Generic.DrawCard(game.Player1, Cards.FromName("Power Word: Shield")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion3)); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell2, minion3)); Assert.Equal(4, minion3.Health); ((Minion)minion3).Damage = 3; game.Process(PlayCardTask.MinionTarget(game.CurrentPlayer, minion4, minion3)); Assert.Equal(1, minion3.Health); }
public void BlackwingCorruptor_BRM_034() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PRIEST, DeckPlayer1 = new List <Card>() { Cards.FromName("Azure Drake"), Cards.FromName("Blackwing Corruptor"), Cards.FromName("Stonetusk Boar"), Cards.FromName("Stonetusk Boar"), Cards.FromName("Bloodfen Raptor"), Cards.FromName("Bloodfen Raptor") }, Player2HeroClass = CardClass.PRIEST, DeckPlayer2 = new List <Card>() { Cards.FromName("Blackwing Corruptor"), Cards.FromName("Stonetusk Boar"), Cards.FromName("Stonetusk Boar"), Cards.FromName("Bloodfen Raptor"), Cards.FromName("Bloodfen Raptor") }, FillDecks = false, Shuffle = false }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; var testCard1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Blackwing Corruptor")); game.Process(PlayCardTask.MinionTarget(game.CurrentPlayer, testCard1, game.CurrentOpponent.Hero)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); var testCard2 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Blackwing Corruptor")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, testCard2)); Assert.AreEqual(1, game.Player1.Board.Count); Assert.AreEqual(1, game.Player2.Board.Count); Assert.AreEqual(30, game.Player1.Hero.Health); Assert.AreEqual(27, game.Player2.Hero.Health); }
public override PlayerTask GetMove(POGame poGame) { // start stop watch if (!Watch.IsRunning) { Watch.Start(); } // calculate a new bunch of solutions if (_currentSolutions == null) { _currentSolutions = new Queue <PlayerTask>(); } Controller currentPlayer = poGame.CurrentPlayer; if (_currentSolutions != null && _currentSolutions.Count < 1) { List <PlayerTask> solutions = GetSolutions(poGame, currentPlayer.Id, _scoring); foreach (PlayerTask solution in solutions) { _currentSolutions.Enqueue(solution); } } PlayerTask result = _currentSolutions.Dequeue(); if (result.PlayerTaskType == PlayerTaskType.CHOOSE && poGame.CurrentPlayer.Choice == null) { result = EndTurnTask.Any(currentPlayer); } // reset watch if (result.PlayerTaskType == PlayerTaskType.END_TURN || poGame.State == SabberStoneCore.Enums.State.COMPLETE || poGame.State == SabberStoneCore.Enums.State.INVALID) { Watch.Reset(); } return(result); }
public static void CardsTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.WARLOCK, Player1Deck = new List <Card>() { Cards.FromName("Bloodreaver Gul'dan") }, Player2HeroClass = CardClass.MAGE, Shuffle = false, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer, game.CurrentOpponent.Hero)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer, game.CurrentOpponent.Hero)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Any(game.CurrentPlayer, "Bloodreaver Gul'dan")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(HeroPowerTask.Any(game.CurrentPlayer, game.CurrentOpponent.Hero)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); ShowLog(game, LogLevel.VERBOSE); //Console.WriteLine(game.CurrentPlayer.BoardZone.FullPrint()); //Console.WriteLine(game.CurrentPlayer.HandZone.FullPrint()); //Console.WriteLine(game.CurrentPlayer.DeckZone.FullPrint()); }
/// <inheritdoc /> public SabberStoneAction Sample(SabberStoneState state, OddmentTable <SabberStonePlayerTask> sideInformation) { var copyState = (SabberStoneState)state.Copy(); var availableTasks = GetAvailablePlayerTasks(copyState); var action = new SabberStoneAction(); var tries = 0; // Keep sampling tasks while we have not passed the turn yet and there are more tasks available than only EndTurn or HeroPower, of if we haven't generated a suitable task in 100 tries while (!action.IsComplete() && availableTasks.Any(i => i.Task.PlayerTaskType != PlayerTaskType.END_TURN && i.Task.PlayerTaskType != PlayerTaskType.HERO_POWER) && tries < 100) { // Sample a task from the OddmentTable var task = sideInformation.Next(); // Check if the task is available in the current state if (!availableTasks.Contains(task, PlayerTaskComparer.Comparer)) { tries++; continue; } tries = 0; action.AddTask(task); copyState.Game.Process(task.Task); availableTasks = GetAvailablePlayerTasks(copyState); } if (action.IsComplete()) { return(action); } // If hero power is available, add it if (availableTasks.Any(i => i.Task.PlayerTaskType == PlayerTaskType.HERO_POWER)) { action.AddTask(availableTasks.First(i => i.Task.PlayerTaskType == PlayerTaskType.HERO_POWER)); } // If the action is not complete yet, add EndTurn action.AddTask((SabberStonePlayerTask)EndTurnTask.Any(state.Game.CurrentPlayer)); return(action); }
/// <summary> /// Determines the best tasks for the game state based on the provided statistics and creates a <see cref="SabberStoneAction"/> from them. /// </summary> /// <param name="state">The game state to create the best action for.</param> /// <returns><see cref="SabberStoneAction"/> created from the best individual tasks available in the provided state.</returns> public SabberStoneAction DetermineBestTasks(SabberStoneState state) { // Clone game so that we can process the selected tasks and get an updated options list. var clonedGame = state.Game.Clone(); // We have to determine which tasks are the best to execute in this state, based on the provided values of the MCTS search. // So we'll check the statistics table for the highest value among tasks that are currently available in the state. // This continues until the end-turn task is selected. var action = new SabberStoneAction(); while (!action.IsComplete() && clonedGame.State != State.COMPLETE) { // Get the available options in this state and find which tasks we have statistics on, but ignore the END-TURN task for now var availableTasks = clonedGame.CurrentPlayer.Options().Where(i => i.PlayerTaskType != PlayerTaskType.END_TURN).Select(i => ((SabberStonePlayerTask)i).GetHashCode()); var stats = TaskStatistics.Where(i => availableTasks.Contains(i.Key)).ToList(); var bestTask = stats.OrderByDescending(i => i.Value.AverageValue()).FirstOrDefault(); // If we can't find any task, stop. if (bestTask.IsDefault()) { // End the turn action.AddTask((SabberStonePlayerTask)EndTurnTask.Any(clonedGame.CurrentPlayer)); break; } // Handle the possibility of tasks with tied average value. var bestValue = bestTask.Value.AverageValue(); var tiedTasks = stats.Where(i => Math.Abs(i.Value.AverageValue() - bestValue) < Constants.DOUBLE_EQUALITY_TOLERANCE); var orderedTies = tiedTasks.OrderByDescending(i => i.Value.Visits); bestTask = orderedTies.First(); // If we found a task, add it to the Action and process it to progress the game. var task = bestTask.Value.Task; action.AddTask(task); clonedGame.Process(task.Task); } // Return the created action consisting of the best action available at each point. return(action); }
public void SecretOrderOfPlay() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player1Deck = new List <Card>() { Cards.FromName("Vaporize"), Cards.FromName("Ice Barrier"), Cards.FromName("Stonetusk Boar") }, Player2HeroClass = CardClass.HUNTER, Player2Deck = new List <Card>() { Cards.FromName("Stonetusk Boar"), Cards.FromName("Freezing Trap"), Cards.FromName("Explosive Trap") }, Shuffle = false, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.Process(PlayCardTask.Spell(game.CurrentPlayer, "Vaporize")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, "Ice Barrier")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Minion(game.CurrentPlayer, "Stonetusk Boar")); game.Process(MinionAttackTask.Any(game.CurrentPlayer, game.CurrentPlayer.BoardZone[0], game.CurrentOpponent.Hero)); Assert.Equal(8, game.CurrentOpponent.Hero.Armor); game.Process(PlayCardTask.Spell(game.CurrentPlayer, "Freezing Trap")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, "Explosive Trap")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Minion(game.CurrentPlayer, "Stonetusk Boar")); game.Process(MinionAttackTask.Any(game.CurrentPlayer, game.CurrentPlayer.BoardZone[0], game.CurrentOpponent.Hero)); Assert.Equal(30, game.CurrentOpponent.Hero.Health); }
public void EmperorThaurissan_BRM_028() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player2HeroClass = CardClass.MAGE, FillDecks = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; var testCard = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Emperor Thaurissan")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, testCard)); var totCost = game.CurrentPlayer.Hand.GetAll.Sum(p => p.Cost); Assert.AreEqual(4, game.CurrentPlayer.Hand.Count); game.Process(EndTurnTask.Any(game.CurrentPlayer)); Assert.AreEqual(totCost - 4, game.CurrentOpponent.Hand.GetAll.Sum(p => p.Cost)); }
public void NerubianEgg_FP1_007() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.MAGE, Player2HeroClass = CardClass.MAGE, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; SabberStoneCore.Model.Entities.IPlayable testCard = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Nerubian Egg")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, testCard)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); SabberStoneCore.Model.Entities.IPlayable spell = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Fireball")); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell, testCard)); Assert.Equal(1, game.CurrentOpponent.BoardZone.Count); Assert.Equal("FP1_007t", game.CurrentOpponent.BoardZone[0].Card.Id); }
public static void TransformationInHand() { var game = new Game(new GameConfig { StartPlayer = 1, FillDecks = true, FillDecksPredictably = true, Shuffle = false, }); game.StartGame(); IPlayable blade = Generic.DrawCard(game.Player1, Cards.FromName("Molten Blade")); IPlayable scroll = Generic.DrawCard(game.Player1, Cards.FromName("Shifting Scroll")); IPlayable zerus = Generic.DrawCard(game.Player1, Cards.FromName("Shifter Zerus")); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); // Next Turn Assert.Equal(blade.Cost, blade.Card.Cost); Assert.Equal(scroll.Cost, scroll.Card.Cost); if (zerus.AuraEffects != null) { Assert.Equal(zerus.Cost, zerus.Card.Cost); } game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); // Next Turn Assert.Equal(blade.Cost, blade.Card.Cost); Assert.Equal(scroll.Cost, scroll.Card.Cost); if (zerus.AuraEffects != null) { Assert.Equal(zerus.Cost, zerus.Card.Cost); } Assert.Equal(zerus.Cost, zerus.Card.Cost); }
public static void CardsTest() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.PRIEST, Player1Deck = new List <Card> { Cards.FromName("Murloc Raider"), Cards.FromName("Murloc Raider"), Cards.FromName("Murloc Tidehunter"), Cards.FromName("Murloc Tidehunter"), Cards.FromName("Herald Volazj"), }, Player2HeroClass = CardClass.PRIEST, FillDecks = false, Shuffle = false }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); // Murloc Raider game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); // Murloc Raider game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); // Murloc Tidehunter game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); // Murloc Tidehunter game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); game.Process(PlayCardTask.Minion(game.CurrentPlayer, game.CurrentPlayer.HandZone[0])); // Herald Volazj ShowLog(game, LogLevel.VERBOSE); Console.WriteLine(game.CurrentPlayer.BoardZone.FullPrint()); Console.WriteLine(game.CurrentPlayer.HandZone.FullPrint()); Console.WriteLine(game.CurrentPlayer.DeckZone.FullPrint()); }
public void SylvanasWindrunner_EX1_016() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.WARLOCK, Player2HeroClass = CardClass.MAGE, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; IPlayable minion11 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Bloodfen Raptor")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion11)); IPlayable minion12 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Leper Gnome")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion12)); game.Process(EndTurnTask.Any(game.CurrentPlayer)); var minion2 = (ICharacter)Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Sylvanas Windrunner")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion2)); int myBoardCount = game.CurrentPlayer.BoardZone.Count; int opBoardCount = game.CurrentOpponent.BoardZone.Count; IPlayable spell1 = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Fireball")); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, spell1, minion2)); Assert.Equal(myBoardCount, game.CurrentPlayer.BoardZone.Count); Assert.Equal(opBoardCount - 1, game.CurrentOpponent.BoardZone.Count); }
public void Vanish_NEW1_004() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.ROGUE, Player2HeroClass = CardClass.ROGUE, FillDecks = true, FillDecksPredictably = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; int player1HandCount = game.CurrentPlayer.HandZone.Count; Assert.Equal(0, game.CurrentPlayer.BoardZone.Count); // player 1 plays 7 minions for (int i = 0; i < 7; i++) { IPlayable minion = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Wisp")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion)); } Assert.Equal(7, game.CurrentPlayer.BoardZone.Count); // end turn game.Process(EndTurnTask.Any(game.CurrentPlayer)); // player 2 plays vanish IPlayable spell = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Vanish")); game.Process(PlayCardTask.Spell(game.CurrentPlayer, spell)); Assert.Equal(0, game.CurrentPlayer.Opponent.BoardZone.Count); Assert.Equal(10, game.CurrentPlayer.Opponent.HandZone.Count); }
public void PowerOverwhelming_EX1_316() { var game = new Game(new GameConfig { StartPlayer = 1, Player1HeroClass = CardClass.WARLOCK, Player2HeroClass = CardClass.WARLOCK, FillDecks = true }); game.StartGame(); game.Player1.BaseMana = 10; game.Player2.BaseMana = 10; var testCard = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Power Overwhelming")); var minion = Generic.DrawCard(game.CurrentPlayer, Cards.FromName("Stonetusk Boar")); game.Process(PlayCardTask.Minion(game.CurrentPlayer, minion)); game.Process(PlayCardTask.SpellTarget(game.CurrentPlayer, testCard, minion)); Assert.AreEqual(5, ((Minion)minion).AttackDamage); Assert.AreEqual(5, ((Minion)minion).Health); game.Process(EndTurnTask.Any(game.CurrentPlayer)); Assert.AreEqual(true, minion.ToBeDestroyed); }