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--;
}
}
}