using System.Collections; using System.Collections.Generic; using UnityEngine; namespace Hallucinate.GameSetup.Maze { public class WilsonsAlgorithm : IMazeAlgorithm { private const int MinBoundary = 2; private const int MaxIterationSafety = 5000; private const int TargetPathNeighbours = 1; private readonly List _directions = new List() { new MapLocation(1, 0), new MapLocation(0, 1), new MapLocation(-1, 0), new MapLocation(0, -1) }; public void Generate(MazeGrid grid) { int x = Random.Range(MinBoundary, grid.Width - MinBoundary); int z = Random.Range(MinBoundary, grid.Depth - MinBoundary); grid.SetCell(x, z, MazeCellType.Corridor); while (GetAvailableCells(grid).Count > 1) { PerformRandomWalk(grid, null, 0); } } public IEnumerator GenerateStepByStep(MazeGrid grid, float interval) { int x = Random.Range(MinBoundary, grid.Width - MinBoundary); int z = Random.Range(MinBoundary, grid.Depth - MinBoundary); grid.SetCell(x, z, MazeCellType.Corridor); yield return new WaitForSeconds(interval); while (true) { var available = GetAvailableCells(grid); if (available.Count <= 1) break; yield return PerformRandomWalk(grid, available, interval); } } private List GetAvailableCells(MazeGrid grid) { List available = new List(); for (int z = 1; z < grid.Depth - 1; z++) { for (int x = 1; x < grid.Width - 1; x++) { if (CountPathNeighbours(grid, x, z) == 0) available.Add(new MapLocation(x, z)); } } return available; } private int CountPathNeighbours(MazeGrid grid, int x, int z) { int count = 0; foreach (var d in _directions) { if (grid.GetCell(x + d.x, z + d.z) == MazeCellType.Corridor) count++; } return count; } private IEnumerator PerformRandomWalk(MazeGrid grid, List available, float interval) { List inWalk = new List(); int rStart = Random.Range(0, available.Count); int cx = available[rStart].x; int cz = available[rStart].z; inWalk.Add(new MapLocation(cx, cz)); bool pathFound = false; int safety = 0; while (grid.IsInBounds(cx, cz) && !pathFound && safety < MaxIterationSafety) { grid.SetCell(cx, cz, MazeCellType.Processing); if (interval > 0) yield return new WaitForSeconds(interval); if (CountPathNeighbours(grid, cx, cz) > 1) break; int rd = Random.Range(0, _directions.Count); int nx = cx + _directions[rd].x; int nz = cz + _directions[rd].z; if (grid.CountSquareNeighbours(nx, nz, MazeCellType.Processing) < 2) { cx = nx; cz = nz; inWalk.Add(new MapLocation(cx, cz)); } pathFound = CountPathNeighbours(grid, cx, cz) == TargetPathNeighbours; safety++; } if (pathFound) { foreach (var m in inWalk) { grid.SetCell(m.x, m.z, MazeCellType.Corridor); if (interval > 0) yield return new WaitForSeconds(interval * 0.5f); } } else { foreach (var m in inWalk) grid.SetCell(m.x, m.z, MazeCellType.Wall); } } } }