refactor(battlenode): M-HC-4 cleanup — EpCount rename, dedupe evolve-ramp, drop tautological guard
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -461,24 +461,13 @@ public class HeadlessConductorTests
|
||||
int attackerIdx = harness.InPlayCardIndex(playerSeat: true, boardPos: 0);
|
||||
|
||||
// --- ramp seat A to the turn its evolve unlocks (EvolveWaitTurnCount counts down per seat-A turn) ---
|
||||
// End turn 1 first (TurnEnd sets NowTurnEvol = true, the other CanEvolution precondition), then
|
||||
// alternate A/B TurnStart/TurnEnd until seat A's EvolveWaitTurnCount reaches 0, leaving seat A's
|
||||
// turn OPEN. A guard bounds the loop so a never-unlocking bug fails loud instead of hanging.
|
||||
// End turn 1 first (TurnEnd sets NowTurnEvol = true, the other CanEvolution precondition), then ramp.
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnEnd, TurnEndBody(), isPlayerSeat: true).Accepted, Is.True, "turn1 TurnEnd");
|
||||
bool seatA = false; // next TurnStart is seat B's
|
||||
int guard = 0;
|
||||
while (harness.EvolveWaitTurnCount(playerSeat: true) > 0)
|
||||
{
|
||||
Assert.That(++guard, Is.LessThan(20), "evolve never unlocked — EvolveWaitTurnCount stuck > 0");
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnStart, TurnStartBody(), isPlayerSeat: seatA).Accepted, Is.True, "ramp TurnStart");
|
||||
if (seatA && harness.EvolveWaitTurnCount(playerSeat: true) == 0) break; // leave seat A's turn open
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnEnd, TurnEndBody(), isPlayerSeat: seatA).Accepted, Is.True, "ramp TurnEnd");
|
||||
seatA = !seatA;
|
||||
}
|
||||
RampSeatAToEvolveTurn(harness);
|
||||
|
||||
// EP precondition: seat A holds at least 1 evolve point and evolve is now unlocked.
|
||||
Assert.That(harness.EvolveWaitTurnCount(playerSeat: true), Is.EqualTo(0), "evolve unlocked on seat A's turn");
|
||||
int epBefore = harness.Ep(playerSeat: true);
|
||||
int epBefore = harness.EpCount(playerSeat: true);
|
||||
Assert.That(epBefore, Is.GreaterThanOrEqualTo(1), "seat A must hold >= 1 EP before evolving");
|
||||
|
||||
// Pre-evolve stats: the un-evolved vanilla is 1/2 and not yet flagged evolved.
|
||||
@@ -499,7 +488,7 @@ public class HeadlessConductorTests
|
||||
"evolved atk must equal the card's evo_atk (3) — base 1 + evolve delta +2");
|
||||
Assert.That(harness.InPlayCardLife(playerSeat: true, boardPos: 0), Is.EqualTo(evolvedLife),
|
||||
"evolved life must equal the card's evo_life (4) — base 2 + evolve delta +2");
|
||||
Assert.That(harness.Ep(playerSeat: true), Is.EqualTo(epBefore - 1),
|
||||
Assert.That(harness.EpCount(playerSeat: true), Is.EqualTo(epBefore - 1),
|
||||
"an evolve must spend exactly one evolve point");
|
||||
}
|
||||
|
||||
@@ -923,6 +912,24 @@ public class HeadlessConductorTests
|
||||
}
|
||||
}
|
||||
|
||||
// Ramp seat A to the turn its evolve unlocks (seat A's EvolveWaitTurnCount counts down per seat-A turn),
|
||||
// leaving seat A's turn OPEN. Caller must have already ended seat A's first turn (TurnEnd sets
|
||||
// NowTurnEvol = true, the other CanEvolution precondition) so the next TurnStart is seat B's. A guard
|
||||
// bounds the loop so a never-unlocking bug fails loud instead of hanging.
|
||||
private static void RampSeatAToEvolveTurn(NodeNativeBattleHarness harness)
|
||||
{
|
||||
bool seatA = false; // next TurnStart is seat B's
|
||||
int guard = 0;
|
||||
while (harness.EvolveWaitTurnCount(playerSeat: true) > 0)
|
||||
{
|
||||
Assert.That(++guard, Is.LessThan(20), "evolve never unlocked — EvolveWaitTurnCount stuck > 0");
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnStart, TurnStartBody(), isPlayerSeat: seatA).Accepted, Is.True, "ramp TurnStart");
|
||||
if (seatA && harness.EvolveWaitTurnCount(playerSeat: true) == 0) break; // leave seat A's turn open
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnEnd, TurnEndBody(), isPlayerSeat: seatA).Accepted, Is.True, "ramp TurnEnd");
|
||||
seatA = !seatA;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Real_spell_charge_drops_engine_cost_and_count_no_seam()
|
||||
{
|
||||
@@ -1094,25 +1101,13 @@ public class HeadlessConductorTests
|
||||
|
||||
// --- ramp seat A to the turn its evolve unlocks (mirrors Evolve_resolves_on_engine_state_headless) ---
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnEnd, TurnEndBody(), isPlayerSeat: true).Accepted, Is.True, "turn1 TurnEnd");
|
||||
bool seatA = false; // next TurnStart is seat B's
|
||||
int guard = 0;
|
||||
while (harness.EvolveWaitTurnCount(playerSeat: true) > 0)
|
||||
{
|
||||
Assert.That(++guard, Is.LessThan(20), "evolve never unlocked — EvolveWaitTurnCount stuck > 0");
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnStart, TurnStartBody(), isPlayerSeat: seatA).Accepted, Is.True, "ramp TurnStart");
|
||||
if (seatA && harness.EvolveWaitTurnCount(playerSeat: true) == 0) break; // leave seat A's turn open
|
||||
Assert.That(harness.Push(NetworkBattleUri.TurnEnd, TurnEndBody(), isPlayerSeat: seatA).Accepted, Is.True, "ramp TurnEnd");
|
||||
seatA = !seatA;
|
||||
}
|
||||
RampSeatAToEvolveTurn(harness);
|
||||
Assert.That(harness.EvolveWaitTurnCount(playerSeat: true), Is.EqualTo(0), "evolve unlocked on seat A's turn");
|
||||
Assert.That(harness.Ep(playerSeat: true), Is.GreaterThanOrEqualTo(1), "seat A must hold >= 1 EP before evolving");
|
||||
Assert.That(harness.EpCount(playerSeat: true), Is.GreaterThanOrEqualTo(1), "seat A must hold >= 1 EP before evolving");
|
||||
|
||||
// The reducer must be IN HAND across the evolve (its when_evolve_other skill is scanned off the hand).
|
||||
int reducerHandIdx = FindHandIdxByCardId(harness, BoardDependentCostCardId);
|
||||
Assert.That(reducerHandIdx, Is.GreaterThan(0), "the board-dependent cost-reducer must be in seat A's hand at the evolve");
|
||||
Assert.That(harness.HandCardId(playerSeat: true,
|
||||
FindHandPosByEngineIdx(harness, reducerHandIdx)), Is.EqualTo((int)BoardDependentCostCardId),
|
||||
"located the reducer by identity");
|
||||
|
||||
// PRE-EVOLVE pin (non-vacuity + causation baseline): the reducer resolves to its BASE cost (6) while
|
||||
// no follower has evolved yet. Read it WHILE in hand by its engine Index.
|
||||
@@ -1395,14 +1390,4 @@ public class HeadlessConductorTests
|
||||
Assert.That(tokenIdx, Is.EqualTo(0),
|
||||
"FINDING: the autonomous token_draw seats the chosen token at engine Index 0 headless — not addressable by a wire idx");
|
||||
}
|
||||
|
||||
// The hand POSITION (0-based) of the seat-A hand card with the given engine Index, or -1. Lets a test
|
||||
// re-derive a HandCardId(seat, pos) lookup from an engine Index it already located by identity.
|
||||
private static int FindHandPosByEngineIdx(NodeNativeBattleHarness harness, int engineIdx)
|
||||
{
|
||||
for (int i = 0; i < harness.HandCount(playerSeat: true); i++)
|
||||
if (harness.HandCardIndex(playerSeat: true, i) == engineIdx)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ internal sealed class NodeNativeBattleHarness : IDisposable
|
||||
public bool IsEvolved(bool playerSeat, int boardPos) => Engine.IsEvolved(playerSeat, boardPos);
|
||||
|
||||
/// <summary>The seat's current evolve-point count (M-HC-4b). An evolve spends one EP.</summary>
|
||||
public int Ep(bool playerSeat) => Engine.Ep(playerSeat);
|
||||
public int EpCount(bool playerSeat) => Engine.EpCount(playerSeat);
|
||||
|
||||
/// <summary>Turns remaining until the seat may evolve (0 == unlocked) (M-HC-4b).</summary>
|
||||
public int EvolveWaitTurnCount(bool playerSeat) => Engine.EvolveWaitTurnCount(playerSeat);
|
||||
|
||||
Reference in New Issue
Block a user