using Chessistics.Engine.Commands; using Chessistics.Engine.Events; using Chessistics.Engine.Model; using Chessistics.Tests.Helpers; using Xunit; namespace Chessistics.Tests.Simulation; public class TransformerTests { /// /// Build a campaign with a production, a transformer, and a demand: /// Production(Wood) → [Transformer: Wood→Tools] → Demand(Tools) /// Layout (5x1): /// (0,0) Production(Wood,4) /// (2,0) Transformer(Wood→Tools, input=2, output=1) /// (4,0) Demand(Tools, 2) /// private static CampaignDef CreateTransformerCampaign() { return new CampaignDef { Name = "Transformer Test", InitialWidth = 5, InitialHeight = 1, Missions = [ new MissionDef { Id = 1, Name = "Forge", TerrainPatch = new TerrainPatch { NewWidth = 5, NewHeight = 1, Cells = [ new PatchCell { Col = 0, Row = 0, Type = CellType.Production, Production = new ProductionDef(new Coords(0, 0), "Scierie", CargoType.Wood, 4) }, new PatchCell { Col = 2, Row = 0, Type = CellType.Transformer, Transformer = new TransformerDef(new Coords(2, 0), "Forge", CargoType.Wood, 2, CargoType.Tools, 1) }, new PatchCell { Col = 4, Row = 0, Type = CellType.Demand, Demand = new DemandDef(new Coords(4, 0), "Armurerie", CargoType.Tools, 2) } ] }, UnlockedPieces = [PieceKind.Rook], UnlockedLevels = [new PieceUpgrade(PieceKind.Rook, 1)], Stock = [new PieceStock(PieceKind.Rook, 3)] } ] }; } [Fact] public void Transformer_ReceivesInputCargo() { var campaign = CreateTransformerCampaign(); var sim = SimHelper.FromCampaign(campaign); sim.Sim.ProcessCommand(new LoadCampaignCommand()); // Place rook between production and transformer: (1,0)↔(2,0) // Rook oscillates between (1,0) and (2,0), picking up wood and delivering to transformer sim.Place(PieceKind.Rook, (0, 0), (1, 0)); var events = sim.StepN(5); // Should see cargo transferred to the transformer position Assert.Contains(events, e => e is CargoTransferredEvent ct && ct.To == new Coords(2, 0) && ct.Type == CargoType.Wood); } [Fact] public void Transformer_ConvertsAfterInputThreshold() { var campaign = CreateTransformerCampaign(); var sim = SimHelper.FromCampaign(campaign); sim.Sim.ProcessCommand(new LoadCampaignCommand()); // Rook delivers wood to transformer sim.Place(PieceKind.Rook, (0, 0), (1, 0)); var events = sim.StepN(10); // After enough deliveries, transformation should occur Assert.Contains(events, e => e is CargoConvertedEvent cc && cc.TransformerCell == new Coords(2, 0) && cc.InputCargo == CargoType.Wood && cc.OutputCargo == CargoType.Tools); } [Fact] public void Transformer_OutputPickedUpByPiece() { var campaign = CreateTransformerCampaign(); var sim = SimHelper.FromCampaign(campaign); sim.Sim.ProcessCommand(new LoadCampaignCommand()); // Rook 1: delivers wood to transformer sim.Place(PieceKind.Rook, (0, 0), (1, 0)); // Rook 2: picks up tools from transformer and delivers to demand sim.Place(PieceKind.Rook, (3, 0), (4, 0)); var events = sim.StepN(20); // Should see tools being transferred from transformer to rook 2 Assert.Contains(events, e => e is CargoTransferredEvent ct && ct.From == new Coords(2, 0) && ct.Type == CargoType.Tools); } [Fact] public void Transformer_FullChain_CompleteMission() { var campaign = CreateTransformerCampaign(); var sim = SimHelper.FromCampaign(campaign); sim.Sim.ProcessCommand(new LoadCampaignCommand()); // Full chain: Production → Rook1 → Transformer → Rook2 → Demand sim.Place(PieceKind.Rook, (0, 0), (1, 0)); // delivers wood to transformer sim.Place(PieceKind.Rook, (3, 0), (4, 0)); // picks up tools, delivers to demand var events = sim.StepN(50); // Mission should complete (2 tools delivered) Assert.Contains(events, e => e is MissionCompleteEvent); } [Fact] public void Transformer_DoesNotConvertWrongCargo() { // Transformer expects Wood but receives Stone — should not convert var campaign = new CampaignDef { Name = "Wrong Cargo", InitialWidth = 4, InitialHeight = 1, Missions = [ new MissionDef { Id = 1, Name = "M1", TerrainPatch = new TerrainPatch { NewWidth = 4, NewHeight = 1, Cells = [ new PatchCell { Col = 0, Row = 0, Type = CellType.Production, Production = new ProductionDef(new Coords(0, 0), "Carriere", CargoType.Stone, 4) }, new PatchCell { Col = 2, Row = 0, Type = CellType.Transformer, Transformer = new TransformerDef(new Coords(2, 0), "Forge", CargoType.Wood, 1, CargoType.Tools, 1) }, new PatchCell { Col = 3, Row = 0, Type = CellType.Demand, Demand = new DemandDef(new Coords(3, 0), "D", CargoType.Tools, 1) } ] }, UnlockedPieces = [PieceKind.Rook], UnlockedLevels = [new PieceUpgrade(PieceKind.Rook, 1)], Stock = [new PieceStock(PieceKind.Rook, 2)] } ] }; var sim = SimHelper.FromCampaign(campaign); sim.Sim.ProcessCommand(new LoadCampaignCommand()); sim.Place(PieceKind.Rook, (0, 0), (1, 0)); var events = sim.StepN(10); // No conversion should happen (stone != wood) Assert.DoesNotContain(events, e => e is CargoConvertedEvent); } [Fact] public void Transformer_AccumulatesInput() { // Transformer with inputRequired=3 should accumulate over multiple deliveries var campaign = new CampaignDef { Name = "Accumulate", InitialWidth = 4, InitialHeight = 1, Missions = [ new MissionDef { Id = 1, Name = "M1", TerrainPatch = new TerrainPatch { NewWidth = 4, NewHeight = 1, Cells = [ new PatchCell { Col = 0, Row = 0, Type = CellType.Production, Production = new ProductionDef(new Coords(0, 0), "Scierie", CargoType.Wood, 4) }, new PatchCell { Col = 2, Row = 0, Type = CellType.Transformer, Transformer = new TransformerDef(new Coords(2, 0), "Forge", CargoType.Wood, 3, CargoType.Tools, 2) }, new PatchCell { Col = 3, Row = 0, Type = CellType.Demand, Demand = new DemandDef(new Coords(3, 0), "D", CargoType.Tools, 2) } ] }, UnlockedPieces = [PieceKind.Rook], UnlockedLevels = [new PieceUpgrade(PieceKind.Rook, 1)], Stock = [new PieceStock(PieceKind.Rook, 2)] } ] }; var sim = SimHelper.FromCampaign(campaign); sim.Sim.ProcessCommand(new LoadCampaignCommand()); sim.Place(PieceKind.Rook, (0, 0), (1, 0)); sim.Place(PieceKind.Rook, (2, 0), (3, 0)); var events = sim.StepN(30); // After 3 wood deliveries, conversion should produce 2 tools var conversions = events.Where(e => e is CargoConvertedEvent cc && cc.OutputAmount == 2).ToList(); Assert.NotEmpty(conversions); // Mission should complete (2 tools delivered) Assert.Contains(events, e => e is MissionCompleteEvent); } }