Example #1
0
    public void CreateHolesAndBalls(int numHoles = 4, MinMax ballDistance = null)
    {
        // divide entire grid up into 9 zones in a 3x3 formation,
        // remove the zones with the start and end point
        // select `numSwitches` zones to put switches in

        int leftZoneBoundaryX   = width / 3;
        int rightZoneBoundaryX  = 2 * width / 3;
        int topZoneBoundaryY    = 2 * height / 3;
        int bottomZoneBoundaryY = height / 3;

        int getZone(Vector3Int v)
        {
            int z = 0;

            if (v.x > rightZoneBoundaryX)
            {
                z += 2;
            }
            else if (v.x > leftZoneBoundaryX)
            {
                z += 1;
            }
            if (v.y > topZoneBoundaryY)
            {
                z += 6;                 // 3 * 2
            }
            else if (v.y > bottomZoneBoundaryY)
            {
                z += 3;
            }
            return(z);
        };

        int        startZone      = getZone(StartingPoint.Coordinates.GetRepresentationalCoordinates());
        int        endZone        = getZone(EndingPoint.Coordinates.GetRepresentationalCoordinates());
        List <int> availableZones = Enumerable.Range(0, 9).Where(e => e != startZone && e != endZone).ToList();

        List <int> switchZones = new List <int>();

        for (int i = 0; i < numHoles; i++)
        {
            int num = UnityEngine.Random.Range(0, availableZones.Count);
            switchZones.Add(availableZones[num]);
            availableZones.RemoveAt(num);
        }

        int border = System.Math.Min(height, width) / 10;

        HexCoordinates getRandomHexInZone(int zone)
        {
            int xZone = zone % 3;
            int yZone = zone / 3;

            int xGridPos, yGridPos;

            switch (xZone)
            {
            default:
            case 0:
                xGridPos = UnityEngine.Random.Range(0, leftZoneBoundaryX - border);
                break;

            case 1:
                xGridPos = UnityEngine.Random.Range(leftZoneBoundaryX + border, rightZoneBoundaryX - border);
                break;

            case 2:
                xGridPos = UnityEngine.Random.Range(rightZoneBoundaryX + border, width);
                break;
            }
            switch (yZone)
            {
            default:
            case 0:
                yGridPos = UnityEngine.Random.Range(0, bottomZoneBoundaryY - border);
                break;

            case 1:
                yGridPos = UnityEngine.Random.Range(bottomZoneBoundaryY + border, topZoneBoundaryY - border);
                break;

            case 2:
                yGridPos = UnityEngine.Random.Range(topZoneBoundaryY + border, height);
                break;
            }

            return(HexCoordinates.FromRepresentationalCoordinates(xGridPos, yGridPos));
        }

        List <HexCoordinates> holeHexes = new List <HexCoordinates>();

        for (int i = 0; i < switchZones.Count; i++)
        {
            bool foundPosition = false;
            int  attempts      = 0;
            int  zone          = switchZones[i];
            while (!foundPosition)
            {
                attempts = 0;
                do
                {
                    HexCoordinates h = getRandomHexInZone(zone);
                    if (cellInfo[h].Reachable && cellInfo[h].NumTouchedWalls > 0)
                    {
                        Hole s = Hole.CreateInstance();
                        s.Place(this, h);
                        holeHexes.Add(h);
                        foundPosition = true;
                        Debug.Log($"Found in zone {zone} in {attempts} attempts");
                    }
                    attempts++;
                } while (!foundPosition && attempts < 10);

                // this zone can't find a place, search another zone for position
                if (!foundPosition)
                {
                    Debug.Log($"Failed to find in zone {zone}");
                    int num = UnityEngine.Random.Range(0, availableZones.Count);
                    zone = availableZones[num];
                    availableZones.RemoveAt(num);
                }
            }
        }

        if (ballDistance == null)
        {
            ballDistance = new MinMax(3, 6);
        }

        foreach (HexCoordinates h in holeHexes)
        {
            int targetDistance = UnityEngine.Random.Range(ballDistance.Min, ballDistance.Max);
            var positions      = GetAllPositionsInDistanceRange(h, ballDistance);
            var position       = positions.Where(p => cellInfo[p.Item2].NumTouchedWalls <= 3).OrderBy(p => Mathf.Abs(p.Item1 - targetDistance)).First();

            Ball b = Ball.CreateInstance();
            b.Place(this, position.Item2);
        }
    }