在发布前让计算机解完100个下落式益智关卡的故事
落ち物パズルの100面を、出す前に全部コンピューターに解かせた話
初次见面。我是爱知县一家小公司ランウィズ的佐藤。
前几天,我们在 Android 和浏览器上发布了一款木块掉落消除游戏。本文将介绍那 100 个关卡和 50 道题“不靠人工制作,而是在发布前全部让计算机求解验证”的做法。
另外,本文的代码由 AI 编程工具(Claude Code)编写,我负责决定要做什么以及是否可以发布。文章草稿也由 AI 撰写,我阅读后进行了修改。
游戏规则(简述)
- 棋盘横 18×纵 30。一开始就几乎填满,有一条细缝一直通到底部。
- 放置落下的棋子,当凑齐的列消除后,上方的方块会落到最底部。
- 如果落下后又有列凑齐,就会继续消除(连锁)。
这个“会落到多深”因棋盘而异,所以好棋盘和坏棋盘之间的差距会变得非常大。
关卡根据“种子”的数量来生成
不是为每一关手动画棋盘,而是根据关卡编号 n 和尝试编号 k 生成种子数,再用该种子生成棋盘。
function candidateSeed(n, k) {
return (Math.imul(n * 7919 + k * 104729 + 1, 2654435761) ^ 0x5eed1e55) >>> 0 || 1;
}
只要种子相同,无论什么时候玩,都会从同一个棋盘开始。
电脑玩家
电脑玩家采用贪心式设计。它会尝试当前棋子的所有可放置位置,并按“连锁更多 → 消除的列更多 → 位置更低”的顺序,把棋子放在最优位置。
function bestPlacement(b, piece) {
let best = null;
for (const p of placements(b, piece)) {
const { res } = tryPlacement(b, p);
const v = res.chain * 1000 + res.rows * 10 + p.y;
if (!best || v > best.v) best = Object.assign({ v, chain: res.chain, rows: res.rows, points: res.points }, p);
}
return best;
}
不做预先推演。我们的想法是:如果是“连比人类更弱的玩家也能通关的盘面”,那么人类无法通关的情况基本不会发生。
作为关卡保留的条件
对每个关卡 n,依次尝试 k = 0, 1, 2 … 作为种子,并把满足以下两个条件的第一个种子写入表中。
- 用初始棋子(直棒)能引发 4 连锁以上
- 在没有计时器的情况下,玩家能用固定数量的棋子通关(关卡越往后,可使用的棋子数量越多)。
第一条是为了“开始瞬间就能爽快地崩塌”,第二条是为了“不会卡死”。找到的种子表会写入游戏本体的文件,并在测试中重新解一遍所有关卡。
50 道题统计的是「全部摆放方式」
连锁拼图(棋子只有 1〜3 个)摆放方式很少,所以可以全部试一遍。在全部摆放方式中,统计能达到目标(几连锁,或几列)的比例,第 1 题能达到目标的摆放方式很多,第 50 题只有极少数才能达到,据此决定目标,并按从易到难的顺序排列。把其中一个答案留在表里,并在测试中实际输入该答案,确认能够解开。
做下来发现的事
- 每次改变生成棋盘的规则时,都能立刻重新生成 100 个关卡并全部验证一遍,这是最大的收获
- 在加入「第一手就达成 4 连锁以上」这个条件之前,会混入一些一开始什么都不发生的关卡
- 因为玩家比较贪心,所以「人来做能解得更好」的关卡偏多
制作的游戏:Timber Drop(免费)
- 浏览器(无需注册):https://timberdrop-web.pages.dev/?s=zenn
- Android:https://play.google.com/store/apps/details?id=com.runwithai.timberdrop&referrer=utm_source%3Dzenn
感谢您读到最后。
来源:zenn · 游戏开发社区 · zenn.dev