
怎么测量的
- 分析了记录数据库中留下的 32 个网格的形状和题目文字。
- 在源代码副本中修改为只记录每个网格来自哪条路径,每种难度各生成了 30 个网格。
- 用与线上服务同一台 Mac 上的 gemma4,把生成新网格的过程每种难度各跑了 3 次。网格设计方面,还解除了时间限制,另外又收集了 6 次回答。
“先做网格”的路径一次也没有成功

生成的 90 个网格全部来自备用路径,也就是第 1 篇中看到的单词连接式放置器。它先在中间放一个单词,再一个字一个字地交叉连接上去,所以网格不对称,而且容易有一边是空的。
- 180° 对称的网格:90 个中 0 个
- 普通和困难的 60 个网格中,有 18 个包含 6 个字以上的答案。如果是“先做网格”的路径,答案不可能超过 5 个字。
- 平均单词数:简单 10.7 个,普通 14.9 个,困难 19.9 个
- 生成时间的中位数:简单 0.6 秒,普通 1.9 秒,困难 6.6 秒。困难中每十个网格就有一个超过 22.9 秒。
实际保存的网格也一样。改成“先做网格”之后保存的 8 个网格中,对称的有 0 个,有 5 个包含 6~8 个字的答案。
之前一直没有察觉是有原因的。判断网格是否达标的检查只看白格比例、横向和纵向题目数、中间交叉数以及连通性。备用路径的网格也能达到这些标准,所以 90 个中有 89 个都“通过”了。

我们对预先画好的 24 个网格,每个都尝试填了 10 次单词。240 次全部失败,填得最多的一次也只填满了单词位置的 28%,平均是 14%。换用其他种子每个网格再跑 20 次,也一次都没成功。随机网格也是 120 个中 0 个。预先画好的 24 个网格中,有两对其实是同一个网格(普通 4 号和 7 号,困难 5 号和 8 号)。
为什么填不满:韩文音节

英语填字游戏用 26 个字母交叉。韩语填字游戏是一个音节占一格,所以字的种类要多得多。仅词库中出现的音节就有 545 种,其中 178 种只出现过一次。
所以一旦交叉确定了一格,剩下的候选就几乎没有了。在 5 个字的格子中确定了一个字时,在那个位置上有相同音节的其他 5 字单词平均只有 0.52 个,70% 的情况下一个都没有。4 个字的平均也只有 0.85 个,55% 为 0 个。
预先画好的网格白格占 64~75%,大部分白格同时属于横向和纵向单词。放进几个单词之后,交叉的格子中必然有一个的候选变成 0 个。实际发出去的网格白格占 36.4%,横纵重叠的格子只有 30~37% 左右。
AI 网格设计:0/9

每次生成新网格时,都要等待网格设计 15 秒。9 次中有 8 次在 15 秒内没有收到回答,有一次收到了回答,但里面没有能用的网格。
解除时间限制后又请求了 6 次。收到回答要花 13~52 秒,收到的 15 个候选中通过规则的网格为 0 个,自动校正后也是 0 个。大部分都像上图那样,是把某一列整个涂黑的一团。有 1 次回答太长,在 1,200 个 token 处被截断了。在现在的结构里,花在网格设计上的 15 秒每次都白白浪费了。
AI 出题:2/9,以及题目质量

出题的时间限制是 25 秒。9 次中有 7 次超时,用的是词库中的默认句子。拿到一个新网格要花 35~54 秒,中位数 44 秒,其中大部分是两次等待 AI 的时间。

实际保存的 8 个网格也差不多。AI 重写了题目的网格只有 2 个。
AI 写的句子也有问题。
- 变成了词典式的解释,而不是问答题。“2026 年美国、墨西哥、加拿大联合举办的足球赛事”变成了“由多个国家的足球国家队聚集在一起进行的国际足球赛事”。为了提高难度而加入的时事题变成了平平无奇的释义。
- 引用错误:孔子的题目中出现了“‘化为鹤而学,时时温习’这样的教诲”。《论语》的第一句是“学而时习之”。
- 时态:把已经结束的 2026 年冬奥会写成了“即将举办的冬季体育盛会”。
- 不存在的书:说达朗贝尔是“撰写了《Pilsoenon》的人物”。
- 把大田广域市说成了“广域自治区”。
词库与时事单词
- 有些条目为了填满 5 个字的格子而把单词截断了。像“仁川国际机”“金浦国际机”“市外巴士总”“国会议员选”这样的共有 8 个,题目是“……的前半部分”。旧金山那座桥的答案不是“金门大桥”,而是“金门”。
- 也有题目本身就错了的条目。“冰箱门”的题目是“开关橱柜的门”。
- 来自维基百科随机条目的答案:如“西瓦利克级驱逐舰”“Randoeo 科”“Illionaire Records”“林赫消歧义”这样的单词。“消歧义”是附在条目标题上的词。题目是把维基条目的第一句截取到 70 个字,所以“李彩允歌手”的题目就像“彩允(本名:李瑟,……)是大韩民国的歌手”这样,几乎把答案说出来了。保存的 8 个网格中有 4 个包含这样的单词。
- 最新消息实际上几乎没被用到。生成新网格的 API 在调用时关掉了根据新闻由 AI 挑选单词的功能。头条只用在一条规则上:如果包含“尼泊尔”“洪水”“冰川”,就加入尼泊尔和喜马拉雅。即使是其他国家的洪水新闻,也会加入尼泊尔。时事题大部分是手工加入的 12 个。
- 按难度区分的词汇等级(常用词、普通词、罕见词)只有计算它的函数,生成器并没有使用。现在的难度只靠网格大小、公开格子和答案长度来区分。
继续解题运作良好
中途保存的网格可以从记录中重新打开接着解,空网格也被删除了。改成整体输入答案之后,解完的 20 道题网格分别输入了 24 次和 27 次,用时 24 分钟和 15 分钟。
有一处需要修正。游戏房间每 5 秒保存一次进行时间,所以即使只是把一个什么都没输入的网格开在标签页里,时间也会不断累积。有一个空网格记录了超过 13 小时,而且因为没有经过大厅,也没有被删除。
修改方向
- 把 AI 从网格设计中去掉,或者往后放。现在花了 15 秒却一无所获。网格由程序来做,并采用横纵重叠格子较少的稀疏网格。
- 根据网格去找单词。像“○ seu ○○”这样,把格子中已确定的字交给模型,让它提出候选单词,再用词典确认后放入。仅靠事先定好的词库,4 个字和 5 个字的单词不够用。
- 提前生成网格。一个网格大约要 44 秒,所以可以按难度在后台生成并储备起来,需要时立即取出。这样也能放宽时间限制,还有时间进行审核。
- 审核题目。让时事题保持问答形式,再确认一遍日期、时态和引用。去掉维基的“消歧义”条目和过长的专有名词,并检查题目中是否包含了部分正确答案。
- 整理被截断的单词和错误的题目,并把词汇等级反映到实际难度中。

这是保存的全部 32 个网格。单词数和网格使用率明显改善了。但这些网格并非来自计划中的“先做网格”路径,而是来自备用路径,剩下的课题是网格形状和题目质量。
这一阶段的实际代码
这是填充网格的顺序。按预先画好的网格 → 随机网格 → 单词连接式放置器的顺序尝试。在测量中,前两个步骤一次也没成功,所以总是一路走到最后一行。
lib/gridFill.ts
for (const mask of shuffle(readyBoards(size, cap), rng)) {
const filled = tryMask(mask);
if (filled) return filled;
}
for (let attempt = 0; attempt < 8; attempt++) {
const mask = makePattern(size, 2, cap, rng);
if (!mask) continue;
const filled = tryMask(mask);
if (filled) return filled;
}
for (let attempt = 0; attempt < 5; attempt++) {
const connected = tryBuildConnected(size, maxLen, bank, prefer, avoid, rng);
if (connected) return connected;
}
return null;这是收集时事单词的部分。生成新网格的 API 把 useLlm 传为 false,所以基于新闻的 AI 单词是空的,头条只用于尼泊尔规则。
lib/dynamicBank.ts
export async function loadDynamicBank(
difficulty: DiffKey,
avoid: Iterable<string>,
options?: { useLlm?: boolean },
): Promise<DynamicBankResult> {
const avoidList = [...avoid];
const [headlines, wiki] = await Promise.all([fetchNewsHeadlines(), fetchWikiEntries(16)]);
const llm = options?.useLlm === false ? [] : await fetchLlmEntries(difficulty, headlines, avoidList);
const newsHints: WordEntry[] = [];
if (headlines.some((h) => h.includes("네팔") || h.includes("홍수") || h.includes("빙하"))) {
const nepal = asHangulEntry("네팔", "이번에 히말라야 빙하가 무너져 큰 홍수가 난 나라");
const himal = asHangulEntry("히말라야", "올해 빙하가 붕괴해 네팔에 대홍수를 일으킨 산맥");
if (nepal) newsHints.push(nepal);
if (himal) newsHints.push(himal);
}
const entries = [...llm, ...newsHints, ...wiki];
const source: DynamicBankResult["source"] = llm.length >= 12 ? "llm" : wiki.length ? "wiki" : headlines.length ? "news" : "bank";
return { entries, source };这些是为了凑够 5 个字而截断的单词。
lib/words.ts
{ word: "시외버스터", clue: "시외버스가 모이는 곳의 앞말" },
{ word: "인천국제공", clue: "서해 관문 국제공항의 앞말" },
{ word: "김포국제공", clue: "서울 서쪽 국제공항의 앞말" },下一篇是“4. 完整源代码与使用的工具”。
COMMENTS · CHAPTER 03
用统计重新审视出题过程与问题 评论 0
还没有评论。阅读时有疑问或想补充的内容,欢迎留言。
发表评论前,请用 Google 开始并登记昵称和邮箱。
用 Google 开始