Claude 3.7 Sonnetのコーディング能力を試す 9
以前の投稿でClaude 3.7 Sonnetのコーディング能力を試した.
今回は引き続きReactを使ってコードを書いてもらいEden成長モデルのシミュレーションを行ってみた.
すると,今回も完璧なシミュレーションを出してくれた.有名なシミュレーションは一通り動きそうだ.
境界面の成長モデルであるEdenモデルのシミュレーションを行うコードを書いて.
Reactで動的に処理できるようにして.
エラーが出ないように自己点検して.
import { useState, useEffect, useRef } from 'react';
export default function EdenModelSimulation() {
const [gridSize, setGridSize] = useState({ width: 100, height: 100 });
const [cellSize, setCellSize] = useState(5);
const [speed, setSpeed] = useState(10);
const [isRunning, setIsRunning] = useState(false);
const [resetTrigger, setResetTrigger] = useState(0);
const canvasRef = useRef(null);
const simulationRef = useRef(null);
const gridRef = useRef(null);
// グリッドの初期化
useEffect(() => {
// 初期状態を設定
const grid = Array(gridSize.height).fill().map(() => Array(gridSize.width).fill(0));
// 最下行を埋める(種となる部分)
for (let x = 0; x < gridSize.width; x++) {
grid[gridSize.height - 1][x] = 1;
}
gridRef.current = grid;
// キャンバスに描画
drawGrid();
}, [gridSize, resetTrigger]);
// キャンバスへの描画
const drawGrid = () => {
const canvas = canvasRef.current;
if (!canvas) return;
const ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (!gridRef.current) return;
for (let y = 0; y < gridSize.height; y++) {
for (let x = 0; x < gridSize.width; x++) {
if (gridRef.current[y][x] === 1) {
ctx.fillStyle = '#2563eb'; // 青色で塗りつぶし
ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
}
}
}
};
// 成長プロセスの更新
const updateEdenModel = () => {
const grid = gridRef.current;
if (!grid) return false;
// 成長可能部分(既存の粒子に隣接する空セル)を見つける
const growthSites = [];
for (let y = 0; y < gridSize.height; y++) {
for (let x = 0; x < gridSize.width; x++) {
if (grid[y][x] === 0 && hasOccupiedNeighbor(grid, x, y)) {
growthSites.push({ x, y });
}
}
}
// 成長可能部分がなければシミュレーション終了
if (growthSites.length === 0) {
return false;
}
// ランダムに1つ選んで成長させる
const randomSite = growthSites[Math.floor(Math.random() * growthSites.length)];
grid[randomSite.y][randomSite.x] = 1;
return true;
};
// 隣接するセルが占有されているかチェック
const hasOccupiedNeighbor = (grid, x, y) => {
const directions = [
{ dx: -1, dy: 0 }, // 左
{ dx: 1, dy: 0 }, // 右
{ dx: 0, dy: -1 }, // 上
{ dx: 0, dy: 1 } // 下
];
for (const dir of directions) {
const nx = x + dir.dx;
const ny = y + dir.dy;
if (nx >= 0 && nx < gridSize.width && ny >= 0 && ny < gridSize.height) {
if (grid[ny][nx] === 1) {
return true;
}
}
}
return false;
};
// シミュレーションのステップ実行
const runSimulationStep = () => {
const canContinue = updateEdenModel();
drawGrid();
return canContinue;
};
// シミュレーションの開始/停止
useEffect(() => {
if (isRunning) {
simulationRef.current = setInterval(() => {
const canContinue = runSimulationStep();
if (!canContinue) {
setIsRunning(false);
}
}, 1000 / speed);
} else {
clearInterval(simulationRef.current);
}
return () => {
clearInterval(simulationRef.current);
};
}, [isRunning, speed]);
// リセットボタンの処理
const handleReset = () => {
setIsRunning(false);
setResetTrigger(prev => prev + 1);
};
// マニュアルステップ実行の処理
const handleStep = () => {
if (!isRunning) {
runSimulationStep();
}
};
return (
<div className="flex flex-col items-center p-4 bg-gray-100 rounded-lg">
<h1 className="text-2xl font-bold mb-4">Edenモデルシミュレーション</h1>
<div className="mb-4 p-2 border border-gray-300 bg-white rounded">
<canvas
ref={canvasRef}
width={gridSize.width * cellSize}
height={gridSize.height * cellSize}
className="border border-gray-400"
/>
</div>
<div className="flex flex-wrap gap-4 mb-4">
<div className="flex flex-col">
<label className="text-sm font-medium mb-1">速度</label>
<input
type="range"
min="1"
max="100"
value={speed}
onChange={(e) => setSpeed(parseInt(e.target.value))}
className="w-32"
/>
<span className="text-xs mt-1">{speed} ステップ/秒</span>
</div>
<div className="flex flex-col">
<label className="text-sm font-medium mb-1">セルサイズ</label>
<select
value={cellSize}
onChange={(e) => setCellSize(parseInt(e.target.value))}
className="border border-gray-300 rounded p-1"
>
<option value="2">小 (2px)</option>
<option value="5">中 (5px)</option>
<option value="10">大 (10px)</option>
</select>
</div>
<div className="flex flex-col">
<label className="text-sm font-medium mb-1">グリッドサイズ</label>
<select
value={`${gridSize.width}x${gridSize.height}`}
onChange={(e) => {
const [width, height] = e.target.value.split('x').map(Number);
setGridSize({ width, height });
}}
className="border border-gray-300 rounded p-1"
>
<option value="50x50">小 (50x50)</option>
<option value="100x100">中 (100x100)</option>
<option value="200x100">大 (200x100)</option>
</select>
</div>
</div>
<div className="flex gap-2">
<button
onClick={() => setIsRunning(!isRunning)}
className={`px-4 py-2 rounded font-medium ${isRunning ? 'bg-red-500 text-white' : 'bg-green-500 text-white'}`}
>
{isRunning ? '停止' : '開始'}
</button>
<button
onClick={handleStep}
disabled={isRunning}
className={`px-4 py-2 rounded font-medium ${isRunning ? 'bg-gray-300 cursor-not-allowed' : 'bg-blue-500 text-white'}`}
>
1ステップ
</button>
<button
onClick={handleReset}
className="px-4 py-2 bg-gray-500 text-white rounded font-medium"
>
リセット
</button>
</div>
<div className="mt-4 text-sm text-gray-600">
<p>Edenモデル: ランダムな選択による境界面成長のシミュレーション</p>
<p>青色のセルは既に成長した部分を示します</p>
</div>
</div>
);
}
