Refactor season futures into World
This commit is contained in:
parent
3242186208
commit
b17ce9485a
|
@ -50,7 +50,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
|
||||
// Invalidate any order given to a unit in the past.
|
||||
AdjudicatorHelpers.InvalidateIfNotMatching(
|
||||
order => !order.Unit.Season.Futures.Any(),
|
||||
order => !world.GetFutures(order.Unit.Season).Any(),
|
||||
ValidationReason.IneligibleForOrder,
|
||||
ref unitOrders,
|
||||
ref validationResults);
|
||||
|
@ -255,7 +255,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
|
||||
// Finally, add implicit hold orders for units without legal orders.
|
||||
List<Unit> allOrderableUnits = world.Units
|
||||
.Where(unit => !unit.Season.Futures.Any())
|
||||
.Where(unit => !world.GetFutures(unit.Season).Any())
|
||||
.ToList();
|
||||
HashSet<Unit> orderedUnits = validOrders.Select(order => order.Unit).ToHashSet();
|
||||
List<Unit> unorderedUnits = allOrderableUnits
|
||||
|
@ -324,7 +324,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
if (advanceTimeline.Outcome == true)
|
||||
{
|
||||
// A timeline that doesn't have a future yet simply continues. Otherwise, it forks.
|
||||
createdFutures[advanceTimeline.Season] = !advanceTimeline.Season.Futures.Any()
|
||||
createdFutures[advanceTimeline.Season] = !world.GetFutures(advanceTimeline.Season).Any()
|
||||
? advanceTimeline.Season.MakeNext()
|
||||
: advanceTimeline.Season.MakeFork();
|
||||
}
|
||||
|
@ -486,7 +486,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
|||
bool progress = false;
|
||||
|
||||
// A season at the head of a timeline always advances.
|
||||
if (!decision.Season.Futures.Any())
|
||||
if (!world.GetFutures(decision.Season).Any())
|
||||
{
|
||||
progress |= LoggedUpdate(decision, true, depth, "A timeline head always advances");
|
||||
return progress;
|
||||
|
|
|
@ -115,7 +115,7 @@ public static class PathFinder
|
|||
|
||||
// The immediate past and all immediate futures are adjacent.
|
||||
if (season.Past != null) adjacents.Add(world.GetSeason(season.Past));
|
||||
adjacents.AddRange(season.Futures);
|
||||
adjacents.AddRange(world.GetFutures(season));
|
||||
|
||||
// Find all adjacent timelines by finding all timelines that branched off of this season's
|
||||
// timeline, i.e. all futures of this season's past that have different timelines. Also
|
||||
|
@ -127,7 +127,7 @@ public static class PathFinder
|
|||
current = world.GetSeason(current.Past))
|
||||
{
|
||||
adjacentTimelineRoots.AddRange(
|
||||
current.Futures.Where(s => s.Timeline != current.Timeline));
|
||||
world.GetFutures(current).Where(s => s.Timeline != current.Timeline));
|
||||
}
|
||||
|
||||
// At the end of the for loop, if this season is part of the first timeline, then current
|
||||
|
@ -137,7 +137,8 @@ public static class PathFinder
|
|||
// the first timeline by definition cannot have co-branches.
|
||||
if (current?.Past != null && world.GetSeason(current.Past) is Season past)
|
||||
{
|
||||
IEnumerable<Season> cobranchRoots = past.Futures
|
||||
IEnumerable<Season> cobranchRoots = world
|
||||
.GetFutures(past)
|
||||
.Where(s => s.Timeline != current.Timeline && s.Timeline != past.Timeline);
|
||||
adjacentTimelineRoots.AddRange(cobranchRoots);
|
||||
}
|
||||
|
@ -147,7 +148,7 @@ public static class PathFinder
|
|||
{
|
||||
for (Season? branchSeason = timelineRoot;
|
||||
branchSeason != null && branchSeason.Turn <= season.Turn + 1;
|
||||
branchSeason = branchSeason.Futures
|
||||
branchSeason = world.GetFutures(branchSeason)
|
||||
.FirstOrDefault(s => s!.Timeline == branchSeason.Timeline, null))
|
||||
{
|
||||
if (branchSeason.Turn >= season.Turn - 1) adjacents.Add(branchSeason);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace MultiversalDiplomacy.Model;
|
||||
|
||||
/// <summary>
|
||||
|
@ -30,36 +32,32 @@ public class Season
|
|||
public string Timeline { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The season's spatial location as a timeline-turn tuple.
|
||||
/// The multiversal designation of this season.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string Designation => $"{this.Timeline}{this.Turn}";
|
||||
|
||||
/// <summary>
|
||||
/// The season's multiversal location as a timeline-turn tuple for convenience.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public (string Timeline, int Turn) Coord => (this.Timeline, this.Turn);
|
||||
|
||||
/// <summary>
|
||||
/// The shared timeline number generator.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
private TimelineFactory Timelines { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Future seasons created directly from this season.
|
||||
/// </summary>
|
||||
public IEnumerable<Season> Futures => this.FutureList;
|
||||
private List<Season> FutureList { get; }
|
||||
|
||||
private Season(Season? past, int turn, string timeline, TimelineFactory factory)
|
||||
{
|
||||
this.Past = 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}";
|
||||
}
|
||||
public override string ToString() => Designation;
|
||||
|
||||
/// <summary>
|
||||
/// Create a root season at the beginning of time.
|
||||
|
|
|
@ -232,6 +232,21 @@ public class World
|
|||
public Season GetSeason(string designation)
|
||||
=> SeasonLookup[designation];
|
||||
|
||||
/// <summary>
|
||||
/// Get all seasons that are immediate futures of a season.
|
||||
/// </summary>
|
||||
/// <param name="present">A season designation.</param>
|
||||
/// <returns>The immediate futures of the designated season.</returns>
|
||||
public IEnumerable<Season> GetFutures(string present)
|
||||
=> Seasons.Where(future => future.Past == present);
|
||||
|
||||
/// <summary>
|
||||
/// Get all seasons that are immediate futures of a season.
|
||||
/// </summary>
|
||||
/// <param name="present">A season.</param>
|
||||
/// <returns>The immediate futures of the season.</returns>
|
||||
public IEnumerable<Season> GetFutures(Season present) => GetFutures(present.Designation);
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
|
|
|
@ -136,12 +136,12 @@ public class TimeTravelTest
|
|||
// change the past and therefore did not create a new timeline.
|
||||
World world = setup.UpdateWorld();
|
||||
Assert.That(
|
||||
s0.Futures.Count(),
|
||||
world.GetFutures(s0).Count(),
|
||||
Is.EqualTo(1),
|
||||
"A failed move incorrectly forked the timeline");
|
||||
Assert.That(s1.Futures.Count(), Is.EqualTo(1));
|
||||
Assert.That(world.GetFutures(s1).Count(), Is.EqualTo(1));
|
||||
Season s2 = world.GetSeason(s1.Timeline, s1.Turn + 1);
|
||||
Assert.That(s2.Futures.Count(), Is.EqualTo(0));
|
||||
Assert.That(world.GetFutures(s2).Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -178,12 +178,12 @@ public class TimeTravelTest
|
|||
// ...since it succeeded anyway, no fork is created.
|
||||
World world = setup.UpdateWorld();
|
||||
Assert.That(
|
||||
s0.Futures.Count(),
|
||||
world.GetFutures(s0).Count(),
|
||||
Is.EqualTo(1),
|
||||
"A superfluous support incorrectly forked the timeline");
|
||||
Assert.That(s1.Futures.Count(), Is.EqualTo(1));
|
||||
Assert.That(world.GetFutures(s1).Count(), Is.EqualTo(1));
|
||||
Season s2 = world.GetSeason(s1.Timeline, s1.Turn + 1);
|
||||
Assert.That(s2.Futures.Count(), Is.EqualTo(0));
|
||||
Assert.That(world.GetFutures(s2).Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -226,17 +226,17 @@ public class TimeTravelTest
|
|||
// Since both seasons were at the head of their timelines, there should be no forking.
|
||||
World world = setup.UpdateWorld();
|
||||
Assert.That(
|
||||
a2.Futures.Count(),
|
||||
world.GetFutures(a2).Count(),
|
||||
Is.EqualTo(1),
|
||||
"A cross-timeline support incorrectly forked the head of the timeline");
|
||||
Assert.That(
|
||||
b1.Futures.Count(),
|
||||
world.GetFutures(b1).Count(),
|
||||
Is.EqualTo(1),
|
||||
"A cross-timeline support incorrectly forked the head of the timeline");
|
||||
Season a3 = world.GetSeason(a2.Timeline, a2.Turn + 1);
|
||||
Assert.That(a3.Futures.Count(), Is.EqualTo(0));
|
||||
Assert.That(world.GetFutures(a3).Count(), Is.EqualTo(0));
|
||||
Season b2 = world.GetSeason(b1.Timeline, b1.Turn + 1);
|
||||
Assert.That(b2.Futures.Count(), Is.EqualTo(0));
|
||||
Assert.That(world.GetFutures(b2).Count(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -297,11 +297,11 @@ public class TimeTravelTest
|
|||
// wasn't changed in this timeline.
|
||||
World world = setup.UpdateWorld();
|
||||
Assert.That(
|
||||
a3.Futures.Count(),
|
||||
world.GetFutures(a3).Count(),
|
||||
Is.EqualTo(1),
|
||||
"A cross-timeline support cut incorrectly forked the timeline");
|
||||
Assert.That(
|
||||
b2.Futures.Count(),
|
||||
world.GetFutures(b2).Count(),
|
||||
Is.EqualTo(1),
|
||||
"A cross-timeline support cut incorrectly forked the timeline");
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ public class MovementAdjudicatorTest
|
|||
Assert.That(updated.Seasons.Count, Is.EqualTo(2));
|
||||
Season future = updated.Seasons.Single(s => s != updated.RootSeason);
|
||||
Assert.That(future.Past, Is.EqualTo(updated.RootSeason.ToString()));
|
||||
Assert.That(future.Futures, Is.Empty);
|
||||
Assert.That(updated.GetFutures(future), Is.Empty);
|
||||
Assert.That(future.Timeline, Is.EqualTo(updated.RootSeason.Timeline));
|
||||
Assert.That(future.Turn, Is.EqualTo(Season.FIRST_TURN + 1));
|
||||
|
||||
|
@ -201,7 +201,7 @@ public class MovementAdjudicatorTest
|
|||
// Confirm the future was created
|
||||
Season s2 = updated.GetSeason("a1");
|
||||
Assert.That(s2.Past, Is.EqualTo(s1.ToString()));
|
||||
Assert.That(s2.Futures, Is.Empty);
|
||||
Assert.That(updated.GetFutures(s2), Is.Empty);
|
||||
Assert.That(s2.Timeline, Is.EqualTo(s1.Timeline));
|
||||
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
||||
|
||||
|
@ -251,7 +251,7 @@ public class MovementAdjudicatorTest
|
|||
// Confirm the future was created
|
||||
Season s2 = updated.GetSeason(s1.Timeline, s1.Turn + 1);
|
||||
Assert.That(s2.Past, Is.EqualTo(s1.ToString()));
|
||||
Assert.That(s2.Futures, Is.Empty);
|
||||
Assert.That(updated.GetFutures(s2), Is.Empty);
|
||||
Assert.That(s2.Timeline, Is.EqualTo(s1.Timeline));
|
||||
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
||||
|
||||
|
|
|
@ -61,5 +61,10 @@ public class SeasonTests
|
|||
Assert.That(world.InAdjacentTimeline(b3, a3), Is.True, "Expected alts to be adjacent to origin");
|
||||
Assert.That(world.InAdjacentTimeline(b3, c2), Is.True, "Expected alts with common origin to be adjacent");
|
||||
Assert.That(world.InAdjacentTimeline(b3, d3), Is.False, "Expected alts from different origins not to be adjacent");
|
||||
|
||||
Assert.That(world.GetFutures(a0), Is.EquivalentTo(new List<Season> { a1 }), "Unexpected futures");
|
||||
Assert.That(world.GetFutures(a1), Is.EquivalentTo(new List<Season> { a2, b2, c2 }), "Unexpected futures");
|
||||
Assert.That(world.GetFutures(a2), Is.EquivalentTo(new List<Season> { a3, d3 }), "Unexpected futures");
|
||||
Assert.That(world.GetFutures(b2), Is.EquivalentTo(new List<Season> { b3 }), "Unexpected futures");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue