using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization; namespace MultiversalDiplomacy.Model; /// /// Represents a multiversal coordinate at which a state of the map exists. /// [JsonConverter(typeof(SeasonJsonConverter))] public struct Season(string timeline, int turn) { /// /// The root season of every game. This is defined to avoid any confusion about what the first turn or timeline /// should be or what season to use to key into a fresh . /// public static readonly Season First = new(Timelines.IntToString(0), 0); /// /// The timeline to which this season belongs. /// public string Timeline { get; } = timeline; /// /// The current turn, beginning at 0. Each season (spring and fall) is one turn. /// Phases that only occur after the fall phase occur when Turn % 2 == 1. /// The current year is (Turn / 2) + 1901. /// public int Turn { get; } = turn; /// /// The multiversal designation of this season. /// [JsonIgnore] public readonly string Key => $"{this.Timeline}{this.Turn}"; /// /// Create a new season from a tuple coordinate. /// public Season((string timeline, int turn) coord) : this(coord.timeline, coord.turn) { } /// /// Create a new season from a combined string designation. /// /// public Season(string designation) : this(SplitKey(designation)) { } /// /// Extract the timeline and turn components of a season designation. /// /// A timeline-turn season designation. /// The timeline and turn components. /// public static (string timeline, int turn) SplitKey(string seasonKey) { int i = 1; for (; !char.IsAsciiDigit(seasonKey[i]) && i < seasonKey.Length; i++); return int.TryParse(seasonKey.AsSpan(i), out int turn) ? (seasonKey[..i], turn) : throw new FormatException($"Could not parse turn from {seasonKey}"); } public override readonly string ToString() => Key; /// /// Seasons are essentially 2D points, so they are equal when their components are equal. /// public override readonly bool Equals([NotNullWhen(true)] object? obj) => obj is Season season && Timeline == season.Timeline && Turn == season.Turn; public static bool operator ==(Season one, Season two) => one.Equals(two); public static bool operator !=(Season one, Season two) => !(one == two); public override readonly int GetHashCode() => (Timeline, Turn).GetHashCode(); }