Add order model and adjudicator framework

This commit is contained in:
Jaculabilis 2022-02-18 14:52:15 -08:00
parent 031d1b60bd
commit c4f5145320
7 changed files with 166 additions and 0 deletions

View File

@ -0,0 +1,22 @@
using MultiversalDiplomacy.Orders;
namespace MultiversalDiplomacy.Adjudicate;
/// <summary>
/// An input handler for game phases.
/// </summary>
public interface IPhaseAdjudicator
{
/// <summary>
/// Given a list of orders, determine which orders are valid for this adjudicator and
/// which should be rejected before adjudication. Adjudication should be performed on
/// all orders in the output for which <see cref="OrderValidation.Valid"/> is true.
/// </summary>
/// <param name="orders">Orders to validate for adjudication.</param>
/// <returns>
/// A list of order validation results. Note that this list may be longer than the input
/// list if illegal orders were replaced with hold orders, as there will be an invalid
/// result for the illegal order and a valid result for the replacement order.
/// </returns>
public IEnumerable<OrderValidation> ValidateOrders(IEnumerable<Order> orders);
}

View File

@ -0,0 +1,46 @@
using MultiversalDiplomacy.Orders;
namespace MultiversalDiplomacy.Adjudicate;
/// <summary>
/// Represents the result of validating an order.
/// </summary>
public class OrderValidation
{
/// <summary>
/// The order that was validated.
/// </summary>
public Order Order { get; }
/// <summary>
/// Whether the order is valid.
/// </summary>
public bool Valid { get; }
/// <summary>
/// The reason for the order validation result.
/// </summary>
public ValidationReason Reason { get; }
internal OrderValidation(Order order, bool valid, ValidationReason reason)
{
this.Order = order;
this.Valid = valid;
this.Reason = reason;
}
}
public static class OrderValidationExtensions
{
/// <summary>
/// Create an <see cref="OrderValidation"/> accepting this order.
/// </summary>
public static OrderValidation Validate(this Order order, ValidationReason reason)
=> new OrderValidation(order, true, reason);
/// <summary>
/// Create an <see cref="OrderValidation"/> rejecting this order.
/// </summary>
public static OrderValidation Invalidate(this Order order, ValidationReason reason)
=> new OrderValidation(order, false, reason);
}

View File

@ -0,0 +1,24 @@
namespace MultiversalDiplomacy.Adjudicate;
public enum ValidationReason
{
/// <summary>
/// The order is valid.
/// </summary>
Valid = 0,
/// <summary>
/// The order type is not valid for the current phase of the game.
/// </summary>
InvalidOrderTypeForPhase = 1,
/// <summary>
/// A hold order was created to replace an illegal order.
/// </summary>
IllegalOrderReplacedWithHold = 2,
/// <summary>
/// Another order was submitted that replaced this order.
/// </summary>
SupersededByLaterOrder = 3,
}

View File

@ -0,0 +1,19 @@
using MultiversalDiplomacy.Model;
namespace MultiversalDiplomacy.Orders;
/// <summary>
/// A submitted action by a power.
/// </summary>
public abstract class Order
{
/// <summary>
/// The power that submitted this order.
/// </summary>
public Power Power { get; }
public Order(Power power)
{
this.Power = power;
}
}

View File

@ -0,0 +1,28 @@
using MultiversalDiplomacy.Adjudicate;
using MultiversalDiplomacy.Model;
using MultiversalDiplomacy.Orders;
using NUnit.Framework;
namespace MultiversalDiplomacyTests;
public class AdjudicatorTests
{
[Test]
public void OrderValidationTest()
{
IPhaseAdjudicator rubberStamp = new TestAdjudicator(orders => {
return orders.Select(o => o.Validate(ValidationReason.Valid));
});
Power power = new Power(nameof(Power));
Order order = new NullOrder(power);
List<Order> orders = new List<Order> { order };
IEnumerable<OrderValidation> results = rubberStamp.ValidateOrders(orders);
Assert.That(results.Count(), Is.EqualTo(1));
Assert.That(results.First().Order, Is.EqualTo(order));
Assert.That(results.First().Reason, Is.EqualTo(ValidationReason.Valid));
Assert.That(results.First().Valid, Is.True);
}
}

View File

@ -0,0 +1,9 @@
using MultiversalDiplomacy.Model;
using MultiversalDiplomacy.Orders;
namespace MultiversalDiplomacyTests;
public class NullOrder : Order
{
public NullOrder(Power power) : base(power) {}
}

View File

@ -0,0 +1,18 @@
using MultiversalDiplomacy.Adjudicate;
using MultiversalDiplomacy.Orders;
namespace MultiversalDiplomacyTests;
public class TestAdjudicator : IPhaseAdjudicator
{
private Func<IEnumerable<Order>, IEnumerable<OrderValidation>> ValidateOrdersCallback;
public TestAdjudicator(
Func<IEnumerable<Order>, IEnumerable<OrderValidation>> validateOrdersCallback)
{
this.ValidateOrdersCallback = validateOrdersCallback;
}
public IEnumerable<OrderValidation> ValidateOrders(IEnumerable<Order> orders)
=> this.ValidateOrdersCallback.Invoke(orders);
}