なんじゃくにっき

プログラミングの話題中心。

ChatGPTでライフゲーム

経緯

ChatGPTが公開されてからたまにクソつまらない質問したりしてただのおしゃべり相手としてしか使用してなかったが、

もうちょっと生産的なことに使おうと思ってお題を考えてみた。

「プログラミングのコード生成で、生成結果が1ファイルに収まって、見た目の確認できるもの」

から始めると良いかなと思ってお題は

ライフゲームのコードをJavaScriptで」

試した結果

GPTのバージョンは3.5

何段階化に質問分けたりも試したが、結局質問は1文で良くて

ライフゲームのコードをjavascriptで書いて」

だけでOK。

生成されるもの

ライフゲーム(Life Game)は、セルオートマトンの一種であり、生命の進化をシミュレートするシンプルなゲームです。セルが生きている(生存している)か死んでいるかの状態を表す格子状の盤面があり、ある一定のルールに基づいてセルの状態が進化します。

以下は、JavaScriptを使用してライフゲームを実装するサンプルコードです。ここでは、HTMLの<canvas>要素を使ってグリッドを描画しますが、他の方法でも実装できます。
<!DOCTYPE html>
<html>
<head>
  <title>Life Game</title>
  <style>
    canvas {
      border: 1px solid #ccc;
    }
  </style>
</head>
<body>
  <canvas id="canvas" width="400" height="400"></canvas>
  <script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    const gridSize = 20;
    const rows = canvas.height / gridSize;
    const cols = canvas.width / gridSize;
    const cellProbability = 0.2; // 初期状態で生きているセルの割合

    // ランダムな初期状態を生成
    function randomInitialState() {
      const initialState = [];
      for (let i = 0; i < rows; i++) {
        const row = [];
        for (let j = 0; j < cols; j++) {
          row.push(Math.random() < cellProbability);
        }
        initialState.push(row);
      }
      return initialState;
    }

    // グリッドを描画する関数
    function drawGrid(grid) {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      for (let i = 0; i < rows; i++) {
        for (let j = 0; j < cols; j++) {
          ctx.fillStyle = grid[i][j] ? 'black' : 'white';
          ctx.fillRect(j * gridSize, i * gridSize, gridSize, gridSize);
          ctx.strokeRect(j * gridSize, i * gridSize, gridSize, gridSize);
        }
      }
    }

    // セルの次の状態を計算する関数
    function computeNextState(grid) {
      const nextGrid = [];
      for (let i = 0; i < rows; i++) {
        const nextRow = [];
        for (let j = 0; j < cols; j++) {
          const cell = grid[i][j];
          const liveNeighbors = countLiveNeighbors(grid, i, j);

          // ライフゲームのルールに基づいて次の状態を計算
          if (cell && (liveNeighbors < 2 || liveNeighbors > 3)) {
            nextRow.push(false); // 孤立または過密のため死亡
          } else if (!cell && liveNeighbors === 3) {
            nextRow.push(true); // 生存条件を満たすため誕生
          } else {
            nextRow.push(cell); // 状態を維持
          }
        }
        nextGrid.push(nextRow);
      }
      return nextGrid;
    }

    // セルの周囲の生きているセルの数を数える関数
    function countLiveNeighbors(grid, row, col) {
      let count = 0;
      for (let i = -1; i <= 1; i++) {
        for (let j = -1; j <= 1; j++) {
          if (i === 0 && j === 0) continue;
          const r = row + i;
          const c = col + j;
          if (r >= 0 && r < rows && c >= 0 && c < cols && grid[r][c]) {
            count++;
          }
        }
      }
      return count;
    }

    // メインの関数
    function main() {
      const initialState = randomInitialState();
      drawGrid(initialState);

      setInterval(() => {
        const nextState = computeNextState(initialState);
        drawGrid(nextState);
        initialState = nextState;
      }, 100); // 100ミリ秒ごとに更新
    }

    main();
  </script>
</body>
</html>

補足

お題自体の説明文も作ってくれたりと想像以上に丁寧だった。

なお、生成されるコードはそのままでは動かなかったが、1行変えるだけで動いた。すごい。

下から10行目くらいの

const initialState = randomInitialState();

let initialState = randomInitialState();

に変えればOK。

自分でデバッグできることは必要だが、ある程度までのコード生成させて時間短縮にはケースを選べば十分使えるな、という感想。