Prototype conditional future battle Truthtrance
Verify and publish checkpoint container / container (push) Failing after 11m11s
Verify and publish checkpoint container / container (push) Failing after 11m11s
This commit is contained in:
1 parent
71009d73e3
commit
02695aea7c
15 files changed
+721
-8
No files matched your search
@@ -0,0 +1,110 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import { viewGame, type Action, type Game } from '../game/engine';
|
||||
import { botActions } from '../game/bots';
|
||||
import { DIFFICULTIES } from '../game/bot-profiles';
|
||||
import {
|
||||
actFutureBattleLeader as act, advanceFutureBattleLeader as advance,
|
||||
answerFutureBattleLeader as answer, createFutureBattleLeaderFixture as fixture,
|
||||
declareFutureBattleLeader as declare, futureBattleLeaderClean as clean,
|
||||
futureBattleLeaderInventory as inventory, futureBattleLeaderRecords as records,
|
||||
reachFutureBattle as reachBattle,
|
||||
} from './fixture-truth-future-battle-leader';
|
||||
|
||||
function rejected(game: Game, actor: string, action: Action) {
|
||||
const before = structuredClone(game);
|
||||
assert.throws(() => act(game, actor, action));
|
||||
assert.deepEqual(game, before);
|
||||
}
|
||||
|
||||
for (const expected of ['yes', 'no'] as const) {
|
||||
void test(`Basic next battle leader ${expected} binds the first real battle and constrains its native plan`, () => {
|
||||
const f = fixture();
|
||||
const asked = declare(f);
|
||||
assert.equal(asked.truthtrance?.stage, 'answer');
|
||||
assert.deepEqual(asked.truthtrance?.question, f.question);
|
||||
let game = answer(asked, f, expected);
|
||||
assert.equal(game.truthtrance, null);
|
||||
assert.equal(game.discard.filter(card => card.id === f.truth).length, 1);
|
||||
assert.equal(records(game).length, 1);
|
||||
assert.equal(records(game)[0].status, 'waiting');
|
||||
assert.equal(records(game)[0].player, f.target);
|
||||
assert.equal(records(game)[0].leader, f.leader);
|
||||
assert.equal(records(game)[0].answer, expected === 'yes');
|
||||
rejected(game, f.target, { type: 'truthAnswer', answer: expected });
|
||||
assert.equal(records(game).length, 1);
|
||||
|
||||
game = reachBattle(game, f);
|
||||
assert.equal(records(game)[0].status, 'bound');
|
||||
assert.equal(records(game)[0].battle, game.battle!.event);
|
||||
const yesPlan = { ...f.targetPlan, leader: f.leader } as Action;
|
||||
const noPlan = { ...f.targetPlan, leader: f.otherLeader } as Action;
|
||||
rejected(game, f.target, expected === 'yes' ? noPlan : yesPlan);
|
||||
game = act(game, f.target, expected === 'yes' ? yesPlan : noPlan);
|
||||
assert.equal(records(game)[0].status, 'bound');
|
||||
game = act(game, f.asker, f.ownPlan);
|
||||
assert.ok(game.battle?.revealed);
|
||||
assert.equal(records(game)[0].status, 'settled');
|
||||
assert.equal(records(game).length, 1);
|
||||
assert.equal(game.discard.filter(card => card.id === f.truth).length, 1);
|
||||
assert.deepEqual(inventory(game), f.originalCards);
|
||||
});
|
||||
}
|
||||
|
||||
void test('Basic next battle leader question expires without creating a battle or forcing a shipment', () => {
|
||||
const f = fixture();
|
||||
for (const expected of ['yes', 'no'] as const) {
|
||||
let game = answer(declare(f), f, expected);
|
||||
const before = structuredClone(game.players.find(player => player.id === f.target));
|
||||
game = act(game, f.target, { type: 'endMovement' });
|
||||
game = advance(game, state => state.turn !== f.game.turn || state.phase > 6 || state.status === 'finished');
|
||||
assert.equal(game.battle, null);
|
||||
assert.equal(records(game).length, 1);
|
||||
assert.equal(records(game)[0].status, 'expired');
|
||||
const after = game.players.find(player => player.id === f.target); assert.ok(before && after);
|
||||
assert.equal(after.reserves, before.reserves);
|
||||
assert.deepEqual(after.forces, before.forces);
|
||||
assert.equal(game.discard.filter(card => card.id === f.truth).length, 1);
|
||||
assert.deepEqual(inventory(game), f.originalCards);
|
||||
assert.ok(clean(game));
|
||||
}
|
||||
});
|
||||
|
||||
void test('future battle questions use a current turn, another seat and that faction’s native public leader', () => {
|
||||
const f = fixture();
|
||||
let game = act(f.game, f.asker, { type: 'card', card: f.truth });
|
||||
for (let count = 0; game.truthtrance?.stage === 'priority' && count < game.players.length; count++) {
|
||||
const player = game.players.find(seat => !game.truthtrance!.passed.includes(seat.id)); assert.ok(player);
|
||||
game = act(game, player.id, { type: 'truthPass' });
|
||||
}
|
||||
assert.equal(game.truthtrance?.stage, 'ask');
|
||||
const invalid = [
|
||||
{ ...f.question, turn: f.game.turn + 1 },
|
||||
{ ...f.question, target: f.asker },
|
||||
{ ...f.question, leader: f.base.leaders.atreides },
|
||||
{ ...f.question, leader: 'unknown-leader' },
|
||||
];
|
||||
for (const question of invalid)
|
||||
rejected(game, f.asker, { type: 'truthAsk', question } as unknown as Action);
|
||||
const asked = act(game, f.asker, f.ask);
|
||||
rejected(asked, f.asker, { type: 'truthAnswer', answer: 'yes' });
|
||||
});
|
||||
|
||||
void test('each AI profile chooses a legal conditional answer and honors it in the real battle', () => {
|
||||
for (const difficulty of DIFFICULTIES) {
|
||||
const f = fixture();
|
||||
const asked = declare(f);
|
||||
const respondent = asked.players.find(player => player.id === f.target)!;
|
||||
respondent.bot = difficulty;
|
||||
const reply = botActions(viewGame(asked, f.target)).find(action => action.type === 'truthAnswer');
|
||||
assert.ok(reply, difficulty);
|
||||
let game = act(asked, f.target, reply);
|
||||
assert.equal(records(game)[0].status, 'waiting');
|
||||
game = reachBattle(game, f);
|
||||
const planned = botActions(viewGame(game, f.target)).find(action => action.type === 'battlePlan');
|
||||
assert.ok(planned, difficulty);
|
||||
game = act(game, f.target, planned);
|
||||
game = act(game, f.asker, f.ownPlan);
|
||||
assert.equal(records(game)[0].status, 'settled');
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user