Files
Dune/tests/fixture-truth-revival-expression.ts

83 lines
4.9 KiB
TypeScript

import assert from 'node:assert/strict';
import { viewGame, type Action, type Game } from '../game/engine';
import { parseRevivalExpression, type RevivalExpression } from '../game/revival-expression-promises';
import {
actTruthLeaderRevival, createTruthLeaderRevivalFixture, declareTruthLeaderRevival,
nextTruthLeaderRevival, truthLeaderRevivalClean, truthLeaderRevivalInventory,
truthLeaderRevivalPlayer, type TruthLeaderRevivalStep,
} from './fixture-truth-leader-revival';
export type TruthRevivalExpressionStep = TruthLeaderRevivalStep;
export const actTruthRevivalExpression = actTruthLeaderRevival;
export const truthRevivalExpressionClean = truthLeaderRevivalClean;
export const truthRevivalExpressionInventory = truthLeaderRevivalInventory;
export const truthRevivalExpressionPlayer = truthLeaderRevivalPlayer;
export function nextTruthRevivalExpression(game: Game): TruthRevivalExpressionStep | null {
if (game.truthtrance) return null;
for (const player of game.players) {
const guide = viewGame(game, player.id).revivalExpressionPromiseGuide;
if (guide?.phase === game.phase) return { actor: player.id, action: guide.action };
}
return nextTruthLeaderRevival(game);
}
export function advanceTruthRevivalExpression(game: Game, until: (state: Game) => boolean,
actions: TruthRevivalExpressionStep[] = []): Game {
for (let count = 0; count < 1600; count++) {
if (until(game)) return game;
assert.notEqual(game.status, 'finished');
const step = nextTruthRevivalExpression(game); assert.ok(step, 'The original grouped Revival source needs a legal native step');
game = actTruthRevivalExpression(game, step.actor, step.action, actions);
}
throw Error('The original grouped Revival source did not reach its finite boundary');
}
export function settleTruthRevivalExpression(game: Game, actions: TruthRevivalExpressionStep[] = []): Game {
return advanceTruthRevivalExpression(game, truthRevivalExpressionClean, actions);
}
export function finishTruthRevivalExpression(game: Game, actions: TruthRevivalExpressionStep[] = []): Game {
const turn = game.turn;
return advanceTruthRevivalExpression(game,
state => state.turn === turn && state.phase === 5 && truthRevivalExpressionClean(state), actions);
}
/** Thin source adapter: the complete public H/A/T Ix47 setup, original deals,
* real paid shipment/projectile death and next Storm are inherited unchanged.
* The question alone changes; no physical state or promise is installed. */
export function createTruthRevivalExpressionFixture(options: {
advanced?: boolean; window?: 'active' | 'waiting'; ghola?: boolean; bothDead?: boolean;
claim?: RevivalExpression;
} = {}) {
const { claim: suppliedClaim, ...sourceOptions } = options;
const base = createTruthLeaderRevivalFixture(sourceOptions);
const claim = parseRevivalExpression(suppliedClaim ?? { kind: 'and', terms: [
{ kind: 'forces', counter: 'total', minimum: 1 }, { kind: 'leader', leader: base.leader },
] });
const question = { kind: 'revivalExpression' as const, target: base.target, turn: base.game.turn, claim };
return { ...base, base, claim, question, questionAction: { type: 'truthAsk', question } as Action,
postStormSourceActions: structuredClone(base.sourceActions.slice(0, base.postStormActionCount)),
phase3SourceActions: structuredClone(base.sourceActions.slice(0, base.phase3ActionCount)),
sourceDisclosure: `${base.sourceDisclosure} This adapter inherits the exact original action prefix and changes only the grouped ordinary Revival question; its progress starts after the actual answer.` };
}
export type TruthRevivalExpressionFixture = ReturnType<typeof createTruthRevivalExpressionFixture>;
export function declareTruthRevivalExpression(f: TruthRevivalExpressionFixture, state = f.game,
options: { copies?: 1 | 2 } = {}) {
return declareTruthLeaderRevival(f.base, state, options);
}
export function askTruthRevivalExpression(game: Game, asker: string, target: string, claim: RevivalExpression,
actions: TruthRevivalExpressionStep[] = []): Game {
return actTruthRevivalExpression(game, asker, { type: 'truthAsk', question: {
kind: 'revivalExpression', target, turn: game.turn, claim: parseRevivalExpression(claim),
} }, actions);
}
export function answerTruthRevivalExpression(game: Game, target: string, answer: 'yes' | 'no',
actions: TruthRevivalExpressionStep[] = []): Game {
return actTruthRevivalExpression(game, target, { type: 'truthAnswer', answer }, actions);
}
export function bindTruthRevivalExpression(f: TruthRevivalExpressionFixture, answer: 'yes' | 'no' = 'yes',
claim = f.claim, state = f.game) {
const declared = declareTruthRevivalExpression(f, state), actions = [...declared.actions];
const asked = askTruthRevivalExpression(declared.game, f.asker, f.target, claim, actions);
const game = answerTruthRevivalExpression(asked, f.target, answer, actions);
return { game, declared, asked, actions, actionCount: actions.length };
}