AI にスネークゲームを作らせると、動くページは比較的早くできます。得点、加速、一時停止の追加も、一見すると難しくありません。

しかし、ボタンが表示されれば本当に一時停止できているのでしょうか。描画だけが止まり、裏で移動と衝突判定が続けば、再開したときには負けているかもしれません。再開のたびにタイマーを作ると、繰り返すほど蛇が速くなる可能性もあります。

画面に機能があることと、要求を満たすことの間には、振る舞いの合意が必要です。AI は実装を速め、未確認の細部も早くコードへ取り込みます。

私が重視するのは、この合意を復元でき、確認できる根拠にすることです。スネークゲームを例に、要求、設計、検証をつなげて考えます。

1. 重要な合意を会話の外へ残す

会話は探索に向いています。不明確な要求は質問や試作で絞り込めますし、局所的な文言変更はそのまま進められます。

継続的に変更する機能では、会話だけで状況を管理すると問題が生じます。初期のルールが履歴へ埋もれ、追加要求で何を維持するかが示されず、ツールが読むコードも一部に限られることがあります。コンテキストの要約、検索の漏れ、要求同士の矛盾も、実装が意図から外れる原因です。

解決する問題、維持する振る舞い、対象外、完了条件を、再び見つけられるように残します。作業前に関連部分を読み、現在のコードと照らすことで、会話や作業期間が変わっても状況を復元できます。

これが仕様駆動開発(Spec-Driven Development)の出発点です。要求、設計、受け入れの根拠を、実装とともに維持します。

2. 「一時停止を追加する」を振る舞いにする

「一時停止に対応する」だけでは未決事項が残ります。何の更新を止めるのか。方向入力は受け付けるのか。再開時に停止中の時間を取り戻すのか。終了後の停止操作はどう扱うのか。

EARS(Easy Approach to Requirements Syntax)は、イベント、状態、条件で自然言語の要求を整理し、きっかけと応答を明確にする記法です。表現の確認には役立ちますが、その要求が利用場面に合うかは別に判断する必要があります。

一人用のゲームを例に、次のように合意できます。

  • P1:実行中に停止操作を受けたら、一時停止状態へ移る。停止中は蛇の位置、餌、得点を維持する。
  • P2:停止中は方向入力を無視する。再開操作後は同じ局面を続け、停止時間をその後の移動に算入しない。
  • **P3:**開始前または終了後の停止操作は、ゲームの状態を変更しない。

P1 はゲーム状態自体を制約し、P2 は入力と時間の扱いを明確にします。画面だけが止まり、再開時にまとめて何歩も動く実装を見分けられます。

合意が明確になると取捨選択も議論できます。方向入力を無視することはプレイヤーの期待に合うでしょうか。再開直後に動くのか、通常の移動間隔を待つのか。ここでは後者を選び、再開時点を新たな計時の起点とします。実装前に判断を揃えることが重要です。

振る舞いの要求、実装上の制約、対象範囲も区別します。既存のゲームを変更する場合、停止中の局面維持は振る舞いの要求です。既存フレームワークを使い、実行時の依存関係を追加しないことは今回の実装上の制約であり、アカウント、ランキング、マルチプレイは対象外です。境界を明示すると、一つの機能追加に伴って AI がプロジェクト全体を書き換えたり、無関係な機能を加えたりすることを減らせます。

3. 振る舞いの合意から実装上の制約へ

要求を決めたら、設計で実現方法を説明します。

一時停止なら、ゲーム状態と描画を分離し、単一の更新ループでゲームを進めます。停止中は状態を進めず、再開時は局面を保ったまま計時の基準をリセットします。ループの作成と破棄を同じモジュールが担当し、重複起動を防ぎます。

利用者の要求が、明確な実装境界に対応します。フレームワークや計時 API は、その制約の中で選択できます。

文書を使う場合は、それぞれの役割を分けます。

文書 一時停止について残す内容
requirements.md P1〜P3 と、再開後に一回分の移動間隔を待つ合意
design.md 状態遷移、単一の更新ループ、入力処理、計時の基準
tasks.md 遷移と入力制限の実装、再開時の計時、対応する検証

タスクはゲーム全体を一度に扱う必要はありません。「停止と再開を実装し、ループが重複しないことを確認する」は、独立してレビューできる変更です。

設計が成立しないと分かったら、矛盾と影響を説明して方式か要求を修正します。完了後は実装との差分を文書へ反映します。cc-sdd などは整理を助けますが、合意と実装が一致しているかは人が確認する必要があります。

4. 誤りを見つけられるテスト

一時停止は複数の層で確認できます。

まず状態遷移です。実行から停止へ、停止から再開へ移れ、開始前と終了後は変わらないことを確かめます。次に制御可能な時計で、入力と計時の動作を確認します。

例えば移動間隔を 200ms に固定し、加速を無効にして、衝突しない局面を用意します。停止中に時計を 10 秒進めても、蛇の位置、餌、得点は変わらないはずです。通常のプレイでは許される方向転換を入力しても、再開後の方向は変わりません。再開後に 199ms 進めても移動せず、さらに 1ms 進めたときに一マス移動することを確かめます。

停止と再開を繰り返した後は、同じシミュレーション時間内の移動回数と、余分なタイマーや更新ループが残っていないかも確認します。「コールバック一回で一マス動く」だけでは不十分です。ループが重複していても、それぞれがこの条件を満たすことがあるためです。

最後にブラウザーで実際のボタンとキーを操作し、表示と振る舞いを照合します。ブラウザーの実行時刻は負荷やバックグラウンド制限の影響を受けるため、制御された計時と実操作は分けて確認します。

注意したいのは、AI が実装を書いた後、その実装からテストを作ることです。両方が同じ誤りを共有する場合があります。

例えば、加速ルールを別途、初期移動間隔 200ms、5 点ごとに 20ms 短縮、下限 80ms と決めます。数値は説明用です。

得点は累計を指し、5 点の区切りに達するたびに加速します。実装が誤って「4 点ごとに加速」になったとすると、次の差が生じます。

得点 要求が定める間隔 誤った実装の結果
4 200ms 180ms
5 180ms 180ms
8 180ms 160ms
10 160ms 160ms

5 点と 10 点だけを確認すると、テストは成功します。閾値の直前や閾値の間も確認すると、誤りを発見しやすくなります。誤った実装の出力をそのまま期待値にすれば、これらの用例も意味を失います。

下限も個別に確認します。25 点では 100ms、30 点では 80ms に達し、35 点でも 80ms を維持する必要があります。通常の流れだけを確認するテストでは、閾値付近や上限・下限に達した後の振る舞いを見落としがちです。

期待値は要求から独立に導きます。私はテストのレビューで、何行を通ったかに加え、正しい振る舞いと誤りを区別できるかを重視します。AI にテスト作成を補助させる場合も、期待値には独立した根拠とレビューが必要です。

5. 明確な仕様でも製品を間違えることがある

仕様は誤りを見つけやすくしますが、明確でも間違った要求を、AI が効率よく実装する場合もあります。

P2 に戻ると、プレイヤーが停止中に次の方向を準備したいなら、入力を無視する動作は期待に合わないかもしれません。仕様どおりでテストが成功していても、試作と利用者の反応からルールを変える必要があります。

実装が合意を満たすかと、その合意が利用者の問題を解決するかは、別の判断です。前者にはテストが役立ち、後者には業務上の確認、利用者の反応、実際の利用結果が必要です。

私は体験とシステム境界に関わる判断を先に確認し、その後で実装を具体化する方法を選びます。議論が残る振る舞いは未決事項とし、小さな試作で確かめます。仮定を AI に膨らませて、完成した仕様に見せるべきではありません。

6. 要求変更が設計の見直しを必要にする

共有空間を持つマルチプレイへ拡張すると、一時停止は参加者間のルールになります。

一人が停止しても、他の人は続けるのでしょうか。停止中の蛇は衝突対象に残るのでしょうか。切断を停止と同じに扱うのでしょうか。公平性、サーバー状態、復旧へ影響し、元の P1〜P3 では足りません。

この設計上の検討では、まず振る舞いを再確認し、その後で重要な状態の裁定者と、入力・結果の同期方法を決めます。権威サーバー方式では、停止のような重要操作もサーバーのルールで判断し、クライアントの表示を裁定結果へ合わせます。

WebSocket、ネットワーク基盤、シリアライズ形式は、その後に通信頻度、部屋の規模、許容遅延、負荷試験で比較します。仕様の変更で旧設計が成立しなくなれば、アーキテクチャ上の判断も更新する必要があります。

7. 仕様の維持コストを抑える

仕様とコードはともに変わり、維持の負担も生みます。文書が旧動作、コードが新ルールを示していると、次の AI による変更がずれを広げる可能性があります。

振る舞いの変更は、要求とテストも含めてレビューします。未確認の仮定を明示し、放棄した判断を現在の実装根拠として残さないようにします。作業前にも関連仕様とコードの一致を確かめます。

変更の完了記録は P1〜P3 に対応づけ、実際に実行したテストと結果、確認したブラウザー操作、未検証の項目を残せます。タスクのチェック欄は、その証拠の代わりにはなりません。受け入れ条件を満たさない場合は、実装が合意から外れたのか、合意自体を修正すべきなのかを先に判断します。現在のコードの出力に合わせて期待値だけを変更すべきではありません。

工程の規模はリスクで調整できます。局所的な文言変更なら、タスクと画面確認で足りることが多いでしょう。権限、決済、データ移行、サービス間連携では、明確な振る舞いの制約と失敗処理に投資する価値があります。文書は誤解を減らすために使い、小さな変更を妨げる関門にすべきではありません。

AI はアイデアをコードにするコストを下げ、未確認の仮定をコードにするコストも下げます。仕様、実装、検証の間には、互いに照合できる根拠が必要です。業務、コード、ランタイムを理解する人が、成果物は問題を解決しているか、その証拠は信頼できるかを引き続き判断する必要があります。

参考資料