同じゲームを10回修正させたら、コードはどれだけ膨らむか
遊びをつくる執筆にClaudeを使用しています。

的をクリックして消すだけの小さなゲームがあるとします。そこへ「制限時間をつけて」「スコアを出して」「難易度を選べるように」と、AIに1つずつ頼んでいく場面を考えてみます。10回目の依頼を出すころ、ファイルの中身は最初と同じ形をしているでしょうか。それとも、継ぎ足しの跡だらけになっているでしょうか。 この記事は、その答えを書くものではありません。答えは使うAIや依頼文、ゲームの種類で変わります。ここでは、読者が自分で10回の修正を行い、膨らみ方を行数と構造の両方で記録するための設計書を示します。 ポイントは、行数だけを見ないことです。機能が10個増えれば行数が増えるのは当然です。確かめたいのは、増え方が機能の数に見合っているかどうかです。関数が整理されて増えているのか、同じ処理のコピーが並んでいるのか、状態を持つ変数が散らばっているのかは、数字の組み合わせで見分けられます。
「膨らむ」を何で測るか
最初に、何を数えるかを決めます。測る項目は、手作業でも小さなスクリプトでも数えられる、粗いものに限ります。
- JS行数(空行を除く)、何を示すか:全体の量、読むときの注意:整形ルールが変わると見かけが変わります
- 関数の数、何を示すか:処理が分割されているか、読むときの注意:無名の小さな関数が増えても数は増えます
- トップレベル宣言の数、何を示すか:状態(変数)が散らばっているか、読むときの注意:行頭にインデントなしで書かれている前提の近似です
- 分岐の数(if・switch・case)、何を示すか:条件の積み重なり、読むときの注意:機能追加で増えるのは自然です
- 重複する行の種類、何を示すか:コピーの多さ、読むときの注意:閉じ括弧など短い行は除いて数えます
- イベント登録の数、何を示すか:入口の増え方、読むときの注意:同じ要素に何度も登録していないかの手がかりです
もう1つ、数字にならない項目を足します。その回の修正で、AIがファイルのどこを書き換えたかです。依頼は1行分の変更で済むはずなのに、全体が書き換わっていないかを見ます。前回版と今回版を差分表示できるツールやエディタの比較機能に並べると、一目でわかります。
準備するもの
用意するものは次の4つです。
- ベースのゲーム(v0)。的が1つ出て、クリックすると消えて別の場所に出る程度の、100行前後のHTMLを1ファイルで用意します。自作でも、AIに最初の1回だけ作らせたものでも構いません。ただし、条件を比べる場合は全員が同じv0から始めます。
- 固定した修正依頼10個。事前に書き出して、途中で変えません。例を挙げます。
- 制限時間30秒とカウントダウン表示を追加する
- スコアを画面に表示し、的を消すたびに加点する
- 的の大きさをランダムにし、小さいほど高得点にする
- 時間切れでリザルト表示とリトライボタンを出す
- 難易度(やさしい・ふつう・むずかしい)を選べるようにする
- 的が一定時間で消え、逃したらミスとして数える
- ミスが3回でゲームオーバーにする
- 連続命中でコンボ倍率をつける
- 命中時に短い効果音を鳴らし、ミュートボタンをつける
- 狭い画面でも遊べるよう、タッチ操作と的の大きさ調整に対応する
- 依頼文の雛形。毎回この形で出します。「次の修正をしてください:(依頼)。ほかの挙動は変えないでください。修正後のファイル全体を省略せずに返してください」。全体を返させるのは、後で説明する「省略」による見かけの行数減少を避けるためです。
- 計測ツール。次のHTMLを保存してブラウザで開き、ゲームのHTML全体を貼り付けて測ります。外部ライブラリは使わず、正規表現による近似です。
<!doctype html>
<meta charset="utf-8">
<textarea id="src" rows="10" cols="60" placeholder="ゲームのHTMLを貼る"></textarea>
<button id="go">計測</button>
<pre id="out"></pre>
<script>
document.getElementById('go').onclick = () => {
const html = document.getElementById('src').value;
const blocks = [...html.matchAll(/<script(?![^>]*\bsrc=)[^>]*>([\s\S]*?)<\/script>/gi)];
const js = blocks.map(b => b[1]).join('\n');
const lines = js.split('\n').filter(l => l.trim() !== '');
const count = re => (js.match(re) || []).length;
const seen = {};
lines.forEach(l => {
const t = l.trim();
if (t.length >= 12) seen[t] = (seen[t] || 0) + 1;
});
const result = {
'HTML全体の行数': html.split('\n').length,
'JS行数(空行除く)': lines.length,
'関数の数': count(/\bfunction\b/g) + count(/=>/g),
'トップレベル宣言': lines.filter(l => /^(let|const|var)\s/.test(l)).length,
'分岐(if/switch/case)': count(/\b(if|switch|case)\b/g),
'イベント登録': count(/addEventListener/g),
'重複する行の種類': Object.values(seen).filter(n => n > 1).length
};
document.getElementById('out').textContent =
Object.entries(result).map(([k, v]) => k + ': ' + v).join('\n');
};
</script>このツールには限界があります。コメント内の語も数え、複数行にまたがる式も区別しません。絶対値の正確さより、同じツールで測った版どうしの比較に意味がある道具だと考えてください。
10回の手順
条件はできるだけ固定し、変える要素は1回の実験につき1つだけにします。AIの種類、会話の方式(同じ会話を続けるか、毎回新しい会話にコードを貼るか)、依頼文の雛形は、条件ごとに決めて記録します。
- v0をそのまま計測し、記録シートの0行目に書きます。ブラウザで開き、動くことも確認します。
- 依頼1を雛形に当てはめてAIに送ります。
- 返ってきたコードを丸ごと新しいファイル(v1)として保存します。手で直さず、エラーが出ても自分では修正しません。
- v1をブラウザで開き、「起動する」「その回の機能が動く」「前の機能が壊れていない」の3点を、○△×で記録します。
- v1を計測ツールに貼り、数値を記録します。
- 前回版との差分を表示し、変更された行の割合と、変更箇所が1か所に集中しているか全体に散っているかをメモします。
- 依頼2から10まで、2〜6を繰り返します。動かなくなった回は、直させる依頼を足さずに、×のまま次の依頼へ進む方法と、1回だけ「動かない」と伝えて直させる方法のどちらかに決めておきます。途中で方法を変えると比較できなくなります。
- 同じ条件で、最低3セット行います。AIの出力は毎回違うため、1セットだけでは偶然の差と傾向を区別できません。
3セット×10回で、1条件につき30回の依頼と計測になります。時間がかかる場合は、依頼を5個に絞って揃えて行う方法もありますが、その場合は題名の「10回」とは別の実験だと記録に書き添えてください。
記録の読み方
記録シートは、縦に版(v0〜v10)、横に各指標と○△×、差分のメモを並べます。3セット分を並べたら、次の順に読みます。
行数の伸び方を見ます。 各版の増分を並べます。毎回ほぼ同じだけ増えているなら、機能追加にほぼ比例しています。後半で増分が大きくなっているなら、既存部分への継ぎ足しや、条件分岐の複製が起きている可能性があります。
行数と他の指標のずれを見ます。 判断の目安は次のとおりです。
- 行数と関数の数が一緒に増える:処理が分割されながら育っています。
- 行数だけが増え、関数の数があまり増えない:既存の関数の中身が太っています。
- 分岐の数が行数より先に増える:条件の継ぎ足しが起きやすい状態です。
- 重複する行の種類が増え続ける:似た処理のコピーが増えています。
- トップレベル宣言が増え続ける:状態があちこちに散らばっています。依頼6〜8のような「状態を増やす依頼」で跳ねるかを見ます。
途中で数値が下がる回に注目します。 AIが勝手に整理した場合と、機能が壊れて消えた場合があります。○△×の欄と見比べれば区別できます。下がったのに前の機能が×になっていたら、整理ではなく欠落です。
依頼の種類で分けて見ます。 「機能を足す依頼(1・2・4)」「既存の挙動を変える依頼(3・5・8)」「横断的な依頼(9・10)」にグループ分けし、どのグループで差分の範囲が広がったかを比べます。横断的な依頼で全体が書き換わるのは自然ですが、足すだけの依頼で全体が書き換わるなら、注意が必要な兆候です。
条件を変えて比べる場合は、たとえば「毎回の会話を新しくする」と「同じ会話を続ける」を並べ、どの指標に差が出たかを3セットの範囲のばらつきと比べます。差がセット間のばらつきより小さいなら、差があるとは言えません。
誤りやすい点
- 「以前と同じ」の省略。 AIが「ここは変更なし」とコメントだけ残して中身を省くと、行数が減ったように見えます。雛形で全体を返させるのはそのためで、返ってきた版に省略の表現がないか、毎回目で確認します。
- 整形ルールの変化。 インデントや括弧の位置が途中で変わると、行数やトップレベル宣言の数がずれます。大きく変わったら、その旨を記録します。
- 動作確認の省略。 動かない版の数字は、動く版と同列には比べられません。○△×を必ず付けます。
- 依頼の言い換え。 条件ごとに依頼文を微調整すると、何を比べているのかわからなくなります。文面は固定します。
- 1回の結果での一般化。 3セットのばらつきを見ないまま「このAIは膨らみやすい」と言い切るのは避けます。
- ツールの数字の過信。 正規表現の近似です。気になる版は、実際のコードを自分で読んで確かめてください。
- 保存機能の依頼を混ぜるとき。 ハイスコアの保存のような依頼を足すなら、保存先の方法で挙動が変わります。アソバースにアップロードした作品内のlocalStorageは一時メモリーの互換処理として扱われる、という点を踏まえ、今回の10個の依頼には保存を含めていません。
次の行動
まずv0を1つ決めて、計測ツールで測り、記録シートの0行目を埋めてください。そのうえで、依頼1と2だけをAIに出して、差分と数字を並べてみると、実験の勘所がつかめます。
遊んで確かめたい場合は、v0とv10のHTMLをそれぞれアソバースにアップロードして、同じ端末で続けて遊び比べる方法もあります。アップロードはHTMLの直接投稿ができ、公開にはメールアドレスの確認が必要です。非公開のまま下書きで保管する使い方もできます。

