import { copyFileSync, existsSync, mkdirSync, readdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import { randomInt } from "node:crypto"; // 盲评用的汇总(任务书 14 第 3.2 节第 1 步最后一条):把导出目录里每次运行的 text.txt 随机编成"运行 A、B……", // 只把这些文本放进 <检验目录>/blind/;对照表(字母 → 运行名)另存到 blind 外面的 blind-key.json,审阅者看不到。 // node eval/round-one/blind.ts const out = process.argv[2]; if (out === undefined) throw new Error("要写 export.ts 写出的检验目录"); const runs = readdirSync(join(out, "runs")).sort(); if (runs.length > 26) throw new Error(`有 ${runs.length} 次运行,字母不够用`); const blind = join(out, "blind"); if (existsSync(blind)) throw new Error(`${blind} 已经有了:重新编号会让旧的对照表作废,先挪走`); mkdirSync(blind); // Fisher–Yates 洗牌,用 crypto 的随机数:编号不能从运行名或目录顺序推出来。 const order = [...runs]; for (let i = order.length - 1; i > 0; i--) { const j = randomInt(i + 1); [order[i], order[j]] = [order[j]!, order[i]!]; } const key: Record = {}; order.forEach((run, i) => { const letter = String.fromCharCode(65 + i); key[`运行 ${letter}`] = run; copyFileSync(join(out, "runs", run, "text.txt"), join(blind, `运行-${letter}.txt`)); }); writeFileSync(join(out, "blind-key.json"), `${JSON.stringify(key, null, 2)}\n`); console.log(`${order.length} 份文本 → ${blind}\n对照表 → ${join(out, "blind-key.json")}`);