Skip to content

Commit

Permalink
Fix a number of bugs relating to retreats
Browse files Browse the repository at this point in the history
  • Loading branch information
Oliveriver committed Oct 7, 2024
1 parent 1752f93 commit 8ed862d
Show file tree
Hide file tree
Showing 14 changed files with 89 additions and 58 deletions.
2 changes: 1 addition & 1 deletion server/Adjudication/Adjudicator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void Adjudicate()
{
if (world.Winner != null)
{
world.Orders = world.Orders.Where(o => o.Status != OrderStatus.New).ToList();
world.Orders = world.Orders.Where(o => o.Status is not OrderStatus.New and not OrderStatus.RetreatNew).ToList();
return;
}

Expand Down
38 changes: 18 additions & 20 deletions server/Adjudication/Evaluation/Evaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,34 +49,32 @@ private List<Order> GetActiveOrders()
{
var newOrders = world.Orders.Where(o => o.Status is OrderStatus.New or OrderStatus.RetreatNew).ToList();

if (world.HasRetreats)
if (!world.HasRetreats)
{
return newOrders;
}

var idleUnits = world.ActiveBoards
.Where(b => b.Phase != Phase.Winter)
.SelectMany(b => b.Units)
.Where(u => newOrders.All(o => o.Unit != u));
var idleUnits = world.ActiveBoards
.Where(b => b.Phase != Phase.Winter)
.SelectMany(b => b.Units)
.Where(u => newOrders.All(o => o.Unit != u));

foreach (var unit in idleUnits)
{
var hold = new Hold
foreach (var unit in idleUnits)
{
Status = OrderStatus.New,
Unit = unit,
UnitId = unit.Id,
Location = unit.Location,
};
world.Orders.Add(hold);
newOrders.Add(hold);
var hold = new Hold
{
Status = OrderStatus.New,
Unit = unit,
UnitId = unit.Id,
Location = unit.Location,
};
world.Orders.Add(hold);
newOrders.Add(hold);
}
}

var activeOrders = touchedOrdersFinder.GetTouchedOrders(newOrders);
var activeOrders = touchedOrdersFinder.GetTouchedOrders(newOrders, world.HasRetreats);

foreach (var order in activeOrders)
{
if (order.Status != OrderStatus.Invalid)
if (!world.HasRetreats && order.Status != OrderStatus.Invalid)
{
order.Status = OrderStatus.New;
}
Expand Down
30 changes: 16 additions & 14 deletions server/Adjudication/Evaluation/MovementEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ private void IdentifyRetreats()

foreach (var order in activeOrders)
{
var unit = order.Unit;

var existingRetreats = world.Orders
.Where(o =>
o.Unit == unit
&& o.Status is OrderStatus.RetreatNew
or OrderStatus.RetreatSuccess
or OrderStatus.RetreatFailure
or OrderStatus.RetreatInvalid)
.ToList();

foreach (var existingRetreat in existingRetreats)
{
world.Orders.Remove(existingRetreat);
}

var isSuccessfulMove = order is Move && order.Status == OrderStatus.Success;
var mustRetreat = !isSuccessfulMove && activeOrders.Any(o =>
o is Move m
Expand All @@ -53,20 +69,6 @@ o is Move m
continue;
}

var unit = order.Unit;

var existingRetreat = world.Orders.FirstOrDefault(o =>
o.Unit == unit
&& o.Status is OrderStatus.RetreatNew
or OrderStatus.RetreatSuccess
or OrderStatus.RetreatFailure
or OrderStatus.RetreatInvalid);

if (existingRetreat != null)
{
world.Orders.Remove(existingRetreat);
}

var canEscape = CanEscape(unit, stationaryOrders, moves.ToList());

if (canEscape)
Expand Down
19 changes: 8 additions & 11 deletions server/Adjudication/Evaluation/TouchedOrdersFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ public class TouchedOrdersFinder(World world, AdjacencyValidator adjacencyValida

private readonly AdjacencyValidator adjacencyValidator = adjacencyValidator;

public List<Order> GetTouchedOrders(List<Order> orders)
public List<Order> GetTouchedOrders(List<Order> orders, bool hasRetreats)
{
var depthFirstSearch = new DepthFirstSearch(world, orders, adjacencyValidator);
foreach (var order in orders)
{
depthFirstSearch.AddTouchedOrders(order);
}

return depthFirstSearch.TouchedOrders;
var retreats = depthFirstSearch.TouchedOrders.Where(o =>
o.Status is OrderStatus.RetreatNew
or OrderStatus.RetreatSuccess
or OrderStatus.RetreatFailure
or OrderStatus.RetreatInvalid).ToList();

return hasRetreats ? retreats : depthFirstSearch.TouchedOrders.Except(retreats).ToList();
}

private class DepthFirstSearch(World world, List<Order> newOrders, AdjacencyValidator adjacencyValidator)
Expand All @@ -30,15 +36,6 @@ private class DepthFirstSearch(World world, List<Order> newOrders, AdjacencyVali

public void AddTouchedOrders(Order order)
{
if (order.Status is OrderStatus.RetreatNew
or OrderStatus.RetreatSuccess
or OrderStatus.RetreatFailure
or OrderStatus.RetreatInvalid)
{
TouchedOrders.Remove(order);
return;
}

if (!TouchedOrders.Contains(order))
{
TouchedOrders.Add(order);
Expand Down
10 changes: 5 additions & 5 deletions server/Adjudication/Execution/Executor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace Adjudication;
public class Executor(World world, List<Region> regions)
{
private readonly World world = world;
private readonly List<Unit> originalRetreatingUnits = world.Boards.SelectMany(b => b.Units).Where(u => u!.MustRetreat).ToList();
private readonly List<Unit> originalRetreatingUnits = world.Boards.SelectMany(b => b.Units).Where(u => u.MustRetreat).ToList();

private readonly List<Region> regions = regions;
private readonly MapComparer mapComparer = new(world.Orders.OfType<Build>().ToList());
Expand Down Expand Up @@ -74,15 +74,15 @@ private Board AdvanceMajorBoard(Board previousBoard)
var year = previousBoard.Year;
var phase = previousBoard.Phase.NextPhase();

var disbands = world.Orders.OfType<Disband>().Where(d => d.Status == OrderStatus.RetreatSuccess);
var retreats = world.Orders.Where(o => o.Status is OrderStatus.RetreatSuccess or OrderStatus.RetreatFailure or OrderStatus.RetreatInvalid);

var holds = world.Orders.Where(o =>
(o is not Move || o.Status != OrderStatus.Success)
&& !disbands.Any(d => d.Unit == o.Unit)
(o is not Move || o.Status != OrderStatus.Success && o.Status != OrderStatus.RetreatSuccess)
&& !retreats.Any(r => r.Unit == o.Unit)
&& previousBoard.Contains(o.Location)
&& !originalRetreatingUnits.Contains(o.Unit));
var incomingMoves = world.Orders.OfType<Move>().Where(m =>
(m.Status == OrderStatus.Success || m.Status == OrderStatus.RetreatSuccess)
m.Status is OrderStatus.Success or OrderStatus.RetreatSuccess
&& previousBoard.Contains(m.Destination));

var units = new List<Unit>();
Expand Down
2 changes: 2 additions & 0 deletions server/Entities/Board.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ public class Board

public bool Contains(Location location)
=> Timeline == location.Timeline && Year == location.Year && Phase == location.Phase;

public override string ToString() => $"({Timeline}, {Year}, {Phase})";
}
2 changes: 1 addition & 1 deletion server/Entities/Orders/Convoy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class Convoy : Order
public Location Destination { get; set; } = null!;

[NotMapped]
public override bool NeedsValidation => Status is OrderStatus.Invalid or OrderStatus.New;
public override bool NeedsValidation => Status is OrderStatus.Invalid or OrderStatus.New or OrderStatus.RetreatNew;

[NotMapped]
public override List<Location> TouchedLocations => [Location, Midpoint, Destination];
Expand Down
2 changes: 1 addition & 1 deletion server/Entities/Orders/Disband.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public class Disband : Order
{
public override string ToString() => $"Disband ${Location}: {Status}";
public override string ToString() => $"Disband {Location}: {Status}";
}
2 changes: 1 addition & 1 deletion server/Entities/Orders/Order.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public abstract class Order
public Location Location { get; set; } = null!;

[NotMapped]
public virtual bool NeedsValidation => Status == OrderStatus.New;
public virtual bool NeedsValidation => Status is OrderStatus.New or OrderStatus.RetreatNew;

[NotMapped]
public virtual List<Location> TouchedLocations => [Location];
Expand Down
2 changes: 1 addition & 1 deletion server/Entities/Orders/Support.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class Support : Order
public Location Destination { get; set; } = null!;

[NotMapped]
public override bool NeedsValidation => Status is OrderStatus.Invalid or OrderStatus.New;
public override bool NeedsValidation => Status is OrderStatus.Invalid or OrderStatus.New or OrderStatus.RetreatNew;

[NotMapped]
public override List<Location> TouchedLocations => [Location, Midpoint, Destination];
Expand Down
2 changes: 2 additions & 0 deletions server/Entities/Unit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@ public class Unit
RegionId = Location.RegionId,
}
};

public override string ToString() => $"{Owner} {Type} at {Location}";
}

2 changes: 1 addition & 1 deletion server/Mappers/EntityMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public Models.World MapWorld(Entities.World world, Nation? player = null)
{
var visibleOrders = player == null
? world.Orders
: world.Orders.Where(o => o.Status != OrderStatus.New || o.Unit?.Owner == player);
: world.Orders.Where(o => o.Status is not OrderStatus.New and not OrderStatus.RetreatNew || o.Unit?.Owner == player);

var builds = world.Orders.OfType<Entities.Build>().ToList();

Expand Down
25 changes: 25 additions & 0 deletions server/Tests/Extensions/UnitExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ public static Hold Hold(this Unit unit, OrderStatus status = OrderStatus.New)
{
var world = unit.Board.World;

if (unit.MustRetreat && status == OrderStatus.New)
{
status = OrderStatus.RetreatNew;
}

var hold = new Hold
{
World = world,
Expand All @@ -38,6 +43,11 @@ public static Move Move(this Unit unit, string regionId, int timeline = 1, int y
{
var world = unit.Board.World;

if (unit.MustRetreat && status == OrderStatus.New)
{
status = OrderStatus.RetreatNew;
}

var move = new Move
{
World = world,
Expand All @@ -61,6 +71,11 @@ public static Support Support(this Unit unit, Unit supportedUnit, string? region
{
var world = unit.Board.World;

if (unit.MustRetreat && status == OrderStatus.New)
{
status = OrderStatus.RetreatNew;
}

var support = new Support
{
World = world,
Expand All @@ -85,6 +100,11 @@ public static Convoy Convoy(this Unit unit, Unit convoyedUnit, string regionId,
{
var world = unit.Board.World;

if (unit.MustRetreat && status == OrderStatus.New)
{
status = OrderStatus.RetreatNew;
}

var convoy = new Convoy
{
World = world,
Expand All @@ -109,6 +129,11 @@ public static Disband Disband(this Unit unit, OrderStatus status = OrderStatus.N
{
var world = unit.Board.World;

if (unit.MustRetreat && status == OrderStatus.New)
{
status = OrderStatus.RetreatNew;
}

var disband = new Disband
{
World = world,
Expand Down
9 changes: 7 additions & 2 deletions server/Tests/MDATC_C.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ public void MDATC_C_1()
var presentBoard = world.AddBoard(phase: Phase.Fall);
var pastBoard = world.AddBoard();

var units = presentBoard.AddUnits([(Nation.England, UnitType.Army, "Lon")]);
List<Unit> units =
[
.. pastBoard.AddUnits([(Nation.England, UnitType.Army, "Lon")]),
.. presentBoard.AddUnits([(Nation.England, UnitType.Army, "Lon")]),
];

units.Get("Lon").Hold(status: OrderStatus.Success);
units.Get("Lon", phase: Phase.Fall).MustRetreat = true;

var order = units.Get("Lon", phase: Phase.Fall).Move("Lon");
var order = units.Get("Lon", phase: Phase.Fall).Move("Wal");

// Act
new Adjudicator(world, false, MapFactory, DefaultWorldFactory).Adjudicate();
Expand Down

0 comments on commit 8ed862d

Please sign in to comment.