示例#1
0
        /// <summary>
        /// Prints the current game board
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public static string PrintBoard(this HearthNode state, string mode = "")
        {
            var str = new StringBuilder();

            if (mode == "json")
            {
                str.AppendLine("\t\t\"play\": {");
                str.AppendLine($"\t\t\t\"turn\": \"{state.Game.Turn}\",");
                str.Append(state.Game.PrintJson(false));
                str.AppendLine("\t\t\t}");
                str.AppendLine("\t\t},");
                return(str.ToString());
            }

            else
            {
                str.AppendLine("------------");
                str.AppendLine($"| Turn {state.Game.Turn} |");
                str.AppendLine("------------");
                str.AppendLine("-----------------------------------------------------------------------------------------------------");
                str.AppendLine(state.Game.FullPrint() + "-----------------------------------------------------------------------------------------------------");
                str.AppendLine($"{state.Game.CurrentPlayer.Hero.Card.Name} is thinking...");
            }

            return(str.ToString());
        }
示例#2
0
        /// <summary>
        /// Returns a list of this HearthNode's children that will
        /// win the game if selected consecutively.
        /// </summary>
        /// <param name="h"></param>
        /// <returns></returns>
        public static List <HearthNode> GetLethalMoves(this HearthNode h)
        {
            //for (int i = 0; i < h.Children.Count; ++i)
            //{
            //	h.Children[i].Process();
            //}

            if (h.Children.Contains(c => c.Damage > 0))
            {
                int oppHealth = h.Game.CurrentOpponent.TotalHealth();

                var        damageMoves = h.Children.Where(c => c.Damage > 0).ToList();
                HearthNode fatigue     = damageMoves.Pop(c => c.IsEndTurn);

                int damageAvailable = damageMoves.DamageAvailable();

                if (damageAvailable > oppHealth)
                {
                    return(damageMoves);
                }

                else if (fatigue != null)
                {
                    if (damageAvailable + fatigue.Damage > oppHealth)
                    {
                        damageMoves.Add(fatigue);
                        return(damageMoves);
                    }
                }
            }
            return(null);
        }
示例#3
0
 /// <summary>
 /// Returns true if each of this HearthNode's children executes an Attack action.
 /// </summary>
 /// <param name="h"></param>
 /// <returns></returns>
 public static bool AttackOnly(this HearthNode h)
 {
     return(h.Frontier.SkipWhile(p => p.IsEndTurn).ToList().All(p =>
                                                                (p.Action.PlayerTaskType == PlayerTaskType.MINION_ATTACK || p.Action.PlayerTaskType == PlayerTaskType.HERO_ATTACK) &&
                                                                h.Game.CurrentOpponent.BoardZone.IsEmpty &&
                                                                h.Game.CurrentOpponent.SecretZone.IsEmpty));
 }
示例#4
0
        /// <summary>
        /// Predicts the opponents deck based on the cards they've played so far.
        /// And, initializes this agent's BlindGame object.
        /// </summary>
        /// <returns></returns>
        void PredictOpponentDeck(HearthNode state)
        {
            if (state.Game.Turn > 1 && PossibleOpponentDecks.Count != 1)
            {
                PlayedSoFar = state.GetPlayedSoFar(state.Game.CurrentOpponent);

                BlindGame = state.Game.Clone();
                Opponent  = BlindGame.CurrentOpponent;

                if (PlayedSoFar.Any(c => c.Name == "The Coin"))
                {
                    PlayedSoFar.RemoveAll(c => c.Name == "The Coin");
                }

                if (PlayedSoFar.Count == 0)
                {
                    OpponentDeck = DeckQuery.GetMostPopular(Opponent.HeroClass);
                }

                var bestMatches = new List <string>();

                if (PossibleOpponentDecks.Count == 0)
                {
                    bestMatches = DeckQuery.GetBestMatch(PlayedSoFar, Opponent.HeroClass);
                }

                else if (PossibleOpponentDecks.Count == 1)
                {
                    if (PossibleOpponentDecks[0] == OpponentDeck.Name)
                    {
                        return;
                    }

                    OpponentDeck = DeckQuery.DeckFromName(PossibleOpponentDecks[0], Opponent.HeroClass);
                }

                else
                {
                    bestMatches = DeckQuery.GetBestMatch(PlayedSoFar, Opponent.HeroClass, PossibleOpponentDecks);
                }

                if (bestMatches.Count == 1)
                {
                    PossibleOpponentDecks.Clear();
                    PossibleOpponentDecks.Add(bestMatches[0]);
                }

                else if (bestMatches.Count > 1)
                {
                    for (int i = 1; i < bestMatches.Count; ++i)
                    {
                        PossibleOpponentDecks.Add(bestMatches[i]);
                    }
                }

                OpponentDeck = DeckQuery.DeckFromName(bestMatches[0], Opponent.HeroClass);
            }
        }
示例#5
0
        /// <summary>
        /// Makes BlindGame a clone of the current game, but replaces all of the
        /// blind information with this agent's best predictions.
        /// </summary>
        /// <param name="realGame"></param>
        /// <param name="firstTurn"></param>
        HearthNode DontCheat(HearthNode state)
        {
            if (PlayedSoFar.Count < 1 || PossibleOpponentDecks.Count == 1)
            {
                return(state.Clone());
            }

            UpdateOpponent(BlindGame.CurrentOpponent.HandZone.Count);

            return(new HearthNode(state.Parent, BlindGame, state.Action));
        }
示例#6
0
        public override HearthNode PlayTurn(HearthNode state)
        {
            var poGame = new POGame(state.Game, false);

            if (!_hasInitialized)
            {
                CustomInit(poGame);
            }

            if (_isTurnBegin)
            {
                OnMyTurnBegin(poGame);
            }

            List <PlayerTask> options = poGame._game.CurrentPlayer.Options();
            PlayerTask        chosen  = ChooseTask(poGame, options);

            HearthNode selected = state.Frontier.Find(h => h.Action.IsEqual(chosen));

            //if (selected == null)
            //	foreach (HearthNode p in state.PossibleActions)
            //	{
            //		if (p.Action.IsEqual(chosen))
            //			selected = p;
            //	}

            //should not happen, but if, just return anything:
            if (selected == null)
            {
                if (TyConst.LOG_UNKNOWN_CORRECTIONS)
                {
                    TyDebug.LogError("Choosen task was null!");
                }

                selected = state.Frontier.Find(h => h.Action.IsEqual(options.GetUniformRandom(_random)));
            }

            //selected.Process();
            try
            {
                state.BirthPossibility(selected);
            }
            catch (Exception)
            {
                Console.Write("Why");
            }

            if (selected.IsEndTurn)
            {
                OnMyTurnEnd();
            }

            return(selected);
        }
示例#7
0
 public static HearthNode Pop(this List <HearthNode> children, Func <HearthNode, bool> p)
 {
     for (int i = 0; i < children.Count; ++i)
     {
         if (p(children[i]))
         {
             HearthNode popped = children[i];
             children.Remove(children[i]);
             return(popped);
         }
     }
     return(null);
 }
示例#8
0
        public override HearthNode PlayTurn(HearthNode state)
        {
            var rnd    = new Random();
            int rndInd = rnd.Next(state.Frontier.Count);

            HearthNode selected = state.Frontier[rndInd];

            state.BirthPossibility(selected);
            //selected.Game.PowerHistory.Dump(@"C:\Users\hgore\SabberStone\core-extensions\SabberStoneCoreAi\src\Meta\SabberStone.log");
            //selected.Write(filename, false, false, true);

            return(selected);
        }
示例#9
0
        /// <summary>
        /// Prints this games overall info
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public static string PrintCreateGame(this HearthNode state)
        {
            var str = new StringBuilder();

            str.AppendLine("{");
            str.AppendLine("\t\"game\": {");
            str.AppendLine($"\t\t\"ts\": \"{DateTime.Now.ToString("yyyy - MM - ddTHH:mm: ss.ffffffK")}\",");
            str.AppendLine("\t\t\"setup\": {");
            str.Append(state.Game.Player1.Hero.FullPrint(true));
            str.Append(state.Game.Player2.Hero.FullPrint(true));
            str.AppendLine("\t},");
            return(str.ToString());
        }
示例#10
0
        /// <summary>
        /// Performs a MCTS to select the best action at this current game state
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        HearthNode PrepAndProcessMCTS(HearthNode state)
        {
            PredictOpponentDeck(state);

            HearthNode MCTSNode = DontCheat(state);

            MCTSNode.FixMolten();

            SimTree = new HearthTree(MCTSNode);
            HearthNode move = SimTree.MCTS();

            state.BirthPossibility(move);
            return(move);
        }
示例#11
0
        /// <summary>
        /// Performs a monte carlo tree search on the current game-state,
        /// and then selects the move with the highest score
        /// </summary>
        /// <param name="state"></param>
        /// <returns>The best move determined by <see cref="MCTSHelper.DoMCTS(MCTSAgent, HearthNode)"/></returns>
        public override HearthNode PlayTurn(HearthNode state)
        {
            if (!OpponentSet)
            {
                SetupOpponent(state.Game);
            }

            HearthNode move = PrepAndProcessMCTS(state);

            //move.Game.PowerHistory.Dump(@"C:\Users\hgore\SabberStone\core-extensions\SabberStoneCoreAi\src\Meta\SabberStone.log", end: move.Game.State == State.COMPLETE ? true : false);
            //move.Game.PowerHistory = new PowerHistory();

            //move.Write(filename, false, false, true);
            return(move);
        }
示例#12
0
        /// <summary>
        /// Checks for and fixes a bug in which Molten Blade costs 1 mana after transformation.
        /// Returns true if the bug was fixed.
        /// </summary>
        /// <param name="state"></param>
        public static bool FixMolten(this HearthNode state)
        {
            var molten = (IPlayable)state.Game.CurrentPlayer.HandZone.Find(c => c.Type == CardType.WEAPON);

            if (molten != null)
            {
                if (molten.Cost != molten.Card.Cost)
                {
                    int moltInd = state.Game.CurrentPlayer.HandZone.IndexOf(molten);
                    //state.Game.CurrentPlayer.HandZone.Remove(molten);
                    state.Game.CurrentPlayer.HandZone[moltInd].Cost = molten.Card.Cost;
                    //state.Game.CurrentPlayer.HandZone.Insert(moltInd, molten);
                    return(true);
                }
            }
            return(false);
        }
示例#13
0
        /// <summary>
        /// Returns a list of the cards the opponent has played so far
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        public static List <Card> GetPlayedSoFar(this HearthNode state, Controller opponent)
        {
            var playedSoFar   = new List <Card>();
            int currentPlayer = opponent.PlayerId;

            while (state.Parent != null)
            {
                if (state.Game.CurrentPlayer.PlayerId == currentPlayer)
                {
                    if (state.Action.PlayerTaskType == PlayerTaskType.PLAY_CARD && state.Action.HasSource)
                    {
                        if (!state.Action.Source?.Card.IsSecret ?? false)
                        {
                            Card card = state.Action.Source.Card;
                            playedSoFar.Add(card);
                        }
                    }
                }
                state = state.Parent;
            }
            return(playedSoFar);
        }
示例#14
0
        /// <summary>
        /// Writes game information to a file including the game board and moves
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="gameInfo"></param>
        public static void Write(this HearthNode state, string filename, bool create = false, bool board = false, bool move = false)
        {
            string newfile = filename;
            string dir     = @"C:\Users\hgore\SabberStone\core-extensions\SabberStoneCoreAi\src\Meta\";
            string path    = dir + newfile + ".json";
            int    count   = 1;

            while (File.Exists(path) && File.GetLastWriteTime(path) + TimeSpan.FromMinutes(3) < DateTime.Now)
            {
                newfile += count++.ToString();
                path     = dir + newfile + ".json";
            }

            using (var sw = new StreamWriter(File.Open(path, FileMode.Append)))
            {
                if (create)
                {
                    sw.Write(state.PrintCreateGame());
                }

                else if (board)
                {
                    sw.Write(state.PrintBoard());
                }

                else if (move)
                {
                    sw.Write(state.PrintAction(true));
                }

                if (state.Game.State == State.COMPLETE)
                {
                    sw.WriteLine("}");
                }
            }
        }
示例#15
0
        public bool PlayGame(int gameNumber, bool addToGameStats = true)
        {
            var _masterGame = new Game(_gameConfig, _setupHeroes);

            _player1.InitializeGame();
            _player2.InitializeGame();

            _masterGame.StartGame();

            var state = HearthNode.CreateRoot(_masterGame);

            AbstractAgent _currentAgent;

            Stopwatch currentStopwatch;

            Stopwatch[] watches = new[] { new Stopwatch(), new Stopwatch() };

            //var state = new HearthNode(_masterRoot, null, _masterGame, null);

            //List<int> gameStateVector = state.Vector();
            //string dt = DateTime.Now.ToString("MM_dd_yyyy HH_mm");
            //int turn = 1;
            //int actionNum = 1;
            var heroClasses = new CardClass[2] {
                state.Game.Player1.HeroClass, state.Game.Player2.HeroClass
            };
            string filename = $"{state.Game.Player1.Deck.Name}_vs_{state.Game.Player2.Deck.Name}.csv";

            try
            {
                while (state.Game.State != State.COMPLETE && state.Game.State != State.INVALID)
                {
                    state.Game.WriteCSV((gameNumber + 1).ToString(), heroClasses, filename);

                    if (_debugMode == "")
                    {
                        Console.WriteLine(state.PrintBoard());
                    }

                    //else if (_debugMode == "python")
                    //	Console.WriteLine(state.PrintBoard());


                    _currentAgent = state.Game.CurrentPlayer == state.Game.Player1 ? _player1 : _player2;
                    //perspective = state.Game.CurrentPlayer == state.Game.Player1 ? 1 : 2;
                    currentStopwatch = state.Game.CurrentPlayer == state.Game.Player1 ? watches[0] : watches[1];

                    currentStopwatch.Start();
                    HearthNode moveNode = _currentAgent.PlayTurn(state);
                    //moveNode.Game.WriteCSV(dt, heroClasses, filename);

                    //actionNum = moveNode.Game.Turn == turn ? actionNum + 1 : 1;

                    //if (moveNode.Action.PlayerTaskType == PlayerTaskType.PLAY_CARD)
                    //	gameStats.AddCard(state.Game.CurrentPlayer.PlayerId);

                    if (_debugMode != null)
                    {
                        Console.Write(moveNode.PrintAction());
                    }

                    state = new HearthNode(null, moveNode.Game, moveNode.Action);
                    //turn = state.Game.Turn;
                    //gameStateVector = state.Vector();
                    currentStopwatch.Stop();

                    state.Game.CurrentPlayer.Game   = state.Game;
                    state.Game.CurrentOpponent.Game = state.Game;

                    ///if (_debug)
                    ///{
                    ///	Console.WriteLine(playerMove);
                    ///	if (playerMove.PlayerTaskType == PlayerTaskType.PLAY_CARD)
                    ///		Console.WriteLine($"\n{currentPlayer.Hero.Card.Name} plays {playerMove.Source.Card.Name}\n");
                    ///
                    ///	if (playerMove.PlayerTaskType == PlayerTaskType.HERO_ATTACK)
                    ///		Console.WriteLine($"\n{currentPlayer.Hero.Card.Name} attacks {currentPlayer.Opponent.Hero.Card.Name}\n");
                    ///
                    ///	if (playerMove.PlayerTaskType == PlayerTaskType.MINION_ATTACK)
                    ///		Console.WriteLine($"\n{playerMove.Source.Card.Name} attacks {playerMove.Target.Card.Name}\n");
                    ///
                    ///	if (playerMove.PlayerTaskType == PlayerTaskType.HERO_POWER)
                    ///		Console.WriteLine($"\n{currentPlayer.Hero.Card.Name} used {currentPlayer.Hero.HeroPower.Card.Name}");
                    ///}
                    ///state.Process(playerMove);
                    ///state = state.Children.Find(s => s._action == playerMove).GetChild(playerMove);
                }
            }

            catch (Exception e)
            //Current Player loses if he throws an exception
            {
                Console.WriteLine(e.Message);
                Console.WriteLine(e.StackTrace);
                state.Game.State = State.COMPLETE;
                state.Game.CurrentPlayer.PlayState   = PlayState.CONCEDED;
                state.Game.CurrentOpponent.PlayState = PlayState.WON;

                //if (addToGameStats && _masterRoot.Game.State != State.INVALID)
                //	gameStats.registerException(_masterRoot.Game, e);
            }

            if (state.Game.State == State.INVALID)
            {
                return(false);
            }

            //if (addToGameStats)
            //{
            //	gameStats.addGame(state.Game, watches);
            //}

            string winner = state.Game.Player1.PlayState == PlayState.WON ?
                            state.Game.Player1.Hero.Card.Name : state.Game.Player2.Hero.Card.Name;

            Console.WriteLine($"{winner} won!");

            int winnerId = state.Game.Player1.PlayState == PlayState.WON ?
                           state.Game.Player1.PlayerId : state.Game.Player2.PlayerId;

            state.Game.WriteCSV((gameNumber + 1).ToString(), heroClasses, filename, winner: winnerId);

            _player1.FinalizeGame();
            _player2.FinalizeGame();

            return(true);
        }
示例#16
0
 public virtual HearthNode PlayTurn(HearthNode state)
 {
     throw new NotImplementedException();
 }
示例#17
0
            public static void MoltenTest()
            {
                var rnd    = new Random();
                var p1Deck = new Deck(CardClass.WARRIOR, Archetype.QUEST, "IceFireWarrior", 100,
                                      new List <Card>
                {
                    Cards.FromName("Fire Plume's Heart"),
                    Cards.FromName("Goldshire Footman"),
                    Cards.FromName("Wax Elemental"),
                    Cards.FromName("Wax Elemental"),
                    Cards.FromName("Cleave"),
                    Cards.FromName("Cornered Sentry"),
                    Cards.FromName("Drywhisker Armorer"),
                    Cards.FromName("Drywhisker Armorer"),
                    Cards.FromName("Execute"),
                    Cards.FromName("Execute"),
                    Cards.FromName("Plated Beetle"),
                    Cards.FromName("Plated Beetle"),
                    Cards.FromName("Warpath"),
                    Cards.FromName("Warpath"),
                    Cards.FromName("Phantom Militia"),
                    Cards.FromName("Phantom Militia"),
                    Cards.FromName("Shield Block"),
                    Cards.FromName("Shield Block"),
                    Cards.FromName("Stonehill Defender"),
                    Cards.FromName("Stonehill Defender"),
                    Cards.FromName("Brawl"),
                    Cards.FromName("Direhorn Hatchling"),
                    Cards.FromName("Direhorn Hatchling"),
                    Cards.FromName("Rotten Applebaum"),
                    Cards.FromName("Ornery Direhorn"),
                    Cards.FromName("Unidentified Shield"),
                    Cards.FromName("Unidentified Shield"),
                    Cards.FromName("Geosculptor Yip"),
                    Cards.FromName("Scourgelord Garrosh"),
                    Cards.FromName("Molten Blade")
                });

                var p2Deck = new Deck();

                var gameConfig = new GameConfig
                {
                    StartPlayer      = rnd.Next(1, 2),
                    Player1HeroClass = CardClass.WARRIOR,
                    Player1Name      = "Garrosh Hellscream",
                    Player1Deck      = p1Deck,
                    Player2HeroClass = CardClass.DRUID,
                    Player2Name      = "Malfurion Stormrage",
                    Player2Deck      = p2Deck.FromDB(CardClass.DRUID, deckName: "Malygos_Druid1"),
                    Shuffle          = false,
                    Logging          = true,
                    History          = true,
                    //SkipMulligan = false
                };

                var testGame = new Game(gameConfig);

                var           player1 = new MCTSAgent();
                AbstractAgent player2 = new RandomAgent();

                player1.InitializeAgent();
                player2.InitializeAgent();

                player1.InitializeGame();
                player2.InitializeGame();

                testGame.StartGame();

                //bool check = true;
                //var molten = (IPlayable)testGame.CurrentPlayer.HandZone.Find(c => c.Type == CardType.WEAPON);
                //if (molten?.Cost != molten?.Card.Cost)
                //	check = false;
                var root = new HearthNode(null, testGame, null);

                //molten = (IPlayable)root.Game.CurrentPlayer.HandZone.Find(c => c.Type == CardType.WEAPON);
                //if (molten.Cost != molten.Card.Cost)
                //	check = false;

                HearthNode state = root.Frontier.Find(p => p.IsEndTurn);

                for (int i = 0; i < 5; ++i)
                {
                    state = state.Frontier.Find(p => p.IsEndTurn);
                }
            }