using System.Text.Json; using System.Text.Json.Serialization; using Chessistics.Engine.Model; namespace Chessistics.Engine.Loading; public static class LevelLoader { private static readonly JsonSerializerOptions Options = new() { PropertyNameCaseInsensitive = true, Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) } }; public static LevelDef Load(string json) { var dto = JsonSerializer.Deserialize(json, Options) ?? throw new JsonException("Failed to deserialize level JSON."); Validate(dto); return new LevelDef { Id = dto.Id, Name = dto.Name, Description = dto.Description ?? "", Width = dto.Width, Height = dto.Height, Productions = dto.Productions.Select(p => new ProductionDef( new Coords(p.Col, p.Row), p.Name, ParseCargo(p.Cargo), p.Amount )).ToList(), Demands = dto.Demands.Select(d => new DemandDef( new Coords(d.Col, d.Row), d.Name, ParseCargo(d.Cargo), d.Amount, d.Deadline )).ToList(), Walls = dto.Walls?.Select(w => new Coords(w.Col, w.Row)).ToList() ?? [], Stock = dto.Stock.Select(s => new PieceStock(ParseKind(s.Kind), s.Count, s.Level)).ToList() }; } public static LevelDef LoadFromFile(string path) { var json = File.ReadAllText(path); return Load(json); } private static CargoType ParseCargo(string cargo) => cargo.ToLowerInvariant() switch { "wood" => CargoType.Wood, "stone" => CargoType.Stone, _ => throw new JsonException($"Unknown cargo type: '{cargo}'") }; private static PieceKind ParseKind(string kind) => kind.ToLowerInvariant() switch { "pawn" => PieceKind.Pawn, "rook" => PieceKind.Rook, "bishop" => PieceKind.Bishop, "knight" => PieceKind.Knight, _ => throw new JsonException($"Unknown piece kind: '{kind}'") }; private static void Validate(LevelDto dto) { if (string.IsNullOrWhiteSpace(dto.Name)) throw new JsonException("Level name is required."); if (dto.Width <= 0 || dto.Height <= 0) throw new JsonException("Level dimensions must be positive."); if (dto.Productions.Count == 0) throw new JsonException("Level must have at least one production."); if (dto.Demands.Count == 0) throw new JsonException("Level must have at least one demand."); if (dto.Stock.Count == 0) throw new JsonException("Level must have at least one piece in stock."); } // DTOs for JSON deserialization private class LevelDto { public int Id { get; set; } public string Name { get; set; } = ""; public string? Description { get; set; } public int Width { get; set; } public int Height { get; set; } public List Productions { get; set; } = []; public List Demands { get; set; } = []; public List? Walls { get; set; } public List Stock { get; set; } = []; } private class ProductionDto { public int Col { get; set; } public int Row { get; set; } public string Name { get; set; } = ""; public string Cargo { get; set; } = ""; public int Amount { get; set; } = 1; } private class DemandDto { public int Col { get; set; } public int Row { get; set; } public string Name { get; set; } = ""; public string Cargo { get; set; } = ""; public int Amount { get; set; } public int Deadline { get; set; } } private class CoordsDto { public int Col { get; set; } public int Row { get; set; } } private class StockDto { public string Kind { get; set; } = ""; public int Count { get; set; } public int Level { get; set; } = 1; } }