121 lines
6.1 KiB
TypeScript
121 lines
6.1 KiB
TypeScript
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 {
|
|
actTruthLeaderRevival as act, answerTruthLeaderRevival as answer,
|
|
createTruthLeaderRevivalFixture as fixture, declareTruthLeaderRevival as declare,
|
|
settleTruthLeaderRevival as settle, truthLeaderRevivalInventory as inventory,
|
|
truthLeaderRevivalPlayer as player,
|
|
} from './fixture-truth-leader-revival';
|
|
|
|
function rejected(game: Game, actor: string, action: Action) {
|
|
const before = structuredClone(game);
|
|
assert.throws(() => act(game, actor, action));
|
|
assert.deepEqual(game, before);
|
|
}
|
|
|
|
function askGhola(f: ReturnType<typeof fixture>) {
|
|
const declared = declare(f);
|
|
const game = act(declared.game, f.asker, { type: 'truthAsk', question: {
|
|
kind: 'gholaLeader', target: f.target, turn: declared.game.turn, leader: f.leader,
|
|
} });
|
|
return game;
|
|
}
|
|
|
|
for (const advanced of [false, true]) {
|
|
void test(`${advanced ? 'Advanced' : 'Basic'} named Ghola Yes is fulfilled by an actual Ghola leader return`, () => {
|
|
const f = fixture({ advanced, ghola: true });
|
|
assert.ok(f.ghola);
|
|
const asked = askGhola(f);
|
|
assert.ok(viewGame(asked, f.target).truthGholaLeaderAnswers?.includes('yes'));
|
|
let game = answer(asked, f.target, 'yes');
|
|
const promise = game.gholaLeaderPromises!.find(row => row.player === f.target)!;
|
|
assert.equal(promise.leader, f.leader);
|
|
assert.ok(!promise.fulfilled);
|
|
// Spending the only dealt Ghola on a force return cannot satisfy the named leader.
|
|
rejected(game, f.target, { type: 'card', card: f.ghola, amount: 1, elite: 0 });
|
|
game = settle(act(game, f.target, { type: 'card', card: f.ghola, leader: f.leader }));
|
|
assert.equal(player(game, f.target).leaders.find(leader => leader.id === f.leader)!.dead, false);
|
|
assert.equal(player(game, f.target).leaderRevived, false);
|
|
assert.equal(game.gholaLeaderPromises!.find(row => row.event === promise.event)!.fulfilled, true);
|
|
assert.equal(game.discard.filter(card => card.id === f.ghola).length, 1);
|
|
assert.deepEqual(inventory(game), f.originalCards);
|
|
});
|
|
}
|
|
|
|
void test('named Ghola No rejects the matching leader return but allows its independent force return', () => {
|
|
const f = fixture({ ghola: true });
|
|
assert.ok(f.ghola);
|
|
const asked = askGhola(f);
|
|
assert.ok(viewGame(asked, f.target).truthGholaLeaderAnswers?.includes('no'));
|
|
let game = answer(asked, f.target, 'no');
|
|
const promise = game.gholaLeaderPromises!.find(row => row.player === f.target)!;
|
|
rejected(game, f.target, { type: 'card', card: f.ghola, leader: f.leader });
|
|
game = settle(act(game, f.target, { type: 'card', card: f.ghola, amount: 1, elite: 0 }));
|
|
assert.equal(player(game, f.target).leaders.find(leader => leader.id === f.leader)!.dead, true);
|
|
assert.ok(!game.gholaLeaderPromises!.find(row => row.event === promise.event)!.fulfilled);
|
|
assert.equal(game.discard.filter(card => card.id === f.ghola).length, 1);
|
|
assert.deepEqual(inventory(game), f.originalCards);
|
|
});
|
|
|
|
void test('two Truthtrances cannot bind contradictory answers about the same Ghola leader', () => {
|
|
const f = fixture({ ghola: true });
|
|
let game = declare(f, f.game, { copies: 2 }).game;
|
|
const question = { kind: 'gholaLeader', target: f.target, turn: game.turn, leader: f.leader };
|
|
game = act(game, f.asker, { type: 'truthAsk', question });
|
|
game = answer(game, f.target, 'yes');
|
|
game = act(game, f.asker, { type: 'truthAsk', question });
|
|
assert.ok(viewGame(game, f.target).truthGholaLeaderAnswers?.includes('yes'));
|
|
assert.ok(!viewGame(game, f.target).truthGholaLeaderAnswers?.includes('no'));
|
|
rejected(game, f.target, { type: 'truthAnswer', answer: 'no' });
|
|
game = answer(game, f.target, 'yes');
|
|
assert.equal(game.gholaLeaderPromises!.filter(row => row.player === f.target).length, 2);
|
|
});
|
|
|
|
void test('prior ordinary-revival Yes prevents a conflicting Ghola leader Yes', () => {
|
|
const f = fixture({ ghola: true });
|
|
let game = declare(f, f.game, { copies: 2 }).game;
|
|
game = act(game, f.asker, { type: 'truthAsk', question: {
|
|
kind: 'leaderRevival', target: f.target, turn: game.turn, leader: f.leader,
|
|
} });
|
|
game = answer(game, f.target, 'yes');
|
|
game = act(game, f.asker, { type: 'truthAsk', question: {
|
|
kind: 'gholaLeader', target: f.target, turn: game.turn, leader: f.leader,
|
|
} });
|
|
assert.ok(!viewGame(game, f.target).truthGholaLeaderAnswers?.includes('yes'));
|
|
assert.ok(viewGame(game, f.target).truthGholaLeaderAnswers?.includes('no'));
|
|
rejected(game, f.target, { type: 'truthAnswer', answer: 'yes' });
|
|
game = answer(game, f.target, 'no');
|
|
assert.ok(game.leaderRevivalPromises!.some(row => row.player === f.target && row.answer));
|
|
assert.ok(game.gholaLeaderPromises!.some(row => row.player === f.target && !row.answer));
|
|
});
|
|
|
|
void test('all bot profiles choose the native named Ghola guide', () => {
|
|
const f = fixture({ ghola: true });
|
|
const game = answer(askGhola(f), f.target, 'yes');
|
|
const view = viewGame(game, f.target);
|
|
const guide = view.gholaLeaderPromiseGuide;
|
|
assert.ok(guide);
|
|
assert.equal(guide.action.type, 'card');
|
|
assert.equal(guide.action.leader, f.leader);
|
|
for (const difficulty of DIFFICULTIES) {
|
|
const botView = viewGame(game, f.target);
|
|
botView.players.find(seat => seat.id === f.target)!.bot = difficulty;
|
|
assert.deepEqual(botActions(botView)[0], guide.action);
|
|
}
|
|
const after = settle(act(game, f.target, guide.action));
|
|
assert.ok(after.gholaLeaderPromises!.find(row => row.player === f.target)?.fulfilled);
|
|
});
|
|
|
|
for (const advanced of [false, true]) {
|
|
void test(`${advanced ? 'Advanced' : 'Basic'} ordinary revival cannot consume the leader promised for Ghola`, () => {
|
|
const f = fixture({ advanced, ghola: true });
|
|
const game = answer(askGhola(f), f.target, 'yes');
|
|
assert.ok(game.gholaLeaderPromises!.some(row => row.player === f.target && row.answer && !row.fulfilled));
|
|
rejected(game, f.target, f.revivalAction);
|
|
assert.ok(player(game, f.target).leaders.find(leader => leader.id === f.leader)!.dead);
|
|
});
|
|
}
|