Claude 3.7 Sonnetのコーディング能力を試す 8
以前の投稿でClaude 3.7 Sonnetのコーディング能力を試した.
今回は引き続きReactを使ってコードを書いてもらいLife gameのシミュレーションを行ってみた.
すると,動的に遊べるシミュレーションを出してくれた.
ライフゲームのシミュレーションを行うコードを書いて.
Reactで動的に処理できるようにして.
エラーが出ないように自己点検して.
import { useState, useEffect, useCallback } from 'react';
export default function GameOfLife() {
const [gridSize, setGridSize] = useState({ rows: 20, cols: 20 });
const [grid, setGrid] = useState([]);
const [running, setRunning] = useState(false);
const [speed, setSpeed] = useState(300); // ミリ秒単位
// グリッドを初期化
const initializeGrid = useCallback(() => {
const rows = [];
for (let i = 0; i < gridSize.rows; i++) {
rows.push(Array.from(Array(gridSize.cols), () => 0));
}
setGrid(rows);
}, [gridSize]);
// ランダムな初期状態を生成
const randomizeGrid = () => {
const rows = [];
for (let i = 0; i < gridSize.rows; i++) {
rows.push(Array.from(Array(gridSize.cols), () => Math.random() > 0.7 ? 1 : 0));
}
setGrid(rows);
};
// セルの状態を切り替える
const toggleCell = (i, j) => {
const newGrid = JSON.parse(JSON.stringify(grid));
newGrid[i][j] = grid[i][j] ? 0 : 1;
setGrid(newGrid);
};
// 次の世代を計算
const computeNextGeneration = useCallback(() => {
const rows = gridSize.rows;
const cols = gridSize.cols;
const currentGrid = grid;
const newGrid = JSON.parse(JSON.stringify(currentGrid));
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
let neighbors = 0;
// 周囲8マスのセルをチェック
for (let ni = -1; ni <= 1; ni++) {
for (let nj = -1; nj <= 1; nj++) {
if (ni === 0 && nj === 0) continue; // 自分自身はスキップ
const newI = (i + ni + rows) % rows; // 画面端の処理(トーラス状にする)
const newJ = (j + nj + cols) % cols;
neighbors += currentGrid[newI][newJ];
}
}
// ライフゲームのルールを適用
if (currentGrid[i][j] === 1 && (neighbors < 2 || neighbors > 3)) {
newGrid[i][j] = 0; // 過疎または過密で死亡
} else if (currentGrid[i][j] === 0 && neighbors === 3) {
newGrid[i][j] = 1; // 誕生
}
}
}
setGrid(newGrid);
}, [grid, gridSize]);
// コンポーネントマウント時に初期化
useEffect(() => {
initializeGrid();
}, [initializeGrid]);
// アニメーションのためのループ処理
useEffect(() => {
let intervalId;
if (running) {
intervalId = setInterval(() => {
computeNextGeneration();
}, speed);
}
return () => {
if (intervalId) {
clearInterval(intervalId);
}
};
}, [running, computeNextGeneration, speed]);
// グリッドサイズ変更ハンドラー
const handleSizeChange = (e) => {
const { name, value } = e.target;
// 入力値を数値に変換し、最小値を5、最大値を50に設定
const newValue = Math.min(Math.max(parseInt(value) || 5, 5), 50);
setGridSize(prev => ({ ...prev, [name]: newValue }));
};
// サイズ変更時にグリッドを再初期化
useEffect(() => {
initializeGrid();
}, [gridSize, initializeGrid]);
return (
<div className="flex flex-col items-center p-4 bg-gray-100 min-h-screen">
<h1 className="text-2xl font-bold mb-4">Conway's Game of Life</h1>
<div className="flex flex-wrap justify-center gap-4 mb-4">
<button
className={`px-4 py-2 rounded ${running ? 'bg-red-500 text-white' : 'bg-green-500 text-white'}`}
onClick={() => setRunning(!running)}
>
{running ? '停止' : '開始'}
</button>
<button
className="px-4 py-2 bg-blue-500 text-white rounded"
onClick={randomizeGrid}
disabled={running}
>
ランダム生成
</button>
<button
className="px-4 py-2 bg-gray-500 text-white rounded"
onClick={initializeGrid}
disabled={running}
>
クリア
</button>
</div>
<div className="flex flex-wrap justify-center gap-4 mb-4">
<div className="flex items-center">
<label htmlFor="rows" className="mr-2">行数:</label>
<input
type="number"
id="rows"
name="rows"
value={gridSize.rows}
onChange={handleSizeChange}
min="5"
max="50"
className="w-16 p-1 border rounded"
disabled={running}
/>
</div>
<div className="flex items-center">
<label htmlFor="cols" className="mr-2">列数:</label>
<input
type="number"
id="cols"
name="cols"
value={gridSize.cols}
onChange={handleSizeChange}
min="5"
max="50"
className="w-16 p-1 border rounded"
disabled={running}
/>
</div>
<div className="flex items-center">
<label htmlFor="speed" className="mr-2">速度:</label>
<input
type="range"
id="speed"
min="50"
max="1000"
step="50"
value={speed}
onChange={(e) => setSpeed(parseInt(e.target.value))}
className="w-32"
/>
<span className="ml-2">{speed}ms</span>
</div>
</div>
<div className="border border-gray-300 bg-white p-1 inline-block">
{grid.map((row, i) => (
<div key={i} className="flex">
{row.map((cell, j) => (
<div
key={`${i}-${j}`}
onClick={() => !running && toggleCell(i, j)}
className={`w-4 h-4 border border-gray-200 ${
cell ? 'bg-black' : 'bg-white'
} ${!running ? 'cursor-pointer hover:bg-gray-300' : ''}`}
/>
))}
</div>
))}
</div>
<div className="mt-4 text-sm text-gray-600">
<p>使い方: セルをクリックして初期状態を設定し、「開始」ボタンを押してシミュレーションを開始します。</p>
<p>ルール: 周囲に生きたセルが2つか3つあれば生存、3つあれば誕生、それ以外は死亡。</p>
</div>
</div>
);
}
