diff --git a/MultiversalDiplomacy/Model/Season.cs b/MultiversalDiplomacy/Model/Season.cs
index a527d48..5d3f539 100644
--- a/MultiversalDiplomacy/Model/Season.cs
+++ b/MultiversalDiplomacy/Model/Season.cs
@@ -17,6 +17,13 @@ public class Season
///
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.
@@ -48,6 +55,7 @@ public class Season
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;
@@ -58,7 +66,7 @@ public class Season
public override string ToString()
{
- return $"{this.Timeline}@{this.Turn}";
+ return $"{this.Timeline}{this.Turn}";
}
///
diff --git a/MultiversalDiplomacy/Model/World.cs b/MultiversalDiplomacy/Model/World.cs
index 80bc62b..5499e2e 100644
--- a/MultiversalDiplomacy/Model/World.cs
+++ b/MultiversalDiplomacy/Model/World.cs
@@ -29,6 +29,11 @@ public class World
///
public ReadOnlyCollection Seasons { get; }
+ ///
+ /// Lookup for seasons by designation.
+ ///
+ public ReadOnlyDictionary SeasonLookup { get; }
+
///
/// The first season of the game.
///
@@ -71,6 +76,8 @@ public class World
this.RetreatingUnits = retreatingUnits;
this.OrderHistory = orderHistory;
this.Options = options;
+
+ this.SeasonLookup = new(Seasons.ToDictionary(season => $"{season.Timeline}{season.Turn}"));
}
///
@@ -192,6 +199,23 @@ public class World
);
}
+ ///
+ /// Create a season immediately after this one in the same timeline.
+ ///
+ public World ContinueSeason(string season)
+ => Update(seasons: Seasons.Append(SeasonLookup[season].MakeNext()));
+
+ ///
+ /// Create a season immediately after this one in the same timeline.
+ ///
+ public World ContinueSeason(Season season) => ContinueSeason(season.ToString());
+
+ ///
+ /// Create a season immediately after this one in a new timeline.
+ ///
+ public World ForkSeason(string season)
+ => Update(seasons: Seasons.Append(SeasonLookup[season].MakeFork()));
+
///
/// A standard Diplomacy game setup.
///
@@ -211,6 +235,9 @@ public class World
return foundSeason;
}
+ public Season GetSeason(string designation)
+ => SeasonLookup[designation];
+
///
/// Returns a unit in a province. Throws if there are duplicate units.
///
diff --git a/MultiversalDiplomacyTests/SeasonTests.cs b/MultiversalDiplomacyTests/SeasonTests.cs
index 5506c49..227fa7a 100644
--- a/MultiversalDiplomacyTests/SeasonTests.cs
+++ b/MultiversalDiplomacyTests/SeasonTests.cs
@@ -9,57 +9,57 @@ public class SeasonTests
[Test]
public void TimelineForking()
{
- Season a0 = Season.MakeRoot();
- Season a1 = a0.MakeNext();
- Season a2 = a1.MakeNext();
- Season a3 = a2.MakeNext();
- Season b1 = a1.MakeFork();
- Season b2 = b1.MakeNext();
- Season c1 = a1.MakeFork();
- Season d1 = a2.MakeFork();
+ World world = World
+ .WithMap(Map.Test)
+ .ContinueSeason("a0")
+ .ContinueSeason("a1")
+ .ContinueSeason("a2")
+ .ForkSeason("a1")
+ .ContinueSeason("b2")
+ .ForkSeason("a1")
+ .ForkSeason("a2");
+
+ Assert.That(
+ world.Seasons.Select(season => season.ToString()),
+ Is.EquivalentTo(new List { "a0", "a1", "a2", "a3", "b2", "b3", "c2", "d3" }),
+ "Unexpected seasons");
+
+ Season a0 = world.GetSeason("a0");
+ Season a1 = world.GetSeason("a1");
+ Season a2 = world.GetSeason("a2");
+ Season a3 = world.GetSeason("a3");
+ Season b2 = world.GetSeason("b2");
+ Season b3 = world.GetSeason("b3");
+ Season c2 = world.GetSeason("c2");
+ Season d3 = world.GetSeason("d3");
Assert.That(a0.Timeline, Is.EqualTo("a"), "Unexpected trunk timeline");
Assert.That(a1.Timeline, Is.EqualTo("a"), "Unexpected trunk timeline");
Assert.That(a2.Timeline, Is.EqualTo("a"), "Unexpected trunk timeline");
Assert.That(a3.Timeline, Is.EqualTo("a"), "Unexpected trunk timeline");
- Assert.That(b1.Timeline, Is.EqualTo("b"), "Unexpected first alt");
Assert.That(b2.Timeline, Is.EqualTo("b"), "Unexpected first alt");
- Assert.That(c1.Timeline, Is.EqualTo("c"), "Unexpected second alt");
- Assert.That(d1.Timeline, Is.EqualTo("d"), "Unexpected third alt");
+ Assert.That(b3.Timeline, Is.EqualTo("b"), "Unexpected first alt");
+ Assert.That(c2.Timeline, Is.EqualTo("c"), "Unexpected second alt");
+ Assert.That(d3.Timeline, Is.EqualTo("d"), "Unexpected third alt");
Assert.That(a0.Turn, Is.EqualTo(Season.FIRST_TURN + 0), "Unexpected first turn number");
Assert.That(a1.Turn, Is.EqualTo(Season.FIRST_TURN + 1), "Unexpected next turn number");
Assert.That(a2.Turn, Is.EqualTo(Season.FIRST_TURN + 2), "Unexpected next turn number");
Assert.That(a3.Turn, Is.EqualTo(Season.FIRST_TURN + 3), "Unexpected next turn number");
- Assert.That(b1.Turn, Is.EqualTo(Season.FIRST_TURN + 2), "Unexpected fork turn number");
- Assert.That(b2.Turn, Is.EqualTo(Season.FIRST_TURN + 3), "Unexpected fork turn number");
- Assert.That(c1.Turn, Is.EqualTo(Season.FIRST_TURN + 2), "Unexpected fork turn number");
- Assert.That(d1.Turn, Is.EqualTo(Season.FIRST_TURN + 3), "Unexpected fork turn number");
+ Assert.That(b2.Turn, Is.EqualTo(Season.FIRST_TURN + 2), "Unexpected fork turn number");
+ Assert.That(b3.Turn, Is.EqualTo(Season.FIRST_TURN + 3), "Unexpected fork turn number");
+ Assert.That(c2.Turn, Is.EqualTo(Season.FIRST_TURN + 2), "Unexpected fork turn number");
+ Assert.That(d3.Turn, Is.EqualTo(Season.FIRST_TURN + 3), "Unexpected fork turn number");
Assert.That(a0.TimelineRoot(), Is.EqualTo(a0), "Expected timeline root to be reflexive");
Assert.That(a3.TimelineRoot(), Is.EqualTo(a0), "Expected trunk timeline to have root");
- Assert.That(b1.TimelineRoot(), Is.EqualTo(b1), "Expected alt timeline root to be reflexive");
- Assert.That(b2.TimelineRoot(), Is.EqualTo(b1), "Expected alt timeline to root at first fork");
- Assert.That(c1.TimelineRoot(), Is.EqualTo(c1), "Expected alt timeline root to be reflexive");
- Assert.That(d1.TimelineRoot(), Is.EqualTo(d1), "Expected alt timeline root to be reflexive");
+ Assert.That(b2.TimelineRoot(), Is.EqualTo(b2), "Expected alt timeline root to be reflexive");
+ Assert.That(b3.TimelineRoot(), Is.EqualTo(b2), "Expected alt timeline to root at first fork");
+ Assert.That(c2.TimelineRoot(), Is.EqualTo(c2), "Expected alt timeline root to be reflexive");
+ Assert.That(d3.TimelineRoot(), Is.EqualTo(d3), "Expected alt timeline root to be reflexive");
- Assert.That(b2.InAdjacentTimeline(a3), Is.True, "Expected alts to be adjacent to origin");
- Assert.That(b2.InAdjacentTimeline(c1), Is.True, "Expected alts with common origin to be adjacent");
- Assert.That(b2.InAdjacentTimeline(d1), Is.False, "Expected alts from different origins not to be adjacent");
+ Assert.That(b3.InAdjacentTimeline(a3), Is.True, "Expected alts to be adjacent to origin");
+ Assert.That(b3.InAdjacentTimeline(c2), Is.True, "Expected alts with common origin to be adjacent");
+ Assert.That(b3.InAdjacentTimeline(d3), Is.False, "Expected alts from different origins not to be adjacent");
}
-
- [Test]
- public void LookupTest()
- {
- World world = World.WithStandardMap();
- Season s2 = world.RootSeason.MakeNext();
- Season s3 = s2.MakeNext();
- Season s4 = s2.MakeFork();
- World updated = world.Update(seasons: world.Seasons.Append(s2).Append(s3).Append(s4));
-
- Assert.That(updated.GetSeason("a", Season.FIRST_TURN), Is.EqualTo(updated.RootSeason));
- Assert.That(updated.GetSeason("a", Season.FIRST_TURN + 1), Is.EqualTo(s2));
- Assert.That(updated.GetSeason("a", Season.FIRST_TURN + 2), Is.EqualTo(s3));
- Assert.That(updated.GetSeason("b", Season.FIRST_TURN + 2), Is.EqualTo(s4));
- }
-}
\ No newline at end of file
+}
diff --git a/MultiversalDiplomacyTests/UnitTests.cs b/MultiversalDiplomacyTests/UnitTests.cs
index 50e387e..faf3028 100644
--- a/MultiversalDiplomacyTests/UnitTests.cs
+++ b/MultiversalDiplomacyTests/UnitTests.cs
@@ -14,22 +14,24 @@ public class UnitTests
Boh = world.Map.GetLand("Boh"),
Tyr = world.Map.GetLand("Tyr");
Power pw1 = world.Map.GetPower("Austria");
- Season s1 = world.RootSeason;
- Unit u1 = Unit.Build(Mun, s1, pw1, UnitType.Army);
+ Season a0 = world.RootSeason;
+ Unit u1 = Unit.Build(Mun, a0, pw1, UnitType.Army);
- Season s2 = s1.MakeNext();
- Unit u2 = u1.Next(Boh, s2);
+ world = world.ContinueSeason(a0);
+ Season a1 = world.GetSeason("a1");
+ Unit u2 = u1.Next(Boh, a1);
- Season s3 = s2.MakeNext();
- Unit u3 = u2.Next(Tyr, s3);
+ world = world.ContinueSeason(a1);
+ Season a2 = world.GetSeason("a2");
+ Unit u3 = u2.Next(Tyr, a2);
Assert.That(u3.Past, Is.EqualTo(u2), "Missing unit past");
Assert.That(u2.Past, Is.EqualTo(u1), "Missing unit past");
Assert.That(u1.Past, Is.Null, "Unexpected unit past");
- Assert.That(u1.Season, Is.EqualTo(s1), "Unexpected unit season");
- Assert.That(u2.Season, Is.EqualTo(s2), "Unexpected unit season");
- Assert.That(u3.Season, Is.EqualTo(s3), "Unexpected unit season");
+ Assert.That(u1.Season, Is.EqualTo(a0), "Unexpected unit season");
+ Assert.That(u2.Season, Is.EqualTo(a1), "Unexpected unit season");
+ Assert.That(u3.Season, Is.EqualTo(a2), "Unexpected unit season");
Assert.That(u1.Location, Is.EqualTo(Mun), "Unexpected unit location");
Assert.That(u2.Location, Is.EqualTo(Boh), "Unexpected unit location");