Compare commits
7 Commits
548d6ddc82
...
dae0658492
Author | SHA1 | Date |
---|---|---|
Jaculabilis | dae0658492 | |
Tim Van Baak | 3db01c0ffd | |
Tim Van Baak | 0fd9c93a70 | |
Tim Van Baak | 5b4758a4ed | |
Tim Van Baak | 7b2176b1d2 | |
Tim Van Baak | 4bbd29ac93 | |
Tim Van Baak | 26e268c3a0 |
|
@ -2,7 +2,7 @@
|
||||||
"terminal.integrated.profiles.linux": {
|
"terminal.integrated.profiles.linux": {
|
||||||
"nix develop": {
|
"nix develop": {
|
||||||
"path": "nix",
|
"path": "nix",
|
||||||
"args": ["develop"]
|
"args": ["develop", "--impure"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terminal.integrated.profiles.windows": {
|
"terminal.integrated.profiles.windows": {
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
// Map adjacency
|
// Map adjacency
|
||||||
order.Unit.Location.Adjacents.Contains(order.Location)
|
order.Unit.Location.Adjacents.Contains(order.Location)
|
||||||
// Turn adjacency
|
// Turn adjacency
|
||||||
&& Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1
|
&& order.Unit.Season.Turn - order.Season.Turn <= 1
|
||||||
// Timeline adjacency
|
// Timeline adjacency
|
||||||
&& order.Unit.Season.InAdjacentTimeline(order.Season));
|
&& order.Unit.Season.InAdjacentTimeline(order.Season));
|
||||||
List<MoveOrder> adjacentMoveOrders = moveOrdersByAdjacency[true].ToList();
|
List<MoveOrder> adjacentMoveOrders = moveOrdersByAdjacency[true].ToList();
|
||||||
|
@ -178,7 +178,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
order.Unit.Location.Adjacents.Any(
|
order.Unit.Location.Adjacents.Any(
|
||||||
adjLocation => adjLocation.Province == order.Target.Province)
|
adjLocation => adjLocation.Province == order.Target.Province)
|
||||||
// Turn adjacency
|
// Turn adjacency
|
||||||
&& Math.Abs(order.Unit.Season.Turn - order.Target.Season.Turn) <= 1
|
&& order.Unit.Season.Turn - order.Target.Season.Turn <= 1
|
||||||
// Timeline adjacency
|
// Timeline adjacency
|
||||||
&& order.Unit.Season.InAdjacentTimeline(order.Target.Season),
|
&& order.Unit.Season.InAdjacentTimeline(order.Target.Season),
|
||||||
ValidationReason.UnreachableSupport,
|
ValidationReason.UnreachableSupport,
|
||||||
|
@ -210,7 +210,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
order.Unit.Location.Adjacents.Any(
|
order.Unit.Location.Adjacents.Any(
|
||||||
adjLocation => adjLocation.Province == order.Province)
|
adjLocation => adjLocation.Province == order.Province)
|
||||||
// Turn adjacency
|
// Turn adjacency
|
||||||
&& Math.Abs(order.Unit.Season.Turn - order.Season.Turn) <= 1
|
&& order.Unit.Season.Turn - order.Season.Turn <= 1
|
||||||
// Timeline adjacency
|
// Timeline adjacency
|
||||||
&& order.Unit.Season.InAdjacentTimeline(order.Season),
|
&& order.Unit.Season.InAdjacentTimeline(order.Season),
|
||||||
ValidationReason.UnreachableSupport,
|
ValidationReason.UnreachableSupport,
|
||||||
|
@ -531,6 +531,20 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
$"History changed for {order.Unit}: dislodge {previous} => {dislodged.Outcome}");
|
$"History changed for {order.Unit}: dislodge {previous} => {dislodged.Outcome}");
|
||||||
return progress;
|
return progress;
|
||||||
}
|
}
|
||||||
|
// logger.Log(0, "world.OrderHistory");
|
||||||
|
// foreach ((Season s, OrderHistory oh) in world.OrderHistory)
|
||||||
|
// {
|
||||||
|
// logger.Log(1, $"{s}");
|
||||||
|
// logger.Log(2, "Orders:");
|
||||||
|
// foreach (UnitOrder o in oh.Orders)
|
||||||
|
// logger.Log(3, $"{o}");
|
||||||
|
// logger.Log(2, "Dislodges:");
|
||||||
|
// foreach ((Unit u, bool outcome) in oh.IsDislodgedOutcomes)
|
||||||
|
// logger.Log(3, $"{u} = {outcome}");
|
||||||
|
// logger.Log(2, "Moves:");
|
||||||
|
// foreach ((MoveOrder m, bool outcome) in oh.DoesMoveOutcomes)
|
||||||
|
// logger.Log(3, $"{m} = {outcome}");
|
||||||
|
// }
|
||||||
anyUnresolved |= !dislodged.Resolved;
|
anyUnresolved |= !dislodged.Resolved;
|
||||||
|
|
||||||
if (order is MoveOrder moveOrder)
|
if (order is MoveOrder moveOrder)
|
||||||
|
@ -637,7 +651,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
if (// Map adjacency
|
if (// Map adjacency
|
||||||
decision.Order.Unit.Location.Adjacents.Contains(decision.Order.Location)
|
decision.Order.Unit.Location.Adjacents.Contains(decision.Order.Location)
|
||||||
// Turn adjacency
|
// Turn adjacency
|
||||||
&& Math.Abs(decision.Order.Unit.Season.Turn - decision.Order.Season.Turn) <= 1
|
&& decision.Order.Unit.Season.Turn - decision.Order.Season.Turn <= 1
|
||||||
// Timeline adjacency
|
// Timeline adjacency
|
||||||
&& decision.Order.Unit.Season.InAdjacentTimeline(decision.Order.Season))
|
&& decision.Order.Unit.Season.InAdjacentTimeline(decision.Order.Season))
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,21 +5,6 @@ namespace MultiversalDiplomacy.Model;
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Season
|
public class Season
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// A shared counter for handing out new timeline numbers.
|
|
||||||
/// </summary>
|
|
||||||
private class TimelineFactory
|
|
||||||
{
|
|
||||||
private int nextTimeline = 0;
|
|
||||||
|
|
||||||
public int NextTimeline() => nextTimeline++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The first turn number.
|
|
||||||
/// </summary>
|
|
||||||
public const int FIRST_TURN = 0;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The season immediately preceding this season.
|
/// The season immediately preceding this season.
|
||||||
/// If this season is an alternate timeline root, the past is from the origin timeline.
|
/// If this season is an alternate timeline root, the past is from the origin timeline.
|
||||||
|
@ -32,7 +17,7 @@ public class Season
|
||||||
/// Phases that only occur after the fall phase occur when Turn % 2 == 1.
|
/// Phases that only occur after the fall phase occur when Turn % 2 == 1.
|
||||||
/// The current year is (Turn / 2) + 1901.
|
/// The current year is (Turn / 2) + 1901.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Turn { get; }
|
public Turn Turn { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The timeline to which this season belongs.
|
/// The timeline to which this season belongs.
|
||||||
|
@ -42,10 +27,10 @@ public class Season
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The season's spatial location as a turn-timeline tuple.
|
/// The season's spatial location as a turn-timeline tuple.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public (int Turn, int Timeline) Coord => (this.Turn, this.Timeline);
|
public (Turn Turn, int Timeline) Coord => (this.Turn, this.Timeline);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The shared timeline number generator.
|
/// The shared timeline number generator created by the root season.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private TimelineFactory Timelines { get; }
|
private TimelineFactory Timelines { get; }
|
||||||
|
|
||||||
|
@ -55,13 +40,13 @@ public class Season
|
||||||
public IEnumerable<Season> Futures => this.FutureList;
|
public IEnumerable<Season> Futures => this.FutureList;
|
||||||
private List<Season> FutureList { get; }
|
private List<Season> FutureList { get; }
|
||||||
|
|
||||||
private Season(Season? past, int turn, int timeline, TimelineFactory factory)
|
private Season(Season? past, Turn turn, int timeline, TimelineFactory factory)
|
||||||
{
|
{
|
||||||
this.Past = past;
|
Past = past;
|
||||||
this.Turn = turn;
|
Turn = turn;
|
||||||
this.Timeline = timeline;
|
Timeline = timeline;
|
||||||
this.Timelines = factory;
|
Timelines = factory;
|
||||||
this.FutureList = new();
|
FutureList = new();
|
||||||
|
|
||||||
if (past != null)
|
if (past != null)
|
||||||
{
|
{
|
||||||
|
@ -71,9 +56,12 @@ public class Season
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"{this.Timeline}@{this.Turn}";
|
return $"{this.Timeline}@{Turn}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ToShort()
|
||||||
|
=> $"{Timeline}@{Turn.ToShort()}";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a root season at the beginning of time.
|
/// Create a root season at the beginning of time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -82,8 +70,8 @@ public class Season
|
||||||
TimelineFactory factory = new TimelineFactory();
|
TimelineFactory factory = new TimelineFactory();
|
||||||
return new Season(
|
return new Season(
|
||||||
past: null,
|
past: null,
|
||||||
turn: FIRST_TURN,
|
turn: new Turn(Turn.FIRST_TURN),
|
||||||
timeline: factory.NextTimeline(),
|
timeline: factory.Next().number,
|
||||||
factory: factory);
|
factory: factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,13 +79,13 @@ public class Season
|
||||||
/// Create a season immediately after this one in the same timeline.
|
/// Create a season immediately after this one in the same timeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Season MakeNext()
|
public Season MakeNext()
|
||||||
=> new Season(this, this.Turn + 1, this.Timeline, this.Timelines);
|
=> new Season(this, Turn.Next, Timeline, Timelines);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a season immediately after this one in a new timeline.
|
/// Create a season immediately after this one in a new timeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Season MakeFork()
|
public Season MakeFork()
|
||||||
=> new Season(this, this.Turn + 1, this.Timelines.NextTimeline(), this.Timelines);
|
=> new Season(this, Turn.Next, Timelines.Next().number, Timelines);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the first season in this season's timeline. The first season is the
|
/// Returns the first season in this season's timeline. The first season is the
|
||||||
|
@ -105,8 +93,8 @@ public class Season
|
||||||
/// the root of that timeline.
|
/// the root of that timeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Season TimelineRoot()
|
public Season TimelineRoot()
|
||||||
=> this.Past != null && this.Timeline == this.Past.Timeline
|
=> Past != null && Timeline == Past.Timeline
|
||||||
? this.Past.TimelineRoot()
|
? Past.TimelineRoot()
|
||||||
: this;
|
: this;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -172,7 +160,7 @@ public class Season
|
||||||
foreach (Season timelineRoot in adjacentTimelineRoots)
|
foreach (Season timelineRoot in adjacentTimelineRoots)
|
||||||
{
|
{
|
||||||
for (Season? branchSeason = timelineRoot;
|
for (Season? branchSeason = timelineRoot;
|
||||||
branchSeason != null && branchSeason.Turn <= this.Turn + 1;
|
branchSeason != null && branchSeason.Turn <= this.Turn.Next;
|
||||||
branchSeason = branchSeason.FutureList
|
branchSeason = branchSeason.FutureList
|
||||||
.FirstOrDefault(s => s!.Timeline == branchSeason.Timeline, null))
|
.FirstOrDefault(s => s!.Timeline == branchSeason.Timeline, null))
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace MultiversalDiplomacy.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A timeline of a game. Essentially a wrapper around <see cref="int"/> for tracking the multiversal dimension.
|
||||||
|
/// </summary>
|
||||||
|
public struct Timeline
|
||||||
|
{
|
||||||
|
public readonly int number;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Timeline designations for differentiating timelines. Shortenable to the first character.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string[] primaryDesignations = new string[]
|
||||||
|
{
|
||||||
|
"alfa",
|
||||||
|
"bravo",
|
||||||
|
"charlie",
|
||||||
|
"delta",
|
||||||
|
"echo",
|
||||||
|
"foxtrot",
|
||||||
|
"golf",
|
||||||
|
"hotel",
|
||||||
|
"india",
|
||||||
|
"juliett",
|
||||||
|
"kilo",
|
||||||
|
"lima",
|
||||||
|
"mike",
|
||||||
|
"november",
|
||||||
|
"oscar",
|
||||||
|
"papa",
|
||||||
|
"quebec",
|
||||||
|
"romeo",
|
||||||
|
"sierra",
|
||||||
|
"tango",
|
||||||
|
"uniform",
|
||||||
|
"victor",
|
||||||
|
"whiskey",
|
||||||
|
"xray",
|
||||||
|
"yankee",
|
||||||
|
"zulu"
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disambiguators used once all primary timeline designations have been used.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string[] secondaryDesignations = new string[]
|
||||||
|
{
|
||||||
|
"",
|
||||||
|
"-prime",
|
||||||
|
"-second",
|
||||||
|
"-third",
|
||||||
|
"-fourth",
|
||||||
|
"-fifth",
|
||||||
|
"-sixth",
|
||||||
|
"-seventh",
|
||||||
|
"-eighth",
|
||||||
|
"-ninth",
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Short versions of the secondary timeline disambiguators.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly string[] secondaryDesignationsShort = new string[]
|
||||||
|
{
|
||||||
|
"",
|
||||||
|
"'",
|
||||||
|
"\"",
|
||||||
|
"\x2073",
|
||||||
|
"\x2074",
|
||||||
|
"\x2075",
|
||||||
|
"\x2076",
|
||||||
|
"\x2077",
|
||||||
|
"\x2078",
|
||||||
|
"\x2079",
|
||||||
|
};
|
||||||
|
|
||||||
|
public Timeline(int number)
|
||||||
|
{
|
||||||
|
if (number < FIRST_TIMELINE)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid timeline number: {number}", nameof(number));
|
||||||
|
}
|
||||||
|
if (number >= primaryDesignations.Length * secondaryDesignations.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Timeline number too high: {number}", nameof(number));
|
||||||
|
}
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The first timeline number.
|
||||||
|
/// </summary>
|
||||||
|
public const int FIRST_TIMELINE = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Which primary designation the timeline has.
|
||||||
|
/// </summary>
|
||||||
|
private int primaryIndex => number % primaryDesignations.Length;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Which secondary designation the timeline has.
|
||||||
|
/// </summary>
|
||||||
|
private int secondaryIndex => number / primaryDesignations.Length;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the timeline's full string representation.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The timeline designation as a string, such as "bravo" or "delta-prime".</returns>
|
||||||
|
public override string ToString()
|
||||||
|
=> primaryDesignations[primaryIndex] + secondaryDesignations[secondaryIndex];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a shorter string representation of the timeline.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The timeline's designation as a string, such as "b" or "d'".</returns>
|
||||||
|
public string ToShort()
|
||||||
|
=> primaryDesignations[primaryIndex][0] + secondaryDesignationsShort[secondaryIndex];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a value indicating whether this instance is equal to a specified <see cref="Timeline"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if obj has the same value as this instance; otherwise, false.</returns>
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
=> obj is Timeline other
|
||||||
|
? number.Equals(other.number)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the hash code for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A 32-bit signed integer hash code.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
=> number.GetHashCode();
|
||||||
|
|
||||||
|
public static int operator -(Timeline first, Timeline second)
|
||||||
|
=> Math.Abs(first.number - second.number);
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
namespace MultiversalDiplomacy.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A ratchet counter for creating timelines.
|
||||||
|
/// </summary>
|
||||||
|
public class TimelineFactory
|
||||||
|
{
|
||||||
|
private int nextTimeline;
|
||||||
|
|
||||||
|
public TimelineFactory()
|
||||||
|
{
|
||||||
|
nextTimeline = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Timeline Next() => new(nextTimeline++);
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
|
namespace MultiversalDiplomacy.Model;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A turn of a game. Essentially a wrapper around <see cref="int"/> for tracking the temporal dimension.
|
||||||
|
/// </summary>
|
||||||
|
public struct Turn
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The first turn number.
|
||||||
|
/// </summary>
|
||||||
|
public const int FIRST_TURN = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The first turn.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly Turn First = new(FIRST_TURN);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This turn's number.
|
||||||
|
/// </summary>
|
||||||
|
private readonly int number;
|
||||||
|
|
||||||
|
public Turn(int number)
|
||||||
|
{
|
||||||
|
if (number < FIRST_TURN)
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"Invalid turn number: {number}", nameof(number));
|
||||||
|
}
|
||||||
|
this.number = number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the turn's string representation as a Diplomacy season.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The season and year as a string, e.g. "Spring 1901".</returns>
|
||||||
|
public override string ToString()
|
||||||
|
=> $"{(number % 2 == 0 ? "Spring" : "Fall")} {1901 + (number / 2)}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a shorter string representation of the turn.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The season and year as a string, e.g. "S'01".</returns>
|
||||||
|
public string ToShort()
|
||||||
|
=> $"{(number % 2 == 0 ? "S" : "F")}'{number / 2:D2}";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a value indicating whether this instance is equal to a specified <see cref="Turn"/> value.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if obj has the same value as this instance; otherwise, false.</returns>
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
=> obj is Turn other
|
||||||
|
? number.Equals(other.number)
|
||||||
|
: false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the hash code for this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A 32-bit signed integer hash code.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
=> number.GetHashCode();
|
||||||
|
|
||||||
|
public static int operator -(Turn first, Turn second)
|
||||||
|
=> Math.Abs(first.number - second.number);
|
||||||
|
|
||||||
|
public static bool operator ==(Turn first, Turn second)
|
||||||
|
=> first.number == second.number;
|
||||||
|
|
||||||
|
public static bool operator !=(Turn first, Turn second)
|
||||||
|
=> first.number != second.number;
|
||||||
|
|
||||||
|
public Turn Next => new Turn(number + 1);
|
||||||
|
}
|
|
@ -256,7 +256,7 @@ public class World
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a season by coordinate. Throws if the season is not found.
|
/// Get a season by coordinate. Throws if the season is not found.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Season GetSeason(int turn, int timeline)
|
public Season GetSeason(Turn turn, int timeline)
|
||||||
{
|
{
|
||||||
Season? foundSeason = this.Seasons.SingleOrDefault(
|
Season? foundSeason = this.Seasons.SingleOrDefault(
|
||||||
s => s!.Turn == turn && s.Timeline == timeline,
|
s => s!.Turn == turn && s.Timeline == timeline,
|
||||||
|
@ -282,7 +282,7 @@ public class World
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a unit in a province. Throws if there are duplicate units.
|
/// Returns a unit in a province. Throws if there are duplicate units.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Unit GetUnitAt(string provinceName, (int turn, int timeline)? seasonCoord = null)
|
public Unit GetUnitAt(string provinceName, (Turn turn, int timeline)? seasonCoord = null)
|
||||||
{
|
{
|
||||||
Province province = GetProvince(provinceName);
|
Province province = GetProvince(provinceName);
|
||||||
seasonCoord ??= (this.RootSeason.Turn, this.RootSeason.Timeline);
|
seasonCoord ??= (this.RootSeason.Turn, this.RootSeason.Timeline);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class TimeTravelTest
|
||||||
"Failed to fork timeline when unit moved in");
|
"Failed to fork timeline when unit moved in");
|
||||||
|
|
||||||
// Confirm that there is a unit in Tyr 1:1 originating from Mun 1:0
|
// Confirm that there is a unit in Tyr 1:1 originating from Mun 1:0
|
||||||
Season fork = world.GetSeason(1, 1);
|
Season fork = world.GetSeason(new(1), 1);
|
||||||
Unit originalUnit = world.GetUnitAt("Mun", s0.Coord);
|
Unit originalUnit = world.GetUnitAt("Mun", s0.Coord);
|
||||||
Unit aMun0 = world.GetUnitAt("Mun", s1.Coord);
|
Unit aMun0 = world.GetUnitAt("Mun", s1.Coord);
|
||||||
Unit aTyr = world.GetUnitAt("Tyr", fork.Coord);
|
Unit aTyr = world.GetUnitAt("Tyr", fork.Coord);
|
||||||
|
@ -91,7 +91,7 @@ public class TimeTravelTest
|
||||||
|
|
||||||
// Confirm that an alternate future is created.
|
// Confirm that an alternate future is created.
|
||||||
World world = setup.UpdateWorld();
|
World world = setup.UpdateWorld();
|
||||||
Season fork = world.GetSeason(1, 1);
|
Season fork = world.GetSeason(new(1), 1);
|
||||||
Unit tyr1 = world.GetUnitAt("Tyr", fork.Coord);
|
Unit tyr1 = world.GetUnitAt("Tyr", fork.Coord);
|
||||||
Assert.That(
|
Assert.That(
|
||||||
tyr1.Past,
|
tyr1.Past,
|
||||||
|
@ -140,7 +140,7 @@ public class TimeTravelTest
|
||||||
Is.EqualTo(1),
|
Is.EqualTo(1),
|
||||||
"A failed move incorrectly forked the timeline");
|
"A failed move incorrectly forked the timeline");
|
||||||
Assert.That(s1.Futures.Count(), Is.EqualTo(1));
|
Assert.That(s1.Futures.Count(), Is.EqualTo(1));
|
||||||
Season s2 = world.GetSeason(s1.Turn + 1, s1.Timeline);
|
Season s2 = world.GetSeason(s1.Turn.Next, s1.Timeline);
|
||||||
Assert.That(s2.Futures.Count(), Is.EqualTo(0));
|
Assert.That(s2.Futures.Count(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +182,7 @@ public class TimeTravelTest
|
||||||
Is.EqualTo(1),
|
Is.EqualTo(1),
|
||||||
"A superfluous support incorrectly forked the timeline");
|
"A superfluous support incorrectly forked the timeline");
|
||||||
Assert.That(s1.Futures.Count(), Is.EqualTo(1));
|
Assert.That(s1.Futures.Count(), Is.EqualTo(1));
|
||||||
Season s2 = world.GetSeason(s1.Turn + 1, s1.Timeline);
|
Season s2 = world.GetSeason(s1.Turn.Next, s1.Timeline);
|
||||||
Assert.That(s2.Futures.Count(), Is.EqualTo(0));
|
Assert.That(s2.Futures.Count(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,9 +233,9 @@ public class TimeTravelTest
|
||||||
s1_1.Futures.Count(),
|
s1_1.Futures.Count(),
|
||||||
Is.EqualTo(1),
|
Is.EqualTo(1),
|
||||||
"A cross-timeline support incorrectly forked the head of the timeline");
|
"A cross-timeline support incorrectly forked the head of the timeline");
|
||||||
Season s3_0 = world.GetSeason(s2_0.Turn + 1, s2_0.Timeline);
|
Season s3_0 = world.GetSeason(s2_0.Turn.Next, s2_0.Timeline);
|
||||||
Assert.That(s3_0.Futures.Count(), Is.EqualTo(0));
|
Assert.That(s3_0.Futures.Count(), Is.EqualTo(0));
|
||||||
Season s2_1 = world.GetSeason(s1_1.Turn + 1, s1_1.Timeline);
|
Season s2_1 = world.GetSeason(s1_1.Turn.Next, s1_1.Timeline);
|
||||||
Assert.That(s2_1.Futures.Count(), Is.EqualTo(0));
|
Assert.That(s2_1.Futures.Count(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ public class MovementAdjudicatorTest
|
||||||
Assert.That(future.Past, Is.EqualTo(updated.RootSeason));
|
Assert.That(future.Past, Is.EqualTo(updated.RootSeason));
|
||||||
Assert.That(future.Futures, Is.Empty);
|
Assert.That(future.Futures, Is.Empty);
|
||||||
Assert.That(future.Timeline, Is.EqualTo(updated.RootSeason.Timeline));
|
Assert.That(future.Timeline, Is.EqualTo(updated.RootSeason.Timeline));
|
||||||
Assert.That(future.Turn, Is.EqualTo(Season.FIRST_TURN + 1));
|
Assert.That(future.Turn, Is.EqualTo(Turn.First.Next));
|
||||||
|
|
||||||
// Confirm the unit was created
|
// Confirm the unit was created
|
||||||
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
||||||
|
@ -199,11 +199,11 @@ public class MovementAdjudicatorTest
|
||||||
World updated = setup.UpdateWorld();
|
World updated = setup.UpdateWorld();
|
||||||
|
|
||||||
// Confirm the future was created
|
// Confirm the future was created
|
||||||
Season s2 = updated.GetSeason(1, 0);
|
Season s2 = updated.GetSeason(new(1), 0);
|
||||||
Assert.That(s2.Past, Is.EqualTo(s1));
|
Assert.That(s2.Past, Is.EqualTo(s1));
|
||||||
Assert.That(s2.Futures, Is.Empty);
|
Assert.That(s2.Futures, Is.Empty);
|
||||||
Assert.That(s2.Timeline, Is.EqualTo(s1.Timeline));
|
Assert.That(s2.Timeline, Is.EqualTo(s1.Timeline));
|
||||||
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
Assert.That(s2.Turn, Is.EqualTo(s1.Turn.Next));
|
||||||
|
|
||||||
// Confirm the unit was created in the future
|
// Confirm the unit was created in the future
|
||||||
Unit u2 = updated.GetUnitAt("Mun", s2.Coord);
|
Unit u2 = updated.GetUnitAt("Mun", s2.Coord);
|
||||||
|
@ -227,7 +227,7 @@ public class MovementAdjudicatorTest
|
||||||
|
|
||||||
// Update the world again
|
// Update the world again
|
||||||
updated = setup.UpdateWorld();
|
updated = setup.UpdateWorld();
|
||||||
Season s3 = updated.GetSeason(s2.Turn + 1, s2.Timeline);
|
Season s3 = updated.GetSeason(s2.Turn.Next, s2.Timeline);
|
||||||
Unit u3 = updated.GetUnitAt("Mun", s3.Coord);
|
Unit u3 = updated.GetUnitAt("Mun", s3.Coord);
|
||||||
Assert.That(u3.Past, Is.EqualTo(mun2.Order.Unit));
|
Assert.That(u3.Past, Is.EqualTo(mun2.Order.Unit));
|
||||||
}
|
}
|
||||||
|
@ -249,11 +249,11 @@ public class MovementAdjudicatorTest
|
||||||
World updated = setup.UpdateWorld();
|
World updated = setup.UpdateWorld();
|
||||||
|
|
||||||
// Confirm the future was created
|
// Confirm the future was created
|
||||||
Season s2 = updated.GetSeason(s1.Turn + 1, s1.Timeline);
|
Season s2 = updated.GetSeason(s1.Turn.Next, s1.Timeline);
|
||||||
Assert.That(s2.Past, Is.EqualTo(s1));
|
Assert.That(s2.Past, Is.EqualTo(s1));
|
||||||
Assert.That(s2.Futures, Is.Empty);
|
Assert.That(s2.Futures, Is.Empty);
|
||||||
Assert.That(s2.Timeline, Is.EqualTo(s1.Timeline));
|
Assert.That(s2.Timeline, Is.EqualTo(s1.Timeline));
|
||||||
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
Assert.That(s2.Turn, Is.EqualTo(s1.Turn.Next));
|
||||||
|
|
||||||
// Confirm the unit was created in the future
|
// Confirm the unit was created in the future
|
||||||
Unit u2 = updated.GetUnitAt("Tyr", s2.Coord);
|
Unit u2 = updated.GetUnitAt("Tyr", s2.Coord);
|
||||||
|
@ -277,7 +277,7 @@ public class MovementAdjudicatorTest
|
||||||
|
|
||||||
// Update the world again
|
// Update the world again
|
||||||
updated = setup.UpdateWorld();
|
updated = setup.UpdateWorld();
|
||||||
Season s3 = updated.GetSeason(s2.Turn + 1, s2.Timeline);
|
Season s3 = updated.GetSeason(s2.Turn.Next, s2.Timeline);
|
||||||
Unit u3 = updated.GetUnitAt("Mun", s3.Coord);
|
Unit u3 = updated.GetUnitAt("Mun", s3.Coord);
|
||||||
Assert.That(u3.Past, Is.EqualTo(u2));
|
Assert.That(u3.Past, Is.EqualTo(u2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
|
|
@ -19,7 +19,7 @@ public class TestCaseBuilder
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Choose a new season to define orders for.
|
/// Choose a new season to define orders for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ISeasonContext this[(int turn, int timeline) seasonCoord] { get; }
|
public ISeasonContext this[(Turn turn, int timeline) seasonCoord] { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the context for defining the orders for a power.
|
/// Get the context for defining the orders for a power.
|
||||||
|
@ -40,7 +40,7 @@ public class TestCaseBuilder
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Choose a new season to define orders for.
|
/// Choose a new season to define orders for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ISeasonContext this[(int turn, int timeline) seasonCoord] { get; }
|
public ISeasonContext this[(Turn turn, int timeline) seasonCoord] { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the context for defining the orders for another power.
|
/// Get the context for defining the orders for another power.
|
||||||
|
@ -188,7 +188,7 @@ public class TestCaseBuilder
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Choose a new season to define orders for.
|
/// Choose a new season to define orders for.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ISeasonContext this[(int turn, int timeline) seasonCoord] { get; }
|
public ISeasonContext this[(Turn turn, int timeline) seasonCoord] { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the context for defining the orders for another power.
|
/// Get the context for defining the orders for another power.
|
||||||
|
@ -234,12 +234,12 @@ public class TestCaseBuilder
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the context for defining the orders for a power. Defaults to the root season.
|
/// Get the context for defining the orders for a power. Defaults to the root season.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IPowerContext this[string powerName] => this[(0, 0)][powerName];
|
public IPowerContext this[string powerName] => this[(Turn.First, 0)][powerName];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the context for defining the orders for a season.
|
/// Get the context for defining the orders for a season.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ISeasonContext this[(int turn, int timeline) seasonCoord]
|
public ISeasonContext this[(Turn turn, int timeline) seasonCoord]
|
||||||
=> new SeasonContext(this, this.World.GetSeason(seasonCoord.turn, seasonCoord.timeline));
|
=> new SeasonContext(this, this.World.GetSeason(seasonCoord.turn, seasonCoord.timeline));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -327,7 +327,7 @@ public class TestCaseBuilder
|
||||||
this.Season = season;
|
this.Season = season;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISeasonContext this[(int turn, int timeline) seasonCoord]
|
public ISeasonContext this[(Turn turn, int timeline) seasonCoord]
|
||||||
=> this.Builder[(seasonCoord.turn, seasonCoord.timeline)];
|
=> this.Builder[(seasonCoord.turn, seasonCoord.timeline)];
|
||||||
|
|
||||||
public IPowerContext this[string powerName]
|
public IPowerContext this[string powerName]
|
||||||
|
@ -353,7 +353,7 @@ public class TestCaseBuilder
|
||||||
this.Power = Power;
|
this.Power = Power;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISeasonContext this[(int turn, int timeline) seasonCoord]
|
public ISeasonContext this[(Turn turn, int timeline) seasonCoord]
|
||||||
=> this.SeasonContext[seasonCoord];
|
=> this.SeasonContext[seasonCoord];
|
||||||
|
|
||||||
public IPowerContext this[string powerName]
|
public IPowerContext this[string powerName]
|
||||||
|
@ -623,7 +623,7 @@ public class TestCaseBuilder
|
||||||
return this.Builder;
|
return this.Builder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISeasonContext this[(int turn, int timeline) seasonCoord]
|
public ISeasonContext this[(Turn turn, int timeline) seasonCoord]
|
||||||
=> this.SeasonContext[seasonCoord];
|
=> this.SeasonContext[seasonCoord];
|
||||||
|
|
||||||
public IPowerContext this[string powerName]
|
public IPowerContext this[string powerName]
|
||||||
|
|
12
flake.lock
12
flake.lock
|
@ -17,16 +17,18 @@
|
||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1667292599,
|
"lastModified": 1717179513,
|
||||||
"narHash": "sha256-7ISOUI1aj6UKMPIL+wwthENL22L3+A9V+jS8Is3QsRo=",
|
"narHash": "sha256-vboIEwIQojofItm2xGCdZCzW96U85l9nDW3ifMuAIdM=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "ef2f213d9659a274985778bff4ca322f3ef3ac68",
|
"rev": "63dacb46bf939521bdc93981b4cbb7ecb58427a0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"owner": "NixOS",
|
||||||
"type": "indirect"
|
"ref": "24.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
|
|
12
flake.nix
12
flake.nix
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
description = "5D Diplomacy With Multiversal Time Travel";
|
description = "5D Diplomacy With Multiversal Time Travel";
|
||||||
|
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/24.05";
|
||||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils }:
|
outputs = { self, nixpkgs, flake-utils }:
|
||||||
|
@ -8,11 +9,14 @@
|
||||||
let pkgs = nixpkgs.legacyPackages.${system};
|
let pkgs = nixpkgs.legacyPackages.${system};
|
||||||
in rec {
|
in rec {
|
||||||
devShell = pkgs.mkShell {
|
devShell = pkgs.mkShell {
|
||||||
shellHook = ''
|
|
||||||
PS1='\[\e[0;94m\]\u@\H\[\e[0;93m\] 5dplomacy \[\e[0;92m\]$(git rev-parse --short HEAD)\[\e[0m\]\n\W$ '
|
|
||||||
'';
|
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT = 1;
|
DOTNET_CLI_TELEMETRY_OPTOUT = 1;
|
||||||
packages = [ pkgs.dotnet-sdk pkgs.dotnetPackages.NUnit3 ];
|
NIX_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [ pkgs.stdenv.cc.cc ];
|
||||||
|
NIX_LD = builtins.readFile "${pkgs.stdenv.cc}/nix-support/dynamic-linker";
|
||||||
|
packages = [
|
||||||
|
pkgs.bashInteractive
|
||||||
|
pkgs.dotnet-sdk_8
|
||||||
|
pkgs.dotnetPackages.NUnit3
|
||||||
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in New Issue