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