Beispiel #1
0
        public Engine(AttributesDictionary playerAttributes)
        {
            _systems  = new List <ISystem>();
            _entities = new List <Entity>();

            // Sets up a keyboard to watch for inputs
            keyboard = new Keyboard();

            // Initializing player entities
            player = new Entity();

            // Initializing enemy entities
            enemy = new Entity();

            // Initializing skill entities
            heavyShot          = new Entity();
            straightShot       = new Entity();
            causticBite        = new Entity();
            stormBite          = new Entity();
            ironJaws           = new Entity();
            refulgentArrow     = new Entity();
            bloodletter        = new Entity();
            empyrealArrow      = new Entity();
            pitchPerfect       = new Entity();
            sidewinder         = new Entity();
            ragingStrikes      = new Entity();
            barrage            = new Entity();
            theWanderersMinuet = new Entity();
            magesBallad        = new Entity();
            armysPaeon         = new Entity();

            // Shared cooldown lists
            gcdSkillList = new List <Entity>
            {
                heavyShot,
                straightShot,
                causticBite,
                stormBite,
                ironJaws,
                refulgentArrow
            };

            riverOfBloodSkillList = new List <Entity>
            {
                bloodletter,
                //rainOfDeath
            };

            // Adding components to skills
            heavyShot.AddComponents(new List <Component>
            {
                new SkillBaseComponent(heavyShot, SkillName.HeavyShot, SkillType.Weaponskill),
                new CooldownComponent(heavyShot, 2.5m, gcdSkillList),
                new PotencyComponent(heavyShot, 150),
                new StraighterShotEffectComponent(heavyShot, StatusName.StraighterShot, 10m, 20)
            });

            straightShot.AddComponents(new List <Component>
            {
                new SkillBaseComponent(straightShot, SkillName.StraightShot, SkillType.Weaponskill),
                new CooldownComponent(straightShot, 2.5m, gcdSkillList),
                new PotencyComponent(straightShot, 140),
                new StatusEffectComponent(straightShot, AttributeType.CriticalHitRate, StatusName.StraightShot, ActorType.Self, 30, 10)
            });

            causticBite.AddComponents(new List <Component>
            {
                new SkillBaseComponent(causticBite, SkillName.CausticBite, SkillType.Weaponskill),
                new CooldownComponent(causticBite, 2.5m, gcdSkillList),
                new PotencyComponent(causticBite, 120),
                new DotEffectComponent(causticBite, DotName.CausticBite, 30m, 45)
            });

            stormBite.AddComponents(new List <Component>
            {
                new SkillBaseComponent(stormBite, SkillName.Stormbite, SkillType.Weaponskill),
                new CooldownComponent(stormBite, 2.5m, gcdSkillList),
                new PotencyComponent(stormBite, 120),
                new DotEffectComponent(stormBite, DotName.Stormbite, 30m, 55)
            });

            ironJaws.AddComponents(new List <Component>
            {
                new SkillBaseComponent(ironJaws, SkillName.IronJaws, SkillType.Weaponskill),
                new CooldownComponent(ironJaws, 2.5m, gcdSkillList),
                new PotencyComponent(ironJaws, 100),
                new IronJawsEffectComponent(ironJaws, new List <DotEffectComponent>
                {
                    (DotEffectComponent)stormBite.Components.Find(x => x is DotEffectComponent),
                    (DotEffectComponent)causticBite.Components.Find(x => x is DotEffectComponent)
                })
            });

            refulgentArrow.AddComponents(new List <Component>
            {
                new SkillBaseComponent(refulgentArrow, SkillName.RefulgentArrow, SkillType.Weaponskill),
                new CooldownComponent(refulgentArrow, 2.5m, gcdSkillList),
                new PotencyComponent(refulgentArrow, 300),
                new UseConditionComponent(refulgentArrow, ConditionalFunctions.IsRefulgentArrowUsable),
                new UsesEnablerComponent(refulgentArrow, StatusName.StraighterShot)
            });

            bloodletter.AddComponents(new List <Component>
            {
                new SkillBaseComponent(bloodletter, SkillName.Bloodletter, SkillType.Ability),
                new CooldownComponent(bloodletter, 15m),
                new PotencyComponent(bloodletter, 130)
            });

            empyrealArrow.AddComponents(new List <Component>
            {
                new SkillBaseComponent(empyrealArrow, SkillName.EmpyrealArrow, SkillType.Weaponskill),
                new CooldownComponent(empyrealArrow, 15m),
                new PotencyComponent(empyrealArrow, 230),
                new EnhancedEmpyrealArrowComponent(empyrealArrow)
            });

            pitchPerfect.AddComponents(new List <Component>
            {
                new SkillBaseComponent(pitchPerfect, SkillName.PitchPerfect, SkillType.Ability),
                new CooldownComponent(pitchPerfect, 3m),
                new ConditionalPotencyComponent(pitchPerfect, ConditionalFunctions.PitchPerfectPotency),
                new UseConditionComponent(pitchPerfect, ConditionalFunctions.IsPitchPerfectUsable),
                new UsesRepertoireComponent(pitchPerfect)
            });

            sidewinder.AddComponents(new List <Component>
            {
                new SkillBaseComponent(sidewinder, SkillName.Sidewinder, SkillType.Ability),
                new CooldownComponent(sidewinder, 60m),
                new ConditionalPotencyComponent(sidewinder, ConditionalFunctions.SidewinderPotency)
            });

            ragingStrikes.AddComponents(new List <Component>
            {
                new SkillBaseComponent(ragingStrikes, SkillName.RagingStrikes, SkillType.Ability),
                new CooldownComponent(ragingStrikes, 80m),
                new StatusEffectComponent(ragingStrikes, AttributeType.Damage, StatusName.RagingStrikes, ActorType.Self, 20m, 1.1m)
            });

            barrage.AddComponents(new List <Component>
            {
                new SkillBaseComponent(barrage, SkillName.Barrage, SkillType.Ability),
                new CooldownComponent(barrage, 80m),
                new GenericStatusEffectComponent(barrage, StatusName.Barrage, 10m)
            });

            theWanderersMinuet.AddComponents(new List <Component>
            {
                new SkillBaseComponent(theWanderersMinuet, SkillName.TheWanderersMinuet, SkillType.Spell),
                new CooldownComponent(theWanderersMinuet, 80m),
                new PotencyComponent(theWanderersMinuet, 100),
                new SongComponent(theWanderersMinuet, SongName.TheWanderersMinuet)
            });

            magesBallad.AddComponents(new List <Component>
            {
                new SkillBaseComponent(magesBallad, SkillName.MagesBallad, SkillType.Spell),
                new CooldownComponent(magesBallad, 80m),
                new PotencyComponent(magesBallad, 100),
                new SongComponent(magesBallad, SongName.MagesBallad)
            });

            armysPaeon.AddComponents(new List <Component>
            {
                new SkillBaseComponent(armysPaeon, SkillName.ArmysPaeon, SkillType.Spell),
                new CooldownComponent(armysPaeon, 80m),
                new PotencyComponent(armysPaeon, 100),
                new SongComponent(armysPaeon, SongName.ArmysPaeon)
            });

            // Initializing player components
            player.AddComponents(new List <Component>
            {
                new BardComponent(player, new List <Entity>
                {
                    heavyShot,
                    straightShot,
                    causticBite,
                    stormBite,
                    ironJaws,
                    refulgentArrow,
                    bloodletter,
                    empyrealArrow,
                    pitchPerfect,
                    sidewinder,
                    ragingStrikes,
                    barrage,
                    theWanderersMinuet,
                    magesBallad,
                    armysPaeon
                }),
                new AttributesComponent(player, playerAttributes),
                new ModifierStateComponent(player),
                new AnimationLockComponent(player),
                new AutoAttackComponent(player, 100),
                new RiverOfBloodComponent(player, riverOfBloodSkillList),
                new SkillControlComponent(player, Job.Bard),
                // DEBUG: Setting enemy as player's target
                new TargetComponent(player, enemy)
            });

            // Initializing enemy components
            enemy.AddComponents(new List <Component>
            {
                new HealthComponent(enemy, 0),
                new OverTimeStateComponent(enemy)
            });

            // Making entities list
            _entities.Add(player);
            _entities.Add(enemy);
            _entities.Add(heavyShot);
            _entities.Add(straightShot);
            _entities.Add(causticBite);
            _entities.Add(stormBite);
            _entities.Add(ironJaws);
            _entities.Add(refulgentArrow);
            _entities.Add(bloodletter);
            _entities.Add(empyrealArrow);
            _entities.Add(pitchPerfect);
            _entities.Add(sidewinder);
            _entities.Add(ragingStrikes);
            _entities.Add(barrage);
            _entities.Add(theWanderersMinuet);
            _entities.Add(magesBallad);
            _entities.Add(armysPaeon);

            foreach (Entity e in _entities)
            {
                foreach (Component c in e.Components)
                {
                    if (c is AnimationLockComponent)
                    {
                        animationLockComponents.Add((AnimationLockComponent)c);
                    }
                    else if (c is AttributesComponent)
                    {
                        attributesComponents.Add((AttributesComponent)c);
                    }
                    else if (c is AutoAttackComponent)
                    {
                        autoAttackComponents.Add((AutoAttackComponent)c);
                    }
                    else if (c is BardComponent)
                    {
                        bardComponents.Add((BardComponent)c);
                    }
                    else if (c is ConditionalPotencyComponent)
                    {
                        conditionalPotencyComponents.Add((ConditionalPotencyComponent)c);
                    }
                    else if (c is CooldownComponent)
                    {
                        cooldownComponents.Add((CooldownComponent)c);
                    }
                    else if (c is DotEffectComponent)
                    {
                        dotEffectComponents.Add((DotEffectComponent)c);
                    }
                    else if (c is EnhancedEmpyrealArrowComponent)
                    {
                        enhancedEmpyrealArrowComponents.Add((EnhancedEmpyrealArrowComponent)c);
                    }
                    else if (c is GenericStatusEffectComponent)
                    {
                        genericStatusEffectComponents.Add((GenericStatusEffectComponent)c);
                    }
                    else if (c is HealthComponent)
                    {
                        healthComponents.Add((HealthComponent)c);
                    }
                    else if (c is IronJawsEffectComponent)
                    {
                        ironJawsEffectComponents.Add((IronJawsEffectComponent)c);
                    }
                    else if (c is ModifierStateComponent)
                    {
                        modifierStateComponents.Add((ModifierStateComponent)c);
                    }
                    else if (c is OverTimeStateComponent)
                    {
                        overtimeStateComponents.Add((OverTimeStateComponent)c);
                    }
                    else if (c is PotencyComponent)
                    {
                        potencyComponents.Add((PotencyComponent)c);
                    }
                    else if (c is RiverOfBloodComponent)
                    {
                        riverOfBloodComponents.Add((RiverOfBloodComponent)c);
                    }
                    else if (c is SkillBaseComponent)
                    {
                        skillBaseComponents.Add((SkillBaseComponent)c);
                    }
                    else if (c is SkillControlComponent)
                    {
                        skillControlComponents.Add((SkillControlComponent)c);
                    }
                    else if (c is SongComponent)
                    {
                        songComponents.Add((SongComponent)c);
                    }
                    else if (c is StatusEffectComponent)
                    {
                        statusEffectComponents.Add((StatusEffectComponent)c);
                    }
                    else if (c is StraighterShotEffectComponent)
                    {
                        straighterShotEffectComponents.Add((StraighterShotEffectComponent)c);
                    }
                    else if (c is TargetComponent)
                    {
                        targetComponents.Add((TargetComponent)c);
                    }
                    else if (c is UseConditionComponent)
                    {
                        useConditionComponents.Add((UseConditionComponent)c);
                    }
                    else if (c is UsesEnablerComponent)
                    {
                        usesEnablerComponents.Add((UsesEnablerComponent)c);
                    }
                    else if (c is UsesRepertoireComponent)
                    {
                        usesRepertoireComponents.Add((UsesRepertoireComponent)c);
                    }
                }
            }

            // Initializing systems
            //_systems.Add(new AIDebugSystem(player, bardComponents, cooldownComponents, modifierStateComponents, overtimeStateComponents, skillBaseComponents, targetComponents));
            _systems.Add(new NewAISystem(player, bardComponents, cooldownComponents, modifierStateComponents, overtimeStateComponents, skillBaseComponents, skillControlComponents, targetComponents));
            _systems.Add(new OverTimeSystem(bardComponents, cooldownComponents, healthComponents, modifierStateComponents, overtimeStateComponents, riverOfBloodComponents));
            _systems.Add(new RepertoireSystem(bardComponents, cooldownComponents, modifierStateComponents, riverOfBloodComponents));
            _systems.Add(new BuffSystem(bardComponents, modifierStateComponents));
            _systems.Add(new AutoAttackSystem(attributesComponents, autoAttackComponents, bardComponents, healthComponents, modifierStateComponents, targetComponents));
            _systems.Add(new SkillSystem(animationLockComponents, attributesComponents, bardComponents, conditionalPotencyComponents, cooldownComponents, dotEffectComponents, enhancedEmpyrealArrowComponents, genericStatusEffectComponents, healthComponents, ironJawsEffectComponents, modifierStateComponents, overtimeStateComponents, potencyComponents, skillBaseComponents, skillControlComponents, songComponents, statusEffectComponents, straighterShotEffectComponents, targetComponents, useConditionComponents, usesEnablerComponents, usesRepertoireComponents));
        }
Beispiel #2
0
        public AttributesDictionary GetAriyalaSet(string code)
        {
            // Checks if the input is valid
            if (!ariyalaRegex.IsMatch(code))
            {
                throw new FormatException("\nInvalid link or code. ");
            }

            // Navigates the page
            string ariyalaLink = "http://ffxiv.ariyala.com/" + ariyalaRegex.Match(code).Groups[3].Value;

            driver.Url = ariyalaLink;
            driver.Navigate();

            wait.Until(new Func <IWebDriver, bool>(IsLoaded));

            //TODO: Change for all jobs
            // Checks if it's a BRD gearset by reading the content of the html element
            if (driver.FindElement(By.Id("categoryBoxContentName")).Text != "Bard")
            {
                throw new NotImplementedException("\nNot a bard gearset. ");
            }

            // Reads the attributes from the html elements
            IReadOnlyCollection <IWebElement> elementList = driver.FindElements(By.XPath(xpath));
            AttributesDictionary attributesFromAriyala    = new AttributesDictionary();

            if (elementList.Count != JobSettings.brdAttributeTypes.Count)
            {
                throw new NotFoundException("\nNumber of attributes read and expected mismatch. ");
            }

            for (int i = 0; i < elementList.Count; i++)
            {
                int.TryParse(attributeRegex.Match(elementList.ElementAt(i).Text).Groups[1].Value, out int attribute);

                if (attribute == 0)
                {
                    throw new FormatException("\nInvalid attribute. ");
                }

                // Stores the read attribute into the dictionary
                attributesFromAriyala[JobSettings.brdAttributeTypes[i]] = attribute;
            }


            bool validAttackPower = true;
            bool validWeapDamage  = true;
            bool validWeapDelay   = true;

            do
            {
                try
                {
                    Console.WriteLine("\nPlease manually input the Attack Power:");
                    int.TryParse(Console.ReadLine(), out int attackPower);
                    if (attackPower <= 0)
                    {
                        throw new InvalidDataException("\nNumber must be greater than zero.");
                    }
                    attributesFromAriyala[JobSettings.brdAttributeTypes[0]] = attackPower;
                    validAttackPower = true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    validAttackPower = false;
                }
            }while (!validAttackPower);

            // Asks for weapon damage and weapon delay
            do
            {
                try
                {
                    Console.WriteLine("\nPlease manually input the Weapon Damage:");
                    int.TryParse(Console.ReadLine(), out int weaponDamage);
                    if (weaponDamage <= 0)
                    {
                        throw new InvalidDataException("\nNumber must be greater than zero.");
                    }
                    attributesFromAriyala[AttributeType.WeaponDamage] = weaponDamage;
                    validWeapDamage = true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    validWeapDamage = false;
                }
            }while (!validWeapDamage);

            do
            {
                try
                {
                    Console.WriteLine("\nPlease manually input the Weapon Delay:");
                    decimal.TryParse(Console.ReadLine(), out decimal weaponDelay);
                    if (weaponDelay <= 0)
                    {
                        throw new InvalidDataException("\nNumber must be greater than zero.");
                    }
                    attributesFromAriyala[AttributeType.WeaponDelay] = weaponDelay;
                    validWeapDelay = true;
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    validWeapDelay = false;
                }
            }while (!validWeapDelay);

            return(attributesFromAriyala);
        }
Beispiel #3
0
        static void Main(string[] args)
        {
            while (true)
            {
                LogData       logData     = new LogData();
                DataTable     dpsTable    = new DataTable("DPS");
                List <string> ariyalaSets = new List <string>();

                int     numberOfSets     = 0;
                int     numberOfRuns     = 0;
                decimal simulationTarget = 0;
                List <AttributesDictionary> listOfAttDicts = new List <AttributesDictionary>();
                AttributesDictionary        singleAttDict  = new AttributesDictionary();

                bool validSetNumber        = true;
                bool validCode             = true;
                bool validRunsNumber       = true;
                bool validSimulationTarget = true;
                SimulationParameters simulationParameter = SimulationParameters.Invalid;
                SimulationType       simulationType      = SimulationType.Invalid;

                // Asks for type of simulation
                do
                {
                    Console.WriteLine("\nEnter 'V' for a single verbose run, or 'M' for multiple runs:");

                    try
                    {
                        char typeChar = Console.ReadLine()[0];

                        if (typeChar == 'V')
                        {
                            simulationType = SimulationType.Verbose;
                        }
                        else if (typeChar == 'M')
                        {
                            simulationType = SimulationType.Multiple;
                        }
                        else
                        {
                            throw new InvalidDataException("Invalid type of simulation.");
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                        simulationType = SimulationType.Invalid;
                    }
                }while (simulationType == SimulationType.Invalid);

                // Multiple simulation
                if (simulationType == SimulationType.Multiple)
                {
                    // Asks for number of gearsets
                    do
                    {
                        Console.WriteLine("\nInput the number of gearsets:");

                        try
                        {
                            int.TryParse(Console.ReadLine(), out numberOfSets);
                            if (numberOfSets <= 0)
                            {
                                throw new InvalidDataException("Number must be greater than zero.");
                            }
                            validSetNumber = true;
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            validSetNumber = false;
                        }
                    }while (!validSetNumber);

                    // Instantiates the HTML scraper for Ariyala
                    AriyalaScraper scraper = new AriyalaScraper();

                    // Iterates over each gearset
                    for (int i = 0; i < numberOfSets; i++)
                    {
                        do
                        {
                            Console.WriteLine("\nEnter the Ariyala link or code #{0}:", i + 1);

                            try
                            {
                                string ariyalaCode = Console.ReadLine();
                                listOfAttDicts.Add(scraper.GetAriyalaSet(ariyalaCode));
                                validCode = true;
                            }
                            catch (Exception e)
                            {
                                Console.WriteLine(e.Message);
                                validCode = false;
                            }
                        }while (!validCode);
                    }

                    // Closes the browser
                    scraper.Dispose();

                    // Asks for number of simulations
                    do
                    {
                        Console.WriteLine("\nInput the number of simulations:");

                        try
                        {
                            int.TryParse(Console.ReadLine(), out numberOfRuns);
                            if (numberOfRuns <= 0)
                            {
                                throw new InvalidDataException("Number must be greater than zero.");
                            }
                            validRunsNumber = true;
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            validRunsNumber = false;
                        }
                    }while (!validRunsNumber);

                    // Asks for type of simulation
                    do
                    {
                        Console.WriteLine("\nEnter 'D' for damage target, or 'T' for time target:");

                        try
                        {
                            char targetChar = Console.ReadLine()[0];

                            if (targetChar == 'D')
                            {
                                simulationParameter = SimulationParameters.DamageTarget;
                            }
                            else if (targetChar == 'T')
                            {
                                simulationParameter = SimulationParameters.TimeTarget;
                            }
                            else
                            {
                                throw new InvalidDataException("Invalid type of simulation.");
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            simulationParameter = SimulationParameters.Invalid;
                        }
                    }while (simulationParameter == SimulationParameters.Invalid);

                    // Asks for target of simulation (seconds or total damage)
                    do
                    {
                        try
                        {
                            if (simulationParameter == SimulationParameters.DamageTarget)
                            {
                                Console.WriteLine("\nInput the  total damage target:");
                                decimal.TryParse(Console.ReadLine(), out simulationTarget);
                            }
                            else if (simulationParameter == SimulationParameters.TimeTarget)
                            {
                                Console.WriteLine("\nInput the time target (in seconds):");
                                decimal.TryParse(Console.ReadLine(), out simulationTarget);
                            }

                            if (simulationTarget <= 0)
                            {
                                throw new InvalidDataException("Value must be greater than zero.");
                            }
                            validSimulationTarget = true;
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            validSimulationTarget = false;
                        }
                    }while (!validSimulationTarget);

                    // Main loop
                    for (int k = 0; k < numberOfSets; k++)
                    {
                        List <decimal> results = new List <decimal>();
                        Engine         engine  = new Engine(listOfAttDicts[k]);
                        Stopwatch      timer   = new Stopwatch();

                        // Simulates each gearset
                        timer.Start();
                        for (int i = 0; i < numberOfRuns; i++)
                        {
                            results.Add(engine.Simulate(simulationParameter, simulationTarget));
                            engine.Reinitialize();
                        }
                        timer.Stop();


                        Console.WriteLine("\nAverage DPS: {0:0.00}\nMax: {1:0.00}\nMin: {2:0.00}", results.Average(), results.Max(), results.Min());

                        Console.WriteLine("\nSimulation time: {0}", timer.ElapsedMilliseconds.MilliToSeconds());

                        // Writes to CSV
                        Console.WriteLine("\nWriting to CSV.");
                        StreamWriter stream    = new StreamWriter(Environment.CurrentDirectory + k.ToString() + @".csv");
                        CsvWriter    csvWriter = new CsvWriter(stream);

                        timer.Restart();
                        foreach (decimal d in results)
                        {
                            csvWriter.WriteRecord((double)d);
                            csvWriter.NextRecord();
                        }
                        timer.Stop();

                        Console.WriteLine("\nWrite time: {0}", timer.ElapsedMilliseconds.MilliToSeconds());

                        stream.Dispose();
                    }
                }

                // Single verbose simulation
                else
                {
                    // Instantiates the HTML scraper for Ariyala
                    AriyalaScraper scraper = new AriyalaScraper();

                    // Asks for an Ariyala code
                    do
                    {
                        Console.WriteLine("\nEnter the Ariyala link or code:");

                        try
                        {
                            string ariyalaCode = Console.ReadLine();
                            singleAttDict = scraper.GetAriyalaSet(ariyalaCode);
                            validCode     = true;
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            validCode = false;
                        }
                    }while (!validCode);

                    // Closes the browser
                    scraper.Dispose();

                    // Asks for type of simulation
                    do
                    {
                        Console.WriteLine("\nEnter 'D' for damage target, or 'T' for time target:");

                        try
                        {
                            char targetChar = Console.ReadLine()[0];

                            if (targetChar == 'D')
                            {
                                simulationParameter = SimulationParameters.DamageTarget;
                            }
                            else if (targetChar == 'T')
                            {
                                simulationParameter = SimulationParameters.TimeTarget;
                            }
                            else
                            {
                                throw new InvalidDataException("Invalid type of simulation.");
                            }
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            simulationParameter = SimulationParameters.Invalid;
                        }
                    }while (simulationParameter == SimulationParameters.Invalid);

                    // Asks for target of simulation (seconds or total damage)
                    do
                    {
                        try
                        {
                            if (simulationParameter == SimulationParameters.DamageTarget)
                            {
                                Console.WriteLine("\nInput the  total damage target:");
                                decimal.TryParse(Console.ReadLine(), out simulationTarget);
                            }
                            else if (simulationParameter == SimulationParameters.TimeTarget)
                            {
                                Console.WriteLine("\nInput the time target (in seconds):");
                                decimal.TryParse(Console.ReadLine(), out simulationTarget);
                            }

                            if (simulationTarget <= 0)
                            {
                                throw new InvalidDataException("Value must be greater than zero.");
                            }
                            validSimulationTarget = true;
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e.Message);
                            validSimulationTarget = false;
                        }
                    }while (!validSimulationTarget);

                    // Main loop

                    decimal   result = 0;
                    Engine    engine = new Engine(singleAttDict);
                    Stopwatch timer  = new Stopwatch();


                    timer.Start();

                    result = engine.Simulate(simulationParameter, simulationTarget, logData);
                    engine.Reinitialize();

                    timer.Stop();

                    List <string> logStrings = logData.GetLog();

                    foreach (string s in logStrings)
                    {
                        Console.Write(s);
                    }

                    Console.WriteLine("\nDPS: {0:0.00}", result);

                    Console.WriteLine("\nSimulation time: {0}", timer.ElapsedMilliseconds.MilliToSeconds());
                }
            }
        }