Chessistics/chessistics-engine/Loading/LevelLoader.cs

123 lines
4 KiB
C#
Raw Permalink Normal View History

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<LevelDto>(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,
"queen" => PieceKind.Queen,
_ => 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<ProductionDto> Productions { get; set; } = [];
public List<DemandDto> Demands { get; set; } = [];
public List<CoordsDto>? Walls { get; set; }
public List<StockDto> 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;
}
}