71 lines
4.0 KiB
TypeScript
71 lines
4.0 KiB
TypeScript
import assert from 'node:assert/strict';
|
|
import test from 'node:test';
|
|
import { applyAction, viewGame } from '../game/engine';
|
|
import { homeworldShipmentActions, richeseHomeworldMarkerChoice } from '../game/homeworld-shipment-options';
|
|
import { botActions } from '../game/bots';
|
|
import { DIFFICULTIES } from '../game/bot-profiles';
|
|
import { freshNativeMarkerFixture, native, owner, pass, player } from './fixture-richese-native-marker';
|
|
|
|
for (const value of [0, 3, 5] as const) void test(
|
|
`Advanced fresh No-Field ${value} reaches native Richese without duplicating reserves`, () => {
|
|
const f = freshNativeMarkerFixture(true, value), before = structuredClone(f.game);
|
|
assert.equal(f.quote.blocked, null);
|
|
assert.equal(f.quote.amount, 1);
|
|
assert.equal(f.quote.cost, 1);
|
|
assert.ok(f.quote.action);
|
|
let game = applyAction(f.game, owner, f.quote.action);
|
|
assert.equal(game.response?.kind, 'richeseNoField');
|
|
assert.equal(player(game, owner).spice, player(before, owner).spice);
|
|
assert.equal(player(game, owner).reserves, player(before, owner).reserves);
|
|
game = pass(game);
|
|
assert.ok(player(game, owner).shipped);
|
|
assert.equal(player(game, owner).spice, player(before, owner).spice - 1);
|
|
assert.equal(player(game, owner).reserves, player(before, owner).reserves);
|
|
assert.deepEqual(game.homeworlds!.custody, before.homeworlds!.custody);
|
|
assert.deepEqual(player(game, owner).noField!.deployed!.location, {homeworld:native});
|
|
assert.equal(player(game, owner).noField!.lastShipped, f.token);
|
|
const publicMarker = viewGame(game, 'emperor').richeseNoField!;
|
|
assert.equal(publicMarker.private, null);
|
|
assert.equal(publicMarker.public.deployed?.effectiveForces, 1);
|
|
assert.equal(JSON.stringify(publicMarker.public).includes(f.token), false);
|
|
const own = player(game, owner);
|
|
game = pass(applyAction(game, owner, {type:'revealNoField', token:f.token, event:own.noFieldEvent}));
|
|
assert.equal(player(game, owner).noField!.deployed, null);
|
|
assert.equal(player(game, owner).reserves, player(before, owner).reserves);
|
|
assert.deepEqual(game.homeworlds!.custody, before.homeworlds!.custody);
|
|
assert.deepEqual(f.game, before, 'Applying the shipment leaves its source snapshot intact');
|
|
});
|
|
|
|
void test('Basic rejects fresh native placement while Advanced rejects same-source companions and stale events', () => {
|
|
const basic = freshNativeMarkerFixture(false);
|
|
const originalBasic = structuredClone(basic.game);
|
|
assert.equal(basic.quote.action, null);
|
|
assert.ok(basic.quote.blocked);
|
|
assert.deepEqual(basic.game, originalBasic);
|
|
|
|
const f = freshNativeMarkerFixture(true), before = structuredClone(f.game);
|
|
const mixed = richeseHomeworldMarkerChoice(f.view, native, f.token, 0, undefined, {normal:1, elite:0});
|
|
assert.equal(mixed.action, null, 'Native reserves cannot move from a World back to itself');
|
|
assert.ok(mixed.blocked);
|
|
assert.ok(f.quote.action);
|
|
assert.throws(() => applyAction(f.game, owner, {...f.quote.action!, noFieldEvent:'stale-marker'}));
|
|
assert.deepEqual(f.game, before);
|
|
});
|
|
|
|
void test('existing bot profiles retain a legal Homeworld action in the fresh native position', () => {
|
|
const f = freshNativeMarkerFixture(true);
|
|
for (const [index, difficulty] of DIFFICULTIES.entries()) {
|
|
const view = viewGame(f.game, owner);
|
|
view.players.find(row => row.id === owner)!.bot = difficulty;
|
|
const candidates = homeworldShipmentActions(view, index);
|
|
assert.ok(candidates.length, difficulty);
|
|
assert.doesNotThrow(() => applyAction(f.game, owner, candidates[0]), difficulty);
|
|
const nativeCandidate = candidates.find(action => action.type === 'homeworldShip' &&
|
|
action.destination === native && action.noField !== undefined);
|
|
assert.ok(nativeCandidate, `${difficulty} can select the native marker route`);
|
|
assert.doesNotThrow(() => applyAction(f.game, owner, nativeCandidate), difficulty);
|
|
const action = botActions(view)[0]; assert.ok(action, difficulty);
|
|
assert.doesNotThrow(() => applyAction(f.game, owner, action), difficulty);
|
|
}
|
|
});
|