namespace MultiversalDiplomacy.Model; /// /// Represents a state of the map produced by a set of move orders on a previous season. /// public class Season { /// /// The first turn number. /// public const int FIRST_TURN = 0; /// /// The season immediately preceding this season. /// If this season is an alternate timeline root, the past is from the origin timeline. /// The initial season does not have a past. /// public Season? Past { get; } /// /// The designation of the season immediately preceding this season. /// If this season is an alternate timeline root, the past is from the origin timeline. /// The initial season does not have a past. /// public string? PastId { get; } /// /// 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; } /// /// The timeline to which this season belongs. /// public string Timeline { get; } /// /// The season's spatial location as a timeline-turn tuple. /// public (string Timeline, int Turn) Coord => (this.Timeline, this.Turn); /// /// The shared timeline number generator. /// private TimelineFactory Timelines { get; } /// /// Future seasons created directly from this season. /// public IEnumerable Futures => this.FutureList; private List FutureList { get; } private Season(Season? past, int turn, string timeline, TimelineFactory factory) { this.Past = past; this.PastId = past?.ToString(); this.Turn = turn; this.Timeline = timeline; this.Timelines = factory; this.FutureList = []; past?.FutureList.Add(this); } public override string ToString() { return $"{this.Timeline}{this.Turn}"; } /// /// Create a root season at the beginning of time. /// public static Season MakeRoot() { TimelineFactory factory = new TimelineFactory(); return new Season( past: null, turn: FIRST_TURN, timeline: factory.NextTimeline(), factory: factory); } /// /// Create a season immediately after this one in the same timeline. /// public Season MakeNext() => new(this, Turn + 1, Timeline, Timelines); /// /// Create a season immediately after this one in a new timeline. /// public Season MakeFork() => new(this, Turn + 1, Timelines.NextTimeline(), Timelines); /// /// Returns the first season in this season's timeline. The first season is the /// root of the first timeline. The earliest season in each alternate timeline is /// the root of that timeline. /// public Season TimelineRoot() => this.Past != null && this.Timeline == this.Past.Timeline ? this.Past.TimelineRoot() : this; /// /// Returns whether this season is in an adjacent timeline to another season. /// Seasons are considered to be in adjacent timelines if they are in the same timeline, /// one is in a timeline that branched from the other's timeline, or both are in timelines /// that branched from the same point. /// public bool InAdjacentTimeline(Season other) { // Timelines are adjacent to themselves. Early out in that case. if (this.Timeline == other.Timeline) return true; // If the timelines aren't identical, one of them isn't the initial trunk. // They can still be adjacent if one of them branched off of the other, or // if they both branched off of the same point. Season thisRoot = this.TimelineRoot(); Season otherRoot = other.TimelineRoot(); return // One branched off the other thisRoot.Past?.Timeline == other.Timeline || otherRoot.Past?.Timeline == this.Timeline // Both branched off of the same point || thisRoot.Past == otherRoot.Past; } }