using System.Collections.Generic; using UnityEngine; namespace Hallucinate.GameSetup.Maze { /// /// Implements Wilson's algorithm for generating a Uniform Spanning Tree of the grid. /// It uses loop-erased random walks to connect unvisited cells to the existing maze. /// public class Wilsons : Maze { private List _notUsed = new List(); /// /// Generates the maze using Wilson's algorithm logic. /// public override void Generate() { // Create a starting cell int x = Random.Range(2, width - 1); int z = Random.Range(2, depth - 1); map[x, z] = Path; while (GetAvailableCells() > 1) { RandomWalk(); } } /// /// Counts how many neighbors are already part of the finalized "Path". /// private int CountSquareMazeNeighbours(int x, int z) { int count = 0; for (int d = 0; d < directions.Count; d++) { int nx = x + directions[d].x; int nz = z + directions[d].z; if (map[nx, nz] == Path) { count++; } } return count; } /// /// Scans the grid for cells that are not yet connected to the maze. /// /// The number of available (unused) cells. private int GetAvailableCells() { _notUsed.Clear(); for (int z = 1; z < depth - 1; z++) { for (int x = 1; x < width - 1; x++) { if (CountSquareMazeNeighbours(x, z) == 0) { _notUsed.Add(new MapLocation(x, z)); } } } return _notUsed.Count; } /// /// Performs a random walk from an unused cell until it hits the existing maze. /// private void RandomWalk() { List inWalk = new List(); int rStartIndex = Random.Range(0, _notUsed.Count); int cx = _notUsed[rStartIndex].x; int cz = _notUsed[rStartIndex].z; inWalk.Add(new MapLocation(cx, cz)); int loopCount = 0; bool validPath = false; while (cx > 0 && cx < width - 1 && cz > 0 && cz < depth - 1 && loopCount < 5000 && !validPath) { map[cx, cz] = Corridor; if (CountSquareMazeNeighbours(cx, cz) > 1) { break; } int rd = Random.Range(0, directions.Count); int nx = cx + directions[rd].x; int nz = cz + directions[rd].z; if (CountSquareNeighbours(nx, nz) < 2) { cx = nx; cz = nz; inWalk.Add(new MapLocation(cx, cz)); } validPath = CountSquareMazeNeighbours(cx, cz) == 1; loopCount++; } if (validPath) { map[cx, cz] = Corridor; Debug.Log("Path Found"); foreach (MapLocation m in inWalk) { map[m.x, m.z] = Path; } inWalk.Clear(); } else { foreach (MapLocation m in inWalk) { map[m.x, m.z] = Wall; } inWalk.Clear(); } } } }