143 lines
5.6 KiB
TypeScript
143 lines
5.6 KiB
TypeScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { applyAction, viewGame } from '../game/engine';
|
|
import { botActions } from '../game/bots';
|
|
import {
|
|
nexusGuildCunningFixture,
|
|
originalGuildCunningTurn,
|
|
nexusGuildCunningAllow,
|
|
settleGuildCunningShipment,
|
|
nexusGuildCunningInventory,
|
|
holdGuildCunningCard,
|
|
} from './fixture-nexus-guild-cunning';
|
|
|
|
void test('all Guild profiles finish the first turn through Cunning then propose a second shipment without ordinary movement', () => {
|
|
for (const profile of ['Easy', 'Medium', 'Hard', 'Brutal'] as const) {
|
|
const f = nexusGuildCunningFixture();
|
|
const first = originalGuildCunningTurn(f);
|
|
const v = viewGame(first, f.owner);
|
|
v.players.find((p) => p.id === f.owner)!.bot = profile;
|
|
const action = botActions(v)[0];
|
|
assert.equal(action.type, 'endMovement');
|
|
assert.equal(action.nexus, v.nexusGuildCunning!.offer!.event);
|
|
const g = nexusGuildCunningAllow(applyAction(first, f.owner, action));
|
|
const next = viewGame(g, f.owner);
|
|
next.players.find((p) => p.id === f.owner)!.bot = profile;
|
|
const candidates = botActions(next);
|
|
assert.ok(
|
|
candidates.some((a) => a.type === 'ship' || a.type === 'guildShip'),
|
|
);
|
|
assert.ok(candidates.every((a) => a.type !== 'move'));
|
|
const shipment = candidates.find(
|
|
(a) => a.type === 'ship' || a.type === 'guildShip',
|
|
)!;
|
|
nexusGuildCunningInventory(
|
|
settleGuildCunningShipment(applyAction(g, f.owner, shipment)),
|
|
);
|
|
}
|
|
});
|
|
void test('all Guild profiles use only an offered unused Hajr after the second shipment and preserve blocked ordinary fallback', () => {
|
|
for (const profile of ['Easy', 'Medium', 'Hard', 'Brutal'] as const) {
|
|
const f = nexusGuildCunningFixture();
|
|
const hajr = holdGuildCunningCard(f.g, f.owner, 'hajr');
|
|
const first = originalGuildCunningTurn(f);
|
|
const v = viewGame(first, f.owner);
|
|
v.players.find((p) => p.id === f.owner)!.bot = profile;
|
|
const declared = botActions(v)[0];
|
|
v.nexusGuildCunning!.offer!.blocked = 'Unavailable';
|
|
assert.equal(botActions(v)[0].nexus, undefined);
|
|
let g = nexusGuildCunningAllow(applyAction(first, f.owner, declared));
|
|
g = settleGuildCunningShipment(
|
|
applyAction(g, f.owner, {
|
|
type: 'ship',
|
|
territory: 'carthag',
|
|
sector: 11,
|
|
amount: 3,
|
|
}),
|
|
);
|
|
const after = viewGame(g, f.owner);
|
|
after.players.find((p) => p.id === f.owner)!.bot = profile;
|
|
assert.deepEqual(botActions(after)[0], { type: 'card', card: hajr.id });
|
|
const prepared = applyAction(g, f.owner, botActions(after)[0]);
|
|
const pv = viewGame(prepared, f.owner);
|
|
pv.players.find((p) => p.id === f.owner)!.bot = profile;
|
|
const move = botActions(pv).find((a) => a.type === 'move');
|
|
assert.ok(move);
|
|
nexusGuildCunningInventory(applyAction(prepared, f.owner, move));
|
|
}
|
|
});
|
|
|
|
void test('all Guild profiles skip an unaffordable second shipment to retain their owned unused Hajr', () => {
|
|
for (const profile of ['Easy', 'Medium', 'Hard', 'Brutal'] as const) {
|
|
const f = nexusGuildCunningFixture({ spice: 3 }),
|
|
hajr = holdGuildCunningCard(f.g, f.owner, 'hajr');
|
|
const first = originalGuildCunningTurn(f),
|
|
fv = viewGame(first, f.owner);
|
|
fv.players[0].bot = profile;
|
|
const g = nexusGuildCunningAllow(
|
|
applyAction(first, f.owner, botActions(fv)[0]),
|
|
);
|
|
const v = viewGame(g, f.owner);
|
|
v.players[0].bot = profile;
|
|
const skip = botActions(v)[0];
|
|
assert.equal(skip.type, 'nexusGuildSkipShipment');
|
|
const next = applyAction(g, f.owner, skip),
|
|
nv = viewGame(next, f.owner);
|
|
nv.players[0].bot = profile;
|
|
assert.deepEqual(botActions(nv)[0], { type: 'card', card: hajr.id });
|
|
nexusGuildCunningInventory(applyAction(next, f.owner, botActions(nv)[0]));
|
|
}
|
|
});
|
|
|
|
void test('a new answered Truthtrance binds the second shipment and all profiles honor its six-force witness despite shipped true', () => {
|
|
for (const profile of ['Easy', 'Medium', 'Hard', 'Brutal'] as const) {
|
|
const f = nexusGuildCunningFixture();
|
|
const truth = holdGuildCunningCard(f.g, f.target, 'truthtrance');
|
|
const first = originalGuildCunningTurn(f);
|
|
const fv = viewGame(first, f.owner);
|
|
fv.players[0].bot = profile;
|
|
let g = nexusGuildCunningAllow(
|
|
applyAction(first, f.owner, botActions(fv)[0]),
|
|
);
|
|
g = applyAction(g, f.target, { type: 'card', card: truth.id });
|
|
for (let n = 0; n < 10 && g.truthtrance?.stage === 'priority'; n++)
|
|
g = applyAction(
|
|
g,
|
|
g.players.find((p) => !g.truthtrance!.passed.includes(p.id))!.id,
|
|
{ type: 'truthPass' },
|
|
);
|
|
g = applyAction(g, f.target, {
|
|
type: 'truthAsk',
|
|
question: {
|
|
kind: 'shipment',
|
|
target: f.owner,
|
|
territory: 'carthag',
|
|
minimum: 6,
|
|
},
|
|
});
|
|
assert.ok(viewGame(g, f.owner).truthShipmentAnswers!.includes('yes'));
|
|
g = applyAction(g, f.owner, { type: 'truthAnswer', answer: 'yes' });
|
|
const v = viewGame(g, f.owner);
|
|
v.players[0].bot = profile;
|
|
assert.equal(v.players[0].shipped, true);
|
|
const actions = botActions(v);
|
|
assert.ok(actions.length);
|
|
assert.ok(
|
|
actions.every(
|
|
(a) =>
|
|
a.type === 'ship' &&
|
|
a.territory === 'carthag' &&
|
|
Number(a.amount) >= 6,
|
|
),
|
|
);
|
|
const done = settleGuildCunningShipment(
|
|
applyAction(g, f.owner, actions[0]),
|
|
);
|
|
assert.ok(
|
|
done.players.find((p) => p.id === f.owner)!.forces['carthag:11'] >= 6,
|
|
);
|
|
assert.ok(done.shipmentPromises!.every((p) => p.fulfilled && !p.released));
|
|
nexusGuildCunningInventory(done);
|
|
}
|
|
});
|