예제 #1
0
        protected override bool TryExecuteTurn(Randomizer randomizer, IGameLayer gameLayer, GameState state)
        {
            var buildingsUnderConstruction = state.GetBuildingsUnderConstruction().ToArray();

            // Randomly choose building
            //var building = buildingsUnderConstruction.ElementAt(randomizer.Random.Next(0, buildingsUnderConstruction.Length));

            // Choose the one closest to completion
            var building = buildingsUnderConstruction.OrderByDescending(x => x.BuildProgress).FirstOrDefault();


            if (building != null)
            {
                var position = building.Position;
                gameLayer.ExecuteAction(GameActions.Build, position);

                building = state.GetCompletedBuildings().FirstOrDefault(x => x.Position.ToString() == position.ToString());

                if (building is BuiltResidenceBuilding residence)
                {
                    if (AdjustHeatOnConstructed)
                    {
                        var blueprint = state.AvailableResidenceBuildings.Find(x => x.BuildingName == building.BuildingName);

                        var energy = blueprint.BaseEnergyNeed + (residence.Temperature - state.CurrentTemp)
                                     * blueprint.Emissivity / 1 - 0.5 - residence.CurrentPop * 0.04;

                        if (IsBetween(energy,
                                      residence.RequestedEnergyIn - AllowedDiffMargin,
                                      residence.RequestedEnergyIn + AllowedDiffMargin))
                        {
                            // current energy setting is sufficient
                        }
                        else
                        {
                            // adjust energy as the first action after completing building (will take one turn)
                            gameLayer.AdjustEnergy(building.Position, energy, state.GameId);
                        }
                    }
                }
                else
                {
                }
                return(true);
            }
            return(false);
        }
        protected override bool TryExecuteTurn(Randomizer randomizer, IGameLayer gameLayer, GameState state)
        {
            double?predictedTrend = null;
            var    outdoorTemp    = state.CurrentTemp;

            if (state.TemperatureHistory?.Count > 2)
            {
                // Predict outdoor temperature
                var prePreviousTemp = state.TemperatureHistory.Reverse().Skip(2).First().Value;
                var previousTemp    = state.TemperatureHistory.Reverse().Skip(1).First().Value;

                var previousDiff = previousTemp - prePreviousTemp;
                var currentDiff  = state.CurrentTemp - previousTemp;
                if (previousDiff > 0 && currentDiff > 0)
                {
                    // Trend is "getting hotter"
                    predictedTrend = (previousDiff + currentDiff) / 2;
                }
                else if (previousDiff < 0 && currentDiff < 0)
                {
                    // Trend is "getting colder"
                    predictedTrend = (previousDiff + currentDiff) / 2;
                }


                if (predictedTrend.HasValue)
                {
                    // Add the trend twice to more quickly react to big temperature changes
                    predictedTrend = predictedTrend.Value * 2;

                    outdoorTemp = state.CurrentTemp + predictedTrend.Value;
                    Logger.LogTrace($"Using prediction for OutdoorTemp: {outdoorTemp:N3}, CurrentTemp: {state.CurrentTemp:N1} (weighted trend: {predictedTrend:N3})");
                }
            }

            var buildings = state.GetCompletedBuildings()
                            .OfType <BuiltResidenceBuilding>()
                            //.Where(x => x.Temperature < MinTemperature + AllowedTemperatureDiffMargin)
                            .OrderBy(x => x.Temperature)
                            .ToArray();

            foreach (var building in buildings)
            {
                var blueprint = state.AvailableResidenceBuildings.Find(x => x.BuildingName == building.BuildingName);

                // Predict next temperature
                var newTemp =
                    building.Temperature +
                    (building.EffectiveEnergyIn - blueprint.BaseEnergyNeed) * _degreesPerExcessMwh +
                    _degreesPerPop * building.CurrentPop -
                    (building.Temperature - outdoorTemp) * blueprint.Emissivity;
                if (IsBetween(newTemp,
                              TargetTemperature - AllowedTemperatureDiffMargin,
                              TargetTemperature + AllowedTemperatureDiffMargin))
                {
                    // close enough to target temperature already...
                    continue;
                }

                if (newTemp < MinTemperature)
                {
                    // Is below minimum, fake that it is much colder than it is to make a faster recovery
                    outdoorTemp -= Math.Abs(TargetTemperature - building.Temperature);
                }
                if (building.Temperature < MinTemperature)
                {
                    // Is below minimum, fake that it is much colder than it is to make a faster recovery
                    outdoorTemp -= Math.Abs(TargetTemperature - building.Temperature);
                }

                if (newTemp > MaxTemperature)
                {
                    // Is above maximum, fake that it is much hotter than it is to make a faster recovery
                    outdoorTemp += Math.Abs(TargetTemperature - building.Temperature);
                }
                if (building.Temperature > MaxTemperature)
                {
                    // Is above maximum, fake that it is much hotter than it is to make a faster recovery
                    outdoorTemp += Math.Abs(TargetTemperature - building.Temperature);
                }


                var energyOld = blueprint.BaseEnergyNeed + (building.Temperature - outdoorTemp)
                                * blueprint.Emissivity / 1 + 0.5 - building.CurrentPop * 0.04;

                var energyNew = (TargetTemperature - building.Temperature
                                 + blueprint.BaseEnergyNeed * _degreesPerExcessMwh
                                 - _degreesPerPop * building.CurrentPop
                                 + building.Temperature * blueprint.Emissivity
                                 - outdoorTemp * blueprint.Emissivity) / _degreesPerExcessMwh;

                var energy = UseSecondaryAlgorithm ? energyNew : energyOld;

                if (predictedTrend.GetValueOrDefault() > 0)
                {
                    // Trend is getting hotter
                    // Then reduce energy to save heating resources and to cooldown appartment...
                    energy *= 0.9;
                }
                else if (predictedTrend.GetValueOrDefault() < 0)
                {
                    // Trend is getting colder
                    // Then apply more energy to make sure has enough heating...
                    energy *= 1.1;
                }

                if (energy < blueprint.BaseEnergyNeed)
                {
                    Logger.LogWarning($"Wanted to set lower energy than BaseEnergyNeed, restoring to base: {blueprint.BaseEnergyNeed:N3} Mwh from {energy:N3} Mwh");
                    energy = blueprint.BaseEnergyNeed;
                }


                // Predict next temperature, if change energy
                var predictedNewTemp =
                    building.Temperature +
                    (energy - blueprint.BaseEnergyNeed) * _degreesPerExcessMwh +
                    _degreesPerPop * building.CurrentPop -
                    (building.Temperature - outdoorTemp) * blueprint.Emissivity;

                Logger.LogTrace($"{building.BuildingName} at {building.Position}");
                Logger.LogTrace($"Current building temp: \t\t{building.Temperature:N3}");
                Logger.LogTrace($"Next building temp: \t\t\t{newTemp:N3}");
                Logger.LogTrace($"Predicted New Temp: \t\t\t{predictedNewTemp:N3}");
                Logger.LogTrace($"Current building energy: \t{building.EffectiveEnergyIn}/{building.RequestedEnergyIn} Mwh");
                Logger.LogTrace($"New requested energy: \t\t{energyOld:N3} Mwh");
                Logger.LogTrace($"New requested energy v2: \t{energyNew:N3} Mwh");

                if (newTemp < TargetTemperature)
                {
                    // Colder than target
                    if (energy < building.RequestedEnergyIn)
                    {
                        // Should not lower energy if already too cold
                        continue;
                    }
                    else
                    {
                    }
                }
                else if (newTemp > TargetTemperature)
                {
                    // Hotter than target
                    if (energy > building.RequestedEnergyIn)
                    {
                        // Should not increase energy if already too hot
                        continue;
                    }
                    else
                    {
                    }
                }

                if (IsBetween(energy,
                              building.RequestedEnergyIn - AllowedDiffMargin,
                              building.RequestedEnergyIn + AllowedDiffMargin))
                {
                    // minimal change, wait to update energy (to reduce calls and save money)
                    continue;
                }


                if (state.Funds < _adjustCost)
                {
                    Logger.LogWarning($"Wanted to apply energy '{energy:N1}' to building at {building.Position}, but has insufficient funds ({state.Funds})");
                    continue;
                }

                Logger.LogInformation($"Adjusting energy for {building.Position} from {building.RequestedEnergyIn} to {energy:N1} (TEMP:: current={building.Temperature:N3}, predicted={predictedNewTemp:N3})");
                gameLayer.AdjustEnergy(building.Position, energy, state.GameId);
                return(true);
            }

            return(false);
        }