Black box sim engine (commands in, events out) with 3 piece types (Rook, Bishop, Knight), cargo transfer system with social status priority, collision detection, and victory/defeat conditions. 57 tests covering rules, simulation, loading, and solvability. Godot 4 presentation layer scaffolding.
89 lines
2.9 KiB
C#
89 lines
2.9 KiB
C#
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));
|
|
|
|
// Sub-phase 1: MOVEMENT
|
|
ExecuteMovement(state, changeList);
|
|
|
|
// Sub-phase 2: COLLISION DETECTION
|
|
var collisions = CollisionDetector.DetectCollisions(state.Pieces);
|
|
if (collisions.Count > 0)
|
|
{
|
|
foreach (var (idA, idB, cell) in collisions)
|
|
changeList.Add(new CollisionDetectedEvent(idA, idB, cell));
|
|
|
|
state.Phase = SimPhase.Collision;
|
|
changeList.Add(new TurnEndedEvent(state.TurnNumber));
|
|
return;
|
|
}
|
|
|
|
// Sub-phase 3: TRANSFERS
|
|
var transferEvents = TransferResolver.ResolveTransfers(state);
|
|
changeList.AddRange(transferEvents);
|
|
|
|
// Sub-phase 4: PRODUCTION
|
|
ExecuteProduction(state, changeList);
|
|
|
|
// Check victory / defeat
|
|
if (VictoryChecker.AllDemandsMet(state))
|
|
{
|
|
state.Phase = SimPhase.Victory;
|
|
changeList.Add(new VictoryEvent(ComputeMetrics(state)));
|
|
}
|
|
else if (VictoryChecker.AnyDeadlineExpired(state))
|
|
{
|
|
state.Phase = SimPhase.Defeat;
|
|
foreach (var demand in VictoryChecker.GetExpiredDemands(state))
|
|
changeList.Add(new DeadlineExpiredEvent(demand.Position, demand.Name));
|
|
}
|
|
|
|
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);
|
|
changeList.Add(new PieceMovedEvent(piece.Id, from, to));
|
|
}
|
|
}
|
|
|
|
private static void ExecuteProduction(BoardState state, List<IWorldEvent> changeList)
|
|
{
|
|
foreach (var (pos, prod) in state.Productions)
|
|
{
|
|
if (state.ProductionBuffers[pos] != null)
|
|
continue; // buffer already full
|
|
|
|
if (state.TurnNumber % prod.Interval == 0)
|
|
{
|
|
state.ProductionBuffers[pos] = prod.Cargo;
|
|
changeList.Add(new CargoProducedEvent(pos, prod.Cargo));
|
|
}
|
|
}
|
|
}
|
|
|
|
private static Metrics ComputeMetrics(BoardState state)
|
|
{
|
|
return new Metrics(
|
|
PiecesUsed: state.Pieces.Count,
|
|
TurnsTaken: state.TurnNumber,
|
|
CellsOccupied: state.OccupiedCells.Count
|
|
);
|
|
}
|
|
}
|