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