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;
