在发布前让计算机解完100个下落式益智关卡的故事
落ち物パズルの100面を、出す前に全部コンピューターに解かせた話
はじめまして。愛知県の小さな会社、ランウィズの佐藤と申します。
先日、木のブロックの落ち物パズルを Android とブラウザーで出しました。この記事では、そのステージ100面と問題50問を「人の手で作らず、出す前に全部コンピューターに解かせて確かめた」やり方を書きます。
なお、この記事のコードは AI のコーディングの道具(Claude Code)が書き、私は何を作るかと、出してよいかを決めました。記事の下書きも AI が書き、私が読んで直しています。
ゲームの決まり(短く)
- 盤は横18×縦30。最初からほぼ埋まっていて、底まで細い割れ目が1本通っている
- 落ちてくる駒を置いて、そろった列が消えると、上のブロックが一番下まで落ちる
- 落ちた結果また列がそろえば、続けて消える(連鎖)
この「どこまで落ちるか」が盤ごとに違うので、良い盤と悪い盤の差がとても大きくなります。
面は「種」の数から作る
1面ごとに盤を手で描く代わりに、面の番号 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 … と種を試し、次の2つを満たした最初の種を表に書きます。
- 最初の駒(まっすぐの棒)で 4 連鎖以上を起こせる
- 時計なしで、遊び手が決まった数の駒でクリアできる(面が進むほど、使える駒の数を増やす)
1つ目は「始めた瞬間に気持ちよく崩れる」ため、2つ目は「詰まない」ためです。見つかった種の表はゲームの本体のファイルに書きこみ、テストでもう一度全部の面を解き直しています。
問題50問は「全部の置き方」を数える
連鎖パズル(駒が1〜3個だけ)は、置き方が少ないので全部試せます。全部の置き方のうち、目標(何連鎖、または何列)に届く割合を数え、1問目は届く置き方が多く、50問目はほんのわずかしか届かないように目標を決め、易しい順に並べました。答えの1つを表に残し、テストでその答えを実際に打って解けることを確かめています。
やってみて分かったこと
- 盤を作る決まりを変えるたびに、100面を作り直してすぐに全部確かめられるのが一番の得でした
- 「最初の1手で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