using Chessistics.Engine.Events; using Chessistics.Engine.Model; using Chessistics.Tests.Helpers; using Xunit; namespace Chessistics.Tests.Simulation; public class FullLevelTests { [Fact] public void Level1_PremierConvoi_Victory() { // GDD Level 1: 4x4, Scierie(0,0) → Depot(3,0), 3 Rooks // Solution: single rook relay at (1,0)↔(2,0) var level = new BoardBuilder(4, 4) .WithProduction(0, 0, "Scierie", CargoType.Wood, 2) .WithDemand(3, 0, "Depot Royal", CargoType.Wood, 3, 30) .WithStock(PieceKind.Rook, 3) .Build(); var sim = SimHelper.FromLevel(level); sim.Place(PieceKind.Rook, (1, 0), (2, 0)); sim.Start(); var allEvents = sim.StepN(30); Assert.Contains(allEvents, e => e is VictoryEvent); } [Fact] public void Level2_DeuxClients_Victory() { // GDD Level 2: 6x6, Scierie(0,0), Depot Royal(5,0), Caserne(5,4) // Stock: 6 Rooks + 1 Bishop (fixed from GDD's 4R+1B — insufficient) // // Solution requires two routes from single source: // Route 1 → (5,0): A(1,0↔2,0), B(2,0↔4,0) // Route 2 → (5,4): C(0,1↔0,2), D(0,2↔2,2), E(2,2↔3,2), // Bishop(3,2↔4,3), G(4,3↔5,3) // Total needed: 6 Rooks + 1 Bishop var level = new BoardBuilder(6, 6) .WithProduction(0, 0, "Scierie", CargoType.Wood, 2) .WithDemand(5, 0, "Depot Royal", CargoType.Wood, 2, 50) .WithDemand(5, 4, "Caserne", CargoType.Wood, 2, 50) .WithStock(PieceKind.Rook, 6) .WithStock(PieceKind.Bishop, 1) .Build(); var sim = SimHelper.FromLevel(level); // Route 1: bottom row → demand (5,0) sim.Place(PieceKind.Rook, (1, 0), (2, 0)); sim.Place(PieceKind.Rook, (2, 0), (4, 0)); // Route 2: up then right → demand (5,4) sim.Place(PieceKind.Rook, (0, 1), (0, 2)); sim.Place(PieceKind.Rook, (0, 2), (2, 2)); // 5th rook — stock exhausted at 4! var events5 = sim.Place(PieceKind.Rook, (2, 2), (3, 2)); Assert.DoesNotContain(events5, e => e is PlacementRejectedEvent); sim.Place(PieceKind.Bishop, (3, 2), (4, 3)); // 6th rook needed but only 4 in stock var events6 = sim.Place(PieceKind.Rook, (4, 3), (5, 3)); Assert.DoesNotContain(events6, e => e is PlacementRejectedEvent); sim.Start(); var allEvents = sim.StepN(60); Assert.Contains(allEvents, e => e is VictoryEvent); } [Fact] public void Level3_LeCol_Victory() { // GDD Level 3: 6x6, L-shaped wall, knight required to jump obstacle // Stock: 6 Rooks + 1 Knight (fixed from GDD's 4R+1B+2K) // // NOTE: Original GDD had 2 cargo types crossing the board, but the // transfer system has no cargo-type filtering — adjacent pieces from // different routes contaminate each other on a 6x6 board. Simplified // to single cargo type. Dual-cargo cross-board routing is Phase 3. // // Route: prod(0,0) → R1(0,1↔1,1) → K1(1,1↔3,2) → R2(3,2↔4,2) // → R3(4,2↔5,2) → R4(5,2↔5,3) → R5(5,3↔5,4) → demand(5,5) // Total: 5 Rooks + 1 Knight var level = new BoardBuilder(6, 6) .WithProduction(0, 0, "Scierie", CargoType.Wood, 2) .WithDemand(5, 5, "Depot Royal", CargoType.Wood, 3, 60) .WithWall(2, 2).WithWall(2, 3).WithWall(2, 4).WithWall(3, 4).WithWall(4, 4) .WithStock(PieceKind.Rook, 6) .WithStock(PieceKind.Knight, 1) .Build(); var sim = SimHelper.FromLevel(level); sim.Place(PieceKind.Rook, (0, 1), (1, 1)); sim.Place(PieceKind.Knight, (1, 1), (3, 2)); sim.Place(PieceKind.Rook, (3, 2), (4, 2)); sim.Place(PieceKind.Rook, (4, 2), (5, 2)); sim.Place(PieceKind.Rook, (5, 2), (5, 3)); sim.Place(PieceKind.Rook, (5, 3), (5, 4)); sim.Start(); var allEvents = sim.StepN(60); Assert.Contains(allEvents, e => e is VictoryEvent); } [Fact] public void Level1_InsufficientPieces_NoVictory() { var level = new BoardBuilder(4, 4) .WithProduction(0, 0, "Scierie", CargoType.Wood, 2) .WithDemand(3, 3, "Depot Royal", CargoType.Wood, 3, 5) .WithStock(PieceKind.Rook, 1) .Build(); var sim = SimHelper.FromLevel(level); sim.Place(PieceKind.Rook, (1, 1), (2, 1)); sim.Start(); var allEvents = sim.StepN(8); Assert.DoesNotContain(allEvents, e => e is VictoryEvent); Assert.Contains(allEvents, e => e is DeadlineExpiredEvent); } }