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


Claude 4 が話題を呼んでいる.今回はClaude 3.7との比較で交通渋滞のシミュレーションを行ってみた.

すると,こちらも3.7の頃よりリッチなシミュレーターを作成してくれた.同じプロンプトでも差が出てくれているのはありがたい.

MASの発想で交通渋滞が起こる様子のシミュレーションを行うコードを書いて.
Reactで動的に処理できるようにして.
エラーが出ないように自己点検して.
import React, { useState, useEffect, useRef } from 'react';
import { Play, Pause, RotateCcw, Settings } from 'lucide-react';

const TrafficSimulation = () => {
  const canvasRef = useRef(null);
  const animationRef = useRef(null);
  
  // シミュレーション設定
  const [isRunning, setIsRunning] = useState(false);
  const [showSettings, setShowSettings] = useState(false);
  const [settings, setSettings] = useState({
    numCars: 30,
    roadLength: 800,
    maxSpeed: 5,
    safeDistance: 40,
    reactionTime: 0.1,
    acceleration: 0.2,
    deceleration: 0.5
  });

  // 車両クラス
  class Car {
    constructor(id, x, lane) {
      this.id = id;
      this.x = x;
      this.y = lane * 60 + 100; // レーン位置
      this.speed = Math.random() * settings.maxSpeed * 0.5 + settings.maxSpeed * 0.5;
      this.maxSpeed = settings.maxSpeed;
      this.safeDistance = settings.safeDistance;
      this.acceleration = settings.acceleration;
      this.deceleration = settings.deceleration;
      this.reactionTime = settings.reactionTime;
      this.color = `hsl(${Math.random() * 360}, 70%, 50%)`;
      this.width = 30;
      this.height = 15;
      this.lane = lane;
    }

    update(cars, roadLength) {
      // 前方車両を検出
      const frontCar = this.findFrontCar(cars);
      
      if (frontCar) {
        const distance = this.calculateDistance(frontCar);
        
        if (distance < this.safeDistance) {
          // 減速
          this.speed = Math.max(0, this.speed - this.deceleration);
          
          // 極端に近い場合は前車の速度に合わせる
          if (distance < this.safeDistance * 0.5) {
            this.speed = Math.min(this.speed, frontCar.speed);
          }
        } else if (distance > this.safeDistance * 1.5) {
          // 加速
          this.speed = Math.min(this.maxSpeed, this.speed + this.acceleration);
        }
      } else {
        // 前方に車両がない場合は最高速度まで加速
        this.speed = Math.min(this.maxSpeed, this.speed + this.acceleration);
      }

      // 位置更新
      this.x += this.speed;
      
      // 道路の端に到達したら反対側から再出現
      if (this.x > roadLength) {
        this.x = -this.width;
        // ランダムに速度をリセット
        this.speed = Math.random() * this.maxSpeed * 0.5 + this.maxSpeed * 0.5;
      }
    }

    findFrontCar(cars) {
      let closestCar = null;
      let minDistance = Infinity;

      for (const car of cars) {
        if (car.id !== this.id && car.lane === this.lane) {
          let distance;
          
          if (car.x > this.x) {
            // 同じループ内の前方車両
            distance = car.x - this.x;
          } else {
            // 道路を一周した前方車両
            distance = (settings.roadLength - this.x) + car.x;
          }

          if (distance < minDistance && distance > 0) {
            minDistance = distance;
            closestCar = car;
          }
        }
      }

      return closestCar;
    }

    calculateDistance(frontCar) {
      if (frontCar.x > this.x) {
        return frontCar.x - this.x - this.width;
      } else {
        return (settings.roadLength - this.x) + frontCar.x - this.width;
      }
    }

    draw(ctx) {
      ctx.save();
      
      // 車両の描画
      ctx.fillStyle = this.color;
      ctx.fillRect(this.x, this.y, this.width, this.height);
      
      // 速度に応じた色の強度
      const speedRatio = this.speed / this.maxSpeed;
      ctx.fillStyle = `rgba(255, ${255 * speedRatio}, 0, 0.7)`;
      ctx.fillRect(this.x, this.y - 5, this.width * speedRatio, 3);
      
      ctx.restore();
    }
  }

  // 車両の状態管理
  const [cars, setCars] = useState([]);

  // 車両初期化
  const initializeCars = () => {
    const newCars = [];
    const lanesCount = 3;
    
    for (let i = 0; i < settings.numCars; i++) {
      const lane = i % lanesCount;
      const x = (i * (settings.roadLength / settings.numCars)) % settings.roadLength;
      newCars.push(new Car(i, x, lane));
    }
    
    setCars(newCars);
  };

  // シミュレーション更新
  const updateSimulation = () => {
    setCars(prevCars => {
      const updatedCars = prevCars.map(car => {
        const newCar = Object.assign(Object.create(Object.getPrototypeOf(car)), car);
        newCar.update(prevCars, settings.roadLength);
        return newCar;
      });
      return updatedCars;
    });
  };

  // 描画
  const draw = () => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    
    // 道路の描画
    ctx.fillStyle = '#333';
    ctx.fillRect(0, 80, settings.roadLength, 200);
    
    // レーン区切り線
    ctx.strokeStyle = '#fff';
    ctx.setLineDash([10, 10]);
    ctx.lineWidth = 2;
    
    for (let i = 1; i < 3; i++) {
      ctx.beginPath();
      ctx.moveTo(0, 80 + i * 60);
      ctx.lineTo(settings.roadLength, 80 + i * 60);
      ctx.stroke();
    }
    
    ctx.setLineDash([]);
    
    // 車両の描画
    cars.forEach(car => {
      if (car.draw) {
        car.draw(ctx);
      }
    });
  };

  // アニメーションループ
  const animate = () => {
    if (isRunning) {
      updateSimulation();
      draw();
      animationRef.current = requestAnimationFrame(animate);
    }
  };

  // エフェクト
  useEffect(() => {
    initializeCars();
  }, [settings.numCars, settings.roadLength]);

  useEffect(() => {
    if (isRunning) {
      animate();
    } else {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    }
    
    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, [isRunning, cars]);

  useEffect(() => {
    draw();
  }, [cars]);

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

  const resetSimulation = () => {
    setIsRunning(false);
    initializeCars();
  };

  const updateSettings = (key, value) => {
    setSettings(prev => ({
      ...prev,
      [key]: parseFloat(value) || 0
    }));
  };

  // 統計計算
  const avgSpeed = cars.length > 0 ? 
    (cars.reduce((sum, car) => sum + car.speed, 0) / cars.length).toFixed(2) : 0;
  
  const slowCars = cars.filter(car => car.speed < settings.maxSpeed * 0.3).length;

  return (
    <div className="w-full max-w-6xl mx-auto p-4 bg-gray-100 rounded-lg">
      <div className="mb-4">
        <h2 className="text-2xl font-bold text-center mb-4">交通渋滞 MASシミュレーション</h2>
        
        {/* コントロールパネル */}
        <div className="flex justify-center items-center gap-4 mb-4">
          <button
            onClick={toggleSimulation}
            className="flex items-center gap-2 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
          >
            {isRunning ? <Pause size={20} /> : <Play size={20} />}
            {isRunning ? '停止' : '開始'}
          </button>
          
          <button
            onClick={resetSimulation}
            className="flex items-center gap-2 px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600"
          >
            <RotateCcw size={20} />
            リセット
          </button>
          
          <button
            onClick={() => setShowSettings(!showSettings)}
            className="flex items-center gap-2 px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
          >
            <Settings size={20} />
            設定
          </button>
        </div>

        {/* 統計情報 */}
        <div className="flex justify-center gap-8 mb-4 text-sm">
          <div className="text-center">
            <div className="font-semibold">平均速度</div>
            <div className="text-blue-600">{avgSpeed}</div>
          </div>
          <div className="text-center">
            <div className="font-semibold">低速車両</div>
            <div className="text-red-600">{slowCars}台</div>
          </div>
          <div className="text-center">
            <div className="font-semibold">総車両数</div>
            <div className="text-green-600">{cars.length}台</div>
          </div>
        </div>

        {/* 設定パネル */}
        {showSettings && (
          <div className="bg-white p-4 rounded border mb-4">
            <h3 className="font-bold mb-3">シミュレーション設定</h3>
            <div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
              <div>
                <label className="block font-medium mb-1">車両数</label>
                <input
                  type="range"
                  min="10"
                  max="50"
                  value={settings.numCars}
                  onChange={(e) => updateSettings('numCars', e.target.value)}
                  className="w-full"
                />
                <div className="text-center">{settings.numCars}</div>
              </div>
              
              <div>
                <label className="block font-medium mb-1">最高速度</label>
                <input
                  type="range"
                  min="2"
                  max="10"
                  step="0.5"
                  value={settings.maxSpeed}
                  onChange={(e) => updateSettings('maxSpeed', e.target.value)}
                  className="w-full"
                />
                <div className="text-center">{settings.maxSpeed}</div>
              </div>
              
              <div>
                <label className="block font-medium mb-1">安全距離</label>
                <input
                  type="range"
                  min="20"
                  max="80"
                  value={settings.safeDistance}
                  onChange={(e) => updateSettings('safeDistance', e.target.value)}
                  className="w-full"
                />
                <div className="text-center">{settings.safeDistance}</div>
              </div>
              
              <div>
                <label className="block font-medium mb-1">加速度</label>
                <input
                  type="range"
                  min="0.1"
                  max="0.5"
                  step="0.1"
                  value={settings.acceleration}
                  onChange={(e) => updateSettings('acceleration', e.target.value)}
                  className="w-full"
                />
                <div className="text-center">{settings.acceleration}</div>
              </div>
            </div>
          </div>
        )}
      </div>

      {/* シミュレーション画面 */}
      <div className="bg-white p-4 rounded border">
        <canvas
          ref={canvasRef}
          width={settings.roadLength}
          height={300}
          className="w-full border border-gray-300 rounded"
          style={{ maxWidth: '100%', height: 'auto' }}
        />
      </div>
      
      {/* 説明 */}
      <div className="mt-4 text-sm text-gray-600">
        <p><strong>説明:</strong> 各車両は独立したエージェントとして動作し、前方車両との距離に基づいて速度を調整します。</p>
        <p>オレンジのバーは各車両の現在速度を表示しています。設定を変更して渋滞の発生パターンを観察できます。</p>
      </div>
    </div>
  );
};

export default TrafficSimulation;

コメントを残す

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