Files
Dune/tests/fixture-truth-movement-sector.ts

80 lines
4.9 KiB
TypeScript

import assert from 'node:assert/strict';
import type { Action, Game } from '../game/engine';
import type { MovementExpression } from '../game/movement-expression-promises';
import type { MixedActionExpression } from '../game/mixed-action-question';
import type { TurnActionLeaf } from '../game/turn-action-promises';
import {
actTruthMovementExpression, createTruthMovementExpressionFixture,
declareTruthMovementExpression, settleTruthMovementExpression,
truthMovementExpressionInventory, truthMovementExpressionPlayer,
} from './fixture-truth-movement-expression';
export type MovementSectorQuestionKind = 'movement' | 'movementExpression' | 'mixedMovement' | 'travel' | 'turnActions';
export const actMovementSector = actTruthMovementExpression;
export const settleMovementSector = settleTruthMovementExpression;
export const movementSectorInventory = truthMovementExpressionInventory;
export const movementSectorPlayer = truthMovementExpressionPlayer;
/** Genuine Basic Atreides/Emperor setup and the original one-force Polar Sink
* shipment. The starting Hajr and Truthtrance are original unopened selected
* deal positions. This adapter chooses two unstormed printed Imperial Basin
* sectors adjacent to the original Arrakeen army; it installs no hand, force,
* wallet, timer, question, promise, progress or saved state. */
export function createTruthMovementSectorFixture() {
const base = createTruthMovementExpressionFixture(), game = structuredClone(base.game);
assert.equal(game.advanced, false); assert.equal(game.phase, 5); assert.equal(game.active, base.target);
assert.ok(base.hajr && movementSectorPlayer(game, base.target).hand.some(card => card.id === base.hajr));
const sectors = [9, 10, 11].filter(sector => sector !== game.storm);
assert.ok(sectors.length >= 2);
const [sector, alternative] = sectors;
const move = (destination: number, amount = 1): Action => ({ type: 'move', from: 'arrakeen:10',
territory: 'imperial_basin', sector: destination, amount });
const leaf = (destination: number, minimum = 1): MovementExpression => ({ kind: 'move',
territory: 'imperial_basin', sector: destination, minimum });
const action = (destination: number, minimum = 1): MixedActionExpression<TurnActionLeaf> => ({
kind: 'action', action: { kind: 'move', territory: 'imperial_basin', sector: destination, minimum },
});
const forceTotal = (state: Game) => {
const player = movementSectorPlayer(state, base.target);
return player.reserves + player.tanks + Object.values(player.forces).reduce((sum, amount) => sum + amount, 0);
};
assert.deepEqual(movementSectorInventory(game), base.originalCards);
return { base, game, target: base.target, asker: base.asker, truth: base.truth, hajr: base.hajr,
sector, alternative, move, leaf, action, originalCards: base.originalCards, forceTotal,
originalForces: forceTotal(game), disclosure: base.sourceDisclosure };
}
export type TruthMovementSectorFixture = ReturnType<typeof createTruthMovementSectorFixture>;
export function askMovementSector(game: Game, f: TruthMovementSectorFixture, kind: MovementSectorQuestionKind,
grouped = false): Game {
const exact = f.leaf(f.sector, grouped ? 2 : 1), other = f.leaf(f.alternative, 1);
let question: Record<string, unknown>;
if (kind === 'movement') {
assert.equal(grouped, false);
question = { kind, target: f.target, territory: 'imperial_basin', sector: f.sector, minimum: 1 };
} else if (kind === 'movementExpression') {
question = { kind, target: f.target, turn: game.turn,
claim: grouped ? { kind: 'and', terms: [exact, other] } : exact };
} else if (kind === 'mixedMovement') {
const physicalHajr = movementSectorPlayer(game, f.target).hand.find(card => card.id === f.hajr);
assert.ok(physicalHajr);
const knownFact = { kind: 'fact', fact: { kind: 'hand', name: physicalHajr.name } };
const selected = { kind: 'action', action: { territory: 'imperial_basin', sector: f.sector, minimum: grouped ? 2 : 1 } };
const second = { kind: 'action', action: { territory: 'imperial_basin', sector: f.alternative, minimum: 1 } };
question = { kind, target: f.target, turn: game.turn,
mixed: { kind: 'and', terms: grouped ? [knownFact, selected, second] : [knownFact, selected] } };
} else {
question = { kind, target: f.target, turn: game.turn, mixed: grouped
? { kind: 'and', terms: [f.action(f.sector, 2), f.action(f.alternative)] }
: f.action(f.sector) };
}
return actMovementSector(game, f.asker, { type: 'truthAsk', question } as Action);
}
export function bindMovementSector(f: TruthMovementSectorFixture, kind: MovementSectorQuestionKind,
answer: 'yes' | 'no', grouped = false) {
const declared = declareTruthMovementExpression(f.base, f.game).game;
const asked = askMovementSector(declared, f, kind, grouped);
const game = actMovementSector(asked, f.target, { type: 'truthAnswer', answer });
return { declared, asked, game };
}