2026-04-10 14:58:03 +02:00
|
|
|
using Chessistics.Engine.Events;
|
|
|
|
|
using Chessistics.Engine.Model;
|
|
|
|
|
using Chessistics.Engine.Rules;
|
|
|
|
|
|
|
|
|
|
namespace Chessistics.Engine.Simulation;
|
|
|
|
|
|
|
|
|
|
public static class TurnExecutor
|
|
|
|
|
{
|
|
|
|
|
public static void ExecuteTurn(BoardState state, List<IWorldEvent> changeList)
|
|
|
|
|
{
|
|
|
|
|
state.TurnNumber++;
|
|
|
|
|
changeList.Add(new TurnStartedEvent(state.TurnNumber));
|
|
|
|
|
|
2026-04-10 21:44:12 +02:00
|
|
|
// Sub-phase 1: PRODUCTION
|
|
|
|
|
ExecuteProduction(state, changeList);
|
2026-04-10 14:58:03 +02:00
|
|
|
|
2026-04-10 21:44:12 +02:00
|
|
|
// Sub-phase 2: TRANSFERS
|
2026-04-10 14:58:03 +02:00
|
|
|
var transferEvents = TransferResolver.ResolveTransfers(state);
|
|
|
|
|
changeList.AddRange(transferEvents);
|
|
|
|
|
|
2026-04-10 21:44:12 +02:00
|
|
|
// Sub-phase 3: MOVEMENT
|
|
|
|
|
ExecuteMovement(state, changeList);
|
|
|
|
|
|
|
|
|
|
// Sub-phase 4: COLLISION RESOLUTION
|
|
|
|
|
var collisions = CollisionResolver.ResolveCollisions(state.Pieces);
|
|
|
|
|
foreach (var (survivor, destroyed, cell) in collisions)
|
|
|
|
|
{
|
|
|
|
|
foreach (var victim in destroyed)
|
|
|
|
|
{
|
|
|
|
|
state.Pieces.Remove(victim);
|
|
|
|
|
state.DestroyedPieces.Add(victim);
|
|
|
|
|
victim.Cargo = null;
|
|
|
|
|
changeList.Add(new PieceDestroyedEvent(
|
|
|
|
|
state.TurnNumber, victim.Id, survivor?.Id, cell));
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-10 14:58:03 +02:00
|
|
|
|
|
|
|
|
// Check victory / defeat
|
|
|
|
|
if (VictoryChecker.AllDemandsMet(state))
|
|
|
|
|
{
|
|
|
|
|
state.Phase = SimPhase.Victory;
|
2026-04-10 21:44:12 +02:00
|
|
|
changeList.Add(new VictoryEvent(state.TurnNumber, ComputeMetrics(state)));
|
2026-04-10 14:58:03 +02:00
|
|
|
}
|
|
|
|
|
else if (VictoryChecker.AnyDeadlineExpired(state))
|
|
|
|
|
{
|
|
|
|
|
state.Phase = SimPhase.Defeat;
|
|
|
|
|
foreach (var demand in VictoryChecker.GetExpiredDemands(state))
|
2026-04-10 21:44:12 +02:00
|
|
|
changeList.Add(new DeadlineExpiredEvent(state.TurnNumber, demand.Position, demand.Name));
|
2026-04-10 14:58:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
changeList.Add(new TurnEndedEvent(state.TurnNumber));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ExecuteMovement(BoardState state, List<IWorldEvent> changeList)
|
|
|
|
|
{
|
|
|
|
|
// Compute all targets first (simultaneous movement)
|
|
|
|
|
var moves = state.Pieces.Select(p => (piece: p, from: p.CurrentCell, to: p.TargetCell)).ToList();
|
|
|
|
|
|
|
|
|
|
// Apply all moves
|
|
|
|
|
foreach (var (piece, from, to) in moves)
|
|
|
|
|
{
|
|
|
|
|
piece.CurrentCell = to;
|
|
|
|
|
state.OccupiedCells.Add(to);
|
2026-04-10 21:44:12 +02:00
|
|
|
changeList.Add(new PieceMovedEvent(state.TurnNumber, piece.Id, from, to));
|
2026-04-10 14:58:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ExecuteProduction(BoardState state, List<IWorldEvent> changeList)
|
|
|
|
|
{
|
|
|
|
|
foreach (var (pos, prod) in state.Productions)
|
|
|
|
|
{
|
2026-04-10 21:44:12 +02:00
|
|
|
state.ProductionBuffers[pos] = prod.Amount;
|
|
|
|
|
changeList.Add(new CargoProducedEvent(state.TurnNumber, pos, prod.Cargo));
|
2026-04-10 14:58:03 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Metrics ComputeMetrics(BoardState state)
|
|
|
|
|
{
|
|
|
|
|
return new Metrics(
|
2026-04-10 21:44:12 +02:00
|
|
|
PiecesUsed: state.Pieces.Count + state.DestroyedPieces.Count,
|
2026-04-10 14:58:03 +02:00
|
|
|
TurnsTaken: state.TurnNumber,
|
|
|
|
|
CellsOccupied: state.OccupiedCells.Count
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|