Пример #1
0
        public OceanData GetOceanData(
            IEnumerable <MapSection> oceanSections, IOceanTemplate oceanTemplate,
            IMapTemplate mapTemplate, GridPartition partition
            )
        {
            var shallowOceanSections = oceanSections.Where(
                section => partition.GetNeighbors(section).Any(neighbor => !oceanSections.Contains(neighbor))
                ).ToList();

            var midOceanSections = oceanSections.Except(shallowOceanSections).Where(
                section => partition.GetNeighbors(section).Any(neighbor => shallowOceanSections.Contains(neighbor))
                ).ToList();

            var deepOceanSections = oceanSections.Except(shallowOceanSections).Except(midOceanSections);

            List <MapRegion>  emptyOceanRegions;
            List <MapRegion>  archipelagoRegions;
            List <RegionData> archipelagoRegionData;

            CarveArchipelagoesFromOcean(
                shallowOceanSections, midOceanSections, deepOceanSections, oceanTemplate, partition,
                mapTemplate, out emptyOceanRegions, out archipelagoRegions, out archipelagoRegionData
                );

            return(new OceanData(emptyOceanRegions, archipelagoRegions, archipelagoRegionData));
        }
Пример #2
0
        private void GetArchipelagoesFromLandAndWater(
            List <MapSection> landSections, List <MapSection> deepWaterSections, List <MapSection> midOceanSections,
            IOceanTemplate template, GridPartition partition, out List <MapRegion> archipelagoRegions,
            out List <MapSection> emptyDeepOcean
            )
        {
            archipelagoRegions = new List <MapRegion>();

            while (landSections.Any())
            {
                var contiguousLand = GetContiguousLand(landSections.Last(), landSections, partition);

                foreach (var land in contiguousLand)
                {
                    landSections.Remove(land);
                }

                var coastSections = contiguousLand.SelectMany(section => partition.GetNeighbors(section))
                                    .Where(neighbor => deepWaterSections.Contains(neighbor) || midOceanSections.Contains(neighbor))
                                    .Distinct().ToList();

                foreach (var coast in coastSections)
                {
                    deepWaterSections.Remove(coast);
                    midOceanSections.Remove(coast);
                }

                archipelagoRegions.Add(new MapRegion(
                                           contiguousLand.SelectMany(section => section.Cells).ToList(),
                                           coastSections.SelectMany(section => section.Cells).ToList()
                                           ));
            }

            emptyDeepOcean = deepWaterSections;
        }
Пример #3
0
        private IEnumerable <MapSection> GetContiguousLand(
            MapSection seed, List <MapSection> landSections, GridPartition partition
            )
        {
            var uncheckedSections = new List <MapSection>()
            {
                seed
            };

            var contiguousSection = new List <MapSection>();

            while (uncheckedSections.Any())
            {
                var uncheckedSection = uncheckedSections.Last();
                uncheckedSections.Remove(uncheckedSection);

                contiguousSection.Add(uncheckedSection);

                foreach (var neighbor in partition.GetNeighbors(uncheckedSection).Intersect(landSections).Except(contiguousSection))
                {
                    uncheckedSections.Add(neighbor);
                }
            }

            return(contiguousSection);
        }
        private void DrawForbiddenLine(
            HashSet <MapSection> unassignedSections, HashSet <MapSection> forbiddenSections,
            GridPartition partition, IMapTemplate mapTemplate
            )
        {
            int lineXCoord = Mathf.RoundToInt(Grid.CellCountX * UnityEngine.Random.Range(
                                                  mapTemplate.ContinentSeparationLineXMin, mapTemplate.ContinentSeparationLineXMax
                                                  ));

            IHexCell startCell = Grid.GetCellAtCoordinates(HexCoordinates.FromOffsetCoordinates(lineXCoord, 0));
            IHexCell endCell   = Grid.GetCellAtCoordinates(HexCoordinates.FromOffsetCoordinates(lineXCoord, Grid.CellCountZ - 1));

            var cellLine = Grid.GetCellsInLine(startCell, endCell);

            var sectionsOnLine = cellLine.Select(cell => partition.GetSectionOfCell(cell)).Distinct();

            var sectionsToForbid = sectionsOnLine.SelectMany(section => partition.GetNeighbors(section))
                                   .Concat(sectionsOnLine).Distinct();

            foreach (var section in sectionsToForbid)
            {
                unassignedSections.Remove(section);
                forbiddenSections.Add(section);
            }
        }
Пример #5
0
        private ExpansionWeightFunction GetExpansionWeightFunction(
            GridPartition partition, IMapTemplate template
            )
        {
            var middleCell = Grid.GetCellAtOffset(Grid.CellCountX / 2, Grid.CellCountZ / 2);

            return(delegate(MapSection section, List <MapSection> chunk) {
                if (IsWithinHardBorder(section.CentroidCell, template))
                {
                    return 0;
                }

                int borderAvoidanceWeight = GetBorderAvoidanceWeight(section.CentroidCell, template);

                int neighborsInContinent = partition.GetNeighbors(section).Intersect(chunk).Count();
                int neighborsInContinentWeight = neighborsInContinent * template.NeighborsInContinentWeight;

                int distanceFromSeedCentroid = Grid.GetDistance(chunk[0].CentroidCell, section.CentroidCell);
                int distanceFromSeedCentroidWeight = distanceFromSeedCentroid * template.DistanceFromSeedCentroidWeight;

                int distanceFromMapCenter = Grid.GetDistance(section.CentroidCell, middleCell) * template.DistanceFromMapCenterWeight;

                int weight = 1 + Math.Max(
                    0, neighborsInContinentWeight + distanceFromSeedCentroidWeight + borderAvoidanceWeight + distanceFromMapCenter
                    );

                return weight;
            });
        }
Пример #6
0
        private List <MapSection> GetCoastForLandSection(
            List <MapSection> landSections, HashSet <MapSection> unassignedSections, GridPartition partition
            )
        {
            var unassignedAdjacentToLand = landSections.SelectMany(section => partition.GetNeighbors(section))
                                           .Intersect(unassignedSections)
                                           .Distinct()
                                           .ToList();

            foreach (var adjacentSection in unassignedAdjacentToLand)
            {
                unassignedSections.Remove(adjacentSection);
            }

            return(unassignedAdjacentToLand);
        }
Пример #7
0
        private void CarveArchipelagoesFromOcean(
            IEnumerable <MapSection> shallowOceanSections, List <MapSection> midOceanSections,
            IEnumerable <MapSection> deepOceanSections, IOceanTemplate oceanTemplate, GridPartition partition,
            IMapTemplate mapTemplate, out List <MapRegion> emptyOceanRegions,
            out List <MapRegion> archipelagoRegions, out List <RegionData> archipelagoRegionData
            )
        {
            int landSectionCount = Mathf.RoundToInt(oceanTemplate.DeepOceanLandPercentage * 0.01f * deepOceanSections.Count());

            var deepOceanLand = MapSectionRandomSampler.SampleElementsFromSet(
                deepOceanSections, landSectionCount, GetArchipelagoWeightFunction(mapTemplate)
                ).ToList();

            var deepOceanWater = deepOceanSections.Except(deepOceanLand).ToList();

            List <MapSection> emptyDeepOcean;

            GetArchipelagoesFromLandAndWater(
                deepOceanLand, deepOceanWater, midOceanSections, oceanTemplate,
                partition, out archipelagoRegions, out emptyDeepOcean
                );

            var emptyOceanCells = shallowOceanSections.Concat(midOceanSections).Concat(emptyDeepOcean);

            var emptyOcean = new MapRegion(
                new List <IHexCell>(),
                emptyOceanCells.SelectMany(section => section.Cells).ToList()
                );

            emptyOceanRegions = new List <MapRegion>()
            {
                emptyOcean
            };

            archipelagoRegionData = archipelagoRegions.Select(region => new RegionData(
                                                                  TemplateSelectionLogic.GetBiomeForLandRegion(region, mapTemplate),
                                                                  TemplateSelectionLogic.GetTopologyForLandRegion(region, mapTemplate),
                                                                  AvailableBalanceStrategies
                                                                  )).ToList();
        }
        public List <List <MapSection> > DivideSectionsIntoChunks(
            HashSet <MapSection> unassignedSections, GridPartition partition,
            int chunkCount, int maxCellsPerChunk, int minSeedSeparation,
            ExpansionWeightFunction weightFunction, IMapTemplate mapTemplate
            )
        {
            if (chunkCount > unassignedSections.Count())
            {
                throw new ArgumentOutOfRangeException("Not enough sections to assign at least one per chunk");
            }

            var finishedChunks   = new List <List <MapSection> >();
            var unfinishedChunks = new List <List <MapSection> >();

            var startingSections  = new List <MapSection>();
            var forbiddenSections = new HashSet <MapSection>();

            if (mapTemplate.SeparateContinents)
            {
                DrawForbiddenLine(unassignedSections, forbiddenSections, partition, mapTemplate);
            }

            for (int i = 0; i < chunkCount; i++)
            {
                var startingSection = GetStartingSection(
                    unassignedSections, startingSections, minSeedSeparation, mapTemplate
                    );

                unfinishedChunks.Add(new List <MapSection>()
                {
                    startingSection
                });

                startingSections.Add(startingSection);

                unassignedSections.Remove(startingSection);
            }

            int desiredContiguousCells = Mathf.RoundToInt(maxCellsPerChunk * mapTemplate.HomelandContiguousPercentage * 0.01f);

            while (unfinishedChunks.Count > 0 && unassignedSections.Count > 0)
            {
                var chunk = unfinishedChunks.Random();

                int cellCount = chunk.Sum(section => section.Cells.Count);

                bool mustBeContiguous = desiredContiguousCells > cellCount;

                if (TryExpandChunk(chunk, unassignedSections, partition, mapTemplate, weightFunction, mustBeContiguous))
                {
                    int cellsInChunk = chunk.Sum(section => section.Cells.Count);

                    if (cellsInChunk >= maxCellsPerChunk)
                    {
                        finishedChunks.Add(chunk);
                        unfinishedChunks.Remove(chunk);
                    }
                }
                else
                {
                    Debug.LogWarning("Failed to assign a new section to a chunk");
                    finishedChunks.Add(chunk);
                    unfinishedChunks.Remove(chunk);
                }
            }

            finishedChunks.AddRange(unfinishedChunks);

            foreach (var section in forbiddenSections)
            {
                unassignedSections.Add(section);
            }

            return(finishedChunks);
        }
        private bool TryExpandChunk(
            List <MapSection> chunk, HashSet <MapSection> unassignedSections,
            GridPartition partition, IMapTemplate mapTemplate,
            ExpansionWeightFunction weightFunction, bool mustBeContiguous
            )
        {
            expansionCandidates.Clear();

            foreach (MapSection section in chunk)
            {
                nearbySections.Clear();

                sectionsWithinDistance.Clear();

                if (mustBeContiguous)
                {
                    foreach (var adjacentSection in partition.GetNeighbors(section))
                    {
                        if (unassignedSections.Contains(adjacentSection))
                        {
                            nearbySections.Add(adjacentSection);
                        }
                    }
                }
                else
                {
                    foreach (IHexCell nearbyCell in Grid.GetCellsInRadius(section.CentroidCell, mapTemplate.HomelandExpansionMaxCentroidSeparation))
                    {
                        MapSection sectionOfCell = partition.GetSectionOfCell(nearbyCell);

                        if (unassignedSections.Contains(sectionOfCell))
                        {
                            sectionsWithinDistance.Add(sectionOfCell);
                        }
                    }

                    var sectionsSurroundedByUnassigned = sectionsWithinDistance.Where(
                        nearby => partition.GetNeighbors(nearby).Count(neighbor => !unassignedSections.Contains(neighbor)) <= 0
                        );

                    if (sectionsSurroundedByUnassigned.Any())
                    {
                        foreach (var surroundedSection in sectionsSurroundedByUnassigned)
                        {
                            nearbySections.Add(surroundedSection);
                        }
                    }
                    else
                    {
                        foreach (var sectionWithin in sectionsWithinDistance)
                        {
                            nearbySections.Add(sectionWithin);
                        }
                    }
                }

                foreach (var nearby in nearbySections)
                {
                    expansionCandidates.Add(nearby);
                }
            }

            if (expansionCandidates.Count > 0)
            {
                var newSection = MapSectionRandomSampler.SampleElementsFromSet(
                    expansionCandidates, 1, section => weightFunction(section, chunk)
                    ).FirstOrDefault();

                if (newSection != null)
                {
                    unassignedSections.Remove(newSection);
                    chunk.Add(newSection);
                    return(true);
                }
            }

            return(false);
        }
Пример #10
0
        public HomelandData GetHomelandData(
            ICivilization civ, List <MapSection> landSections, List <MapSection> waterSections,
            GridPartition partition, IHomelandTemplate homelandTemplate, IMapTemplate mapTemplate
            )
        {
            var landChunks  = new List <List <MapSection> >();
            var waterChunks = new List <List <MapSection> >();

            IHexCell seedCentroid = landSections[0].CentroidCell;

            var startingLandSections =
                Grid.GetCellsInRadius(seedCentroid, homelandTemplate.StartingRegionRadius)
                .Select(cell => partition.GetSectionOfCell(cell))
                .Distinct()
                .Intersect(landSections);

            var startingWaterSections =
                Grid.GetCellsInRadius(seedCentroid, homelandTemplate.StartingRegionRadius)
                .Select(cell => partition.GetSectionOfCell(cell))
                .Distinct()
                .Intersect(waterSections);

            var startingRegion = new MapRegion(
                startingLandSections.SelectMany(section => section.Cells).ToList(),
                startingWaterSections.SelectMany(section => section.Cells).ToList()
                );

            foreach (var cell in startingRegion.Cells)
            {
                cell.SetMapData(1f);
            }

            var unassignedLand  = landSections.Except(startingLandSections);
            var unassignedWater = waterSections.Except(startingWaterSections);

            DivideSectionsIntoRectangularChunks(
                unassignedLand, unassignedWater, homelandTemplate.RegionCount,
                out landChunks, out waterChunks
                );

            var regions = new List <MapRegion>();

            regions.Add(startingRegion);

            for (int i = 0; i < landChunks.Count; i++)
            {
                var region = new MapRegion(
                    landChunks [i].SelectMany(section => section.Cells).ToList(),
                    waterChunks[i].SelectMany(section => section.Cells).ToList()
                    );

                regions.Add(region);
            }

            var startingData = new RegionData(
                TemplateSelectionLogic.GetBiomeForLandRegion(startingRegion, mapTemplate),
                TemplateSelectionLogic.GetTopologyForLandRegion(startingRegion, mapTemplate),
                AvailableBalanceStrategies
                );

            var otherRegions = regions.Where(region => region != startingRegion).ToList();

            var otherData = otherRegions.Select(region => new RegionData(
                                                    TemplateSelectionLogic.GetBiomeForLandRegion(region, mapTemplate),
                                                    TemplateSelectionLogic.GetTopologyForLandRegion(region, mapTemplate),
                                                    AvailableBalanceStrategies
                                                    )).ToList();

            return(new HomelandData(
                       startingRegion, startingData, otherRegions, otherData,
                       homelandTemplate.LuxuryResourceData, homelandTemplate.YieldAndResources
                       ));
        }