using System.Collections.Generic; using UnityEngine; namespace MazeGen { /// /// The full set of generated rooms so far, plus O(1)-ish id lookup, spatial queries and /// exit-usage bookkeeping. Everything else (agent tracking, visualization, collision/merge /// logic) reads from here instead of walking the scene hierarchy. /// public class MazeGraph { public readonly Dictionary Rooms = new Dictionary(); public readonly List StartRooms = new List(); public readonly List ExitRooms = new List(); private readonly SpatialRoomIndex _spatialIndex; private int _nextRoomId; private int _nextExitId; public int RoomCount => Rooms.Count; /// /// Total exits across the whole graph that are not yet used. This must never be /// allowed to reach 0 while ExitRooms.Count == 0 - if it did, the maze would have no /// remaining way to grow and could never produce a reachable exit. /// public int UnusedExitCount { get; private set; } public MazeGraph(float spatialCellSize) { _spatialIndex = new SpatialRoomIndex(spatialCellSize); } public int AllocateRoomId() => _nextRoomId++; public int AllocateExitId() => _nextExitId++; public void Register(Room room) { Rooms[room.Id] = room; if (room.Kind == RoomKind.Start) StartRooms.Add(room); if (room.Kind == RoomKind.Exit) ExitRooms.Add(room); _spatialIndex.Add(room); } public Room Get(int id) => Rooms.TryGetValue(id, out var room) ? room : null; public IEnumerable QueryRoomsNear(Vector2 position, float radius) => _spatialIndex.QueryNearby(position, radius); /// Adds an exit to a room and keeps the unused-exit counter in sync. public void AddExit(Room room, Exit exit) { room.Exits.Add(exit); if (!exit.IsUsed) UnusedExitCount++; } /// Marks an exit as used (idempotent) and keeps the unused-exit counter in sync. public void MarkExitUsed(Exit exit) { if (exit.IsUsed) return; exit.IsUsed = true; UnusedExitCount--; } /// /// Undoes a speculative AddExit for an exit that turned out to be unusable (e.g. a /// door added on-the-fly to close a loop, where the path to it was later found to be /// blocked). Only valid for still-unused exits. /// public void RemoveUnusedExit(Room room, Exit exit) { if (exit.IsUsed) return; if (room.Exits.Remove(exit)) UnusedExitCount--; } } }