Claude 3.7 Sonnetのコーディング能力を試す 8


以前の投稿でClaude 3.7 Sonnetのコーディング能力を試した.

今回は引き続きReactを使ってコードを書いてもらいLife gameのシミュレーションを行ってみた.

すると,動的に遊べるシミュレーションを出してくれた.

ライフゲームのシミュレーションを行うコードを書いて.
Reactで動的に処理できるようにして.
エラーが出ないように自己点検して.
import { useState, useEffect, useCallback } from 'react';

export default function GameOfLife() {
  const [gridSize, setGridSize] = useState({ rows: 20, cols: 20 });
  const [grid, setGrid] = useState([]);
  const [running, setRunning] = useState(false);
  const [speed, setSpeed] = useState(300); // ミリ秒単位

  // グリッドを初期化
  const initializeGrid = useCallback(() => {
    const rows = [];
    for (let i = 0; i < gridSize.rows; i++) {
      rows.push(Array.from(Array(gridSize.cols), () => 0));
    }
    setGrid(rows);
  }, [gridSize]);

  // ランダムな初期状態を生成
  const randomizeGrid = () => {
    const rows = [];
    for (let i = 0; i < gridSize.rows; i++) {
      rows.push(Array.from(Array(gridSize.cols), () => Math.random() > 0.7 ? 1 : 0));
    }
    setGrid(rows);
  };

  // セルの状態を切り替える
  const toggleCell = (i, j) => {
    const newGrid = JSON.parse(JSON.stringify(grid));
    newGrid[i][j] = grid[i][j] ? 0 : 1;
    setGrid(newGrid);
  };

  // 次の世代を計算
  const computeNextGeneration = useCallback(() => {
    const rows = gridSize.rows;
    const cols = gridSize.cols;
    const currentGrid = grid;
    const newGrid = JSON.parse(JSON.stringify(currentGrid));

    for (let i = 0; i < rows; i++) {
      for (let j = 0; j < cols; j++) {
        let neighbors = 0;
        // 周囲8マスのセルをチェック
        for (let ni = -1; ni <= 1; ni++) {
          for (let nj = -1; nj <= 1; nj++) {
            if (ni === 0 && nj === 0) continue; // 自分自身はスキップ
            const newI = (i + ni + rows) % rows; // 画面端の処理(トーラス状にする)
            const newJ = (j + nj + cols) % cols;
            neighbors += currentGrid[newI][newJ];
          }
        }

        // ライフゲームのルールを適用
        if (currentGrid[i][j] === 1 && (neighbors < 2 || neighbors > 3)) {
          newGrid[i][j] = 0; // 過疎または過密で死亡
        } else if (currentGrid[i][j] === 0 && neighbors === 3) {
          newGrid[i][j] = 1; // 誕生
        }
      }
    }

    setGrid(newGrid);
  }, [grid, gridSize]);

  // コンポーネントマウント時に初期化
  useEffect(() => {
    initializeGrid();
  }, [initializeGrid]);

  // アニメーションのためのループ処理
  useEffect(() => {
    let intervalId;
    if (running) {
      intervalId = setInterval(() => {
        computeNextGeneration();
      }, speed);
    }
    return () => {
      if (intervalId) {
        clearInterval(intervalId);
      }
    };
  }, [running, computeNextGeneration, speed]);

  // グリッドサイズ変更ハンドラー
  const handleSizeChange = (e) => {
    const { name, value } = e.target;
    // 入力値を数値に変換し、最小値を5、最大値を50に設定
    const newValue = Math.min(Math.max(parseInt(value) || 5, 5), 50);
    setGridSize(prev => ({ ...prev, [name]: newValue }));
  };

  // サイズ変更時にグリッドを再初期化
  useEffect(() => {
    initializeGrid();
  }, [gridSize, initializeGrid]);

  return (
    <div className="flex flex-col items-center p-4 bg-gray-100 min-h-screen">
      <h1 className="text-2xl font-bold mb-4">Conway's Game of Life</h1>
      
      <div className="flex flex-wrap justify-center gap-4 mb-4">
        <button
          className={`px-4 py-2 rounded ${running ? 'bg-red-500 text-white' : 'bg-green-500 text-white'}`}
          onClick={() => setRunning(!running)}
        >
          {running ? '停止' : '開始'}
        </button>
        
        <button
          className="px-4 py-2 bg-blue-500 text-white rounded"
          onClick={randomizeGrid}
          disabled={running}
        >
          ランダム生成
        </button>
        
        <button
          className="px-4 py-2 bg-gray-500 text-white rounded"
          onClick={initializeGrid}
          disabled={running}
        >
          クリア
        </button>
      </div>

      <div className="flex flex-wrap justify-center gap-4 mb-4">
        <div className="flex items-center">
          <label htmlFor="rows" className="mr-2">行数:</label>
          <input
            type="number"
            id="rows"
            name="rows"
            value={gridSize.rows}
            onChange={handleSizeChange}
            min="5"
            max="50"
            className="w-16 p-1 border rounded"
            disabled={running}
          />
        </div>
        
        <div className="flex items-center">
          <label htmlFor="cols" className="mr-2">列数:</label>
          <input
            type="number"
            id="cols"
            name="cols"
            value={gridSize.cols}
            onChange={handleSizeChange}
            min="5"
            max="50"
            className="w-16 p-1 border rounded"
            disabled={running}
          />
        </div>
        
        <div className="flex items-center">
          <label htmlFor="speed" className="mr-2">速度:</label>
          <input
            type="range"
            id="speed"
            min="50"
            max="1000"
            step="50"
            value={speed}
            onChange={(e) => setSpeed(parseInt(e.target.value))}
            className="w-32"
          />
          <span className="ml-2">{speed}ms</span>
        </div>
      </div>
      
      <div className="border border-gray-300 bg-white p-1 inline-block">
        {grid.map((row, i) => (
          <div key={i} className="flex">
            {row.map((cell, j) => (
              <div
                key={`${i}-${j}`}
                onClick={() => !running && toggleCell(i, j)}
                className={`w-4 h-4 border border-gray-200 ${
                  cell ? 'bg-black' : 'bg-white'
                } ${!running ? 'cursor-pointer hover:bg-gray-300' : ''}`}
              />
            ))}
          </div>
        ))}
      </div>
      
      <div className="mt-4 text-sm text-gray-600">
        <p>使い方: セルをクリックして初期状態を設定し、「開始」ボタンを押してシミュレーションを開始します。</p>
        <p>ルール: 周囲に生きたセルが2つか3つあれば生存、3つあれば誕生、それ以外は死亡。</p>
      </div>
    </div>
  );
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です