63 lines
3.5 KiB
TypeScript
63 lines
3.5 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import type { Game } from '../game/engine';
|
|
import { actTruthBid, advanceTruthBid, createTruthBidFixture, declareTruthBid,
|
|
nextTruthBid, truthBidClean, truthBidPlayer, type TruthBidStep } from './fixture-truth-bid';
|
|
|
|
export type TruthTurnBidStep = TruthBidStep;
|
|
export const actTruthTurnBid = actTruthBid;
|
|
export const truthTurnBidPlayer = truthBidPlayer;
|
|
export const truthTurnBidClean = truthBidClean;
|
|
export const advanceTruthTurnBid = advanceTruthBid;
|
|
|
|
/** Original H/A/E (optional G) setup, starting deal, ordinary lot creation,
|
|
* and native controls from the shared fixture; only unopened original deal,
|
|
* lot/Spice positions and scalar lotteries are selected. */
|
|
export function createTruthTurnBidFixture(options: { advanced?: boolean; extraGuild?: boolean } = {}) {
|
|
const original = createTruthBidFixture({ advanced: options.advanced, extraGuild: options.extraGuild, window:'waiting' });
|
|
return { ...original, phaseQuestion: { kind:'phaseBid' as const, target:original.target,
|
|
turn:original.game.turn, minimum:4 },
|
|
sourceDisclosure: `${original.sourceDisclosure} Phase-wide question, answer and all subsequent bids remain caller actions.` };
|
|
}
|
|
export type TruthTurnBidFixture = ReturnType<typeof createTruthTurnBidFixture>;
|
|
|
|
export function bindTruthTurnBid(f: TruthTurnBidFixture, answer: 'yes'|'no', minimum = 4, state = f.game) {
|
|
const declared = declareTruthBid(f,state), actions = [...declared.actions];
|
|
let game = actTruthBid(declared.game,f.asker,{ type:'truthAsk', question: {
|
|
kind:'phaseBid', target:f.target, turn:declared.game.turn, minimum,
|
|
} },actions);
|
|
const asked = structuredClone(game);
|
|
game = actTruthBid(game,f.target,{type:'truthAnswer',answer},actions);
|
|
return { game, declared, asked, actions };
|
|
}
|
|
|
|
/** Finish exactly the existing lot after a genuine winning bid; no future bid
|
|
* or pool is installed. Neutral native continuations pay and advance it. */
|
|
export function finishTruthTurnBidLot(game: Game, actions: TruthBidStep[] = []) {
|
|
assert.ok(game.auction && game.auction.bidder && game.auction.bid > 0);
|
|
const turn = game.turn, index = game.auction.index;
|
|
return advanceTruthBid(game,state => truthBidClean(state) &&
|
|
(state.turn !== turn || state.phase !== 3 || !state.auction || state.auction.index !== index),actions);
|
|
}
|
|
|
|
/** Purchase this actual lot for one spice by the named player. Other bidders
|
|
* pass using native controls; native payment and Emperor income settle. */
|
|
export function purchaseTruthTurnBidLot(game: Game, winner: string, actions: TruthBidStep[] = []) {
|
|
assert.ok(game.auction); const turn = game.turn, index = game.auction.index;
|
|
const card = game.auction.cards[index].id, before = structuredClone(game);
|
|
for (let n = 0; n < 150; n++) {
|
|
if (truthBidClean(game) && (game.turn !== turn || game.phase !== 3 || !game.auction || game.auction.index !== index)) {
|
|
assert.ok(truthBidPlayer(game,winner).hand.some(c => c.id === card));
|
|
return {game,before,card};
|
|
}
|
|
if (truthBidClean(game) && game.auction && game.auction.index === index && !game.currentAuctionSale) {
|
|
const actor = game.auction.active;
|
|
game = actTruthBid(game,actor,actor === winner && !game.auction.bidder
|
|
? {type:'bid',amount:1,allyPayment:0} : {type:'passBid'},actions);
|
|
} else {
|
|
const step = nextTruthBid(game); assert.ok(step);
|
|
game = actTruthBid(game,step.actor,step.action,actions);
|
|
}
|
|
}
|
|
throw Error('The actual funded ordinary purchase did not finish');
|
|
}
|