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;
}
}