Compare commits
No commits in common. "c9bd8c8194d1d6781542ed324ae575786588d95b" and "b17ce9485ad607308b7d1865cf5af6fd7aff158d" have entirely different histories.
c9bd8c8194
...
b17ce9485a
|
@ -61,25 +61,25 @@ public class MovementDecisions
|
||||||
case MoveOrder move:
|
case MoveOrder move:
|
||||||
AdvanceTimeline.Ensure(
|
AdvanceTimeline.Ensure(
|
||||||
move.Season,
|
move.Season,
|
||||||
() => new(move.Season, world.OrderHistory[move.Season.Designation].Orders));
|
() => new(move.Season, world.OrderHistory[move.Season].Orders));
|
||||||
AdvanceTimeline[move.Season].Orders.Add(move);
|
AdvanceTimeline[move.Season].Orders.Add(move);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SupportHoldOrder supportHold:
|
case SupportHoldOrder supportHold:
|
||||||
AdvanceTimeline.Ensure(
|
AdvanceTimeline.Ensure(
|
||||||
supportHold.Target.Season,
|
supportHold.Target.Season,
|
||||||
() => new(supportHold.Target.Season, world.OrderHistory[supportHold.Target.Season.Designation].Orders));
|
() => new(supportHold.Target.Season, world.OrderHistory[supportHold.Target.Season].Orders));
|
||||||
AdvanceTimeline[supportHold.Target.Season].Orders.Add(supportHold);
|
AdvanceTimeline[supportHold.Target.Season].Orders.Add(supportHold);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SupportMoveOrder supportMove:
|
case SupportMoveOrder supportMove:
|
||||||
AdvanceTimeline.Ensure(
|
AdvanceTimeline.Ensure(
|
||||||
supportMove.Target.Season,
|
supportMove.Target.Season,
|
||||||
() => new(supportMove.Target.Season, world.OrderHistory[supportMove.Target.Season.Designation].Orders));
|
() => new(supportMove.Target.Season, world.OrderHistory[supportMove.Target.Season].Orders));
|
||||||
AdvanceTimeline[supportMove.Target.Season].Orders.Add(supportMove);
|
AdvanceTimeline[supportMove.Target.Season].Orders.Add(supportMove);
|
||||||
AdvanceTimeline.Ensure(
|
AdvanceTimeline.Ensure(
|
||||||
supportMove.Season,
|
supportMove.Season,
|
||||||
() => new(supportMove.Season, world.OrderHistory[supportMove.Season.Designation].Orders));
|
() => new(supportMove.Season, world.OrderHistory[supportMove.Season].Orders));
|
||||||
AdvanceTimeline[supportMove.Season].Orders.Add(supportMove);
|
AdvanceTimeline[supportMove.Season].Orders.Add(supportMove);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,9 +312,9 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
|
|
||||||
// All moves to a particular season in a single phase result in the same future. Keep a
|
// All moves to a particular season in a single phase result in the same future. Keep a
|
||||||
// record of when a future season has been created.
|
// record of when a future season has been created.
|
||||||
Dictionary<Season, Season> createdFutures = [];
|
Dictionary<Season, Season> createdFutures = new();
|
||||||
List<Unit> createdUnits = [];
|
List<Unit> createdUnits = new();
|
||||||
List<RetreatingUnit> retreats = [];
|
List<RetreatingUnit> retreats = new();
|
||||||
|
|
||||||
// Populate createdFutures with the timeline fork decisions
|
// Populate createdFutures with the timeline fork decisions
|
||||||
logger.Log(1, "Processing AdvanceTimeline decisions");
|
logger.Log(1, "Processing AdvanceTimeline decisions");
|
||||||
|
@ -324,7 +324,9 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
if (advanceTimeline.Outcome == true)
|
if (advanceTimeline.Outcome == true)
|
||||||
{
|
{
|
||||||
// A timeline that doesn't have a future yet simply continues. Otherwise, it forks.
|
// A timeline that doesn't have a future yet simply continues. Otherwise, it forks.
|
||||||
createdFutures[advanceTimeline.Season] = world.ContinueOrFork(advanceTimeline.Season);
|
createdFutures[advanceTimeline.Season] = !world.GetFutures(advanceTimeline.Season).Any()
|
||||||
|
? advanceTimeline.Season.MakeNext()
|
||||||
|
: advanceTimeline.Season.MakeFork();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,11 +386,11 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the adjudication results to the season's order history
|
// Record the adjudication results to the season's order history
|
||||||
Dictionary<string, OrderHistory> newHistory = [];
|
Dictionary<Season, OrderHistory> newHistory = new();
|
||||||
foreach (UnitOrder unitOrder in decisions.OfType<IsDislodged>().Select(d => d.Order))
|
foreach (UnitOrder unitOrder in decisions.OfType<IsDislodged>().Select(d => d.Order))
|
||||||
{
|
{
|
||||||
newHistory.Ensure(unitOrder.Unit.Season.Designation, () => new());
|
newHistory.Ensure(unitOrder.Unit.Season, () => new());
|
||||||
OrderHistory history = newHistory[unitOrder.Unit.Season.Designation];
|
OrderHistory history = newHistory[unitOrder.Unit.Season];
|
||||||
// TODO does this add every order to every season??
|
// TODO does this add every order to every season??
|
||||||
history.Orders.Add(unitOrder);
|
history.Orders.Add(unitOrder);
|
||||||
history.IsDislodgedOutcomes[unitOrder.Unit] = dislodges[unitOrder.Unit].Outcome == true;
|
history.IsDislodgedOutcomes[unitOrder.Unit] = dislodges[unitOrder.Unit].Outcome == true;
|
||||||
|
@ -399,7 +401,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log the new order history
|
// Log the new order history
|
||||||
foreach ((string season, OrderHistory history) in newHistory)
|
foreach ((Season season, OrderHistory history) in newHistory)
|
||||||
{
|
{
|
||||||
string verb = world.OrderHistory.ContainsKey(season) ? "Updating" : "Adding";
|
string verb = world.OrderHistory.ContainsKey(season) ? "Updating" : "Adding";
|
||||||
logger.Log(1, "{0} history for {1}", verb, season);
|
logger.Log(1, "{0} history for {1}", verb, season);
|
||||||
|
@ -409,7 +411,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerable<KeyValuePair<string, OrderHistory>> updatedHistory = world.OrderHistory
|
IEnumerable<KeyValuePair<Season, OrderHistory>> updatedHistory = world.OrderHistory
|
||||||
.Where(kvp => !newHistory.ContainsKey(kvp.Key))
|
.Where(kvp => !newHistory.ContainsKey(kvp.Key))
|
||||||
.Concat(newHistory);
|
.Concat(newHistory);
|
||||||
|
|
||||||
|
@ -494,7 +496,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
IEnumerable<MoveOrder> newIncomingMoves = decision.Orders
|
IEnumerable<MoveOrder> newIncomingMoves = decision.Orders
|
||||||
.OfType<MoveOrder>()
|
.OfType<MoveOrder>()
|
||||||
.Where(order => order.Season == decision.Season
|
.Where(order => order.Season == decision.Season
|
||||||
&& !world.OrderHistory[order.Season.Designation].DoesMoveOutcomes.ContainsKey(order));
|
&& !world.OrderHistory[order.Season].DoesMoveOutcomes.ContainsKey(order));
|
||||||
foreach (MoveOrder moveOrder in newIncomingMoves)
|
foreach (MoveOrder moveOrder in newIncomingMoves)
|
||||||
{
|
{
|
||||||
DoesMove doesMove = decisions.DoesMove[moveOrder];
|
DoesMove doesMove = decisions.DoesMove[moveOrder];
|
||||||
|
@ -511,7 +513,7 @@ public class MovementPhaseAdjudicator : IPhaseAdjudicator
|
||||||
// 1. The outcome of a dislodge decision is changed,
|
// 1. The outcome of a dislodge decision is changed,
|
||||||
// 2. The outcome of an intra-timeline move decision is changed, or
|
// 2. The outcome of an intra-timeline move decision is changed, or
|
||||||
// 3. The outcome of an inter-timeline move decision with that season as the destination is changed.
|
// 3. The outcome of an inter-timeline move decision with that season as the destination is changed.
|
||||||
OrderHistory history = world.OrderHistory[decision.Season.Designation];
|
OrderHistory history = world.OrderHistory[decision.Season];
|
||||||
bool anyUnresolved = false;
|
bool anyUnresolved = false;
|
||||||
foreach (UnitOrder order in decision.Orders)
|
foreach (UnitOrder order in decision.Orders)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
using CommandLine;
|
|
||||||
|
|
||||||
namespace MultiversalDiplomacy.CommandLine;
|
|
||||||
|
|
||||||
[Verb("image", HelpText = "Generate an image of a game state.")]
|
|
||||||
public class ImageOptions
|
|
||||||
{
|
|
||||||
[Value(0, HelpText = "Input file describing the game state to visualize, or - to read from stdin.")]
|
|
||||||
public string? InputFile { get; set; }
|
|
||||||
|
|
||||||
public static void Execute(ImageOptions args)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
using CommandLine;
|
|
||||||
|
|
||||||
namespace MultiversalDiplomacy.CommandLine;
|
|
||||||
|
|
||||||
[Verb("repl", HelpText = "Begin an interactive 5dplomacy session.")]
|
|
||||||
public class ReplOptions
|
|
||||||
{
|
|
||||||
[Option('i', "input", HelpText = "Begin the repl session by executing the commands in this file.")]
|
|
||||||
public string? InputFile { get; set; }
|
|
||||||
|
|
||||||
[Option('o', "output", HelpText = "Echo the repl session to this file. Specify a directory to autogenerate a filename.")]
|
|
||||||
public string? OutputFile { get; set; }
|
|
||||||
|
|
||||||
public static void Execute(ReplOptions args)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,3 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MultiversalDiplomacy.Model;
|
namespace MultiversalDiplomacy.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -11,12 +9,8 @@ public class Location
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The province to which this location belongs.
|
/// The province to which this location belongs.
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public Province Province { get; }
|
public Province Province { get; }
|
||||||
|
|
||||||
public string ProvinceName => Province.Name;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The location's full human-readable name.
|
/// The location's full human-readable name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -35,7 +29,6 @@ public class Location
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The locations that border this location.
|
/// The locations that border this location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
public IEnumerable<Location> Adjacents => this.AdjacentList;
|
public IEnumerable<Location> Adjacents => this.AdjacentList;
|
||||||
private List<Location> AdjacentList { get; set; }
|
private List<Location> AdjacentList { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,7 @@ namespace MultiversalDiplomacy.Model;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encapsulation of the world map and playable powers constituting a Diplomacy variant.
|
/// Encapsulation of the world map and playable powers constituting a Diplomacy variant.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Map
|
public class Map {
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The map type.
|
|
||||||
/// </summary>
|
|
||||||
public MapType Type { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The game map.
|
/// The game map.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -22,7 +16,7 @@ public class Map
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReadOnlyCollection<Power> Powers { get; }
|
public ReadOnlyCollection<Power> Powers { get; }
|
||||||
|
|
||||||
private Map(MapType type, IEnumerable<Province> provinces, IEnumerable<Power> powers)
|
private Map(IEnumerable<Province> provinces, IEnumerable<Power> powers)
|
||||||
{
|
{
|
||||||
Provinces = new(provinces.ToList());
|
Provinces = new(provinces.ToList());
|
||||||
Powers = new(powers.ToList());
|
Powers = new(powers.ToList());
|
||||||
|
@ -108,7 +102,7 @@ public class Map
|
||||||
Power a = new("Alpha");
|
Power a = new("Alpha");
|
||||||
Power b = new("Beta");
|
Power b = new("Beta");
|
||||||
|
|
||||||
return new(MapType.Test, [lef, cen, rig], [a, b]);
|
return new([lef, cen, rig], [a, b]);
|
||||||
});
|
});
|
||||||
|
|
||||||
public static Map Classical => _Classical.Value;
|
public static Map Classical => _Classical.Value;
|
||||||
|
@ -559,7 +553,7 @@ public class Map
|
||||||
new("Turkey"),
|
new("Turkey"),
|
||||||
];
|
];
|
||||||
|
|
||||||
return new(MapType.Classical, provinces, powers);
|
return new(provinces, powers);
|
||||||
});
|
});
|
||||||
|
|
||||||
#endregion Variants
|
#endregion Variants
|
||||||
|
|
|
@ -20,10 +20,4 @@ public static class ModelExtensions
|
||||||
{
|
{
|
||||||
return $"{coord.season.Timeline}-{coord.province.Abbreviations[0]}@{coord.season.Turn}";
|
return $"{coord.season.Timeline}-{coord.province.Abbreviations[0]}@{coord.season.Turn}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static World ContinueOrFork(this World world, Season season, out Season future)
|
|
||||||
{
|
|
||||||
future = world.ContinueOrFork(season);
|
|
||||||
return world.Update(seasons: world.Seasons.Append(future));
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -13,7 +13,7 @@ public class OrderHistory
|
||||||
public Dictionary<MoveOrder, bool> DoesMoveOutcomes;
|
public Dictionary<MoveOrder, bool> DoesMoveOutcomes;
|
||||||
|
|
||||||
public OrderHistory()
|
public OrderHistory()
|
||||||
: this([], [], [])
|
: this(new(), new(), new())
|
||||||
{}
|
{}
|
||||||
|
|
||||||
public OrderHistory(
|
public OrderHistory(
|
||||||
|
|
|
@ -5,10 +5,10 @@ namespace MultiversalDiplomacy.Model;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a state of the map produced by a set of move orders on a previous season.
|
/// Represents a state of the map produced by a set of move orders on a previous season.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Season(string? past, int turn, string timeline)
|
public class Season
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The first turn number. This is defined to reduce confusion about whether the first turn is 0 or 1.
|
/// The first turn number.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int FIRST_TURN = 0;
|
public const int FIRST_TURN = 0;
|
||||||
|
|
||||||
|
@ -17,19 +17,19 @@ public class Season(string? past, int turn, string timeline)
|
||||||
/// 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.
|
||||||
/// The initial season does not have a past.
|
/// The initial season does not have a past.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Past { get; } = past;
|
public string? Past { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current turn, beginning at 0. Each season (spring and fall) is one turn.
|
/// 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.
|
/// 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; } = turn;
|
public int Turn { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The timeline to which this season belongs.
|
/// The timeline to which this season belongs.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Timeline { get; } = timeline;
|
public string Timeline { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The multiversal designation of this season.
|
/// The multiversal designation of this season.
|
||||||
|
@ -37,5 +37,50 @@ public class Season(string? past, int turn, string timeline)
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public string Designation => $"{this.Timeline}{this.Turn}";
|
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; }
|
||||||
|
|
||||||
|
private Season(Season? past, int turn, string timeline, TimelineFactory factory)
|
||||||
|
{
|
||||||
|
this.Past = past?.ToString();
|
||||||
|
this.Turn = turn;
|
||||||
|
this.Timeline = timeline;
|
||||||
|
this.Timelines = factory;
|
||||||
|
}
|
||||||
|
|
||||||
public override string ToString() => Designation;
|
public override string ToString() => Designation;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a root season at the beginning of time.
|
||||||
|
/// </summary>
|
||||||
|
public static Season MakeRoot()
|
||||||
|
{
|
||||||
|
TimelineFactory factory = new TimelineFactory();
|
||||||
|
return new Season(
|
||||||
|
past: null,
|
||||||
|
turn: FIRST_TURN,
|
||||||
|
timeline: factory.NextTimeline(),
|
||||||
|
factory: factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a season immediately after this one in the same timeline.
|
||||||
|
/// </summary>
|
||||||
|
public Season MakeNext()
|
||||||
|
=> new(this, Turn + 1, Timeline, Timelines);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a season immediately after this one in a new timeline.
|
||||||
|
/// </summary>
|
||||||
|
public Season MakeFork()
|
||||||
|
=> new(this, Turn + 1, Timelines.NextTimeline(), Timelines);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ namespace MultiversalDiplomacy.Model;
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A shared counter for handing out new timeline designations.
|
/// A shared counter for handing out new timeline designations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class TimelineFactory
|
internal class TimelineFactory
|
||||||
{
|
{
|
||||||
private static readonly char[] Letters = [
|
private static readonly char[] Letters = [
|
||||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
|
||||||
namespace MultiversalDiplomacy.Model;
|
namespace MultiversalDiplomacy.Model;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -20,7 +18,6 @@ public class Unit
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The province where the unit is.
|
/// The province where the unit is.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
public Province Province => this.Location.Province;
|
public Province Province => this.Location.Province;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -62,11 +59,11 @@ public class Unit
|
||||||
/// method after accepting a build order.
|
/// method after accepting a build order.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static Unit Build(Location location, Season season, Power power, UnitType type)
|
public static Unit Build(Location location, Season season, Power power, UnitType type)
|
||||||
=> new(past: null, location, season, power, type);
|
=> new Unit(past: null, location, season, power, type);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Advance this unit's timeline to a new location and season.
|
/// Advance this unit's timeline to a new location and season.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Unit Next(Location location, Season season)
|
public Unit Next(Location location, Season season)
|
||||||
=> new(past: this, location, season, this.Power, this.Type);
|
=> new Unit(past: this, location, season, this.Power, this.Type);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Text.Json.Serialization;
|
|
||||||
|
using MultiversalDiplomacy.Orders;
|
||||||
|
|
||||||
namespace MultiversalDiplomacy.Model;
|
namespace MultiversalDiplomacy.Model;
|
||||||
|
|
||||||
|
@ -11,24 +12,16 @@ public class World
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The map variant of the game.
|
/// The map variant of the game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
public readonly Map Map;
|
||||||
public Map Map { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The map variant of the game.
|
|
||||||
/// </summary>
|
|
||||||
public MapType MapType => this.Map.Type;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The game map.
|
/// The game map.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
public ReadOnlyCollection<Province> Provinces => this.Map.Provinces;
|
public ReadOnlyCollection<Province> Provinces => this.Map.Provinces;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The game powers.
|
/// The game powers.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
public ReadOnlyCollection<Power> Powers => this.Map.Powers;
|
public ReadOnlyCollection<Power> Powers => this.Map.Powers;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -39,13 +32,11 @@ public class World
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lookup for seasons by designation.
|
/// Lookup for seasons by designation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
public ReadOnlyDictionary<string, Season> SeasonLookup { get; }
|
public ReadOnlyDictionary<string, Season> SeasonLookup { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The first season of the game.
|
/// The first season of the game.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonIgnore]
|
|
||||||
public Season RootSeason => GetSeason("a0");
|
public Season RootSeason => GetSeason("a0");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -61,12 +52,7 @@ public class World
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Orders given to units in each season.
|
/// Orders given to units in each season.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReadOnlyDictionary<string, OrderHistory> OrderHistory { get; }
|
public ReadOnlyDictionary<Season, OrderHistory> OrderHistory { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The shared timeline number generator.
|
|
||||||
/// </summary>
|
|
||||||
public TimelineFactory Timelines { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Immutable game options.
|
/// Immutable game options.
|
||||||
|
@ -81,8 +67,7 @@ public class World
|
||||||
ReadOnlyCollection<Season> seasons,
|
ReadOnlyCollection<Season> seasons,
|
||||||
ReadOnlyCollection<Unit> units,
|
ReadOnlyCollection<Unit> units,
|
||||||
ReadOnlyCollection<RetreatingUnit> retreatingUnits,
|
ReadOnlyCollection<RetreatingUnit> retreatingUnits,
|
||||||
ReadOnlyDictionary<string, OrderHistory> orderHistory,
|
ReadOnlyDictionary<Season, OrderHistory> orderHistory,
|
||||||
TimelineFactory timelines,
|
|
||||||
Options options)
|
Options options)
|
||||||
{
|
{
|
||||||
this.Map = map;
|
this.Map = map;
|
||||||
|
@ -90,7 +75,6 @@ public class World
|
||||||
this.Units = units;
|
this.Units = units;
|
||||||
this.RetreatingUnits = retreatingUnits;
|
this.RetreatingUnits = retreatingUnits;
|
||||||
this.OrderHistory = orderHistory;
|
this.OrderHistory = orderHistory;
|
||||||
this.Timelines = timelines;
|
|
||||||
this.Options = options;
|
this.Options = options;
|
||||||
|
|
||||||
this.SeasonLookup = new(Seasons.ToDictionary(season => $"{season.Timeline}{season.Turn}"));
|
this.SeasonLookup = new(Seasons.ToDictionary(season => $"{season.Timeline}{season.Turn}"));
|
||||||
|
@ -104,7 +88,7 @@ public class World
|
||||||
ReadOnlyCollection<Season>? seasons = null,
|
ReadOnlyCollection<Season>? seasons = null,
|
||||||
ReadOnlyCollection<Unit>? units = null,
|
ReadOnlyCollection<Unit>? units = null,
|
||||||
ReadOnlyCollection<RetreatingUnit>? retreatingUnits = null,
|
ReadOnlyCollection<RetreatingUnit>? retreatingUnits = null,
|
||||||
ReadOnlyDictionary<string, OrderHistory>? orderHistory = null,
|
ReadOnlyDictionary<Season, OrderHistory>? orderHistory = null,
|
||||||
Options? options = null)
|
Options? options = null)
|
||||||
: this(
|
: this(
|
||||||
previous.Map,
|
previous.Map,
|
||||||
|
@ -112,7 +96,6 @@ public class World
|
||||||
units ?? previous.Units,
|
units ?? previous.Units,
|
||||||
retreatingUnits ?? previous.RetreatingUnits,
|
retreatingUnits ?? previous.RetreatingUnits,
|
||||||
orderHistory ?? previous.OrderHistory,
|
orderHistory ?? previous.OrderHistory,
|
||||||
previous.Timelines,
|
|
||||||
options ?? previous.Options)
|
options ?? previous.Options)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -122,14 +105,12 @@ public class World
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static World WithMap(Map map)
|
public static World WithMap(Map map)
|
||||||
{
|
{
|
||||||
TimelineFactory timelines = new();
|
|
||||||
return new World(
|
return new World(
|
||||||
map,
|
map,
|
||||||
new([new(past: null, Season.FIRST_TURN, timelines.NextTimeline())]),
|
new([Season.MakeRoot()]),
|
||||||
new([]),
|
new([]),
|
||||||
new([]),
|
new([]),
|
||||||
new(new Dictionary<string, OrderHistory>()),
|
new(new Dictionary<Season, OrderHistory>()),
|
||||||
timelines,
|
|
||||||
new Options());
|
new Options());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +124,7 @@ public class World
|
||||||
IEnumerable<Season>? seasons = null,
|
IEnumerable<Season>? seasons = null,
|
||||||
IEnumerable<Unit>? units = null,
|
IEnumerable<Unit>? units = null,
|
||||||
IEnumerable<RetreatingUnit>? retreats = null,
|
IEnumerable<RetreatingUnit>? retreats = null,
|
||||||
IEnumerable<KeyValuePair<string, OrderHistory>>? orders = null)
|
IEnumerable<KeyValuePair<Season, OrderHistory>>? orders = null)
|
||||||
=> new(
|
=> new(
|
||||||
previous: this,
|
previous: this,
|
||||||
seasons: seasons == null
|
seasons: seasons == null
|
||||||
|
@ -219,17 +200,28 @@ public class World
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a continuation of this season if it has no futures, otherwise ceate a fork.
|
/// Create a season immediately after this one in the same timeline.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Season ContinueOrFork(Season season)
|
public World ContinueSeason(string season)
|
||||||
=> GetFutures(season).Any()
|
=> Update(seasons: Seasons.Append(SeasonLookup[season].MakeNext()));
|
||||||
? new(season.Designation, season.Turn + 1, Timelines.NextTimeline())
|
|
||||||
: new(season.Designation, season.Turn + 1, season.Timeline);
|
/// <summary>
|
||||||
|
/// Create a season immediately after this one in the same timeline.
|
||||||
|
/// </summary>
|
||||||
|
public World ContinueSeason(Season season) => ContinueSeason(season.ToString());
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a season immediately after this one in a new timeline.
|
||||||
|
/// </summary>
|
||||||
|
public World ForkSeason(string season)
|
||||||
|
=> Update(seasons: Seasons.Append(SeasonLookup[season].MakeFork()));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A standard Diplomacy game setup.
|
/// A standard Diplomacy game setup.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static World Standard => WithStandardMap().AddStandardUnits();
|
public static World Standard => World
|
||||||
|
.WithStandardMap()
|
||||||
|
.AddStandardUnits();
|
||||||
|
|
||||||
/// <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.
|
||||||
|
@ -296,10 +288,11 @@ 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, Season? season = null)
|
public Unit GetUnitAt(string provinceName, (string timeline, int turn)? seasonCoord = null)
|
||||||
{
|
{
|
||||||
Province province = Map.GetProvince(provinceName);
|
Province province = Map.GetProvince(provinceName);
|
||||||
season ??= RootSeason;
|
seasonCoord ??= (this.RootSeason.Timeline, this.RootSeason.Turn);
|
||||||
|
Season season = GetSeason(seasonCoord.Value.timeline, seasonCoord.Value.turn);
|
||||||
Unit? foundUnit = this.Units.SingleOrDefault(
|
Unit? foundUnit = this.Units.SingleOrDefault(
|
||||||
u => u!.Province == province && u.Season == season,
|
u => u!.Province == province && u.Season == season,
|
||||||
null)
|
null)
|
||||||
|
|
|
@ -9,15 +9,9 @@ internal class Program
|
||||||
static void Main(string[] args)
|
static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var parser = Parser.Default;
|
var parser = Parser.Default;
|
||||||
var parseResult = parser.ParseArguments(
|
var parseResult = parser.ParseArguments<AdjudicateOptions>(args);
|
||||||
args,
|
|
||||||
typeof(AdjudicateOptions),
|
|
||||||
typeof(ImageOptions),
|
|
||||||
typeof(ReplOptions));
|
|
||||||
|
|
||||||
parseResult
|
parseResult
|
||||||
.WithParsed<AdjudicateOptions>(AdjudicateOptions.Execute)
|
.WithParsed(AdjudicateOptions.Execute);
|
||||||
.WithParsed<ImageOptions>(ImageOptions.Execute)
|
|
||||||
.WithParsed<ReplOptions>(ReplOptions.Execute);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,14 +43,14 @@ public class TimeTravelTest
|
||||||
|
|
||||||
// Confirm that there is a unit in Tyr b1 originating from Mun a1
|
// Confirm that there is a unit in Tyr b1 originating from Mun a1
|
||||||
Season fork = world.GetSeason("b1");
|
Season fork = world.GetSeason("b1");
|
||||||
Unit originalUnit = world.GetUnitAt("Mun", s0);
|
Unit originalUnit = world.GetUnitAt("Mun", s0.Coord);
|
||||||
Unit aMun0 = world.GetUnitAt("Mun", s1);
|
Unit aMun0 = world.GetUnitAt("Mun", s1.Coord);
|
||||||
Unit aTyr = world.GetUnitAt("Tyr", fork);
|
Unit aTyr = world.GetUnitAt("Tyr", fork.Coord);
|
||||||
Assert.That(aTyr.Past, Is.EqualTo(mun1.Order.Unit));
|
Assert.That(aTyr.Past, Is.EqualTo(mun1.Order.Unit));
|
||||||
Assert.That(aTyr.Past?.Past, Is.EqualTo(mun0.Order.Unit));
|
Assert.That(aTyr.Past?.Past, Is.EqualTo(mun0.Order.Unit));
|
||||||
|
|
||||||
// Confirm that there is a unit in Mun b1 originating from Mun a0
|
// Confirm that there is a unit in Mun b1 originating from Mun a0
|
||||||
Unit aMun1 = world.GetUnitAt("Mun", fork);
|
Unit aMun1 = world.GetUnitAt("Mun", fork.Coord);
|
||||||
Assert.That(aMun1.Past, Is.EqualTo(originalUnit));
|
Assert.That(aMun1.Past, Is.EqualTo(originalUnit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +92,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("b1");
|
Season fork = world.GetSeason("b1");
|
||||||
Unit tyr1 = world.GetUnitAt("Tyr", fork);
|
Unit tyr1 = world.GetUnitAt("Tyr", fork.Coord);
|
||||||
Assert.That(
|
Assert.That(
|
||||||
tyr1.Past,
|
tyr1.Past,
|
||||||
Is.EqualTo(mun0.Order.Unit),
|
Is.EqualTo(mun0.Order.Unit),
|
||||||
|
|
|
@ -206,7 +206,7 @@ public class MovementAdjudicatorTest
|
||||||
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
||||||
|
|
||||||
// Confirm the unit was created in the future
|
// Confirm the unit was created in the future
|
||||||
Unit u2 = updated.GetUnitAt("Mun", s2);
|
Unit u2 = updated.GetUnitAt("Mun", s2.Coord);
|
||||||
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
||||||
Assert.That(u2, Is.Not.EqualTo(mun1.Order.Unit));
|
Assert.That(u2, Is.Not.EqualTo(mun1.Order.Unit));
|
||||||
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
|
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
|
||||||
|
@ -228,7 +228,7 @@ public class MovementAdjudicatorTest
|
||||||
// Update the world again
|
// Update the world again
|
||||||
updated = setup.UpdateWorld();
|
updated = setup.UpdateWorld();
|
||||||
Season s3 = updated.GetSeason(s2.Timeline, s2.Turn + 1);
|
Season s3 = updated.GetSeason(s2.Timeline, s2.Turn + 1);
|
||||||
Unit u3 = updated.GetUnitAt("Mun", s3);
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +256,7 @@ public class MovementAdjudicatorTest
|
||||||
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
Assert.That(s2.Turn, Is.EqualTo(s1.Turn + 1));
|
||||||
|
|
||||||
// Confirm the unit was created in the future
|
// Confirm the unit was created in the future
|
||||||
Unit u2 = updated.GetUnitAt("Tyr", s2);
|
Unit u2 = updated.GetUnitAt("Tyr", s2.Coord);
|
||||||
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
Assert.That(updated.Units.Count, Is.EqualTo(2));
|
||||||
Assert.That(u2, Is.Not.EqualTo(mun1.Order.Unit));
|
Assert.That(u2, Is.Not.EqualTo(mun1.Order.Unit));
|
||||||
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
|
Assert.That(u2.Past, Is.EqualTo(mun1.Order.Unit));
|
||||||
|
@ -278,7 +278,7 @@ public class MovementAdjudicatorTest
|
||||||
// Update the world again
|
// Update the world again
|
||||||
updated = setup.UpdateWorld();
|
updated = setup.UpdateWorld();
|
||||||
Season s3 = updated.GetSeason(s2.Timeline, s2.Turn + 1);
|
Season s3 = updated.GetSeason(s2.Timeline, s2.Turn + 1);
|
||||||
Unit u3 = updated.GetUnitAt("Mun", s3);
|
Unit u3 = updated.GetUnitAt("Mun", s3.Coord);
|
||||||
Assert.That(u3.Past, Is.EqualTo(u2));
|
Assert.That(u3.Past, Is.EqualTo(u2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,22 +9,30 @@ public class SeasonTests
|
||||||
[Test]
|
[Test]
|
||||||
public void TimelineForking()
|
public void TimelineForking()
|
||||||
{
|
{
|
||||||
World world = World.WithMap(Map.Test);
|
World world = World
|
||||||
Season a0 = world.GetSeason("a0");
|
.WithMap(Map.Test)
|
||||||
world = world
|
.ContinueSeason("a0")
|
||||||
.ContinueOrFork(a0, out Season a1)
|
.ContinueSeason("a1")
|
||||||
.ContinueOrFork(a1, out Season a2)
|
.ContinueSeason("a2")
|
||||||
.ContinueOrFork(a2, out Season a3)
|
.ForkSeason("a1")
|
||||||
.ContinueOrFork(a1, out Season b2)
|
.ContinueSeason("b2")
|
||||||
.ContinueOrFork(b2, out Season b3)
|
.ForkSeason("a1")
|
||||||
.ContinueOrFork(a1, out Season c2)
|
.ForkSeason("a2");
|
||||||
.ContinueOrFork(a2, out Season d3);
|
|
||||||
|
|
||||||
Assert.That(
|
Assert.That(
|
||||||
world.Seasons.Select(season => season.ToString()),
|
world.Seasons.Select(season => season.ToString()),
|
||||||
Is.EquivalentTo(new List<string> { "a0", "a1", "a2", "a3", "b2", "b3", "c2", "d3" }),
|
Is.EquivalentTo(new List<string> { "a0", "a1", "a2", "a3", "b2", "b3", "c2", "d3" }),
|
||||||
"Unexpected seasons");
|
"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(a0.Timeline, Is.EqualTo("a"), "Unexpected trunk timeline");
|
||||||
Assert.That(a1.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(a2.Timeline, Is.EqualTo("a"), "Unexpected trunk timeline");
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
using System.Text.Json;
|
|
||||||
|
|
||||||
using MultiversalDiplomacy.Adjudicate;
|
|
||||||
using MultiversalDiplomacy.Model;
|
|
||||||
|
|
||||||
using NUnit.Framework;
|
|
||||||
|
|
||||||
namespace MultiversalDiplomacyTests;
|
|
||||||
|
|
||||||
public class SerializationTest
|
|
||||||
{
|
|
||||||
[Test]
|
|
||||||
public void SerializeRoundTrip_NewGame()
|
|
||||||
{
|
|
||||||
JsonSerializerOptions options = new() {
|
|
||||||
WriteIndented = true,
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
};
|
|
||||||
|
|
||||||
World world = World.WithStandardMap();
|
|
||||||
string serialized = JsonSerializer.Serialize(world, options);
|
|
||||||
Console.WriteLine(serialized);
|
|
||||||
World? deserialized = JsonSerializer.Deserialize<World>(serialized, options);
|
|
||||||
Assert.That(deserialized, Is.Not.Null, "Failed to deserialize");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SerializeRoundTrip_MDATC_3_A_2()
|
|
||||||
{
|
|
||||||
// Set up MDATC 3.A.2
|
|
||||||
TestCaseBuilder setup = new(World.WithStandardMap(), MovementPhaseAdjudicator.Instance);
|
|
||||||
setup[("a", 0)]
|
|
||||||
.GetReference(out Season s0)
|
|
||||||
["Germany"]
|
|
||||||
.Army("Mun").MovesTo("Tyr").GetReference(out var mun0)
|
|
||||||
["Austria"]
|
|
||||||
.Army("Tyr").Holds().GetReference(out var tyr0);
|
|
||||||
|
|
||||||
setup.ValidateOrders();
|
|
||||||
Assert.That(mun0, Is.Valid);
|
|
||||||
Assert.That(tyr0, Is.Valid);
|
|
||||||
setup.AdjudicateOrders();
|
|
||||||
Assert.That(mun0, Is.Repelled);
|
|
||||||
Assert.That(tyr0, Is.NotDislodged);
|
|
||||||
setup.UpdateWorld();
|
|
||||||
|
|
||||||
// Serialize the world
|
|
||||||
JsonSerializerOptions options = new() {
|
|
||||||
WriteIndented = true,
|
|
||||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
||||||
};
|
|
||||||
JsonElement serialized = JsonSerializer.SerializeToDocument(setup.World, options).RootElement;
|
|
||||||
|
|
||||||
Assert.That(
|
|
||||||
serialized.EnumerateObject().Select(prop => prop.Name),
|
|
||||||
Is.EquivalentTo(new List<string> {
|
|
||||||
"mapType",
|
|
||||||
"seasons",
|
|
||||||
"units",
|
|
||||||
"retreatingUnits",
|
|
||||||
"orderHistory",
|
|
||||||
"options",
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Deserialize the world
|
|
||||||
World reserialized = JsonSerializer.Deserialize<World>(serialized)
|
|
||||||
?? throw new AssertionException("Failed to reserialize world");
|
|
||||||
|
|
||||||
// Resume the test case
|
|
||||||
setup = new(reserialized, MovementPhaseAdjudicator.Instance);
|
|
||||||
setup[("a", 1)]
|
|
||||||
["Germany"]
|
|
||||||
.Army("Mun").Supports.Army("Mun", season: reserialized.GetSeason("a0")).MoveTo("Tyr").GetReference(out var mun1)
|
|
||||||
["Austria"]
|
|
||||||
.Army("Tyr").Holds();
|
|
||||||
|
|
||||||
setup.ValidateOrders();
|
|
||||||
Assert.That(mun1, Is.Valid);
|
|
||||||
setup.AdjudicateOrders();
|
|
||||||
Assert.That(mun1, Is.NotCut);
|
|
||||||
Assert.That(mun0, Is.Victorious);
|
|
||||||
Assert.That(tyr0, Is.Dislodged);
|
|
||||||
|
|
||||||
// Confirm that an alternate future is created.
|
|
||||||
World world = setup.UpdateWorld();
|
|
||||||
Season fork = world.GetSeason("b1");
|
|
||||||
Unit tyr1 = world.GetUnitAt("Tyr", fork);
|
|
||||||
Assert.That(
|
|
||||||
tyr1.Past,
|
|
||||||
Is.EqualTo(mun0.Order.Unit),
|
|
||||||
"Expected A Mun a0 to advance to Tyr b1");
|
|
||||||
Assert.That(
|
|
||||||
world.RetreatingUnits.Count,
|
|
||||||
Is.EqualTo(1),
|
|
||||||
"Expected A Tyr a0 to be in retreat");
|
|
||||||
Assert.That(world.RetreatingUnits.First().Unit, Is.EqualTo(tyr0.Order.Unit));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,10 +17,12 @@ public class UnitTests
|
||||||
Season a0 = world.RootSeason;
|
Season a0 = world.RootSeason;
|
||||||
Unit u1 = Unit.Build(Mun, a0, pw1, UnitType.Army);
|
Unit u1 = Unit.Build(Mun, a0, pw1, UnitType.Army);
|
||||||
|
|
||||||
world = world.ContinueOrFork(a0, out Season a1);
|
world = world.ContinueSeason(a0);
|
||||||
|
Season a1 = world.GetSeason("a1");
|
||||||
Unit u2 = u1.Next(Boh, a1);
|
Unit u2 = u1.Next(Boh, a1);
|
||||||
|
|
||||||
_ = world.ContinueOrFork(a1, out Season a2);
|
world = world.ContinueSeason(a1);
|
||||||
|
Season a2 = world.GetSeason("a2");
|
||||||
Unit u3 = u2.Next(Tyr, a2);
|
Unit u3 = u2.Next(Tyr, a2);
|
||||||
|
|
||||||
Assert.That(u3.Past, Is.EqualTo(u2), "Missing unit past");
|
Assert.That(u3.Past, Is.EqualTo(u2), "Missing unit past");
|
||||||
|
|
Loading…
Reference in New Issue