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);"); } } }
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(); } }