2022-03-16 00:24:16 +00:00
|
|
|
using System.Collections.ObjectModel;
|
|
|
|
|
2022-03-23 03:13:49 +00:00
|
|
|
using MultiversalDiplomacy.Adjudicate;
|
2022-03-16 00:24:16 +00:00
|
|
|
using MultiversalDiplomacy.Model;
|
|
|
|
using MultiversalDiplomacy.Orders;
|
2024-08-15 14:54:38 +00:00
|
|
|
using NUnit.Framework;
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
namespace MultiversalDiplomacyTests;
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// A fluent interface for defining adjudication test cases.
|
|
|
|
/// </summary>
|
|
|
|
public class TestCaseBuilder
|
|
|
|
{
|
2022-03-30 00:16:00 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Context for choosing a season to define orders for.
|
|
|
|
/// </summary>
|
|
|
|
public interface ISeasonContext
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Choose a new season to define orders for.
|
|
|
|
/// </summary>
|
2024-08-12 16:28:56 +00:00
|
|
|
public ISeasonContext this[(string timeline, int turn) seasonCoord] { get; }
|
2022-03-30 00:16:00 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Get the context for defining the orders for a power.
|
|
|
|
/// </summary>
|
|
|
|
public IPowerContext this[string powerName] { get; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Save a reference to this season.
|
|
|
|
/// </summary>
|
|
|
|
public ISeasonContext GetReference(out Season season);
|
|
|
|
}
|
|
|
|
|
2022-03-16 00:24:16 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Context for defining orders given by a power.
|
|
|
|
/// </summary>
|
|
|
|
public interface IPowerContext
|
|
|
|
{
|
2022-03-30 00:16:00 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Choose a new season to define orders for.
|
|
|
|
/// </summary>
|
2024-08-12 16:28:56 +00:00
|
|
|
public ISeasonContext this[(string timeline, int turn) seasonCoord] { get; }
|
2022-03-30 00:16:00 +00:00
|
|
|
|
2022-03-16 00:24:16 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Get the context for defining the orders for another power.
|
|
|
|
/// </summary>
|
|
|
|
public IPowerContext this[string powerName] { get; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Define an order for an army in a province.
|
|
|
|
/// </summary>
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Army(string provinceName, string? powerName = null);
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Define an order for a fleet in a province, optionally on a specific coast.
|
|
|
|
/// </summary>
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Fleet(string provinceName, string? coast = null, string? powerName = null);
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context for defining an order given to a unit.
|
|
|
|
/// </summary>
|
|
|
|
public interface IUnitContext
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Ensure the unit exists, but don't create an order for it.
|
|
|
|
/// </summary>
|
|
|
|
public IPowerContext Exists();
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Give the unit a hold order.
|
|
|
|
/// </summary>
|
2022-03-23 03:13:49 +00:00
|
|
|
public IOrderDefinedContext<HoldOrder> Holds();
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Give the unit a move order.
|
|
|
|
/// </summary>
|
2022-03-30 03:40:19 +00:00
|
|
|
/// <param name="season">
|
|
|
|
/// The destination season. If not specified, defaults to the same season as the unit.
|
|
|
|
/// </param>
|
|
|
|
public IOrderDefinedContext<MoveOrder> MovesTo(
|
|
|
|
string provinceName,
|
|
|
|
Season? season = null,
|
|
|
|
string? coast = null);
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Give the unit a convoy order.
|
|
|
|
/// </summary>
|
|
|
|
public IConvoyContext Convoys { get; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Give the unit a support order.
|
|
|
|
/// </summary>
|
|
|
|
public ISupportContext Supports { get; }
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context for defining a convoy order.
|
|
|
|
/// </summary>
|
|
|
|
public interface IConvoyContext
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Make the convoy order target an army.
|
|
|
|
/// </summary>
|
|
|
|
public IConvoyDestinationContext Army(string provinceName, string? powerName = null);
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Make the convoy order target a fleet.
|
|
|
|
/// </summary>
|
|
|
|
public IConvoyDestinationContext Fleet(
|
|
|
|
string provinceName,
|
|
|
|
string? coast = null,
|
|
|
|
string? powerName = null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context for defining the destination of a convoy order.
|
|
|
|
/// </summary>
|
|
|
|
public interface IConvoyDestinationContext
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Define the destination of the convoy order.
|
|
|
|
/// </summary>
|
2022-03-23 03:13:49 +00:00
|
|
|
public IOrderDefinedContext<ConvoyOrder> To(string provinceName);
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context for defining a support order.
|
|
|
|
/// </summary>
|
|
|
|
public interface ISupportContext
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Make the support order target an army.
|
|
|
|
/// </summary>
|
2022-03-30 20:00:51 +00:00
|
|
|
/// <param name="season">
|
|
|
|
/// The unit season. If not specified, defaults to the same season as the ordered unit.
|
|
|
|
/// </param>
|
|
|
|
public ISupportTypeContext Army(
|
|
|
|
string provinceName,
|
|
|
|
Season? season = null,
|
|
|
|
string? powerName = null);
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Make the support order target a fleet.
|
|
|
|
/// </summary>
|
|
|
|
public ISupportTypeContext Fleet(
|
|
|
|
string provinceName,
|
|
|
|
string? coast = null,
|
|
|
|
string? powerName = null);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context for defining the type of support order.
|
|
|
|
/// </summary>
|
|
|
|
public interface ISupportTypeContext
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Give the unit an order to support the target's hold order.
|
|
|
|
/// </summary>
|
2022-03-23 03:13:49 +00:00
|
|
|
public IOrderDefinedContext<SupportHoldOrder> Hold();
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Give the unit an order to support the target's move order.
|
|
|
|
/// </summary>
|
2022-03-30 20:00:51 +00:00
|
|
|
/// <param name="season">
|
|
|
|
/// The target's destination season. If not specified, defaults to the same season as the
|
|
|
|
/// target (not the ordered unit).
|
|
|
|
/// </param>
|
|
|
|
public IOrderDefinedContext<SupportMoveOrder> MoveTo(
|
|
|
|
string provinceName,
|
|
|
|
Season? season = null,
|
|
|
|
string? coast = null);
|
2022-03-23 03:13:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Context for additional operations on a defined order or defining another order. This
|
|
|
|
/// context mimics the <see cref="IPowerContext"/> with additional functionality related to
|
|
|
|
/// the order that was just defined.
|
|
|
|
/// </summary>
|
|
|
|
public interface IOrderDefinedContext<OrderType> where OrderType : Order
|
|
|
|
{
|
2022-03-30 04:01:15 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Perform validation, adjudication, and update using the defined orders.
|
|
|
|
/// </summary>
|
2022-03-30 15:04:44 +00:00
|
|
|
public TestCaseBuilder Execute(IPhaseAdjudicator? adjudicator = null);
|
2022-03-30 04:01:15 +00:00
|
|
|
|
2022-03-30 00:16:00 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Choose a new season to define orders for.
|
|
|
|
/// </summary>
|
2024-08-12 16:28:56 +00:00
|
|
|
public ISeasonContext this[(string timeline, int turn) seasonCoord] { get; }
|
2022-03-30 00:16:00 +00:00
|
|
|
|
2022-03-23 03:13:49 +00:00
|
|
|
/// <summary>
|
|
|
|
/// Get the context for defining the orders for another power.
|
|
|
|
/// </summary>
|
|
|
|
public IPowerContext this[string powerName] { get; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Define an order for a new army in a province.
|
|
|
|
/// </summary>
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Army(string provinceName, string? powerName = null);
|
2022-03-23 03:13:49 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Define an order for a new fleet in a province, optionally on a specific coast.
|
|
|
|
/// </summary>
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Fleet(string provinceName, string? coast = null, string? powerName = null);
|
2022-03-23 03:13:49 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Save a reference to the order just defined.
|
|
|
|
/// </summary>
|
|
|
|
public IOrderDefinedContext<OrderType> GetReference(out OrderReference<OrderType> order);
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public World World { get; private set; }
|
2022-03-30 15:04:44 +00:00
|
|
|
private IPhaseAdjudicator LastUsedAdjudicator { get; set; }
|
2022-03-16 00:24:16 +00:00
|
|
|
public ReadOnlyCollection<Order> Orders { get; }
|
|
|
|
private List<Order> OrderList;
|
2022-03-23 03:13:49 +00:00
|
|
|
public List<OrderValidation>? ValidationResults { get; private set; }
|
2022-03-27 21:36:49 +00:00
|
|
|
public List<AdjudicationDecision>? AdjudicationResults { get; private set; }
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Create a test case builder that will operate on a world.
|
|
|
|
/// </summary>
|
2022-03-30 15:04:44 +00:00
|
|
|
public TestCaseBuilder(World world, IPhaseAdjudicator? adjudicator = null)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
|
|
|
this.World = world;
|
2022-03-30 15:04:44 +00:00
|
|
|
this.LastUsedAdjudicator = adjudicator ?? new TestAdjudicator();
|
2022-03-23 03:13:49 +00:00
|
|
|
this.OrderList = new();
|
2022-03-16 00:24:16 +00:00
|
|
|
this.Orders = new(this.OrderList);
|
2022-03-23 03:13:49 +00:00
|
|
|
this.ValidationResults = null;
|
2022-03-27 21:36:49 +00:00
|
|
|
this.AdjudicationResults = null;
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
2022-03-30 00:16:00 +00:00
|
|
|
/// Get the context for defining the orders for a power. Defaults to the root season.
|
2022-03-16 00:24:16 +00:00
|
|
|
/// </summary>
|
2024-08-12 16:28:56 +00:00
|
|
|
public IPowerContext this[string powerName] => this[("a", 0)][powerName];
|
2022-03-30 00:16:00 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Get the context for defining the orders for a season.
|
|
|
|
/// </summary>
|
2024-08-12 16:28:56 +00:00
|
|
|
public ISeasonContext this[(string timeline, int turn) seasonCoord]
|
|
|
|
=> new SeasonContext(this, this.World.GetSeason(seasonCoord.timeline, seasonCoord.turn));
|
2022-03-16 00:24:16 +00:00
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Get a unit matching a description. If no such unit exists, one is created and added to the
|
|
|
|
/// <see cref="World"/>.
|
|
|
|
/// </summary>
|
|
|
|
/// <param name="type">
|
|
|
|
/// The unit type to create if the unit does not exist.
|
|
|
|
/// Per DATC 4.C.1-2, mismatching unit designations should not invalidate an order, which
|
|
|
|
/// effectively makes the designations superfluous. To support this, the test case builder
|
|
|
|
/// returns a unit that matches the power, location, and season even if the unit found is not
|
|
|
|
/// of this type.
|
|
|
|
/// </param>
|
|
|
|
private Unit GetOrBuildUnit(
|
2024-08-15 14:54:38 +00:00
|
|
|
string power,
|
2022-03-16 00:24:16 +00:00
|
|
|
Location location,
|
|
|
|
Season season,
|
|
|
|
UnitType type)
|
|
|
|
{
|
|
|
|
foreach (Unit unit in this.World.Units)
|
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
if (unit.Power == power
|
2024-08-14 15:15:10 +00:00
|
|
|
&& World.Map.GetLocation(unit).Province == location.Province
|
2022-03-16 00:24:16 +00:00
|
|
|
&& unit.Season == season)
|
|
|
|
{
|
|
|
|
return unit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not found
|
2024-08-15 14:54:38 +00:00
|
|
|
Unit newUnit = Unit.Build(location.Key, season, power, type);
|
2022-03-29 05:34:57 +00:00
|
|
|
this.World = this.World.Update(units: this.World.Units.Append(newUnit));
|
2022-03-16 00:24:16 +00:00
|
|
|
return newUnit;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:04:44 +00:00
|
|
|
public List<OrderValidation> ValidateOrders(IPhaseAdjudicator? adjudicator = null)
|
2022-03-23 03:13:49 +00:00
|
|
|
{
|
2022-03-30 15:04:44 +00:00
|
|
|
adjudicator ??= this.LastUsedAdjudicator;
|
|
|
|
this.LastUsedAdjudicator = adjudicator;
|
2022-03-23 03:13:49 +00:00
|
|
|
this.ValidationResults = adjudicator.ValidateOrders(this.World, this.Orders.ToList());
|
2022-03-30 03:49:33 +00:00
|
|
|
this.OrderList.Clear();
|
2022-03-23 03:13:49 +00:00
|
|
|
return this.ValidationResults;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:04:44 +00:00
|
|
|
public List<AdjudicationDecision> AdjudicateOrders(IPhaseAdjudicator? adjudicator = null)
|
2022-03-27 21:36:49 +00:00
|
|
|
{
|
|
|
|
if (this.ValidationResults == null)
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException("Cannot adjudicate before validation");
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:04:44 +00:00
|
|
|
adjudicator ??= this.LastUsedAdjudicator;
|
|
|
|
this.LastUsedAdjudicator = adjudicator;
|
2022-03-27 21:36:49 +00:00
|
|
|
List<Order> orders = this.ValidationResults
|
|
|
|
.Where(validation => validation.Valid)
|
|
|
|
.Select(validation => validation.Order)
|
|
|
|
.ToList();
|
|
|
|
this.AdjudicationResults = adjudicator.AdjudicateOrders(this.World, orders);
|
2022-03-30 03:49:33 +00:00
|
|
|
this.ValidationResults = null;
|
2022-03-27 21:36:49 +00:00
|
|
|
return this.AdjudicationResults;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:04:44 +00:00
|
|
|
public World UpdateWorld(IPhaseAdjudicator? adjudicator = null)
|
2022-03-27 21:36:49 +00:00
|
|
|
{
|
|
|
|
if (this.AdjudicationResults == null)
|
|
|
|
{
|
|
|
|
throw new InvalidOperationException("Cannot update before adjudication");
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:04:44 +00:00
|
|
|
adjudicator ??= this.LastUsedAdjudicator;
|
|
|
|
this.LastUsedAdjudicator = adjudicator;
|
2022-03-27 21:36:49 +00:00
|
|
|
this.World = adjudicator.UpdateWorld(this.World, this.AdjudicationResults);
|
2022-03-30 03:49:33 +00:00
|
|
|
this.AdjudicationResults = null;
|
2022-03-27 21:36:49 +00:00
|
|
|
return this.World;
|
|
|
|
}
|
|
|
|
|
2022-03-30 00:16:00 +00:00
|
|
|
private class SeasonContext : ISeasonContext
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
|
|
|
public Season Season;
|
|
|
|
|
|
|
|
public SeasonContext(TestCaseBuilder Builder, Season season)
|
|
|
|
{
|
|
|
|
this.Builder = Builder;
|
|
|
|
this.Season = season;
|
|
|
|
}
|
|
|
|
|
2024-08-12 16:28:56 +00:00
|
|
|
public ISeasonContext this[(string timeline, int turn) seasonCoord]
|
|
|
|
=> this.Builder[(seasonCoord.timeline, seasonCoord.turn)];
|
2022-03-30 00:16:00 +00:00
|
|
|
|
|
|
|
public IPowerContext this[string powerName]
|
2024-08-12 04:01:05 +00:00
|
|
|
=> new PowerContext(this, this.Builder.World.Map.GetPower(powerName));
|
2022-03-30 00:16:00 +00:00
|
|
|
|
|
|
|
public ISeasonContext GetReference(out Season season)
|
|
|
|
{
|
|
|
|
season = this.Season;
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-16 00:24:16 +00:00
|
|
|
private class PowerContext : IPowerContext
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
public SeasonContext SeasonContext;
|
2024-08-15 14:54:38 +00:00
|
|
|
public string Power;
|
2022-03-16 00:24:16 +00:00
|
|
|
|
2024-08-15 14:54:38 +00:00
|
|
|
public PowerContext(SeasonContext seasonContext, string power)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
Assert.That(power, Is.AnyOf([.. seasonContext.Builder.World.Map.Powers]), "Invalid power");
|
|
|
|
|
2022-03-30 00:16:00 +00:00
|
|
|
this.Builder = seasonContext.Builder;
|
|
|
|
this.SeasonContext = seasonContext;
|
2024-08-15 14:54:38 +00:00
|
|
|
this.Power = power;
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
2024-08-12 16:28:56 +00:00
|
|
|
public ISeasonContext this[(string timeline, int turn) seasonCoord]
|
2022-03-30 00:16:00 +00:00
|
|
|
=> this.SeasonContext[seasonCoord];
|
|
|
|
|
2022-03-16 00:24:16 +00:00
|
|
|
public IPowerContext this[string powerName]
|
2022-03-30 00:16:00 +00:00
|
|
|
=> this.SeasonContext[powerName];
|
2022-03-16 00:24:16 +00:00
|
|
|
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Army(string provinceName, string? powerName = null)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
string power = powerName == null
|
2022-03-23 06:16:02 +00:00
|
|
|
? this.Power
|
2024-08-12 04:01:05 +00:00
|
|
|
: this.Builder.World.Map.GetPower(powerName);
|
|
|
|
Location location = this.Builder.World.Map.GetLand(provinceName);
|
2022-03-16 00:24:16 +00:00
|
|
|
Unit unit = this.Builder.GetOrBuildUnit(
|
2022-03-30 00:16:00 +00:00
|
|
|
power, location, this.SeasonContext.Season, UnitType.Army);
|
2022-03-16 00:24:16 +00:00
|
|
|
return new UnitContext(this, unit);
|
|
|
|
}
|
|
|
|
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Fleet(string provinceName, string? coast = null, string? powerName = null)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
string power = powerName == null
|
2022-03-23 06:16:02 +00:00
|
|
|
? this.Power
|
2024-08-12 04:01:05 +00:00
|
|
|
: this.Builder.World.Map.GetPower(powerName);
|
|
|
|
Location location = this.Builder.World.Map.GetWater(provinceName, coast);
|
2022-03-16 00:24:16 +00:00
|
|
|
Unit unit = this.Builder.GetOrBuildUnit(
|
2022-03-30 00:16:00 +00:00
|
|
|
power, location, this.SeasonContext.Season, UnitType.Fleet);
|
2022-03-16 00:24:16 +00:00
|
|
|
return new UnitContext(this, unit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class UnitContext : IUnitContext
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
public SeasonContext SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
public PowerContext PowerContext;
|
|
|
|
public Unit Unit;
|
|
|
|
|
|
|
|
public UnitContext(PowerContext powerContext, Unit unit)
|
|
|
|
{
|
|
|
|
this.Builder = powerContext.Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
this.SeasonContext = powerContext.SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
this.PowerContext = powerContext;
|
|
|
|
this.Unit = unit;
|
|
|
|
}
|
|
|
|
|
|
|
|
public IPowerContext Exists()
|
|
|
|
=> this.PowerContext;
|
|
|
|
|
2022-03-23 03:13:49 +00:00
|
|
|
public IOrderDefinedContext<HoldOrder> Holds()
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
HoldOrder order = new HoldOrder(this.PowerContext.Power, this.Unit);
|
2022-03-16 00:24:16 +00:00
|
|
|
this.Builder.OrderList.Add(order);
|
2022-03-23 03:13:49 +00:00
|
|
|
return new OrderDefinedContext<HoldOrder>(this, order);
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
2022-03-30 03:40:19 +00:00
|
|
|
public IOrderDefinedContext<MoveOrder> MovesTo(
|
|
|
|
string provinceName,
|
|
|
|
Season? season = null,
|
|
|
|
string? coast = null)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
|
|
|
Location destination = this.Unit.Type == UnitType.Army
|
2024-08-12 04:01:05 +00:00
|
|
|
? this.Builder.World.Map.GetLand(provinceName)
|
|
|
|
: this.Builder.World.Map.GetWater(provinceName, coast);
|
2022-03-30 03:40:19 +00:00
|
|
|
Season destSeason = season ?? this.SeasonContext.Season;
|
2022-03-16 00:24:16 +00:00
|
|
|
MoveOrder moveOrder = new MoveOrder(
|
2024-08-15 14:54:38 +00:00
|
|
|
this.PowerContext.Power,
|
2022-03-16 00:24:16 +00:00
|
|
|
this.Unit,
|
2024-08-15 13:52:08 +00:00
|
|
|
destSeason.Key,
|
2022-03-16 00:24:16 +00:00
|
|
|
destination);
|
|
|
|
this.Builder.OrderList.Add(moveOrder);
|
2022-03-23 03:13:49 +00:00
|
|
|
return new OrderDefinedContext<MoveOrder>(this, moveOrder);
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public IConvoyContext Convoys
|
|
|
|
=> new ConvoyContext(this);
|
|
|
|
|
|
|
|
public ISupportContext Supports
|
|
|
|
=> new SupportContext(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ConvoyContext : IConvoyContext
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
public SeasonContext SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
public PowerContext PowerContext;
|
|
|
|
public UnitContext UnitContext;
|
|
|
|
|
|
|
|
public ConvoyContext(UnitContext unitContext)
|
|
|
|
{
|
|
|
|
this.Builder = unitContext.Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
this.SeasonContext = unitContext.SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
this.PowerContext = unitContext.PowerContext;
|
|
|
|
this.UnitContext = unitContext;
|
|
|
|
}
|
|
|
|
|
|
|
|
public IConvoyDestinationContext Army(string provinceName, string? powerName = null)
|
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
string power = powerName == null
|
2022-03-16 00:24:16 +00:00
|
|
|
? this.PowerContext.Power
|
2024-08-12 04:01:05 +00:00
|
|
|
: this.Builder.World.Map.GetPower(powerName);
|
|
|
|
Location location = this.Builder.World.Map.GetLand(provinceName);
|
2022-03-16 00:24:16 +00:00
|
|
|
Unit unit = this.Builder.GetOrBuildUnit(
|
2022-03-30 00:16:00 +00:00
|
|
|
power, location, this.SeasonContext.Season, UnitType.Army);
|
2022-03-16 00:24:16 +00:00
|
|
|
return new ConvoyDestinationContext(this, unit);
|
|
|
|
}
|
|
|
|
|
|
|
|
public IConvoyDestinationContext Fleet(
|
|
|
|
string provinceName,
|
|
|
|
string? coast = null,
|
|
|
|
string? powerName = null)
|
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
string power = powerName == null
|
2022-03-16 00:24:16 +00:00
|
|
|
? this.PowerContext.Power
|
2024-08-12 04:01:05 +00:00
|
|
|
: this.Builder.World.Map.GetPower(powerName);
|
|
|
|
Location location = this.Builder.World.Map.GetWater(provinceName, coast);
|
2022-03-16 00:24:16 +00:00
|
|
|
Unit unit = this.Builder.GetOrBuildUnit(
|
2022-03-30 00:16:00 +00:00
|
|
|
power, location, this.SeasonContext.Season, UnitType.Fleet);
|
2022-03-16 00:24:16 +00:00
|
|
|
return new ConvoyDestinationContext(this, unit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class ConvoyDestinationContext : IConvoyDestinationContext
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
public SeasonContext SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
public PowerContext PowerContext;
|
|
|
|
public UnitContext UnitContext;
|
|
|
|
public Unit Target;
|
|
|
|
|
|
|
|
public ConvoyDestinationContext(ConvoyContext convoyContext, Unit target)
|
|
|
|
{
|
|
|
|
this.Builder = convoyContext.Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
this.SeasonContext = convoyContext.SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
this.PowerContext = convoyContext.PowerContext;
|
|
|
|
this.UnitContext = convoyContext.UnitContext;
|
|
|
|
this.Target = target;
|
|
|
|
}
|
|
|
|
|
2022-03-23 03:13:49 +00:00
|
|
|
public IOrderDefinedContext<ConvoyOrder> To(string provinceName)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
2024-08-12 04:01:05 +00:00
|
|
|
Location location = this.Builder.World.Map.GetLand(provinceName);
|
2022-03-16 00:24:16 +00:00
|
|
|
ConvoyOrder order = new ConvoyOrder(
|
2024-08-15 14:54:38 +00:00
|
|
|
this.PowerContext.Power,
|
2022-03-16 00:24:16 +00:00
|
|
|
this.UnitContext.Unit,
|
|
|
|
this.Target,
|
2022-03-30 00:16:00 +00:00
|
|
|
this.SeasonContext.Season,
|
2022-03-16 00:24:16 +00:00
|
|
|
location);
|
|
|
|
this.Builder.OrderList.Add(order);
|
2022-03-23 03:13:49 +00:00
|
|
|
return new OrderDefinedContext<ConvoyOrder>(this.UnitContext, order);
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class SupportContext : ISupportContext
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
public SeasonContext SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
public PowerContext PowerContext;
|
|
|
|
public UnitContext UnitContext;
|
|
|
|
|
|
|
|
public SupportContext(UnitContext unitContext)
|
|
|
|
{
|
|
|
|
this.Builder = unitContext.Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
this.SeasonContext = unitContext.SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
this.PowerContext = unitContext.PowerContext;
|
|
|
|
this.UnitContext = unitContext;
|
|
|
|
}
|
|
|
|
|
2022-03-30 20:00:51 +00:00
|
|
|
public ISupportTypeContext Army(
|
|
|
|
string provinceName,
|
|
|
|
Season? season = null,
|
|
|
|
string? powerName = null)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
string power = powerName == null
|
2022-03-16 00:24:16 +00:00
|
|
|
? this.PowerContext.Power
|
2024-08-12 04:01:05 +00:00
|
|
|
: this.Builder.World.Map.GetPower(powerName);
|
|
|
|
Location location = this.Builder.World.Map.GetLand(provinceName);
|
2022-03-30 20:00:51 +00:00
|
|
|
Season destSeason = season ?? this.SeasonContext.Season;
|
2022-03-16 00:24:16 +00:00
|
|
|
Unit unit = this.Builder.GetOrBuildUnit(
|
2022-03-30 20:00:51 +00:00
|
|
|
power, location, destSeason, UnitType.Army);
|
2022-03-16 00:24:16 +00:00
|
|
|
return new SupportTypeContext(this, unit);
|
|
|
|
}
|
|
|
|
|
|
|
|
public ISupportTypeContext Fleet(
|
|
|
|
string provinceName,
|
|
|
|
string? coast = null,
|
|
|
|
string? powerName = null)
|
|
|
|
{
|
2024-08-15 14:54:38 +00:00
|
|
|
string power = powerName == null
|
2022-03-16 00:24:16 +00:00
|
|
|
? this.PowerContext.Power
|
2024-08-12 04:01:05 +00:00
|
|
|
: this.Builder.World.Map.GetPower(powerName);
|
|
|
|
Location location = this.Builder.World.Map.GetWater(provinceName, coast);
|
2022-03-16 00:24:16 +00:00
|
|
|
Unit unit = this.Builder.GetOrBuildUnit(
|
2022-03-30 00:16:00 +00:00
|
|
|
power, location, this.SeasonContext.Season, UnitType.Fleet);
|
2022-03-16 00:24:16 +00:00
|
|
|
return new SupportTypeContext(this, unit);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class SupportTypeContext : ISupportTypeContext
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
public SeasonContext SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
public PowerContext PowerContext;
|
|
|
|
public UnitContext UnitContext;
|
|
|
|
public Unit Target;
|
|
|
|
|
|
|
|
public SupportTypeContext(SupportContext supportContext, Unit target)
|
|
|
|
{
|
|
|
|
this.Builder = supportContext.Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
this.SeasonContext = supportContext.SeasonContext;
|
2022-03-16 00:24:16 +00:00
|
|
|
this.PowerContext = supportContext.PowerContext;
|
|
|
|
this.UnitContext = supportContext.UnitContext;
|
|
|
|
this.Target = target;
|
|
|
|
}
|
|
|
|
|
2022-03-23 03:13:49 +00:00
|
|
|
public IOrderDefinedContext<SupportHoldOrder> Hold()
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
|
|
|
SupportHoldOrder order = new SupportHoldOrder(
|
2024-08-15 14:54:38 +00:00
|
|
|
this.PowerContext.Power,
|
2022-03-16 00:24:16 +00:00
|
|
|
this.UnitContext.Unit,
|
|
|
|
this.Target);
|
|
|
|
this.Builder.OrderList.Add(order);
|
2022-03-23 03:13:49 +00:00
|
|
|
return new OrderDefinedContext<SupportHoldOrder>(this.UnitContext, order);
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
|
2022-03-30 20:00:51 +00:00
|
|
|
public IOrderDefinedContext<SupportMoveOrder> MoveTo(
|
|
|
|
string provinceName,
|
|
|
|
Season? season = null,
|
|
|
|
string? coast = null)
|
2022-03-16 00:24:16 +00:00
|
|
|
{
|
|
|
|
Location destination = this.Target.Type == UnitType.Army
|
2024-08-12 04:01:05 +00:00
|
|
|
? this.Builder.World.Map.GetLand(provinceName)
|
|
|
|
: this.Builder.World.Map.GetWater(provinceName, coast);
|
2022-03-30 20:00:51 +00:00
|
|
|
Season targetDestSeason = season ?? this.Target.Season;
|
2022-03-16 00:24:16 +00:00
|
|
|
SupportMoveOrder order = new SupportMoveOrder(
|
2024-08-15 14:54:38 +00:00
|
|
|
this.PowerContext.Power,
|
2022-03-16 00:24:16 +00:00
|
|
|
this.UnitContext.Unit,
|
|
|
|
this.Target,
|
2022-03-30 20:00:51 +00:00
|
|
|
targetDestSeason,
|
2022-03-16 00:24:16 +00:00
|
|
|
destination);
|
|
|
|
this.Builder.OrderList.Add(order);
|
2022-03-23 03:13:49 +00:00
|
|
|
return new OrderDefinedContext<SupportMoveOrder>(this.UnitContext, order);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private class OrderDefinedContext<OrderType> : IOrderDefinedContext<OrderType> where OrderType : Order
|
|
|
|
{
|
|
|
|
public TestCaseBuilder Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
public SeasonContext SeasonContext;
|
2022-03-23 03:13:49 +00:00
|
|
|
public PowerContext PowerContext;
|
|
|
|
public UnitContext UnitContext;
|
|
|
|
public OrderType Order;
|
|
|
|
|
|
|
|
public OrderDefinedContext(UnitContext unitContext, OrderType order)
|
|
|
|
{
|
|
|
|
this.Builder = unitContext.Builder;
|
2022-03-30 00:16:00 +00:00
|
|
|
this.SeasonContext = unitContext.SeasonContext;
|
2022-03-23 03:13:49 +00:00
|
|
|
this.PowerContext = unitContext.PowerContext;
|
|
|
|
this.UnitContext = unitContext;
|
|
|
|
this.Order = order;
|
|
|
|
}
|
|
|
|
|
2022-03-30 15:04:44 +00:00
|
|
|
public TestCaseBuilder Execute(IPhaseAdjudicator? adjudicator = null)
|
2022-03-30 04:01:15 +00:00
|
|
|
{
|
2022-03-30 15:04:44 +00:00
|
|
|
adjudicator ??= this.Builder.LastUsedAdjudicator;
|
|
|
|
this.Builder.LastUsedAdjudicator = adjudicator;
|
2022-03-30 04:01:15 +00:00
|
|
|
this.Builder.ValidateOrders(adjudicator);
|
|
|
|
this.Builder.AdjudicateOrders(adjudicator);
|
|
|
|
this.Builder.UpdateWorld(adjudicator);
|
|
|
|
return this.Builder;
|
|
|
|
}
|
|
|
|
|
2024-08-12 16:28:56 +00:00
|
|
|
public ISeasonContext this[(string timeline, int turn) seasonCoord]
|
2022-03-30 00:16:00 +00:00
|
|
|
=> this.SeasonContext[seasonCoord];
|
|
|
|
|
|
|
|
public IPowerContext this[string powerName]
|
|
|
|
=> this.SeasonContext[powerName];
|
2022-03-23 03:13:49 +00:00
|
|
|
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Army(string provinceName, string? powerName = null)
|
|
|
|
=> this.PowerContext.Army(provinceName, powerName);
|
2022-03-23 03:13:49 +00:00
|
|
|
|
2022-03-23 06:16:02 +00:00
|
|
|
public IUnitContext Fleet(string provinceName, string? coast = null, string? powerName = null)
|
|
|
|
=> this.PowerContext.Fleet(provinceName, coast, powerName);
|
2022-03-23 03:13:49 +00:00
|
|
|
|
|
|
|
public IOrderDefinedContext<OrderType> GetReference(out OrderReference<OrderType> order)
|
|
|
|
{
|
|
|
|
order = new OrderReference<OrderType>(this.Builder, this.Order);
|
|
|
|
return this;
|
2022-03-16 00:24:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|