Exemplo n.º 1
0
        /// <summary>
        /// We fill in values bottom down.  So sometimes when you set a new value you should check parents too.
        /// Also if we are a choice and just added a worse value, don't recalculate parent.
        /// </summary>
        private void SetValue(NodeValue v)
        {
            var oldValue = Value;

            Value = v;
            switch (GetChoiceType())
            {
            case NodeType.Choice:
                if (v > oldValue || object.ReferenceEquals(oldValue, null))
                {
                    Parent?.CalcValue();
                }
                break;

            case NodeType.Random:
                //TODO this is optimizable.
                Parent?.CalcValue();
                break;

            case NodeType.Leaf:
                Parent.CalcValue();
                break;
            }
        }
Exemplo n.º 2
0
        public static void TestCultistMC()
        {
            var turnNumber = 0;

            var initialDeck = new List <string>()
            {
                "Strike", "Strike", "Strike", "Strike", "Strike", "Defend", "Defend", "Defend", "Defend", "Bash"
            };
            //initialHand.AddRange(new List<string>() {"Pummel", "Exhume"});

            var hand        = gsl();
            var drawPile    = initialDeck;
            var exhaustPile = gsl();
            var discardPile = gsl();
            var enemyHp     = 51;
            var playerHp    = 1;
            var firstDraw   = new List <string>()
            {
                "Strike", "Strike", "Defend", "Defend", "Bash"
            };
            var statuses = new List <StatusInstance>()
            {
            };

            if (false)
            {
                turnNumber  = 1;
                discardPile = firstDraw;
                drawPile    = gsl("Strike", "Strike", "Defend", "Defend", "Strike");
                firstDraw   = gsl("Strike", "Strike", "Defend", "Defend", "Strike");
                statuses    = new List <StatusInstance>()
                {
                    GS(new Feather(), 3), GS(new Vulnerable(), 1)
                };
            }

            var enemy = new Cultist(hp: enemyHp);

            enemy.StatusInstances = statuses;
            var player = new Player(hp: playerHp);

            var deck = new Deck(drawPile, hand, discardPile, exhaustPile);

            var mc        = new MonteCarlo(deck, enemy, player, turnNumber, firstDraw);
            var bestValue = new NodeValue(-100, 0, null);

            for (var ii = 0; ii < 100000; ii++)
            {
                var leaf  = mc.MC(mc.Root.Randoms.First());
                var value = leaf.GetValue();
                if (value > bestValue)
                {
                    bestValue = value;
                    SaveLeaf(leaf, ii);
                    ShowInitialValues(mc.Root.Randoms.First());
                }
            }

            System.IO.File.AppendAllText(Output, $"==========Final First move best lines");
            ShowInitialValues(mc.Root.Randoms.First());
            SaveAllLeaves(mc.Root);
        }
Exemplo n.º 3
0
        private void CalcValue()
        {
            ValueCalculated = true;
            switch (GetChoiceType())
            {
            case NodeType.TooLong:
                var tooLongVal = Fight._Player.HP - Fight._Enemies[0].HP;
                SetValue(new NodeValue(tooLongVal, 0, null));
                break;

            case NodeType.Leaf:
                var val = 0;
                var tt  = this;
                switch (Fight.Status)
                {
                case FightStatus.Ongoing:
                    var hh = AALeafHistory();
                    throw new Exception("Leaves can't have ongoing fights.");
                    //this happens when we get toolong
                    //A
                    //BC
                    // B is toolong, C ended.
                    // we backgrack to A but can't calc b.  B is a leaf.
                    //TODO this is obviously wrong.
                    //no point in calculating them as we go.
                    //val = Fight._Player.HP - Fight._Enemies[0].HP;
                    return;

                case FightStatus.Won:
                    val = Fight._Player.HP;
                    break;

                case FightStatus.Lost:
                    val = -1 * Fight._Enemies[0].HP;
                    break;
                }
                var cards = 0;
                if (Fight.FightAction.FightActionType == FightActionEnum.PlayCard)
                {
                    cards++;
                }
                SetValue(new NodeValue(val, cards, null));
                break;

            case NodeType.Choice:
                if (FightAction == null)
                {
                    throw new Exception("This should not happen");
                }
                NodeValue value = null;
                FightNode bc    = null;
                foreach (var c in Choices)
                {
                    var cval = c.GetValue();
                    if (value == null || cval > value)
                    {
                        value = cval;
                        bc    = c;
                    }
                }
                int cards2 = 0;
                //Todo prefer playing cards to playing potions!
                if (FightAction.FightActionType == FightActionEnum.PlayCard || FightAction.FightActionType == FightActionEnum.Potion)
                {
                    cards2++;
                }
                var myVal = new NodeValue(value.Value, value.Cards + cards2, bc);
                SetValue(myVal);
                break;

            case NodeType.Random:
                var rsum = 0.0d;
                var rc   = 0;
                foreach (var r in Randoms)
                {
                    rsum += r.GetValue().Value *r.Weight;
                    rc   += r.Weight;
                }
                SetValue(new NodeValue(rsum * 1.0 / rc, 0, null));
                //TODO okay to not assign bestchild? it doesn't make sense over random.
                break;
            }
        }