Chessistics/chessistics-tests/Simulation/FullLevelTests.cs

125 lines
4.7 KiB
C#
Raw Normal View History

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