Ejemplo n.º 1
0
        static void SaveLeaf(FightNode leaf, int mcCount)
        {
            System.IO.File.AppendAllText(Output, $"\n==============Fight {mcCount} {leaf.Fight.Status} {leaf.Value}\n");
            var hh = leaf.AALeafHistory();

            System.IO.File.AppendAllText(Output, SJ('\n', hh));
        }
Ejemplo n.º 2
0
        public void Setup()
        {
            SetRandom(164);
            var relics  = GetRandomRelics(3);
            var potions = GetRandomPotions(2);
            var enemyHp = 100;

            _Player = new Player(hp: 80, relics: relics, potions: potions);
            _Enemy  = new Cultist(enemyHp);
            //var hand = gsl("Strike", "Strike", "Strike", "Strike", "Strike", "Defend", "Defend", "Defend", "Defend", "Bash","WildStrike","PommelStrike+");
            var cis = GetRandomCards(10);

            cis.Add(Helpers.GetCi("Armaments"));
            cis.Add(Helpers.GetCi("Armaments"));
            cis.Add(Helpers.GetCi("Armaments+"));
            cis.Add(Helpers.GetCi("TrueGrit"));
            Console.WriteLine("Deck: " + SJ(separator: ' ', cis.OrderBy(el => el.Card.Name)));
            var deck = new Deck(cis);

            deck.InteractiveContext = true;
            _Fight           = new Fight(deck, _Player, _Enemy);
            _Root            = new FightNode(_Fight);
            _Current         = _Root;
            _Fight.FightNode = _Root;
            _Fight.StartFight();
        }
Ejemplo n.º 3
0
        public MonteCarlo(Deck deck, Enemy enemy, Player player, int turnNumber = 0, List <string> firstHand = null)
        {
            _Deck       = deck ?? throw new ArgumentNullException(nameof(deck));
            _Enemy      = enemy ?? throw new ArgumentNullException();
            _Player     = player ?? throw new ArgumentNullException();
            _TurnNumber = turnNumber;

            if (firstHand == null)
            {
                //by default shuffle the deck at fight start.
                _Deck.Reshuffle(new EffectSet(), new List <string>());
            }
            else
            {
                var cards       = _Deck.FindSetOfCards(_Deck.GetDrawPile, firstHand);
                var firstAction = new FightAction(FightActionEnum.StartTurn, cardTargets: cards);
                _FirstAction = firstAction;
            }

            var fight = new Fight(_Deck, _Player, _Enemy);

            fight.TurnNumber = _TurnNumber;

            var root = new FightNode(fight);

            fight.FightNode = root;
            root.StartFight();
            Root = root;
            if (_FirstAction != null)
            {
                root.ApplyAction(_FirstAction);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Returns the leaf node of a single mc run.
        /// </summary>
        public FightNode MC(FightNode fn)
        {
            if (fn.Depth == 1)
            {
                MCCount++;
            }
            var actions = fn.Fight.GetAllActions();

            var ii = Rnd.Next(actions.Count());
            //ii = 0;
            var action = actions[ii];


            var childNode = fn.ApplyAction(action);

            switch (childNode.Fight.Status)
            {
            case FightStatus.Ongoing:
                return(MC(childNode));

            case FightStatus.Won:
                return(childNode);

            case FightStatus.Lost:
                return(childNode);

            default:
                throw new Exception("Other status");
            }
        }
Ejemplo n.º 5
0
 public static void ShowInitialValues(FightNode drawNode)
 {
     System.IO.File.AppendAllText(Output, $"\n---------Best FirstRound Choices: {drawNode.Choices.Count}");
     foreach (var c in drawNode.Choices.OrderByDescending(el => el.Value))
     {
         ShowRound(c);
     }
 }
Ejemplo n.º 6
0
        public NodeValue(double value, int cards, FightNode bestChoice)
        {
            Value = value;

            //How many cards played this round. inherited from non-round ending child bestnode.
            Cards      = cards;
            BestChoice = bestChoice;
        }
Ejemplo n.º 7
0
        public static void SaveAllLeaves(FightNode root)
        {
            var leaves = GetAllLeaves(root);
            var ii     = 0;

            foreach (var l in leaves)
            {
                ii++;
                SaveLeaf(l, ii);
                if (ii > 10000)
                {
                    break;
                }
            }
        }
Ejemplo n.º 8
0
        public static void ShowRound(FightNode c)
        {
            var target = c;
            var res    = new List <string>();

            res.Add($"{c.Value.ToString()} W:{c.Weight}");
            while (true)
            {
                res.Add(target.ToString());
                if (target.Value.BestChoice == null)
                {
                    break;
                }
                target = target.Value.BestChoice;
            }

            System.IO.File.AppendAllText(Output, "\n");
            System.IO.File.AppendAllLines(Output, res);
        }
Ejemplo n.º 9
0
        private void DisplayStatus(FightNode current)
        {
            var fa = _Current.Fight.FightAction?.GetList();

            if (fa != null)
            {
                Console.WriteLine("===== Last Action:");
                foreach (var part in fa)
                {
                    Console.WriteLine($"\t{part}");
                }
            }
            var status = _Current.Fight.Status;

            Console.WriteLine($"\nTurn:{ _Current.Fight.TurnNumber,2} - {status}");
            Console.WriteLine(_Current.Fight._Player.Details());
            Console.WriteLine(_Current.Fight._Enemies[0].Details());
            Console.WriteLine($"\tEnergy: {_Current.Fight._Player.Energy}/{_Current.Fight._Player.MaxEnergy()}");
        }
Ejemplo n.º 10
0
        public static List <FightNode> GetLeaves(FightNode node)
        {
            var res = new List <FightNode>();

            foreach (var set in new List <IList <FightNode> > {
                node.Choices, node.Randoms
            })
            {
                foreach (var c in set)
                {
                    if (c.Fight.Status != FightStatus.Ongoing)
                    {
                        res.Add(c);
                    }
                    else
                    {
                        res.AddRange(GetLeaves(c));
                    }
                }
            }
            return(res);
        }
Ejemplo n.º 11
0
        public static List <FightNode> GetAllLeaves(FightNode root)
        {
            var res  = new List <FightNode>();
            var leaf = true;

            foreach (var c in root.Choices)
            {
                res.AddRange(GetAllLeaves(c));
                leaf = false;
            }
            foreach (var r in root.Randoms)
            {
                res.AddRange(GetAllLeaves(r));
                leaf = false;
            }
            if (leaf)
            {
                res.Add(root);
            }

            return(res);
        }
Ejemplo n.º 12
0
 /// <summary>
 ///// What should we actually do if there are multiple randoms?
 ///// </summary>
 public static FightNode GetBestLeaf(FightNode root)
 {
     return(root.Choices.OrderBy(el => el.GetValue().Value).First());
 }
Ejemplo n.º 13
0
        /// <summary>
        /// Add node to the proper place and return it for further MCing
        /// </summary>
        public FightNode AddChild(FightNode child)
        {
            //interesting, although enemymoves are also randoms, there is no point in having an intermediate copy node.
            //i.e. Cendturn => RenemyMove => [Rvarious enemy moves] is kind of of pointless
            //unlike CstartTurn => Rwildstrike => [Rvarious wildstrikes]
            //                  => Rother random card => [ROther random card random outputs]
            child.FightAction = child.Fight.FightAction;

            if (child.FightAction.FightActionType == FightActionEnum.EnemyMove)
            {
                child.Parent      = this;
                child.FightAction = child.Fight.FightAction;
                Randoms.Add(child);
            }

            else if (child.FightAction.Random)
            {
                //two cases:
                //the intermediate node is already created:
                FightNode intermediateNode = null;
                foreach (var c in Choices)
                {
                    if (c.FightAction.IsEqual(child.FightAction))
                    {
                        intermediateNode = c;
                        break;
                    }
                }

                if (intermediateNode == null)
                {
                    //if we have a random, then consider it a c with this as a random child.
                    intermediateNode        = new FightNode(child.Fight.Copy());
                    intermediateNode.Parent = this;
                    var src = child.Fight.FightAction;

                    //we convert the specced out action into a generic one again.
                    var nonspecifiecAction = new FightAction(fightActionType: src.FightActionType,
                                                             card: src.CardInstance, cardTargets: src.CardTargets, potion: src.Potion, target: src.Target,
                                                             hadRandomEffects: src.Random);
                    intermediateNode.FightAction = nonspecifiecAction;

                    //zero these out since at this stage they represent the action pre-randomization.
                    if (intermediateNode.Fight.FightNode != null)
                    {
                        intermediateNode.Fight.FightNode.FightAction.Key = null;
                    }
                    intermediateNode.FightAction.Key = null;
                    Choices.Add(intermediateNode);
                    //there is not a random with this key already since this is the first time we played this card with random children.
                }

                //we also have to check for identity with the child nodes.
                foreach (var other in intermediateNode.Randoms)
                {
                    if (other.FightAction.IsEqual(child.Fight.FightAction) && other.FightAction.Key == child.Fight.FightAction.Key)
                    {
                        //I should just compare the order of the draw pile actually.
                        other.Weight++;
                        return(other);
                    }
                    else
                    {
                        var ae = 4;
                    }
                }
                child.Parent      = intermediateNode;
                child.FightAction = child.Fight.FightAction;
                //child.fightaction still has its key
                intermediateNode.Randoms.Add(child);
            }
            else
            {
                child.Parent      = this;
                child.FightAction = child.Fight.FightAction;
                Choices.Add(child);
            }

            //Fight is over. Calc values.
            if (child.Fight.Status != FightStatus.Ongoing)
            {
                child.CalcValue();
            }

            return(child);
        }
Ejemplo n.º 14
0
        public FightNode GetNode()
        {
            var child = new FightNode(Fight.Copy(), Depth + 1);

            return(child);
        }
Ejemplo n.º 15
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;
            }
        }
Ejemplo n.º 16
0
        public void Start()
        {
            while (true)
            {
                DisplayStatus(_Current);

                var ii        = 0;
                var actionMap = new Dictionary <int, FightAction>()
                {
                };

                var actions = _Current.Fight.GetAllActions(includeUnplayable: true);

                FightAction action;
                if (actions.Count == 1)
                {
                    action = actions[0];
                }
                else
                {
                    var orderedActions = actions
                                         .OrderBy(el => el.CardInstance == null)
                                         .ThenByDescending(el => el.Playable)
                                         .ThenBy(el => el.CardInstance?.Card?.Name)
                                         .ThenBy(el => el.CardInstance?.EnergyCost());
                    foreach (var a in orderedActions)
                    {
                        var cost = "";
                        if (a.FightActionType == FightActionEnum.PlayCard)
                        {
                            ///no indexer but still show the energy cost.
                            if (a.Playable)
                            {
                                cost = $" E: {a.CardInstance.EnergyCost()}";
                            }
                            else
                            {
                                cost = $" E: -";
                            }
                        }
                        if (a.Playable)
                        {
                            Console.WriteLine($"\t{ii}: {a}{cost}");
                            actionMap[ii] = a;
                            ii++;
                        }
                        else
                        {
                            Console.WriteLine($"\t-: {a}{cost}");
                        }
                    }

                    var parsed = Int32.TryParse(Console.ReadLine(), out int num);
                    if (!parsed)
                    {
                        continue;
                    }
                    if (!actionMap.ContainsKey(num))
                    {
                        continue;
                    }
                    action = actionMap[num];
                }
                _Current = _Current.ApplyAction(action);
                if (_Current.Fight.Status != FightStatus.Ongoing)
                {
                    DisplayStatus(_Current);
                    break;
                }
            }
        }