Files
ark-stronghold-protocol/test/match/fullmatch.test.js
T
sganggs 01a44cd288 卫戍协议:盟约 web remake — initial import
Online co-op browser remake of Arknights' Stronghold Protocol: Alliance
(client-simulated combat, official waves/bonds/items/strategies, 3D board,
facing wheel, operator loadout, official emotes, deployment scripts).
2026-09-29 16:21:31 +08:00

57 lines
3.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Full matches with the REAL simulation (server/sim/Battle.js) run to RESULT in virtual time with zero errors:
// solo × every difficulty and co-op 2/3/4 (humans on "AI 托管" + AI teammates), 20 seeds each; invariants checked at
// every phase change; every m.public / m.private frame JSON-safe. Plus boosted-LP runs that reach the Final Assault
// with the real sim.
// The co-op configurations live in fullmatch-coop*.test.js (separate files run in parallel).
import { test, after } from 'node:test';
import assert from 'node:assert/strict';
import { makeMatch, checkInvariants } from './harness.js';
import { SEEDS, runFull, reportSimIssues } from './fullmatchRun.js';
after(reportSimIssues);
for (const difficulty of ['FUNNY', 'NORMAL', 'HARD', 'ABYSS']) {
test(`solo ${difficulty}: ${SEEDS} seeds to RESULT with zero errors`, () => {
for (let seed = 1; seed <= SEEDS; seed++) runFull({ mode: 'solo', difficulty, humans: 1, bots: 0, seed });
});
}
test('boosted LP: the real sim reaches the Final Assault (solo FUNNY R9, co-op NORMAL R14) and ends cleanly', () => {
for (const seed of [1, 2]) {
const { res } = runFull({ mode: 'solo', difficulty: 'FUNNY', humans: 1, bots: 0, seed, boostLp: 400 });
assert.ok(res.roundsPassed >= 8, `reached the boss round (${res.roundsPassed})`);
}
const { res } = runFull({ mode: 'coop', difficulty: 'NORMAL', humans: 1, bots: 1, seed: 7, boostLp: 400 });
assert.ok(res.roundsPassed >= 13);
});
test('determinism: the same seed and inputs give the same match (client-side and server-run combat)', () => {
const a = runFull({ mode: 'coop', difficulty: 'HARD', humans: 1, bots: 2, seed: 4242 }).res;
const b = runFull({ mode: 'coop', difficulty: 'HARD', humans: 1, bots: 2, seed: 4242 }).res;
const strip = (r) => JSON.stringify({ ...r, durationMs: 0 });
assert.equal(strip(a), strip(b));
const c = runFull({ mode: 'coop', difficulty: 'HARD', humans: 1, bots: 2, seed: 4243 }).res;
assert.notEqual(strip(a), strip(c));
const s1 = runFull({ mode: 'coop', difficulty: 'HARD', humans: 1, bots: 2, seed: 4242, clientCombat: false }).res;
const s2 = runFull({ mode: 'coop', difficulty: 'HARD', humans: 1, bots: 2, seed: 4242, clientCombat: false }).res;
assert.equal(strip(s1), strip(s2));
});
test('server-run fallback (SP_COMBAT=server): solo and co-op matches still run to RESULT with zero errors', () => {
runFull({ mode: 'solo', difficulty: 'HARD', humans: 1, bots: 0, seed: 77, clientCombat: false });
runFull({ mode: 'coop', difficulty: 'NORMAL', humans: 2, bots: 1, seed: 78, clientCombat: false });
});
test('degraded data (chess + bands only, no config/waves/stages): a bot match still runs to RESULT without errors', async () => {
const { DATA } = await import('./harness.js');
const data = { chess: DATA.chess, bands: DATA.bands, bonds: DATA.bonds };
const h = makeMatch({ mode: 'coop', difficulty: 'NORMAL', humans: 1, bots: 1, seed: 9, data, captureFrames: false, clientCombat: true });
h.autoHumans();
h.m.start();
h.run(() => h.ended != null, { maxSteps: 2e6 });
assert.ok(h.ended, `ended (${h.m.phase} R${h.m.round})`);
assert.equal(h.m.errorCount, 0, JSON.stringify(h.m.errors.slice(0, 2)));
checkInvariants(h.m);
h.m.dispose();
});