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


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

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

すると今回は描画も挙動も素晴らしいものを出してくれた.

MASの発想で交通渋滞が起こる様子のシミュレーションを行うコードを書いて.
    Reactで動的に処理できるようにして.

    エラーが出ないように自己点検して.
import { useState, useEffect, useRef } from 'react';

// 車両エージェントの定義
class Vehicle {
  constructor(id, x, lane, speed, maxSpeed, length) {
    this.id = id;
    this.x = x;            // 道路上の位置
    this.lane = lane;      // 車線
    this.speed = speed;    // 現在の速度
    this.maxSpeed = maxSpeed;  // 最高速度
    this.length = length;  // 車両の長さ
    this.color = this.getRandomColor();
    this.braking = false;  // ブレーキ状態
  }

  // ランダムな車両カラーを生成
  getRandomColor() {
    const colors = ['#e74c3c', '#3498db', '#2ecc71', '#f1c40f', '#9b59b6', '#1abc9c', '#34495e', '#e67e22'];
    return colors[Math.floor(Math.random() * colors.length)];
  }

  // 前方の車両との距離を計算して速度を調整
  update(vehicles, roadLength) {
    // 安全距離 (車両の長さの2倍 + 速度に応じた距離)
    const safeDistance = this.length * 2 + this.speed * 2;
    
    // 同じ車線の前方車両を探す
    let nearestFrontVehicle = null;
    let minDistance = roadLength;
    
    for (const vehicle of vehicles) {
      if (vehicle.id === this.id || vehicle.lane !== this.lane) continue;
      
      // 前方の車両かどうか判定(円環状の道路を考慮)
      let distance = vehicle.x - this.x;
      if (distance < 0) distance += roadLength;
      
      if (distance > 0 && distance < minDistance) {
        minDistance = distance;
        nearestFrontVehicle = vehicle;
      }
    }
    
    // 前方に車がいる場合
    if (nearestFrontVehicle && minDistance < safeDistance) {
      // 前方車両との距離に応じて減速
      this.speed = Math.max(0, this.speed - 0.5);
      this.braking = true;
    } else {
      // 安全距離が確保されている場合、徐々に加速
      this.speed = Math.min(this.maxSpeed, this.speed + 0.1);
      this.braking = false;
    }
    
    // 位置の更新(円環状道路)
    this.x = (this.x + this.speed) % roadLength;
  }
}

export default function TrafficSimulation() {
  const [vehicles, setVehicles] = useState([]);
  const [isRunning, setIsRunning] = useState(false);
  const [vehicleCount, setVehicleCount] = useState(20);
  const [roadLength, setRoadLength] = useState(1000);
  const [density, setDensity] = useState(20); // 車両密度 (%)
  const [speedVariation, setSpeedVariation] = useState(true); // 速度のばらつき
  const animationRef = useRef(null);
  const canvasRef = useRef(null);
  
  // シミュレーション初期化
  const initializeSimulation = () => {
    const newVehicles = [];
    const segmentLength = roadLength / vehicleCount;
    
    // 車両の生成
    for (let i = 0; i < vehicleCount; i++) {
      // 密度パラメータに基づいて車両を配置するかどうかを決定
      if (Math.random() * 100 > density) continue;
      
      // 基本速度 + ばらつき (speedVariationがtrueの場合)
      const baseSpeed = 2;
      const speedVar = speedVariation ? Math.random() * 2 - 0.5 : 0;
      const maxSpeed = baseSpeed + speedVar;
      
      // 車両を生成(位置を少しランダムに散らす)
      const position = i * segmentLength + Math.random() * (segmentLength * 0.5);
      const lane = Math.floor(Math.random() * 2); // 2車線
      
      newVehicles.push(new Vehicle(
        i,
        position % roadLength,
        lane,
        maxSpeed * 0.5, // 初期速度は最高速度の半分
        maxSpeed,
        20 // 車両の長さ
      ));
    }
    
    setVehicles(newVehicles);
  };

  // シミュレーションの更新
  const updateSimulation = () => {
    setVehicles(prevVehicles => {
      const updatedVehicles = [...prevVehicles];
      
      // すべての車両を更新
      for (let vehicle of updatedVehicles) {
        vehicle.update(updatedVehicles, roadLength);
      }
      
      return updatedVehicles;
    });
    
    // キャンバスの描画
    renderCanvas();
    
    // アニメーションフレームを要求
    if (isRunning) {
      animationRef.current = requestAnimationFrame(updateSimulation);
    }
  };

  // キャンバスへの描画
  const renderCanvas = () => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    
    const ctx = canvas.getContext('2d');
    const canvasWidth = canvas.width;
    const canvasHeight = canvas.height;
    
    // キャンバスをクリア
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    
    // 道路を描画
    ctx.fillStyle = '#555';
    ctx.fillRect(0, 0, canvasWidth, canvasHeight);
    
    // 車線区分線を描画
    ctx.strokeStyle = '#fff';
    ctx.setLineDash([20, 20]);
    ctx.beginPath();
    ctx.moveTo(0, canvasHeight / 2);
    ctx.lineTo(canvasWidth, canvasHeight / 2);
    ctx.stroke();
    ctx.setLineDash([]);
    
    // 道路の外枠を描画
    ctx.strokeStyle = '#fff';
    ctx.lineWidth = 3;
    ctx.strokeRect(0, 0, canvasWidth, canvasHeight);
    
    // 車両を描画
    for (const vehicle of vehicles) {
      // 道路上の位置をキャンバス座標に変換
      const x = (vehicle.x / roadLength) * canvasWidth;
      const laneHeight = canvasHeight / 2;
      const y = vehicle.lane * laneHeight + laneHeight / 2;
      
      // 車両の描画
      ctx.fillStyle = vehicle.color;
      ctx.beginPath();
      const vehicleWidth = 30;
      const vehicleHeight = 15;
      ctx.rect(x - vehicleWidth/2, y - vehicleHeight/2, vehicleWidth, vehicleHeight);
      ctx.fill();
      
      // ブレーキランプを描画
      if (vehicle.braking) {
        ctx.fillStyle = '#ff0000';
        ctx.beginPath();
        ctx.rect(x - vehicleWidth/2, y - vehicleHeight/2 + vehicleHeight - 3, vehicleWidth, 3);
        ctx.fill();
      }
    }
  };

  // シミュレーション開始/停止
  const toggleSimulation = () => {
    setIsRunning(prev => !prev);
  };

  // パラメータ変更時の再初期化
  useEffect(() => {
    if (isRunning) {
      setIsRunning(false);
      cancelAnimationFrame(animationRef.current);
    }
    initializeSimulation();
  }, [vehicleCount, roadLength, density, speedVariation]);

  // シミュレーション実行状態の管理
  useEffect(() => {
    if (isRunning) {
      animationRef.current = requestAnimationFrame(updateSimulation);
    } else if (animationRef.current) {
      cancelAnimationFrame(animationRef.current);
    }
    
    return () => {
      if (animationRef.current) {
        cancelAnimationFrame(animationRef.current);
      }
    };
  }, [isRunning]);

  // 初期化
  useEffect(() => {
    initializeSimulation();
    
    // キャンバスのサイズ設定
    const canvas = canvasRef.current;
    if (canvas) {
      canvas.width = 800;
      canvas.height = 200;
      renderCanvas();
    }
  }, []);

  return (
    <div className="flex flex-col items-center w-full max-w-4xl mx-auto p-4 bg-gray-100 rounded-lg">
      <h1 className="text-2xl font-bold mb-4">交通渋滞MASシミュレーション</h1>
      
      <div className="w-full mb-4 bg-white p-4 rounded shadow">
        <canvas ref={canvasRef} className="w-full h-auto border border-gray-300"></canvas>
      </div>
      
      <div className="w-full grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
        <div className="flex flex-col">
          <label className="mb-1 font-medium">車両数: {vehicleCount}</label>
          <input
            type="range"
            min="5"
            max="50"
            value={vehicleCount}
            onChange={(e) => setVehicleCount(parseInt(e.target.value))}
            className="w-full"
          />
        </div>
        
        <div className="flex flex-col">
          <label className="mb-1 font-medium">車両密度: {density}%</label>
          <input
            type="range"
            min="10"
            max="100"
            value={density}
            onChange={(e) => setDensity(parseInt(e.target.value))}
            className="w-full"
          />
        </div>
      </div>
      
      <div className="w-full flex flex-col md:flex-row justify-between mb-4">
        <div className="flex items-center mb-2 md:mb-0">
          <input
            type="checkbox"
            id="speedVariation"
            checked={speedVariation}
            onChange={() => setSpeedVariation(!speedVariation)}
            className="mr-2"
          />
          <label htmlFor="speedVariation" className="font-medium">速度のばらつき</label>
        </div>
        
        <div className="flex space-x-4">
          <button
            onClick={toggleSimulation}
            className={`px-4 py-2 rounded font-medium ${isRunning ? 'bg-red-500 text-white' : 'bg-green-500 text-white'}`}
          >
            {isRunning ? '停止' : '開始'}
          </button>
          
          <button
            onClick={initializeSimulation}
            className="px-4 py-2 bg-blue-500 text-white rounded font-medium"
            disabled={isRunning}
          >
            リセット
          </button>
        </div>
      </div>
      
      <div className="w-full bg-white p-4 rounded shadow">
        <h2 className="text-lg font-semibold mb-2">シミュレーション説明</h2>
        <p className="mb-2">
          このシミュレーションは、マルチエージェントシステム(MAS)の概念に基づく交通流シミュレーションです。
          各車両はエージェントとして独立して行動し、周囲の状況に応じて速度を調整します。
        </p>
        <p className="mb-2">
          車両は前方の車両との安全距離を保とうとし、前方車両が近すぎる場合は減速します。
          このシンプルなルールから、実際の交通と同様の渋滞パターンが自然発生します。
        </p>
        <ul className="list-disc pl-5">
          <li className="mb-1">赤いライトは車両がブレーキをかけていることを示します</li>
          <li className="mb-1">密度を高くするほど渋滞が発生しやすくなります</li>
          <li className="mb-1">速度のばらつきをオンにすると、車両ごとに最高速度が異なり、より自然な交通流になります</li>
        </ul>
      </div>
    </div>
  );
}

コメントを残す

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