78 lines
2.8 KiB
C#
78 lines
2.8 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace MultiversalDiplomacy.Model;
|
|
|
|
/// <summary>
|
|
/// Represents a multiversal coordinate at which a state of the map exists.
|
|
/// </summary>
|
|
[JsonConverter(typeof(SeasonJsonConverter))]
|
|
public struct Season(string timeline, int turn)
|
|
{
|
|
/// <summary>
|
|
/// 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 <see cref="Timelines"/>.
|
|
/// </summary>
|
|
public static readonly Season First = new(Timelines.IntToString(0), 0);
|
|
|
|
/// <summary>
|
|
/// The timeline to which this season belongs.
|
|
/// </summary>
|
|
public string Timeline { get; } = timeline;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public int Turn { get; } = turn;
|
|
|
|
/// <summary>
|
|
/// The multiversal designation of this season.
|
|
/// </summary>
|
|
[JsonIgnore]
|
|
public readonly string Key => $"{this.Timeline}{this.Turn}";
|
|
|
|
/// <summary>
|
|
/// Create a new season from a tuple coordinate.
|
|
/// </summary>
|
|
public Season((string timeline, int turn) coord) : this(coord.timeline, coord.turn) { }
|
|
|
|
/// <summary>
|
|
/// Create a new season from a combined string designation.
|
|
/// </summary>
|
|
/// <param name="designation"></param>
|
|
public Season(string designation) : this(SplitKey(designation)) { }
|
|
|
|
/// <summary>
|
|
/// Extract the timeline and turn components of a season designation.
|
|
/// </summary>
|
|
/// <param name="seasonKey">A timeline-turn season designation.</param>
|
|
/// <returns>The timeline and turn components.</returns>
|
|
/// <exception cref="FormatException"></exception>
|
|
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;
|
|
|
|
/// <remarks>
|
|
/// Seasons are essentially 2D points, so they are equal when their components are equal.
|
|
/// </remarks>
|
|
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();
|
|
}
|