internal void GenerateRiver(ZoneInfoGrid repo, bool isHorizontal)
        {
            Func <ZonePoint, int> coordinateOne = isHorizontal
                ? new Func <ZonePoint, int>(x => x.X) :
                                                  new Func <ZonePoint, int>(x => x.Y);

            Func <ZonePoint, int> coordinateTwo = isHorizontal
                ? new Func <ZonePoint, int>(x => x.Y) :
                                                  new Func <ZonePoint, int>(x => x.X);

            var xRange = repo.ZoneInfos
                         .Keys
                         .GroupBy(coordinateOne)
                         .OrderBy(x => x.Key);

            int currentRiverCenter = _random.Next(repo.ZoneInfos.Keys.Min(coordinateTwo), repo.ZoneInfos.Keys.Max(coordinateTwo));
            int currentRiverWidth  = 6;

            foreach (var xRangeEntry in xRange)
            {
                if (xRangeEntry.Key % 2 == 0)
                {
                    currentRiverCenter = _random.Next(0, 50) % 2 == 0 ? currentRiverCenter + 1 : currentRiverCenter - 1;
                }
                else
                {
                    currentRiverWidth = _random.Next(0, 50) % 2 == 0
                        ? currentRiverWidth + 1
                        : currentRiverWidth - 1;

                    if (currentRiverWidth < 4)
                    {
                        currentRiverWidth++;
                    }
                    else if (currentRiverWidth > 10)
                    {
                        currentRiverWidth--;
                    }
                }

                var entry = xRangeEntry
                            .SingleOrDefault(x => coordinateTwo(x) == currentRiverCenter);

                if (entry == default(ZonePoint))
                {
                    continue;
                }

                foreach (var zoneInfo in repo.ZoneInfos[entry].GetSurroundingZoneInfosDiamond(currentRiverWidth).Where(x => x.HasMatch))
                {
                    var action = zoneInfo.MatchingObject.ConsumptionState
                                 .TryConsumeWith(_waterZoneFactory());

                    if (action.CanOverrideWithResult.WillSucceed)
                    {
                        action.Apply();
                    }
                }
            }
        }
        internal void GenerateCoastLine(
            ZoneInfoGrid repo,
            Func <ZonePoint, int> zonePointCoordinateSelector,
            Func <IEnumerable <int>, int> pointValueSelector)
        {
            var max = pointValueSelector(repo
                                         .ZoneInfos
                                         .Select(x => zonePointCoordinateSelector(x.Key)));

            Func <ZonePoint, bool> isPartOfSelectedCoastLine = x => zonePointCoordinateSelector(x) == max;

            foreach (var zoneInfo in repo
                     .ZoneInfos
                     .Where(x => isPartOfSelectedCoastLine(x.Key))
                     .SelectMany(x => x.Value.GetSurroundingZoneInfosDiamond(_random.Next(15, 30)).Where(y => y.HasMatch)))
            {
                var action = zoneInfo.MatchingObject.ConsumptionState
                             .TryConsumeWith(_waterZoneFactory());

                if (action.CanOverrideWithResult.WillSucceed)
                {
                    action.Apply();
                }
            }
        }
        internal void ApplyWith(ZoneInfoGrid repo, TerraformingOptions options)
        {
            ScatterZoneConsumptionClouds(
                repo: repo,
                options: options,
                random: _random,
                valueSelector: o => o.Woodlands,
                createZoneConsumption: _woodlandZoneFactory
                );
            ScatterZoneConsumptionClouds(
                repo: repo,
                options: options,
                random: _random,
                valueSelector: o => o.Lakes,
                createZoneConsumption: _waterZoneFactory
                );

            if (options.HorizontalRiver)
            {
                GenerateRiver(repo: repo, isHorizontal: true);
            }
            if (options.VerticalRiver)
            {
                GenerateRiver(repo: repo, isHorizontal: false);
            }
            if (options.EastCoast)
            {
                GenerateCoastLine(
                    repo: repo,
                    zonePointCoordinateSelector: x => x.X,
                    pointValueSelector: x => x.Max()
                    );
            }
            if (options.WestCoast)
            {
                GenerateCoastLine(
                    repo: repo,
                    zonePointCoordinateSelector: x => x.X,
                    pointValueSelector: x => x.Min()
                    );
            }
            if (options.SouthCoast)
            {
                GenerateCoastLine(
                    repo: repo,
                    zonePointCoordinateSelector: x => x.Y,
                    pointValueSelector: x => x.Max()
                    );
            }
            if (options.NorthCoast)
            {
                GenerateCoastLine(
                    repo: repo,
                    zonePointCoordinateSelector: x => x.Y,
                    pointValueSelector: x => x.Min()
                    );
            }
        }
        internal static void ScatterZoneConsumptionClouds(
            ZoneInfoGrid repo,
            TerraformingOptions options,
            Random random,
            Func <TerraformingOptions, int> valueSelector,
            Func <IAreaZoneConsumption> createZoneConsumption)
        {
            foreach (var iteration in Enumerable.Range(0, valueSelector(options)))
            {
                var woodlandTargetPoint = repo.ZoneInfos[new ZonePoint
                                                         {
                                                             X = random.Next(10, (repo.ZoneWidthAndHeight - 10)),
                                                             Y = random.Next(10, (repo.ZoneWidthAndHeight - 10))
                                                         }];

                foreach (var subiteration in Enumerable.Range(0, 4))
                {
                    var center = woodlandTargetPoint
                                 .GetRelativeZoneInfo(new RelativeZoneInfoQuery(
                                                          relativeX: random.Next(-3, 3),
                                                          relativeY: random.Next(-3, 3)

                                                          )
                                                      );

                    if (center.HasNoMatch)
                    {
                        continue;
                    }

                    var targets = center.MatchingObject.GetSurroundingZoneInfosDiamond(3);

                    foreach (var target in targets
                             .Where(x => x.HasMatch))
                    {
                        var action = target.MatchingObject.ConsumptionState
                                     .TryConsumeWith(createZoneConsumption());

                        if (action.CanOverrideWithResult.WillSucceed)
                        {
                            action.Apply();
                        }
                    }
                }
            }
        }
Exemple #5
0
        public Area(AreaOptions options)
        {
            _areaOptions          = options;
            _createZoneInfoFinder = () => new ZoneInfoFinder(
                queryObject => _zoneInfoGrid
                .GetZoneInfoFor(queryObject));
            _zoneInfoGrid = new ZoneInfoGrid(options.GetZoneWidthAndHeight(), options.GetLandValueCalculator());

            options.WithTerraformingOptions(terraFormingOptions =>
            {
                var randomTerraformer = new RandomTerraformer(CreateWaterZone, CreateWoodlandZone);
                randomTerraformer.ApplyWith(_zoneInfoGrid, terraFormingOptions);
            });

            options.WithPersistedArea(persistedArea =>
            {
                var factoriesAndNames =
                    GetSupportedZoneConsumptionFactoriesPrivate()
                    .ToDictionary(x => x().Name, x => x);

                if (persistedArea
                    .PersistedSingleZoneConsumptions
                    .Select(
                        x =>
                        ConsumeZoneAt(_zoneInfoGrid.ZoneInfos[new ZonePoint {
                                                                  X = x.X, Y = x.Y
                                                              }],
                                      factoriesAndNames[x.Name]()))
                    .Concat(persistedArea
                            .PersistedStaticZoneClusterCentralMemberConsumptions
                            .Select(
                                x =>
                                ConsumeZoneAt(_zoneInfoGrid.ZoneInfos[new ZonePoint {
                                                                          X = x.X, Y = x.Y
                                                                      }],
                                              factoriesAndNames[x.Name]())
                                )
                            )
                    .Any(result => !result.Success)
                    )
                {
                    throw new InvalidOperationException();
                }

                if (persistedArea
                    .PersistedIntersectingZoneConsumptions
                    .Select(
                        x =>
                        ConsumeZoneAt(_zoneInfoGrid.ZoneInfos[new ZonePoint {
                                                                  X = x.X, Y = x.Y
                                                              }],
                                      new IntersectingZoneConsumption(_createZoneInfoFinder(),
                                                                      factoriesAndNames[x.EastWestName]() as BaseInfrastructureNetworkZoneConsumption,
                                                                      factoriesAndNames[x.NorthSouthName]() as BaseInfrastructureNetworkZoneConsumption)
                                      ))
                    .Any(result => !result.Success))
                {
                    throw new InvalidOperationException();
                }

                if (persistedArea
                    .PersistedGrowthZoneClusterCentralMemberConsumptions
                    .Select(x =>
                {
                    var consumption = factoriesAndNames[x.Name]() as IBaseGrowthZoneClusterConsumptionInLoadContext;

                    consumption.Set(x.Id, x.Population);

                    return(ConsumeZoneAt(_zoneInfoGrid.ZoneInfos[new ZonePoint {
                                                                     X = x.X, Y = x.Y
                                                                 }], consumption
                                         ));
                })
                    .Any(result => !result.Success))
                {
                    throw new InvalidOperationException();
                }

                if (persistedArea.PersistedTrafficStates != null)
                {
                    foreach (var trafficState in persistedArea.PersistedTrafficStates)
                    {
                        var localTrafficState = trafficState;
                        _zoneInfoGrid.ZoneInfos[new ZonePoint {
                                                    X = trafficState.X, Y = trafficState.Y
                                                }]
                        .WithNetworkConsumptionIf(
                            (RoadZoneConsumption x) => { x.SetTrafficDensity(trafficState.Traffic); });
                    }
                }
            });

            var zoneInfos = new HashSet <IZoneInfo>(_zoneInfoGrid.ZoneInfos.Values);

            TrainController    = new TrainController(() => zoneInfos);
            AirplaneController = new AirplaneController(() => zoneInfos);
            ShipController     = new ShipController(this, () => zoneInfos);
        }