マガジン

途中まで自分で書いたコードを渡すと、AIは書き方を合わせてくるか

遊びをつくる

執筆にClaudeを使用しています。

折りたたみ紙が広がる枠で、言語による文字量に対応する画面設計を表したイラスト。
記事のテーマをもとに制作したAI生成イラスト。

セミコロンは付けない、定数は大文字の蛇腹(UPPER_SNAKE)、状態は state というオブジェクト一つにまとめる。そんな癖で書いたゲームの前半をAIに渡し、「続きを書いてください」と頼む場面を考えてみます。返ってきたコードは動いたとして、書き方まで元のコードと地続きになっているでしょうか。それとも、セミコロンが戻り、状態が別々の変数に散らばっているでしょうか。 この記事は、その問いに答えを出すための実験の設計書です。結果は書きません。同じコードと同じ指示を使い、条件だけを変えて何度か試せば、自分の癖がどの程度AIに伝わるかを自分の環境で確かめられます。そのうえで、合わなかったときの直し方も試せる形にまとめます。 確かめたいことは二つです。一つは、コードを見せただけで書き方への追従が起きるのか、それとも言葉で頼まないと起きないのかです。もう一つは、追従しない軸があったとき、どの直し方が効くのかです。

この記事の目次
  1. 「合わせた」を数えられる形にする
  2. 準備するもの
  3. 手順と記録の取り方
  4. 結果の読み方
  5. 合わないときの直し方
  6. 次の行動

「合わせた」を数えられる形にする

「なんとなく自分のコードっぽい」という印象のまま実験すると、結果の読み方が揺れます。先に、合わせたかどうかを一つずつ○×で付けられる軸に分けておきます。

  • 1、観察する軸:セミコロン、渡すコードでの癖:付けない
  • 2、観察する軸:インデント、渡すコードでの癖:半角スペース2つ
  • 3、観察する軸:定数の名前、渡すコードでの癖:TARGET_RADIUS のような大文字と下線
  • 4、観察する軸:関数の名前、渡すコードでの癖:動詞+名詞の camelCase(spawnTarget、drawTargets)
  • 5、観察する軸:状態の持ち方、渡すコードでの癖:state という一つのオブジェクトに集約
  • 6、観察する軸:コメント、渡すコードでの癖:日本語で、何をするかより「なぜ」を書く
  • 7、観察する軸:文字列のクォート、渡すコードでの癖:シングルクォート
  • 8、観察する軸:処理の分け方、渡すコードでの癖:更新(update…)と描画(draw…)を別の関数にする

1〜3と7は見た目の規則です。4〜6と8は、コードの設計や考え方に近い癖です。見た目の規則は後から整形ツールで揃えられますが、設計の癖は揃えにくいので、軸を分けて数えると読み方が変わってきます。

もう一つ、動作の確認も別枠で持っておきます。9は「クリックで的が消える」、10は「スコアが増える」です。書き方がそろっていても動かないコードは、追従の成功例として数えにくいためです。

準備するもの

渡すコード

次のコードを index.html として保存し、ブラウザで開いてください。的が一定間隔で現れて描画されるところまでが書いてあり、クリック判定とスコア加算は未実装です。外部ライブラリは使わず、単独で動きます。

html
<canvas id="game" width="320" height="240"></canvas>
<script>
const TARGET_RADIUS = 20
const SPAWN_INTERVAL_MS = 800

const state = {
  targets: [],
  score: 0,
  lastSpawnAt: 0,
}

// 的は端に半分はみ出さないよう、半径ぶん内側に出す
function spawnTarget(canvas) {
  state.targets.push({
    x: TARGET_RADIUS + Math.random() * (canvas.width - TARGET_RADIUS * 2),
    y: TARGET_RADIUS + Math.random() * (canvas.height - TARGET_RADIUS * 2),
  })
}

function drawTargets(ctx) {
  for (const target of state.targets) {
    ctx.beginPath()
    ctx.arc(target.x, target.y, TARGET_RADIUS, 0, Math.PI * 2)
    ctx.fill()
  }
}

function updateGame(now, canvas) {
  if (now - state.lastSpawnAt > SPAWN_INTERVAL_MS) {
    spawnTarget(canvas)
    state.lastSpawnAt = now
  }
}

function loop(now) {
  const canvas = document.getElementById('game')
  const ctx = canvas.getContext('2d')
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  updateGame(now, canvas)
  drawTargets(ctx)
  requestAnimationFrame(loop)
}

// TODO: クリックで的を消してスコアを加算する
requestAnimationFrame(loop)
</script>

自分のゲームの途中コードを使っても構いません。その場合は、上の表を自分の癖に書き換えてから始めてください。軸の定義は、AIの返答を見る前に確定させておくことが大切です。

条件と指示文

同じお題を、次の4条件で試します。

  • 条件A(コードなし):コードを渡さず、「canvas で、クリックすると消える的のゲームを1ファイルのHTMLで作ってください」とだけ頼みます。基準線になります。
  • 条件B(コードだけ):コードを貼り、「作りかけのゲームです。TODO の部分を実装し、全体のコードを返してください」と頼みます。書き方への言及は一切しません。
  • 条件C(書き方を守るよう依頼):条件Bの指示に「既存コードの書き方に合わせてください」と一文だけ足します。具体的なルールは書きません。
  • 条件D(癖が混在するコード):渡すコードの後半を、セミコロン付き・let の変数が散らばる形に書き換えて貼ります。前半は変えません。指示文は条件Bと同じです。

各条件は3回ずつ、毎回新しい会話で行います。合計12回です。同じ会話の中で繰り返すと、前の返答が文脈に残り、条件の差が見えなくなります。

手順と記録の取り方

  1. 条件ごとにフォルダを作り、返ってきたコードを A-1.html、A-2.html、B-1.html のように保存します。返答の説明文は読まず、まずコードだけを保存してください。
  2. 保存したファイルをブラウザで開き、軸9と10(的が消える、スコアが増える)を確認します。スコアは画面に表示されていなければ、開発者ツールのコンソールで state.score を見る方法もあります。状態の名前がAIの返答で変わっている場合は、変わっていること自体が軸5の記録になります。
  3. 軸1〜8を、コードを見ながら○(全体でそろっている)、△(一部だけそろっている)、×(そろっていない)で付けます。△を使うときは、どこが崩れていたかを一言メモします。たとえばセミコロンが新しく書いた関数にだけ付いている場合は、「追加部分のみ付与」と書きます。
  4. 軸1と7は機械的に数えられます。エディタの検索で、行末の ; の数と " の数を数えてください。目視の判定と食い違うときは、数えた値を優先します。
  5. 記録は次のような表にまとめます。
  • B-1、1:、2:、3:、4:、5:、6:、7:、8:、動作:、メモ:

追従率は「○の数÷8」で出しますが、△を0.5と数えるかどうかは、最初に決めて途中で変えないでください。

結果の読み方

12枚の表がそろったら、まず条件ごとに追従率を並べます。見るポイントは次のとおりです。

  • Aより B が明らかに高い場合:コードを見せるだけで、書き方がある程度伝わっていると読めます。さらにBとCの差が小さければ、わざわざ頼まなくても追従していることになります。
  • BよりCが高い場合:癖は暗黙のままでは拾われにくく、一文の依頼で変わると読めます。どの軸が上がったのかを見ると、「頼むと効く軸」が分かります。
  • BもCもAと変わらない場合:渡したコードの量が少なすぎるか、癖が目立たないか、軸の定義があいまいだった可能性があります。結論を急がず、癖をもっとはっきり出したコードで再度試してください。
  • 軸ごとに差がある場合:見た目の規則(1〜3、7)は合うのに、設計の癖(5、8)は崩れる、またはその逆、といった偏りが出るかもしれません。偏りが出たなら、直し方を軸ごとに変える根拠になります。
  • 条件Dの場合:混在したコードに対して、多数派の書き方に寄るのか、直近に書かれた書き方に寄るのか、どちらにも寄らないのかを見ます。3回だけでは断定できませんから、傾向のメモにとどめてください。

3回の間に結果が大きく揺れた条件は、平均よりも揺れ幅を記録します。同じ指示でも毎回そろうとは限らない、という情報自体が実用上は重要です。また、追従率が高くても動作が×のファイルは、別に集計してください。「そろえようとして壊した」のか、「そろえずに動いた」のかで、次の手が変わります。

合わないときの直し方

追従が崩れた軸があったら、直し方を一つずつ足して再測定します。同じお題・同じコード・3回ずつで、条件E以降として記録してください。

  1. 癖を言葉にして添える(条件E):「セミコロンなし、インデントはスペース2、定数は UPPER_SNAKE、状態は state に集約、コメントは日本語で理由を書く」のように、3〜5行のルールにして指示文へ入れます。条件Cの「合わせてください」より具体的になるので、差を見る価値があります。
  2. 見本を指す:「drawTargets と同じ形で、handleClick を書いてください」のように、既存の関数を名指しします。命名や引数の取り方は、ルールより見本のほうが伝わることがあります。
  3. 書く範囲を絞る:「TODO の部分に入るコードだけを返してください」とすると、既存部分を書き直されて癖が混ざる事故を減らせます。ただし、貼り付けの手間が増えるため、動作の確認も忘れないでください。
  4. 整形は機械に任せる:セミコロンやインデントなど見た目の規則は、Prettier のような整形ツールで後から揃えるほうが確実です。AIに期待するのは、機械では揃えられない設計の癖の側に絞れます。
  5. 直し方も同じ表で測る:直し方を足したあとの追従率を、条件Bと同じ8軸で付けます。体感で「良くなった」と判断すると、最初に決めた基準から離れてしまいます。

起こりやすい誤りもまとめておきます。

  • 同じ会話で連続して試し、前の返答の影響を受けてしまうこと
  • 条件ごとにお題や指示文を少しずつ変えてしまい、差の原因が分からなくなること
  • 結果を見たあとで軸の定義を変えること
  • 使うAIのモデルや設定が、途中で変わること
  • 1回の結果だけを見て、傾向があると決めること

次の行動

まず条件Aと条件Bだけを3回ずつ行い、8軸の表を埋めてみてください。その差を見てから、条件C以降を足すかどうかを決めても十分です。

追従を確かめたコードで1本のゲームが仕上がったら、アソバースへの投稿も選べます。HTMLを直下の index.html にしたZIP、または単独のHTMLをアップロードでき、下書き保存もできます。公開にはメールアドレスの確認が必要です。投稿前の最新の条件は、投稿画面の案内で確認してください。