Files
Dune/tests/fixture-sapho-truth-richese.ts

74 lines
4.7 KiB
TypeScript

import assert from 'node:assert/strict';
import { type Game } from '../game/engine';
import { createTruthRicheseBidFixture } from './fixture-truth-richese-bid';
import { createTruthRicheseSilentFixture } from './fixture-truth-richese-silent';
import { act, inventory, player } from './fixture-truth-richese-bid';
import { truthOrderFrame } from './fixture-sapho-truth-order';
export { act, inventory, player };
/** Native public R/A/E setup and actual started first cache lot. Controlled,
* conserved custody supplements: swap the original cached Sapho for Emperor's
* dealt card; move an undealt original Truth to his vacant hand slot; optionally
* swap original cached Semuta for Richese's dealt card. None is represented as
* an earned purchase. The other actual dealt Truth, lot and funds stay native. */
export function createSaphoTruthRicheseFixture(options: {
advanced?: boolean; method?: 'onceAround' | 'silent'; semuta?: boolean; standingBid?: boolean;
} = {}) {
const advanced = options.advanced ?? false, method = options.method ?? 'onceAround';
const source = method === 'silent' ? createTruthRicheseSilentFixture(advanced) : createTruthRicheseBidFixture(advanced);
let game = structuredClone(source.game);
const owner = source.target, other = source.asker, semutaHolder = source.owner, lot = source.lot;
const cache = game.richeseCache!;
const saphoAt = cache.findIndex(card => card.effect === 'juiceOfSapho');
assert.ok(saphoAt >= 0, 'The original cache must contain Sapho');
const receiver = player(game,owner);
assert.ok(receiver.hand.length);
const [sapho] = cache.splice(saphoAt,1), [exchange] = receiver.hand.splice(0,1);
receiver.hand.push(sapho); cache.push(exchange);
const truthAt = game.deck.findIndex(card => card.effect === 'truthtrance');
assert.ok(truthAt >= 0, 'A second original Truth is available in the undealt deck');
const [truth] = game.deck.splice(truthAt,1); receiver.hand.push(truth);
let semuta: string | null = null;
if (options.semuta) {
const at = cache.findIndex(card => card.effect === 'semutaDrug'); assert.ok(at >= 0);
const claimant = player(game,semutaHolder); assert.ok(claimant.hand.length);
const [drug] = cache.splice(at,1), [held] = claimant.hand.splice(0,1);
claimant.hand.push(drug); cache.push(held); semuta = drug.id;
}
assert.deepEqual(inventory(game),source.originalCards);
if (options.standingBid) {
const bidder = method === 'silent' ? semutaHolder : game.richeseAuction!.active!;
game = act(game,bidder,{type:'richeseBid',event:lot,amount:1,allyPayment:0});
assert.ok(game.richeseAuction && !game.richeseAuction.outcome);
}
const mode = game.order.indexOf(owner) > game.order.indexOf(other) ? 'first' as const : 'last' as const;
const parent = {
turn:game.turn, phase:game.phase, active:game.active, order:structuredClone(game.order),
auction:structuredClone(game.richeseAuction), funding:structuredClone(game.richeseFunding),
bidding:structuredClone(game.richeseBidding), aid:structuredClone(game.aid),
offered:structuredClone(game.richeseOfferedCard),
players:game.players.map(row => ({id:row.id,spice:row.spice,reserves:row.reserves,tanks:row.tanks})),
};
const beforeTruth = structuredClone(game);
for (const [actor,card] of [[owner,truth.id],[other,source.truth]] as const)
game = act(game,actor,{type:'card',card});
while (game.truthtrance?.stage === 'priority') {
const next = game.players.find(row => !game.truthtrance!.passed.includes(row.id)); assert.ok(next);
game = act(game,next.id,{type:'truthPass'});
}
assert.deepEqual([...truthOrderFrame(game).holders].sort(),[owner,other].sort());
assertRicheseParent(game,parent);
return {game,source,advanced,method,owner,other,semutaHolder,card:sapho.id,semuta,truth:truth.id,
otherTruth:source.truth,lot,mode,parent,beforeTruth,originalCards:source.originalCards,
disclosure:'Actual public setup and native cache lot; labelled conserved cache/hand swaps and undealt Truth placement.'};
}
export type SaphoTruthRicheseFixture = ReturnType<typeof createSaphoTruthRicheseFixture>;
export function assertRicheseParent(game: Game, parent: SaphoTruthRicheseFixture['parent']) {
assert.equal(game.turn,parent.turn); assert.equal(game.phase,parent.phase); assert.equal(game.active,parent.active);
assert.deepEqual(game.order,parent.order); assert.deepEqual(game.richeseAuction,parent.auction);
assert.deepEqual(game.richeseFunding,parent.funding); assert.deepEqual(game.richeseBidding,parent.bidding);
assert.deepEqual(game.aid,parent.aid); assert.deepEqual(game.richeseOfferedCard,parent.offered);
assert.deepEqual(game.players.map(row => ({id:row.id,spice:row.spice,reserves:row.reserves,tanks:row.tanks})),parent.players);
}