IEnumerator GeneratePathsRecursively(Tuple <int, int> currentZone, List <Tuple <int, int> > availableZones,
                                      int zoneAmountToReach, int zoneAmount)
 {
     if (availableZones.Count > 0)
     {
         List <Tuple <int, int> > nearestZones = new List <Tuple <int, int> >();
         for (int i = 0; i < zoneAmountToReach; i++)
         {
             Tuple <int, int> nearestZone;
             lock (zoneLocationsLock)
             {
                 nearestZone = WorldGeneratorHelper.FindNearestLocationInLocations(currentZone, availableZones);
                 if (nearestZone != null)
                 {
                     availableZones.Remove(nearestZone);
                 }
             }
             if (nearestZone == null)
             {
                 break;
             }
             nearestZones.Add(nearestZone);
         }
         if (nearestZones.Count > 0)
         {
             foreach (var nearestZone in nearestZones)
             {
                 GeneratePathBetweenLocations(currentZone, nearestZone);
                 zonesReachedByPaths++;
                 if (zonesReachedByPaths == zoneAmount)
                 {
                     EventManager.TriggerEvent(Events.worldGenerationEnd);
                 }
                 else
                 {
                     yield return(StartCoroutine(
                                      GeneratePathsRecursively(currentZone, availableZones, zoneAmountToReach, zoneAmount)));
                 }
             }
         }
     }
 }
    public void InitializeGeneration(int zoneAmount, int maxTilesPerZone) //10, 10
    {
        // Find out how many tiles there are according to how many tiles there should be per zone
        // (the zone itself and border tiles to separate it from other zones). Then, find the square root of
        // that (always thinking about generating a square matrix/map) and approximate that number to the nearest
        // upper integer. Then, construct a square matrix with that number.
        // This is to not use a zoneAmount ** 2 matrix, but optimize it a bit.
        int worldWidthAndHeight = (int)Math.Ceiling(Math.Sqrt(zoneAmount * maxTilesPerZone));

        WorldMatrix = new WorldCellType[worldWidthAndHeight, worldWidthAndHeight];
        // Initialize world.
        // Generate available positions
        List <Tuple <int, int> > availablePositions = new List <Tuple <int, int> >();

        for (int i = 0; i < worldWidthAndHeight; i++)
        {
            for (int j = 0; j < worldWidthAndHeight; j++)
            {
                WorldMatrix[i, j] = 0;
                availablePositions.Add(Tuple.Create(i, j));
            }
        }
        // Assign initial position for player (chooses randomly between four corners of the map).
        List <Tuple <int, int> > possibleInitialPositionsForPlayer = availablePositions.FindAll(t =>
                                                                                                (t.Item1 == 0 || t.Item1 == worldWidthAndHeight - 1) &&
                                                                                                (t.Item2 == 0 || t.Item2 == worldWidthAndHeight - 1));

        playerInitialPosition = possibleInitialPositionsForPlayer.PickOne();
        availablePositions.Remove(playerInitialPosition);
        WorldMatrix[playerInitialPosition.Item1, playerInitialPosition.Item2] = WorldCellType.PlayerInitialPosition;
        // Store zone locations in list.
        zoneLocations = new List <Tuple <int, int> >();
        // Keep adding zone locations until all have been created.
        while (zoneLocations.Count < zoneAmount)
        {
            Tuple <int, int> chosenPosition = availablePositions.PickOne();
            zoneLocations.Add(chosenPosition);
            // Remove adjacent positions (and itself) since not available for any other zones
            for (int i = chosenPosition.Item1 - 1; i <= chosenPosition.Item1 + 1; i++)
            {
                for (int j = chosenPosition.Item2 - 1; j <= chosenPosition.Item2 + 1; j++)
                {
                    // Attempt to find it among availablePositions, since one of them could be out of the matrix' bounds.
                    Tuple <int, int> adjacentPosition =
                        availablePositions.FirstOrDefault(t => t.Item1 == i && t.Item2 == j);
                    if (adjacentPosition != null)
                    {
                        availablePositions.Remove(adjacentPosition);
                    }
                }
            }
        }
        // Go through zone locations and update matrix.
        foreach (var zoneLocation in zoneLocations)
        {
            WorldMatrix[zoneLocation.Item1, zoneLocation.Item2] = WorldCellType.Zone;
        }
        zonesReachedByPaths = 0;
        // Generate initial path from player to its nearest location.
        Tuple <int, int> nearestLocationToPlayer =
            WorldGeneratorHelper.FindNearestLocationInLocations(playerInitialPosition, zoneLocations);

        GeneratePathBetweenLocations(playerInitialPosition, nearestLocationToPlayer);
        zonesReachedByPaths++;
        // From this nearest location onwards, auto-generate paths.
        zoneLocations.Remove(nearestLocationToPlayer);
        var currentZone       = nearestLocationToPlayer; // alias
        var zoneAmountToReach = 1;

        StartCoroutine(GeneratePathsRecursively(currentZone, zoneLocations, zoneAmountToReach, zoneAmount));
    }