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


以前の投稿でClaude 3.7 Sonnetのコーディング能力を試した.今回はリッチなという文言を追加してみてやってみたが,やはりこの文言を入れるとClaudeはReactを組み合わせた素晴らしいものを作ってくれる.しかし,多少のバグが含まれている.

Langton's Antのシミュレーションを可能な限りリッチな表現を用いたコードで書いて.その過程をアニメーションとして出力できるようにして.
import { useState, useEffect, useRef } from 'react';

const LangtonAnt = () => {
  // 定数の設定
  const GRID_SIZE = 75;
  const CELL_SIZE = 8;
  const ANIMATION_SPEED = 10; // ミリ秒単位のフレームの間隔
  const MAX_STEPS = 15000; // 最大ステップ数
  
  // 色の設定
  const COLORS = {
    WHITE: '#ffffff',
    BLACK: '#000000',
    ANT: '#ff0000',
    TRAIL: '#ffcccc',
    GRID_LINE: '#dddddd',
    BACKGROUND: '#f5f5f5'
  };
  
  // アリの向きの列挙型
  const Direction = {
    UP: 0,
    RIGHT: 1,
    DOWN: 2,
    LEFT: 3
  };
  
  // 状態の管理
  const [grid, setGrid] = useState(() => {
    const initialGrid = Array(GRID_SIZE).fill(null).map(() => Array(GRID_SIZE).fill(0));
    return initialGrid;
  });
  
  const [ant, setAnt] = useState({
    x: Math.floor(GRID_SIZE / 2),
    y: Math.floor(GRID_SIZE / 2),
    direction: Direction.UP
  });
  
  const [isRunning, setIsRunning] = useState(false);
  const [steps, setSteps] = useState(0);
  const [speed, setSpeed] = useState(ANIMATION_SPEED);
  const requestRef = useRef(null);
  const canvasRef = useRef(null);
  
  // アリの移動ロジック
  const moveAnt = () => {
    setSteps(prevSteps => prevSteps + 1);
    
    setGrid(prevGrid => {
      const newGrid = [...prevGrid];
      const { x, y } = ant;
      
      // 現在のセルの色を変更
      newGrid[y][x] = newGrid[y][x] === 0 ? 1 : 0;
      return newGrid;
    });
    
    setAnt(prevAnt => {
      const { x, y, direction } = prevAnt;
      const currentColor = grid[y][x];
      
      // アリの向きを変更
      let newDirection;
      if (currentColor === 0) {
        // 白いセルでは右に90度回転
        newDirection = (direction + 1) % 4;
      } else {
        // 黒いセルでは左に90度回転
        newDirection = (direction - 1 + 4) % 4;
      }
      
      // 新しい位置を計算
      let newX = x;
      let newY = y;
      
      switch (newDirection) {
        case Direction.UP:
          newY = (y - 1 + GRID_SIZE) % GRID_SIZE;
          break;
        case Direction.RIGHT:
          newX = (x + 1) % GRID_SIZE;
          break;
        case Direction.DOWN:
          newY = (y + 1) % GRID_SIZE;
          break;
        case Direction.LEFT:
          newX = (x - 1 + GRID_SIZE) % GRID_SIZE;
          break;
      }
      
      return {
        x: newX,
        y: newY,
        direction: newDirection
      };
    });
  };
  
  // キャンバスの描画
  const draw = () => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    
    const ctx = canvas.getContext('2d');
    const width = GRID_SIZE * CELL_SIZE;
    const height = GRID_SIZE * CELL_SIZE;
    
    // キャンバスをクリア
    ctx.fillStyle = COLORS.BACKGROUND;
    ctx.fillRect(0, 0, width, height);
    
    // グリッドの描画
    for (let y = 0; y < GRID_SIZE; y++) {
      for (let x = 0; x < GRID_SIZE; x++) {
        const cellX = x * CELL_SIZE;
        const cellY = y * CELL_SIZE;
        
        // セルの色を設定
        ctx.fillStyle = grid[y][x] === 0 ? COLORS.WHITE : COLORS.BLACK;
        ctx.fillRect(cellX, cellY, CELL_SIZE, CELL_SIZE);
        
        // グリッド線の描画
        ctx.strokeStyle = COLORS.GRID_LINE;
        ctx.strokeRect(cellX, cellY, CELL_SIZE, CELL_SIZE);
      }
    }
    
    // アリの描画
    const antX = ant.x * CELL_SIZE;
    const antY = ant.y * CELL_SIZE;
    
    ctx.fillStyle = COLORS.ANT;
    ctx.fillRect(antX, antY, CELL_SIZE, CELL_SIZE);
    
    // アリの向きを表す三角形を描画
    ctx.beginPath();
    ctx.fillStyle = COLORS.WHITE;
    
    switch (ant.direction) {
      case Direction.UP:
        ctx.moveTo(antX + CELL_SIZE / 2, antY);
        ctx.lineTo(antX + CELL_SIZE, antY + CELL_SIZE);
        ctx.lineTo(antX, antY + CELL_SIZE);
        break;
      case Direction.RIGHT:
        ctx.moveTo(antX + CELL_SIZE, antY + CELL_SIZE / 2);
        ctx.lineTo(antX, antY + CELL_SIZE);
        ctx.lineTo(antX, antY);
        break;
      case Direction.DOWN:
        ctx.moveTo(antX + CELL_SIZE / 2, antY + CELL_SIZE);
        ctx.lineTo(antX, antY);
        ctx.lineTo(antX + CELL_SIZE, antY);
        break;
      case Direction.LEFT:
        ctx.moveTo(antX, antY + CELL_SIZE / 2);
        ctx.lineTo(antX + CELL_SIZE, antY);
        ctx.lineTo(antX + CELL_SIZE, antY + CELL_SIZE);
        break;
    }
    
    ctx.closePath();
    ctx.fill();
  };
  
  // アニメーションループ
  const animate = () => {
    if (steps >= MAX_STEPS) {
      setIsRunning(false);
      return;
    }
    
    moveAnt();
    draw();
    
    requestRef.current = setTimeout(() => {
      if (isRunning) {
        requestAnimationFrame(animate);
      }
    }, speed);
  };
  
  // アニメーションの開始/停止
  const toggleSimulation = () => {
    setIsRunning(!isRunning);
  };
  
  // リセット
  const resetSimulation = () => {
    setIsRunning(false);
    setSteps(0);
    setGrid(Array(GRID_SIZE).fill(null).map(() => Array(GRID_SIZE).fill(0)));
    setAnt({
      x: Math.floor(GRID_SIZE / 2),
      y: Math.floor(GRID_SIZE / 2),
      direction: Direction.UP
    });
    
    // キャンバスの再描画
    if (canvasRef.current) {
      const ctx = canvasRef.current.getContext('2d');
      ctx.clearRect(0, 0, GRID_SIZE * CELL_SIZE, GRID_SIZE * CELL_SIZE);
      draw();
    }
  };
  
  // ステップ実行
  const stepSimulation = () => {
    if (steps < MAX_STEPS) {
      moveAnt();
      draw();
    }
  };
  
  // 速度変更
  const handleSpeedChange = (e) => {
    setSpeed(parseInt(e.target.value));
  };
  
  // 初期化時の描画
  useEffect(() => {
    draw();
  }, []);
  
  // アニメーションの管理
  useEffect(() => {
    if (isRunning) {
      requestAnimationFrame(animate);
    }
    
    return () => {
      if (requestRef.current) {
        clearTimeout(requestRef.current);
      }
    };
  }, [isRunning, speed]);
  
  // 描画の更新
  useEffect(() => {
    draw();
  }, [grid, ant]);
  
  return (
    <div className="flex flex-col items-center p-4 bg-gray-100 rounded-lg">
      <h1 className="text-2xl font-bold mb-4 text-gray-800">ラングトンのアリ シミュレーション</h1>
      
      <div className="mb-4">
        <canvas
          ref={canvasRef}
          width={GRID_SIZE * CELL_SIZE}
          height={GRID_SIZE * CELL_SIZE}
          className="border border-gray-300 bg-white"
        />
      </div>
      
      <div className="flex items-center justify-center space-x-2 mb-4">
        <button
          onClick={toggleSimulation}
          className={`px-4 py-2 rounded-md ${isRunning ? 'bg-red-500 hover:bg-red-600' : 'bg-green-500 hover:bg-green-600'} text-white font-medium`}
        >
          {isRunning ? '停止' : '開始'}
        </button>
        
        <button
          onClick={stepSimulation}
          className="px-4 py-2 rounded-md bg-blue-500 hover:bg-blue-600 text-white font-medium"
          disabled={isRunning}
        >
          ステップ実行
        </button>
        
        <button
          onClick={resetSimulation}
          className="px-4 py-2 rounded-md bg-gray-500 hover:bg-gray-600 text-white font-medium"
        >
          リセット
        </button>
      </div>
      
      <div className="flex items-center justify-center space-x-2 mb-4">
        <label htmlFor="speed" className="text-gray-700">速度:</label>
        <input
          id="speed"
          type="range"
          min="1"
          max="100"
          value={speed}
          onChange={handleSpeedChange}
          className="w-32"
        />
        <span className="text-gray-700">{speed}ms</span>
      </div>
      
      <div className="flex items-center justify-center space-x-4">
        <p className="text-gray-700">ステップ数: <strong>{steps}</strong></p>
        <p className="text-gray-700">位置: <strong>({ant.x}, {ant.y})</strong></p>
      </div>
      
      <div className="mt-4 p-4 bg-white rounded-md shadow-md">
        <h2 className="text-lg font-semibold mb-2 text-gray-800">ラングトンのアリのルール:</h2>
        <ul className="list-disc pl-5 text-gray-700">
          <li>白いセルにアリがいる場合、右に90度回転し、セルを黒に変え、前進する</li>
          <li>黒いセルにアリがいる場合、左に90度回転し、セルを白に変え、前進する</li>
        </ul>
      </div>
    </div>
  );
};

export default LangtonAnt;

コメントを残す

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