public void AttackCalculator_ReturnsAttackResultWithinMarginOfError()
        {
            const int iterations = 1000000;

            //<attack, defense, attackResult>
            Dictionary <int, Dictionary <int, Dictionary <AttackResult, decimal> > > resultAverages =
                new Dictionary <int, Dictionary <int, Dictionary <AttackResult, decimal> > >();

            AttackCalculator attackCalculator = new AttackCalculator();

            for (int a = 2; a < 9; a++)
            {
                //There are no attacks powers of 5
                if (a == 5)
                {
                    continue;
                }

                for (int d = 2; d < 9; d++)
                {
                    if (!resultAverages.ContainsKey(a))
                    {
                        resultAverages.Add(a, new Dictionary <int, Dictionary <AttackResult, decimal> >());
                    }
                    if (!resultAverages[a].ContainsKey(d))
                    {
                        resultAverages[a].Add(d, new Dictionary <AttackResult, decimal>());
                    }
                    resultAverages[a][d].Add(AttackResult.Kill, 0);
                    resultAverages[a][d].Add(AttackResult.Push, 0);
                    resultAverages[a][d].Add(AttackResult.CounterPush, 0);
                    resultAverages[a][d].Add(AttackResult.CounterKill, 0);
                }

                for (int d = 2; d < 9; d++)
                {
                    for (int i = 0; i < iterations; i++)
                    {
                        AttackResult result = attackCalculator.Calculate(a, d);
                        switch (result)
                        {
                        case AttackResult.Kill:
                            resultAverages[a][d][AttackResult.Kill]++;
                            break;

                        case AttackResult.Push:
                            resultAverages[a][d][AttackResult.Push]++;
                            break;

                        case AttackResult.CounterPush:
                            resultAverages[a][d][AttackResult.CounterPush]++;
                            break;

                        case AttackResult.CounterKill:
                            resultAverages[a][d][AttackResult.CounterKill]++;
                            break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }

                    resultAverages[a][d][AttackResult.Kill] =
                        Math.Round(resultAverages[a][d][AttackResult.Kill] / iterations, 4);
                    resultAverages[a][d][AttackResult.Push] =
                        Math.Round(resultAverages[a][d][AttackResult.Push] / iterations, 4);
                    resultAverages[a][d][AttackResult.CounterPush] =
                        Math.Round(resultAverages[a][d][AttackResult.CounterPush] / iterations, 4);
                    resultAverages[a][d][AttackResult.CounterKill] =
                        Math.Round(resultAverages[a][d][AttackResult.CounterKill] / iterations, 4);
                }
            }


            System.Diagnostics.Debug.WriteLine(
                "Dictionary<int, Dictionary<int, Dictionary<AttackResult, decimal>>> resultAverages = new Dictionary<int, Dictionary<int, Dictionary<AttackResult, decimal>>>(); ");

            for (int a = 2; a < 9; a++)
            {
                //There are no attacks powers of 5
                if (a == 5)
                {
                    continue;
                }

                System.Diagnostics.Debug.WriteLine("resultAverages.Add(" + a +
                                                   ", new Dictionary<int, Dictionary<AttackResult, decimal>>());");

                for (int d = 2; d < 9; d++)
                {
                    System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "].Add(" + d +
                                                       ", new Dictionary<AttackResult, decimal>());");

                    System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.Kill, " +
                                                       resultAverages[a][d][AttackResult.Kill] + "m);");
                    System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.Push, " +
                                                       resultAverages[a][d][AttackResult.Push] + "m);");
                    System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.CounterPush, " +
                                                       resultAverages[a][d][AttackResult.CounterPush] + "m);");
                    System.Diagnostics.Debug.WriteLine("resultAverages[" + a + "][" + d + "].Add(AttackResult.CounterKill, " +
                                                       resultAverages[a][d][AttackResult.CounterKill] + "m);");
                }
            }
        }
Example #2
0
        public void ProcessAttackAction(int attackingMonsterTypeId, int defendingMonsterTypeId)
        {
            Monster attacker;
            Monster defender;
            bool    isHostAttacker = ActionNumber == 1 || ActionNumber == 2;

            if (isHostAttacker)
            {
                attacker = HostMonsters.Single(m => m.MonsterTypeId == attackingMonsterTypeId);
                defender = GuestMonsters.Single(m => m.MonsterTypeId == defendingMonsterTypeId);
            }
            else
            {
                attacker = GuestMonsters.Single(m => m.MonsterTypeId == attackingMonsterTypeId);
                defender = HostMonsters.Single(m => m.MonsterTypeId == defendingMonsterTypeId);
            }

            AttackResult       attackResult          = AttackCalculator.Calculate(attacker.AttackRating, defender.DefenseRating);
            IEnumerable <Node> friendlyOccupiedNodes = HostMonsters.Select(monster => monster.CurrentNode).ToList();
            IEnumerable <Node> enemyOccupiedNodes    = GuestMonsters.Select(monster => monster.CurrentNode).ToList();

            switch (attackResult)
            {
            case AttackResult.Kill:
                if (isHostAttacker)
                {
                    GuestMonsters.Remove(defender);
                }
                else
                {
                    HostMonsters.Remove(defender);
                }
                SubActionNumber = 0;

                _hostServer.SendToAll(CustomMessageTypes.AttackKillResponse, new AttackKillResponseMessage
                {
                    ActionNumber           = ActionNumber,
                    SubActionNumber        = SubActionNumber,
                    AttackingMonsterTypeId = attackingMonsterTypeId,
                    DefendingMonsterTypeId = defendingMonsterTypeId,
                    AttackResultId         = (int)AttackResult.Kill,
                    Message = "Kill"
                });
                break;

            case AttackResult.CounterKill:
                if (isHostAttacker)
                {
                    HostMonsters.Remove(attacker);
                }
                else
                {
                    GuestMonsters.Remove(attacker);
                }
                SelectedMonster = null;
                SubActionNumber = 0;

                _hostServer.SendToAll(CustomMessageTypes.AttackKillResponse, new AttackKillResponseMessage
                {
                    ActionNumber           = ActionNumber,
                    SubActionNumber        = SubActionNumber,
                    AttackingMonsterTypeId = attackingMonsterTypeId,
                    DefendingMonsterTypeId = defendingMonsterTypeId,
                    AttackResultId         = (int)AttackResult.CounterKill,
                    Message = "Counter Kill"
                });
                break;

            case AttackResult.Push:

                AvailablePushDestinations = MoveCalculator.FindMoves(defender.CurrentNode, 1,
                                                                     friendlyOccupiedNodes.Union(enemyOccupiedNodes)).Select(m => m.DestinationNode);

                if (!AvailablePushDestinations.Any())
                {
                    SubActionNumber = 0;
                    _hostServer.SendToAll(CustomMessageTypes.GameState, new GameStateMessage
                    {
                        ActionNumber      = ActionNumber,
                        SubActionNumber   = SubActionNumber,
                        Message           = "No available push destinations.",
                        HostMonsterState  = JsonConvert.SerializeObject(HostMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)),
                        GuestMonsterState = JsonConvert.SerializeObject(GuestMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id))
                    });
                }
                else
                {
                    SubActionNumber = 6;
                    _hostServer.SendToAll(CustomMessageTypes.AttackPushResponse, new AttackPushResponseMessage
                    {
                        ActionNumber                = ActionNumber,
                        SubActionNumber             = SubActionNumber,
                        AttackingMonsterTypeId      = attackingMonsterTypeId,
                        DefendingMonsterTypeId      = defendingMonsterTypeId,
                        AvailablePushDestinationIds = AvailablePushDestinations.Select(d => d.Id).ToArray(),
                        AttackResultId              = (int)AttackResult.Push,
                        Message = "Push"
                    });
                }

                break;

            case AttackResult.CounterPush:

                AvailablePushDestinations = MoveCalculator.FindMoves(attacker.CurrentNode, 1,
                                                                     friendlyOccupiedNodes.Union(enemyOccupiedNodes)).Select(m => m.DestinationNode);

                if (!AvailablePushDestinations.Any())
                {
                    SubActionNumber = 0;
                    _hostServer.SendToAll(CustomMessageTypes.GameState, new GameStateMessage
                    {
                        ActionNumber      = ActionNumber,
                        SubActionNumber   = SubActionNumber,
                        Message           = "No available push destinations.",
                        HostMonsterState  = JsonConvert.SerializeObject(HostMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id)),
                        GuestMonsterState = JsonConvert.SerializeObject(GuestMonsters.Select(m => new { m.MonsterTypeId, m.CurrentNode.Id }).ToDictionary(k => k.MonsterTypeId, v => v.Id))
                    });
                }
                else
                {
                    SubActionNumber = 7;
                    _hostServer.SendToAll(CustomMessageTypes.AttackPushResponse, new AttackPushResponseMessage
                    {
                        ActionNumber                = ActionNumber,
                        SubActionNumber             = SubActionNumber,
                        AttackingMonsterTypeId      = attackingMonsterTypeId,
                        DefendingMonsterTypeId      = defendingMonsterTypeId,
                        AvailablePushDestinationIds = AvailablePushDestinations.Select(d => d.Id).ToArray(),
                        AttackResultId              = (int)AttackResult.CounterPush,
                        Message = "Counter Push"
                    });
                }
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }