private bool IsDone(IRaceDefinition raceDefinition, IStrategieResult strategie)
        {
            var done = false;

            switch (raceDefinition.RaceMode)
            {
            case RaceMode.Race:
                if (strategie.NumberOfLaps == raceDefinition.NumberOfLaps)
                {
                    done = true;
                }

                break;

            case RaceMode.Endurance:
                if (strategie.RaceTime >= raceDefinition.RaceDuration)
                {
                    done = true;
                }

                break;
            }

            return(done);
        }
        private void RunLaps(IRaceDefinition raceDefinition, ItemsProvider <TiresType> tiresProvider, double fuelConsumptionPerLap, PitStrategie pitStrategie, IStrategieResult strategie, ItemsProvider <int> fuelProvider)
        {
            var tireDefinition = raceDefinition.TiresDefinitions.First(t => t.TiresType == strategie.StartTiresType);

            var currentFuelRate       = 100.0;
            var currentTiresRate      = 100.0;
            var tireConsumptionPerLap = 100.0 / tireDefinition.OptimalNumberOfLaps;
            var needRefuel            = false;
            var needChangeTires       = false;

            var nextRefuel = fuelProvider.GetNext();

            do
            {
                strategie.NumberOfLaps++;
                currentFuelRate  -= fuelConsumptionPerLap;
                currentTiresRate -= tireConsumptionPerLap;

                if (currentFuelRate <= raceDefinition.FuelReservePercent)
                {
                    needRefuel = true;
                }

                if (currentTiresRate <= 10)
                {
                    needChangeTires = true;
                }

                if (needChangeTires || needRefuel)
                {
                    switch (pitStrategie)
                    {
                    case PitStrategie.OnlyNeeded:
                        break;

                    case PitStrategie.FuelEachTime:
                        needRefuel = currentFuelRate < nextRefuel;
                        break;

                    case PitStrategie.TiresEachTime:
                        needChangeTires = true;
                        break;

                    case PitStrategie.FuelAndTiresEachTime:
                        needRefuel      = currentFuelRate < nextRefuel;
                        needChangeTires = true;
                        break;
                    }

                    var pitStop = new PitStop
                    {
                        Refuel      = needRefuel ? nextRefuel : 0,
                        ChangeTires = needChangeTires,
                        LapNumber   = strategie.NumberOfLaps,
                        TiresType   = tireDefinition.TiresType,
                        FuelState   = currentFuelRate,
                        TiresState  = currentTiresRate
                    };
                    strategie.PitStops.Add(pitStop);

                    if (needChangeTires)
                    {
                        strategie.RaceTime = strategie.RaceTime.Add(raceDefinition.TiresChangeDuration);
                        needChangeTires    = false;
                        currentTiresRate   = 100.0;
                        var nextTires = tiresProvider.GetNext();
                        tireDefinition        = raceDefinition.TiresDefinitions.First(t => t.TiresType == nextTires);
                        tireConsumptionPerLap = 100.0 / tireDefinition.OptimalNumberOfLaps;
                        pitStop.TiresType     = tireDefinition.TiresType;
                    }

                    if (needRefuel)
                    {
                        strategie.RaceTime = strategie.RaceTime.Add(GetFuelFillingTime(raceDefinition, currentFuelRate, nextRefuel));
                        needRefuel         = false;
                        currentFuelRate    = nextRefuel;
                        nextRefuel         = fuelProvider.GetNext();
                    }

                    strategie.RaceTime = strategie.RaceTime.Add(raceDefinition.TimeLostForPitStop);
                }

                strategie.RaceTime      = strategie.RaceTime.Add(tireDefinition.AverageLapTime);
                strategie.TiresEndState = currentTiresRate;
                strategie.FuelEndState  = currentFuelRate;
            } while (!IsDone(raceDefinition, strategie));
        }