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


Claude 3.7 Sonnetのコーディング能力を試していたらClaude 4.0 が発表された.

そこで今回はその比較をすべく,以前と同じ内容のプロンプトを4.0Sonnetに打ち込んでみた.

すると,Claude 3.7 Sonnetよりも工夫された出力を返してくれた.

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

const GRID_SIZE = 30;
const CELL_SIZE = 12;

// 空のグリッドを作成
const createEmptyGrid = () => {
  return Array(GRID_SIZE).fill().map(() => Array(GRID_SIZE).fill(false));
};

// セルの近傍の生きているセル数を数える
const countNeighbors = (grid, x, y) => {
  let count = 0;
  const directions = [
    [-1, -1], [-1, 0], [-1, 1],
    [0, -1],           [0, 1],
    [1, -1],  [1, 0],  [1, 1]
  ];
  
  for (const [dx, dy] of directions) {
    const newX = x + dx;
    const newY = y + dy;
    
    if (newX >= 0 && newX < GRID_SIZE && newY >= 0 && newY < GRID_SIZE) {
      if (grid[newX][newY]) {
        count++;
      }
    }
  }
  
  return count;
};

// 次の世代を計算
const getNextGeneration = (currentGrid) => {
  const newGrid = createEmptyGrid();
  
  for (let i = 0; i < GRID_SIZE; i++) {
    for (let j = 0; j < GRID_SIZE; j++) {
      const neighbors = countNeighbors(currentGrid, i, j);
      const isAlive = currentGrid[i][j];
      
      if (isAlive) {
        // 生きているセルの場合
        newGrid[i][j] = neighbors === 2 || neighbors === 3;
      } else {
        // 死んでいるセルの場合
        newGrid[i][j] = neighbors === 3;
      }
    }
  }
  
  return newGrid;
};

// よく知られたパターンを生成
const generatePattern = (pattern) => {
  const grid = createEmptyGrid();
  const centerX = Math.floor(GRID_SIZE / 2);
  const centerY = Math.floor(GRID_SIZE / 2);
  
  switch (pattern) {
    case 'glider':
      const glider = [[0, 1], [1, 2], [2, 0], [2, 1], [2, 2]];
      glider.forEach(([x, y]) => {
        if (centerX + x < GRID_SIZE && centerY + y < GRID_SIZE) {
          grid[centerX + x][centerY + y] = true;
        }
      });
      break;
      
    case 'blinker':
      for (let i = -1; i <= 1; i++) {
        if (centerX + i >= 0 && centerX + i < GRID_SIZE) {
          grid[centerX + i][centerY] = true;
        }
      }
      break;
      
    case 'block':
      for (let i = 0; i < 2; i++) {
        for (let j = 0; j < 2; j++) {
          if (centerX + i < GRID_SIZE && centerY + j < GRID_SIZE) {
            grid[centerX + i][centerY + j] = true;
          }
        }
      }
      break;
      
    default:
      // ランダムパターン
      for (let i = 0; i < GRID_SIZE; i++) {
        for (let j = 0; j < GRID_SIZE; j++) {
          grid[i][j] = Math.random() < 0.3;
        }
      }
  }
  
  return grid;
};

const GameOfLife = () => {
  const [grid, setGrid] = useState(() => createEmptyGrid());
  const [isRunning, setIsRunning] = useState(false);
  const [generation, setGeneration] = useState(0);
  const [speed, setSpeed] = useState(200);
  const intervalRef = useRef(null);

  // シミュレーションの実行
  const runSimulation = useCallback(() => {
    if (!isRunning) return;
    
    setGrid(currentGrid => {
      const newGrid = getNextGeneration(currentGrid);
      setGeneration(gen => gen + 1);
      return newGrid;
    });
  }, [isRunning]);

  // インターバルの管理
  useEffect(() => {
    if (isRunning) {
      intervalRef.current = setInterval(runSimulation, speed);
    } else {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
    }
    
    return () => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
      }
    };
  }, [isRunning, speed, runSimulation]);

  // セルのクリック処理
  const toggleCell = (x, y) => {
    if (isRunning) return;
    
    setGrid(currentGrid => {
      const newGrid = currentGrid.map(row => [...row]);
      newGrid[x][y] = !newGrid[x][y];
      return newGrid;
    });
  };

  // コントロール関数
  const startStop = () => {
    setIsRunning(!isRunning);
  };

  const reset = () => {
    setIsRunning(false);
    setGrid(createEmptyGrid());
    setGeneration(0);
  };

  const loadPattern = (pattern) => {
    if (isRunning) return;
    setGrid(generatePattern(pattern));
    setGeneration(0);
  };

  const nextStep = () => {
    if (isRunning) return;
    setGrid(currentGrid => getNextGeneration(currentGrid));
    setGeneration(gen => gen + 1);
  };

  return (
    <div className="p-6 bg-gray-100 min-h-screen">
      <div className="max-w-4xl mx-auto">
        <h1 className="text-3xl font-bold text-center mb-6 text-gray-800">
          Conway's Game of Life
        </h1>
        
        {/* コントロールパネル */}
        <div className="bg-white rounded-lg shadow-md p-4 mb-6">
          <div className="flex flex-wrap items-center justify-center gap-4 mb-4">
            <button
              onClick={startStop}
              className={`flex items-center gap-2 px-4 py-2 rounded font-medium transition-colors ${
                isRunning 
                  ? 'bg-red-500 hover:bg-red-600 text-white' 
                  : 'bg-green-500 hover:bg-green-600 text-white'
              }`}
            >
              {isRunning ? <Pause size={16} /> : <Play size={16} />}
              {isRunning ? '停止' : '開始'}
            </button>
            
            <button
              onClick={nextStep}
              disabled={isRunning}
              className="flex items-center gap-2 px-4 py-2 bg-blue-500 hover:bg-blue-600 disabled:bg-gray-300 text-white rounded font-medium transition-colors"
            >
              <Grid3X3 size={16} />
              次の世代
            </button>
            
            <button
              onClick={reset}
              className="flex items-center gap-2 px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded font-medium transition-colors"
            >
              <RotateCcw size={16} />
              リセット
            </button>
          </div>
          
          {/* パターン選択 */}
          <div className="flex flex-wrap items-center justify-center gap-2 mb-4">
            <span className="font-medium text-gray-700">パターン:</span>
            <button
              onClick={() => loadPattern('random')}
              disabled={isRunning}
              className="px-3 py-1 bg-purple-500 hover:bg-purple-600 disabled:bg-gray-300 text-white rounded text-sm transition-colors"
            >
              ランダム
            </button>
            <button
              onClick={() => loadPattern('glider')}
              disabled={isRunning}
              className="px-3 py-1 bg-purple-500 hover:bg-purple-600 disabled:bg-gray-300 text-white rounded text-sm transition-colors"
            >
              グライダー
            </button>
            <button
              onClick={() => loadPattern('blinker')}
              disabled={isRunning}
              className="px-3 py-1 bg-purple-500 hover:bg-purple-600 disabled:bg-gray-300 text-white rounded text-sm transition-colors"
            >
              ブリンカー
            </button>
            <button
              onClick={() => loadPattern('block')}
              disabled={isRunning}
              className="px-3 py-1 bg-purple-500 hover:bg-purple-600 disabled:bg-gray-300 text-white rounded text-sm transition-colors"
            >
              ブロック
            </button>
          </div>
          
          {/* スピード調整 */}
          <div className="flex items-center justify-center gap-4">
            <label className="font-medium text-gray-700">速度:</label>
            <input
              type="range"
              min="50"
              max="1000"
              value={speed}
              onChange={(e) => setSpeed(parseInt(e.target.value))}
              className="w-32"
            />
            <span className="text-sm text-gray-600">{speed}ms</span>
          </div>
        </div>
        
        {/* 情報表示 */}
        <div className="text-center mb-4">
          <span className="text-lg font-semibold text-gray-700">
            世代: {generation}
          </span>
        </div>
        
        {/* ゲームグリッド */}
        <div className="flex justify-center">
          <div 
            className="inline-block bg-white p-4 rounded-lg shadow-md"
            style={{
              display: 'grid',
              gridTemplateColumns: `repeat(${GRID_SIZE}, ${CELL_SIZE}px)`,
              gap: '1px',
              backgroundColor: '#e5e7eb'
            }}
          >
            {grid.map((row, i) =>
              row.map((cell, j) => (
                <div
                  key={`${i}-${j}`}
                  className={`cursor-pointer transition-colors duration-100 ${
                    cell ? 'bg-blue-600 hover:bg-blue-700' : 'bg-white hover:bg-gray-100'
                  }`}
                  style={{
                    width: `${CELL_SIZE}px`,
                    height: `${CELL_SIZE}px`
                  }}
                  onClick={() => toggleCell(i, j)}
                />
              ))
            )}
          </div>
        </div>
        
        {/* 説明 */}
        <div className="mt-6 bg-white rounded-lg shadow-md p-4">
          <h3 className="font-bold mb-2 text-gray-800">遊び方:</h3>
          <ul className="text-sm text-gray-600 space-y-1">
            <li>• セルをクリックして生きているセル(青)と死んでいるセル(白)を切り替えます</li>
            <li>• 「開始」ボタンでシミュレーションを開始/停止します</li>
            <li>• 「次の世代」ボタンで1ステップずつ進めます</li>
            <li>• パターンボタンで有名な図形を配置できます</li>
            <li>• スライダーでシミュレーションの速度を調整できます</li>
          </ul>
          
          <h3 className="font-bold mt-4 mb-2 text-gray-800">ルール:</h3>
          <ul className="text-sm text-gray-600 space-y-1">
            <li>• 生きているセルは2または3の近傍を持つ場合、次の世代でも生存</li>
            <li>• 死んでいるセルは3の近傍を持つ場合、次の世代で誕生</li>
            <li>• その他の場合は死滅または死んだまま</li>
          </ul>
        </div>
      </div>
    </div>
  );
};

export default GameOfLife;

コメントを残す

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