using NUnit.Framework; using ProjectM.Simulation; namespace ProjectM.Tests { /// /// Pure-function tests for (no ECS world): the deterministic, save-reproducible /// expedition-wave composition. Pins the lower bound, the per-epoch ramp, and the grunt-heavy -> charger-heavy /// shift (grunt count held fixed; the per-epoch growth is all chargers). /// public class ZoneEnemyMathTests { [Test] public void WaveSize_LowerBoundedAtOne() { Assert.AreEqual(1, ZoneEnemyMath.WaveSize(0, 0, 0), "an occupied expedition always has at least one enemy"); Assert.AreEqual(1, ZoneEnemyMath.WaveSize(-5, 0, 0), "epoch is floored at 1 internally"); } [Test] public void WaveSize_BaselinePlusOnePerEpoch() { Assert.AreEqual(5, ZoneEnemyMath.WaveSize(1, 4, 1), "epoch 1: 4 grunts + 1 charger"); Assert.AreEqual(7, ZoneEnemyMath.WaveSize(3, 4, 1), "epoch 3: baseline 5 + (3-1) ramp"); } [Test] public void IsChargerSlot_Epoch1_GruntsFirst_OneChargerLast() { // epoch 1, G=4 C=1 -> size 5, only the last slot is a charger. Assert.IsFalse(ZoneEnemyMath.IsChargerSlot(1, 0, 4, 1)); Assert.IsFalse(ZoneEnemyMath.IsChargerSlot(1, 3, 4, 1)); Assert.IsTrue(ZoneEnemyMath.IsChargerSlot(1, 4, 4, 1)); } [Test] public void Composition_GruntCountFixed_ChargerShareGrowsWithEpoch() { AssertComposition(epoch: 1, grunts: 4, chargers: 1, expectGrunts: 4, expectChargers: 1); AssertComposition(epoch: 5, grunts: 4, chargers: 1, expectGrunts: 4, expectChargers: 5); } static void AssertComposition(int epoch, int grunts, int chargers, int expectGrunts, int expectChargers) { int size = ZoneEnemyMath.WaveSize(epoch, grunts, chargers); int g = 0, c = 0; for (int slot = 0; slot < size; slot++) if (ZoneEnemyMath.IsChargerSlot(epoch, slot, grunts, chargers)) c++; else g++; Assert.AreEqual(expectGrunts, g, $"grunt count at epoch {epoch}"); Assert.AreEqual(expectChargers, c, $"charger count at epoch {epoch}"); } [Test] public void IsChargerSlot_Deterministic() { for (int slot = 0; slot < 9; slot++) Assert.AreEqual(ZoneEnemyMath.IsChargerSlot(5, slot, 4, 1), ZoneEnemyMath.IsChargerSlot(5, slot, 4, 1)); } } }