namespace HSchool.Content; /// One school's map instance: tree grouping plus a walkable graph of territory and rooms. public sealed class MapLayout { public TerritoryNode? Territory { get; init; } public IReadOnlyList Buildings { get; init; } = []; public IReadOnlyList Floors { get; init; } = []; public IReadOnlyList Rooms { get; init; } = []; public IReadOnlyList Links { get; init; } = []; public static MapLayout Parse(string jsonc, string? source = null) => Jsonc.Deserialize(Jsonc.Parse(jsonc, source)); /// RoomDef or TerritoryDef of this node, or null when the id is not on the map. public string? NodeDef(string nodeId) { if (Territory is { } territory && territory.Id.Equals(nodeId, StringComparison.Ordinal)) { return territory.Def; } foreach (var room in Rooms) { if (room.Id.Equals(nodeId, StringComparison.Ordinal)) { return room.Def; } } return null; } } public sealed class TerritoryNode { public required string Id { get; init; } public required string Def { get; init; } } public sealed class BuildingNode { public required string Id { get; init; } public required string Def { get; init; } } public sealed class FloorNode { public required string Id { get; init; } public required string Def { get; init; } public required string Building { get; init; } public string? Label { get; init; } } public sealed class RoomNode { public required string Id { get; init; } public required string Def { get; init; } public required string Building { get; init; } public required string Floor { get; init; } /// Optional designation such as a classroom number. The def label still supplies the noun. public string? Label { get; init; } /// /// Homeroom seat count. Capacity is SeatThing.PupilSlots × Seats. Named /// stay on rooms whose furnishing actually varies. /// public int Seats { get; init; } public IReadOnlyList Slots { get; init; } = []; } public sealed class SlotFill { public required string Key { get; init; } public required string Thing { get; init; } /// /// How many of occupy this slot. Missing or non-positive JSON is 1, so /// older maps without a count still round-trip. /// public int Count { get; init; } = 1; } public sealed class MapLink { public required string A { get; init; } public required string B { get; init; } }