Files
2026-08-16 20:50:31 +02:00

81 lines
3.8 KiB
JavaScript

/* Aggressive end-to-end: force a full game to completion (eliminations). */
const BASE = "http://localhost:3000";
const { request } = require("http");
function sse(uid) {
return new Promise((resolve) => {
const res = request({ host: "localhost", port: 3000, path: `/api/events?uid=${uid}`, method: "GET" }, (r) => {
let buf = ""; const states = [];
r.on("data", (c) => {
buf += c;
let idx;
while ((idx = buf.indexOf("\n\n")) >= 0) {
const chunk = buf.slice(0, idx); buf = buf.slice(idx + 2);
for (const l of chunk.split("\n")) {
if (l.startsWith("data: ")) { try { const m = JSON.parse(l.slice(6)); if (m.type === "state") states.push(m.snap); } catch (e) {} }
}
}
});
resolve({ states, res });
});
res.on("error", () => {});
res.end();
});
}
const api = async (action, uid, name, extra = {}) => {
const r = await fetch(BASE + "/api", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action, uid, name, ...extra }) });
const d = await r.json();
if (!r.ok) throw new Error(`${action}: ${d.error}`);
return d;
};
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
const COMBOS = [[1,2],[1,3],[6,6],[5,5],[4,4],[3,3],[2,2],[1,1],[6,5],[6,4]];
const DYN = [[6,3],[6,2],[5,4],[5,3],[5,2],[4,3],[4,2],[3,2]];
function rankOf(a, b) { const x = Math.min(a, b), y = Math.max(a, b); for (let i = 0; i < COMBOS.length; i++) if (COMBOS[i][0] === y && COMBOS[i][1] === x) return i; const i = DYN.findIndex(c => c[0] === y && c[1] === x); return i >= 0 ? 10 + i : -1; }
(async () => {
const c1 = await api("create", null, "Alice", { roomName: "Finaltest", addBot: true });
const c2 = await api("join", null, "Bob", { roomId: c1.room });
const u1 = c1.uid, u2 = c2.uid;
const [s1, s2] = await Promise.all([sse(u1), sse(u2)]);
await api("start", u1, "Alice");
const t0 = Date.now();
while (Date.now() - t0 < 300000) {
await sleep(1200);
const snap = s1.states[s1.states.length - 1];
if (!snap) continue;
if (snap.phase === "waiting" && snap.gameOver) {
console.log("GAME OVER. Final:", JSON.stringify(snap.players.map(p => [p.name, p.score, p.eliminated])));
console.log("Last log lines:", snap.log.slice(-4).map(l => l.t).join(" | "));
// test restart works
await api("restart", u1, "Alice");
await sleep(800);
const s2snap = s2.states[s2.states.length - 1];
console.log("After restart: phase=", s2snap.phase, "scores=", JSON.stringify(s2snap.players.map(p => [p.name, p.score, p.eliminated])));
process.exit(0);
}
const actor = snap.phase === "challenging" && snap.pending ? snap.pending.challenger : snap.turnUid;
for (const [uid, states, name] of [[u1, s1.states, "Alice"], [u2, s2.states, "Bob"]]) {
if (actor !== uid) continue;
if (snap.phase === "acting") await api("roll", uid, name);
else if (snap.phase === "peeking") {
await api("peek", uid, name, { revealed: true });
await sleep(150);
const fresh = states[states.length - 1];
if (!fresh.myDice) continue;
const truth = rankOf(fresh.myDice[0], fresh.myDice[1]);
const minR = fresh.lastClaim ? fresh.lastClaim.rank + 1 : 0;
// AGGRESSIVE: always bluff 3 above (capped), guarantees busts & eliminations
let r = Math.min(Math.max(minR, truth + 3), 17);
if (r < minR) await api("sendForward", uid, name);
else await api("declare", uid, name, { rank: r });
} else if (snap.phase === "challenging" && snap.pending && snap.pending.challenger === uid) {
await api("challenge", uid, name); // always challenge -> busts everywhere
}
}
}
console.log("TIMEOUT - game did not finish in time");
process.exit(1);
})().catch(e => { console.error("FAIL:", e); process.exit(1); });