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");