using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; namespace Vanguard.Content; public sealed record TrialDeckCard(string PrintingId, int Count); public sealed record TrialDeckDefinition( string Id, string Name, string? Clan, IReadOnlyList Cards) { public int TotalCards => Cards.Sum(card => card.Count); /// Разворачивает counts в список printingId длиной 50. public IReadOnlyList ToDeck() => Cards.SelectMany(card => Enumerable.Repeat(card.PrintingId, card.Count)).ToList(); } /// Две триал-деки из content/trial-decks.yaml. public sealed class TrialDeckCatalog { private readonly Dictionary _decks; private TrialDeckCatalog(IEnumerable decks) { _decks = decks.ToDictionary(deck => deck.Id, StringComparer.OrdinalIgnoreCase); } public IReadOnlyList Decks => _decks.Values.ToList(); public bool TryGet(string id, out TrialDeckDefinition deck) => _decks.TryGetValue(id, out deck!); public static TrialDeckCatalog Load(string path) { if (!File.Exists(path)) throw new FileNotFoundException($"Файл триал-дек не найден: {path}"); var deserializer = new DeserializerBuilder() .WithNamingConvention(CamelCaseNamingConvention.Instance) .IgnoreUnmatchedProperties() .Build(); var file = deserializer.Deserialize(File.ReadAllText(path)) ?? throw new InvalidOperationException($"Пустой файл триал-дек: {path}"); if (file.Decks.Count == 0) throw new InvalidOperationException("В trial-decks.yaml нет дек."); var decks = new List(); var ids = new HashSet(StringComparer.OrdinalIgnoreCase); foreach (var entry in file.Decks) { if (string.IsNullOrWhiteSpace(entry.Id) || string.IsNullOrWhiteSpace(entry.Name)) throw new InvalidOperationException("У триал-деки должны быть id и name."); if (!ids.Add(entry.Id)) throw new InvalidOperationException($"Дубликат id триал-деки: {entry.Id}"); var cards = entry.Cards .Where(card => !string.IsNullOrWhiteSpace(card.PrintingId) && card.Count > 0) .Select(card => new TrialDeckCard(card.PrintingId, card.Count)) .ToList(); var total = cards.Sum(card => card.Count); if (total != 50) throw new InvalidOperationException( $"Триал-дека {entry.Id}: {total} карт, требуется 50."); decks.Add(new TrialDeckDefinition(entry.Id, entry.Name, entry.Clan, cards)); } return new TrialDeckCatalog(decks); } private sealed class TrialDeckFile { public List Decks { get; set; } = new(); } private sealed class TrialDeckEntry { public string Id { get; set; } = string.Empty; public string Name { get; set; } = string.Empty; public string? Clan { get; set; } public List Cards { get; set; } = new(); } private sealed class TrialDeckCardEntry { public string PrintingId { get; set; } = string.Empty; public int Count { get; set; } } }