ByteNoteByteNote
从朗读界面到字母接龙游戏:一次对话式编程的五轮迭代
字

字节笔记本

2026年10月7日 · 约 7 分钟读完

从朗读界面到字母接龙游戏:一次对话式编程的五轮迭代

API中转
¥120

给孩子做英语启蒙工具,是前端练手的经典选题:界面简单、规则清晰、成果能立刻拿给孩子玩。最近用 AI 结对做了一个字母接龙小游戏,考察的内容很基础——字母表的先后顺序。别小看这件事,它是日后查字典、理解条目排序、建立序列记忆的地基。整个开发前后五轮对话,从「点击字母朗读」一路迭代到「三字母挖中间、三选一」的稳定题式。回头看,比代码本身更有价值的,是这五轮暴露出来的典型问题:需求歧义、交互想当然、题目规则有暗洞。这篇文章按时间线复盘全程,思路可以直接搬走。

五轮迭代时间线

起步只要二十行:浏览器自带的发音能力

第一版需求很简单:26 个字母按钮,点哪个读哪个。实现上完全不需要任何库——浏览器的 Web Speech API 里,用 SpeechSynthesisUtterance 构造一个朗读实例,设好 lang,丢给 speechSynthesis.speak() 就出声了:

js
function speakLetter(letter) {
  const utterance = new SpeechSynthesisUtterance(letter);
  utterance.lang = 'en-US';
  speechSynthesis.speak(utterance);
}

26 个按钮用 CSS Grid 六列排开,整个页面单文件不到一百行。这类合成调用的是操作系统内置的语音引擎,全程在本地完成、不发起网络请求,天然免费、离线可用,做发音反馈比引第三方 TTS SDK 简单一个数量级。不过有两条使用常识要记住:语音合成应当由用户手势触发,页面加载就自动朗读会被浏览器的自动播放策略拦下;可用音色列表是异步加载的,若要指定 voice,得监听 voiceschanged 事件,不能在初始化时直接取。单做发音页,到这一步已经完工。

第一次跑偏:「连续的」到底是词还是字母

第二轮提出改造成游戏,原话是「三个连续的××,中间缺一到两个,由用户拖入补充」。AI 把「连续」理解成了词库里的相邻单词,做出来的是单词补全:三个单词排开,中间那个随机挖掉一两个字母,把下方打乱的字母拖回空槽。

这版顺手把两块通用实现写扎实了。其一是 HTML5 拖放三件套:被拖元素设 draggable 并在 dragstart 里用 dataTransfer.setData() 存值;空槽上 dragover 必须调 e.preventDefault(),否则 drop 事件根本不会触发,这是新手最常见的坑;最后在 drop 里 getData() 取值填槽。其二是洗牌用 Fisher-Yates:从后往前,每个位置与一个随机前位交换,O(n) 且无偏。

但方向错了。单词补全和字母接龙对应两种不同的学习目标:前者练拼写与词形,得先认识几十个单词才玩得动;后者练序列记忆,不识字的孩子也能上手。给孩子启蒙,后者门槛低得多。这轮的教训很典型:自然语言需求里的模糊量词,双方对「连续的」各自脑补,第一轮就该贴一个「A _ C」式的具体样例确认。

从拖拽到点击:一次值得的交互降级

第三版改成 5 到 7 个连续字母挖洞,洞的位置限制在非首尾,干扰项在答案之外再随机补三个,游戏逻辑终于对了。但拖拽的问题开始显现:拖错字母后槽位被永久占住,没有任何恢复手段;更麻烦的是拖拽交互本身的隐性成本——拖拽中的视觉反馈、命中区域大小、半路松手的收尾,每一条都是额外的设计和代码。

压垮它的还有兼容性:HTML5 拖放事件是桌面鼠标时代的产物,触屏浏览器长期没有完整实现,要支持移动端得另写一套 touch 事件模拟,复杂度直接翻倍。

于是第四轮做了个明智的降级:拖拽全部换成点击,序列缩到三个字母,选项池五个(答案加四个去重干扰项),点击填入第一个空槽,填错 1.5 秒后自动清空重置。交互降级听着像倒退,实际上是更成熟的方案——面向低龄用户和触屏场景,点击的确定性远高于拖拽。

题目设计的两次返工

真正见功夫的是题目规则本身。前几版埋着两个暗洞:其一,挖两个洞时两次随机可能落在同一位置,展示出的洞数和待填字母数对不上;其二,有一版双洞情况的展示串直接多出一个字符,答案比对时永远是四个字符对三个字符,题目永远判不对。玩家看到的症状是「怎么填都错」,根因却在出题函数里。

最终版把规则收敛到最简:永远显示三个连续字母,固定挖掉中间一个,下方三个选项。再配两条细节:干扰项生成时排除首尾字母,否则玩家会把首尾字母点进中间空位,造成「看似也说得通」的多解;选项一经点击立刻全部禁用,防止连点导致状态错乱。答完无论对错都亮出正确答案,再进下一题。

最终版题式的交互流程

干扰项的设计还有讲究:好的干扰项要「够近但不等」。从 26 个字母里纯随机抽,大概率出「M、Q、X」这种一眼假的选项,等于送分;更讲究的做法是从正确答案的相邻字母里抽。本例只做了去重和排除首尾,属于最低配,认真做题库值得在这里下功夫。而「每题恰好一个正确答案、每次交互都有明确反馈、错误状态可自动恢复」这三条,放任何题库类应用里都成立。

五轮迭代之后的三条心得

第一,小需求也要交底样例。一句「三个连续的、中间缺两个」,AI 与人理解岔开的概率不低,第一轮就贴出目标形态,能省掉后面整整一轮返工。第二,交互方案选朴素的那个。HTML5 拖放在桌面顺手、在触屏失灵,点击虽然朴素但全端可用,面向儿童的产品尤其如此。第三,规则收敛比功能堆叠优先。从「5 到 7 个字母、1 到 2 个洞、五个选项」退到「三个字母、一个洞、三个选项」,题式稳定了,后面加计分、计时、换词库才有地基。

这类单文件、无构建、规则可枚举的小工具,正是对话式编程的舒适区:改起来快、验证靠眼、出错损失小。骨架也很容易改造复用:把选项池加大、序列拉长,难度曲线就出来了;把字母数组换成数字、注音或假名,同一套出题与判题逻辑可以直接迁移到其他启蒙工具。而涉及持久化、多端同步、服务端状态的复杂需求,依然应该先写清规格再动手,对话式开发不是免写规格的通行证。

整个游戏最终沉淀为一个 HTML 文件,双击就能玩,想换题库直接改一个数组。五轮对话、几百行代码,没有引入任何依赖和构建工具。AI 结对的价值不在于一次把东西做对,而在于把「想清楚」这件事,拆成了几轮便宜又快速的对话。

相关文章

分享: