diff --git a/src/components/EternalDominationGame.tsx b/src/components/EternalDominationGame.tsx index cb01d45..481b610 100644 --- a/src/components/EternalDominationGame.tsx +++ b/src/components/EternalDominationGame.tsx @@ -282,35 +282,15 @@ const defendAttack = (guards: Set, attack: Position): { shiftBorderToFillGap(newGuards, movements, currentGap); } - // STEP 3: Check if we need a second chain (Figure 10 shows two chains) - // This happens when the attack disrupts multiple domination lines - - // Find interior positions that are now undominated and need filling - for (let x = 1; x < COLS - 1; x++) { - for (let y = 2; y < ROWS - 2; y++) { - if (!isDominated(x, y, newGuards)) { - // Need to get a guard here - const nbs = getHexNeighbors(x, y); - const nearbyGuard = nbs.find(n => newGuards.has(posKey(n)) && isInterior(n.x, n.y)); - - if (nearbyGuard) { - newGuards.delete(posKey(nearbyGuard)); - newGuards.add(posKey({ x, y })); - movements.push({ from: nearbyGuard, to: { x, y }, type: 'interior' }); - } else { - // Use border guard - const borderGuard = nbs.find(n => newGuards.has(posKey(n)) && isBorder(n.x, n.y)); - if (borderGuard) { - newGuards.delete(posKey(borderGuard)); - newGuards.add(posKey({ x, y })); - movements.push({ from: borderGuard, to: { x, y }, type: 'toInterior' }); - shiftBorderToFillGap(newGuards, movements, borderGuard); - } - } - } - } - } - + // NOTE: The paper's strategy restores the original configuration via the border "patchwork" + // (complementary paths) rather than ad-hoc re-domination fixes. + // + // The previous implementation included an extra "scan for undominated vertices and move a nearby guard" + // step, which can look like guards "manifest" and is not part of the Figure 10 defense. + + // Safety: guards are never created/destroyed—only moved. + if (newGuards.size !== guards.size) return null; + return { newGuards, movements }; };