public FightSimulationResult Run(TextWriter log)
        {
            FightSimulationResult res = new FightSimulationResult();

            if (Fight.Attacker.Items == null)
            {
                return(res);
            }

            foreach (object refItem in Fight.Attacker.Items)
            {
                if (refItem is CreatureRef)
                {
                    CreatureRef attackerRef = (CreatureRef)refItem;
                    if (Fight.Defender.Items == null)
                    {
                        return(res);
                    }

                    foreach (object refDefItem in Fight.Defender.Items)
                    {
                        if (refDefItem is CreatureRef)
                        {
                            CreatureRef defenderRef         = (CreatureRef)refDefItem;
                            FightSimulationResult.Info info = new FightSimulationResult.Info()
                            {
                                Attacker = attackerRef, Defender = defenderRef
                            };
                            CreatureFightSimulation(Fight, SimulationType.MinimalDamage, info, attackerRef, defenderRef, log);
                            CreatureFightSimulation(Fight, SimulationType.MaximalDamage, info, attackerRef, defenderRef, log);
                            CreatureFightSimulation(Fight, SimulationType.AverageDamage, info, attackerRef, defenderRef, log);

                            res.Add(info);
                        }
                    }
                }
            }

            return(res);
        }
        private void CreatureFightSimulation(Fight fight, SimulationType type, FightSimulationResult.Info info, CreatureRef attackerRef, CreatureRef defenderRef, TextWriter log)
        {
            string val  = string.Format("Fight simulation ({2}) between {0} and {1}", attackerRef.Name, defenderRef.Name, System.Enum.GetName(type.GetType(), type));
            string dash = new string('-', val.Length);

            log.WriteLine(dash);
            log.WriteLine(val);
            log.WriteLine(dash);

            AttackType attackType         = attackerRef.AttackType[0];
            int        attackerCount      = attackerRef.Count;
            int        attackerDamageLeft = 0;
            int        defenderCount      = defenderRef.Count;
            int        defenderDamageLeft = 0;

            CreatureRef currentAttackerRef = attackerRef;
            CreatureRef currentDefenderRef = defenderRef;

            Hero attackerHero = Fight.Attacker;
            Hero defenderHero = Fight.Defender;

            int rounds = 0;

            do
            {
                log.WriteLine("ROUND: {0}", rounds + 1);
                log.WriteLine("*** Strike ***");
                FightResult strike = CreatureFight(Fight, attackerHero, defenderHero, currentAttackerRef, currentDefenderRef, attackerCount, defenderCount, log, attackType, defenderDamageLeft);
                defenderCount      = UpdateKillsCount(defenderCount, strike, type);
                defenderDamageLeft = GetLeftDamage(strike, type);
                FightResult counterStrike = new FightResult();

                int retaliations = strike.Retaliations;
                if (retaliations > 0 && defenderCount > 0)
                {
                    log.WriteLine("*** Counterstrike ***");
                    log.WriteLine("Conterstrike attack, atack type is always melee");
                    counterStrike = CreatureFight(Fight, defenderHero, attackerHero, currentDefenderRef, currentAttackerRef, defenderCount, attackerCount, log, AttackType.Melee, attackerDamageLeft);
                    --retaliations;
                    attackerCount      = UpdateKillsCount(attackerCount, counterStrike, type);
                    attackerDamageLeft = GetLeftDamage(counterStrike, type);
                }
                if (strike.DoubleAttack && attackerCount > 0)
                {
                    log.WriteLine("*** Double Attack ***");
                    FightResult secondStrike = CreatureFight(Fight, attackerHero, defenderHero, currentAttackerRef, currentDefenderRef, attackerCount, defenderCount, log, attackType, defenderDamageLeft);
                    defenderCount      = UpdateKillsCount(defenderCount, secondStrike, type);
                    defenderDamageLeft = GetLeftDamage(secondStrike, type);
                    MergeFightResult(strike, secondStrike);
                }
                if (retaliations > 0 && defenderCount > 0)
                {
                    log.WriteLine("*** Counterstrike ***");
                    log.WriteLine("Conterstrike attack, atack type is always melee");
                    FightResult secondCounterStrike = CreatureFight(Fight, defenderHero, attackerHero, currentDefenderRef, currentAttackerRef, defenderCount, attackerCount, log, AttackType.Melee, attackerDamageLeft);
                    --retaliations;
                    attackerCount      = UpdateKillsCount(attackerCount, secondCounterStrike, type);
                    attackerDamageLeft = GetLeftDamage(secondCounterStrike, type);
                    MergeFightResult(counterStrike, secondCounterStrike);
                }

                if (attackerRef.AttackType[0] == AttackType.Melee || defenderRef.AttackType[0] == AttackType.Melee)
                {
                    log.WriteLine("One of the fighers did melee attack, rest of the battle is melee.");
                    attackType = AttackType.Melee;
                }

                // store info about first attack
                if (rounds == 0)
                {
                    info.Strike = strike;
                    switch (type)
                    {
                    case SimulationType.MinimalDamage:
                        info.CounterMin = counterStrike;
                        break;

                    case SimulationType.MaximalDamage:
                        info.CounterMax = counterStrike;
                        break;

                    case SimulationType.AverageDamage:
                        info.CounterAvg = counterStrike;
                        break;

                    default:
                        break;
                    }
                }
                CreatureRef tmp        = currentDefenderRef;
                int         countTmp   = defenderCount;
                int         dmgLeftTmp = defenderDamageLeft;
                Hero        heroTmp    = defenderHero;

                currentDefenderRef = currentAttackerRef;
                currentAttackerRef = tmp;

                defenderCount = attackerCount;
                attackerCount = countTmp;

                defenderDamageLeft = attackerDamageLeft;
                attackerDamageLeft = dmgLeftTmp;

                defenderHero = attackerHero;
                attackerHero = heroTmp;

                ++rounds;
            }while (attackerCount > 0 && defenderCount > 0);

            FightFinalResult res = new FightFinalResult();

            if (rounds % 2 > 0)
            {
                res.AttackerLeft = defenderCount;
                res.DefenderLeft = attackerCount;
            }
            else
            {
                res.AttackerLeft = attackerCount;
                res.DefenderLeft = defenderCount;
            }
            res.Rounds = rounds;

            switch (type)
            {
            case SimulationType.MinimalDamage:
                info.FinalMin = res;
                break;

            case SimulationType.MaximalDamage:
                info.FinalMax = res;
                break;

            case SimulationType.AverageDamage:
                info.FinalAvg = res;
                break;

            default:
                break;
            }
        }