实时对局选你的对手
加入
main
70 行 · 3.0 KB 原始文件 永久链接 历史
1// Try a room locally: node src/try-room.mjs [seed]. Starts referee/room.mjs with a scripted person at seat 0 and a
2// scripted agent at seat 1 (both play like the starter bot), the field and auto at the others, and prints every
3// @shoal line, shortened. On the way it hands seat 0 to an agent and sends one move with the old version (the room
4// drops it), lets seat 1 miss its time limit once (auto plays), then hands seat 1 back to auto.
5import { spawn } from 'node:child_process';
6import { createInterface } from 'node:readline';
7import path from 'node:path';
8import { fileURLToPath } from 'node:url';
9import starter from '../routes/bot.mjs';
10
11const GAME = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
12const seats = {
13 0: { kind: 'human', name: 'ada' },
14 1: { kind: 'agent', name: 'bob-codex' },
15 2: { kind: 'bot', field: 'upstream' },
16 3: { kind: 'bot', field: 'random' },
17};
18const room = spawn(process.execPath, ['referee/room.mjs'], {
19 cwd: process.env.ROOM_DIR ?? GAME,
20 env: { ...process.env, SS_ROOM: JSON.stringify({ seats, seed: Number(process.argv[2] ?? 3), limit: 2 }) },
21 stdio: ['pipe', 'pipe', 'inherit'],
22});
23const send = (m) => {
24 console.log(`>> ${JSON.stringify(m)}`);
25 room.stdin.write(`${JSON.stringify(m)}\n`);
26};
27const short = (s) => (s.length > 300 ? `${s.slice(0, 300)}… (${s.length} bytes)` : s);
28
29let asked = { 0: 0, 1: 0 };
30let handedOver = false;
31let stale = null;
32let missed = false;
33const lines = { event: 0, private: 0, request: 0 };
34for await (const line of createInterface({ input: room.stdout })) {
35 if (!line.startsWith('@shoal ')) {
36 console.log(` log: ${line}`);
37 continue;
38 }
39 const m = JSON.parse(line.slice(7));
40 if (m.event) lines.event++;
41 else if (m.to !== undefined && m.version === undefined) lines.private++;
42 else if (m.version !== undefined) lines.request++;
43 console.log(`<< ${short(JSON.stringify(m))}`);
44 if (m.end) break;
45 if (m.version === undefined) continue;
46 const seat = Number(m.to);
47 if (!(seat in asked)) continue;
48 asked[seat]++;
49 // Seat 1 misses its limit once: no answer, auto plays for it after 2 s.
50 if (seat === 1 && asked[1] === 3 && !missed) {
51 missed = true;
52 console.log(' (seat 1 lets its time run out)');
53 continue;
54 }
55 // After seat 0's fifth ask, a person hands it to their agent; the old controller's late move must be dropped.
56 if (seat === 0 && asked[0] === 5 && !handedOver) {
57 handedOver = true;
58 stale = m.version;
59 send({ control: { seat: '0', kind: 'agent', name: 'ada-codex' } });
60 continue;
61 }
62 if (seat === 0 && stale !== null && m.version !== stale) {
63 send({ act: { seat: '0', version: stale, action: starter(m.obs, m.legal) } });
64 stale = null;
65 }
66 send({ act: { seat: String(seat), version: m.version, action: starter(m.obs, m.legal) } });
67 if (seat === 1 && asked[1] === 6) send({ control: { seat: '1', kind: 'auto' } });
68}
69console.log(`\n${lines.event} public events, ${lines.private} private updates, ${lines.request} requests`);
70room.stdin.end();