Compose native Ecaz and Moritani Stronghold rule paths

This commit is contained in:
Quintine committed 2026-10-04 01:31:22 +10:00
1 parent 50808aed5e
commit 39e2954ab4
15 files changed
+1010 -91

No files matched your search

-63
View File
@@ -14,10 +14,6 @@ import { tmpdir } from 'node:os';
import { join } from 'node:path';
import type { Game } from '../game/engine';
import { isAuditorLeader, treacheryDeck } from '../game/cards';
import { richeseCards } from '../game/richese-cards';
import { STRONGHOLD_CARDS } from '../game/stronghold-cards';
import { sampleInventory, verifySampleCustody } from '../tools/sample-custody';
import { createTechTokens } from '../game/tech-tokens';
const root = new URL('../', import.meta.url).pathname;
const cli = new URL('../tools/faction-games.ts', import.meta.url).pathname;
@@ -102,65 +98,6 @@ function assertFailedEvidence(
return report;
}
void test('native Stronghold samples admit every two-to-six-seat roster and preserve canonical physical inventories', (t) => {
const area = temporary(t);
const out = join(area, 'native');
assert.equal(run(out, '--profile', 'stronghold-factions',
'--players', 'all', '--seed', '1000', '--max-actions', '1').status, 1);
const results = json<{ results: CliResult[] }>(join(out, 'results.json')).results;
const families = [
{ native: 'ixians-choam', expansions: ['ix', 'choam'],
roster: ['ixians', 'choam', 'emperor', 'fremen', 'harkonnen', 'beneGesserit'], counts: [2, 3, 4, 5, 6], ordinal: 151 },
{ native: 'ixians-tleilaxu', expansions: ['ix'],
roster: ['ixians', 'tleilaxu', 'emperor', 'fremen', 'harkonnen', 'beneGesserit'], counts: [2, 3, 4, 5, 6], ordinal: 156 },
{ native: 'choam-richese', expansions: ['choam'],
roster: ['choam', 'richese', 'emperor', 'fremen', 'harkonnen', 'beneGesserit'], counts: [2, 3, 4, 5, 6], ordinal: 161 },
{ native: 'ixians-tleilaxu-choam-richese', expansions: ['ix', 'choam'],
roster: ['ixians', 'tleilaxu', 'choam', 'richese', 'emperor', 'fremen'], counts: [4, 5, 6], ordinal: 166 },
];
const scenarios = families.flatMap(family => family.counts.map((count, index) => ({
...family, count, seed: 1000 + family.ordinal + index,
name: `stronghold-factions-${family.native}-${count}-advanced`,
})));
assert.deepEqual(results.map(result => result.name), scenarios.map(scenario => scenario.name));
for (const [index, result] of results.entries()) {
const scenario = scenarios[index];
assert.equal(result.seed, scenario.seed);
assert.equal(result.error, 'Error: Action limit');
assert.equal(result.actions, 1);
const game = json<Game>(join(out, `failed-${result.name}.json`));
assert.equal(game.advanced, true);
assert.deepEqual(game.expansions, scenario.expansions);
assert.deepEqual(game.players.map(player => player.faction), scenario.roster.slice(0, scenario.count));
assert.deepEqual(game.players.map(player => player.bot),
['Easy', 'Medium', 'Hard', 'Brutal', 'Easy', 'Medium'].slice(0, scenario.count));
const deck = treacheryDeck(scenario.expansions).map(card => card.id).sort();
assert.equal(deck.length, scenario.expansions.includes('ix') ? 47 : 35);
const cache = scenario.roster.includes('richese') ? richeseCards().map(card => card.id).sort() : [];
const inventory = sampleInventory(game);
assert.deepEqual(inventory.cards, [...deck, ...cache].sort());
assert.deepEqual((game.richeseCache ?? []).map(card => card.id).sort(), cache);
verifySampleCustody(game, inventory);
assert.deepEqual(Object.keys(game.strongholdCards!.owners).sort(),
STRONGHOLD_CARDS.map(card => card.id).sort());
assert.ok(Object.values(game.strongholdCards!.owners).every(owner => owner === null));
assert.equal(game.strongholdCards!.claimedTurn, 0);
const choam = game.players.find(player => player.faction === 'choam');
if (choam) assert.equal(choam.leaders.filter(isAuditorLeader).length, 1);
}
for (const scenario of scenarios.filter(candidate => candidate.count === 6)) {
const snapshot = join(out, `failed-${scenario.name}.json`);
const original = readFileSync(snapshot, 'utf8');
const continued = join(area, `continued-${scenario.native}`);
assert.equal(run(continued, '--resume', snapshot, '--seed', '1000',
'--max-actions', '1').status, 1);
const report = assertFailedEvidence(continued, scenario.name, scenario.seed, true);
assert.equal(report.options.resume?.path, snapshot);
verifySampleCustody(json<Game>(join(continued, `failed-${scenario.name}.json`)),
sampleInventory(json<Game>(snapshot)), json<Game>(snapshot));
assert.equal(readFileSync(snapshot, 'utf8'), original);
}
});
void test('native Stronghold admission and resume reject foreign profiles and corrupted custody before gameplay', (t) => {
const area = temporary(t);