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)); }
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; }
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); } }
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; }); }
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); }
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); }
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 )); }