Chessistics/chessistics-engine/Simulation/TurnExecutor.cs
Samuel Bouchet e6eaae43ab Initial commit: Chessistics prototype v0.3
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.
2026-04-10 14:58:03 +02:00

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
);
}
}