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


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

すると,これ以上改善点がないくらい素晴らしいものを作成してくれた.

Weasel Programのシミュレーションを行うコードを書いて. 
        Reactで動的に処理できるようにして. 
        エラーが出ないように自己点検して.
    一切の遠慮は不要です!!最高品質を追い求めて.
import React, { useState, useEffect, useCallback, useRef } from 'react';
import { Play, Pause, RotateCcw, Settings, TrendingUp } from 'lucide-react';

const WeaselProgramSimulator = () => {
  const [target, setTarget] = useState("METHINKS IT IS LIKE A WEASEL");
  const [populationSize, setPopulationSize] = useState(100);
  const [mutationRate, setMutationRate] = useState(0.05);
  const [currentGeneration, setCurrentGeneration] = useState(0);
  const [bestIndividual, setBestIndividual] = useState("");
  const [bestFitness, setBestFitness] = useState(0);
  const [fitnessHistory, setFitnessHistory] = useState([]);
  const [isRunning, setIsRunning] = useState(false);
  const [isComplete, setIsComplete] = useState(false);
  const [showSettings, setShowSettings] = useState(false);
  const [speed, setSpeed] = useState(100);
  const [population, setPopulation] = useState([]);
  
  const intervalRef = useRef(null);
  const CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ ";

  // 初期個体群の生成
  const generateRandomString = useCallback((length) => {
    return Array.from({ length }, () => 
      CHARACTERS[Math.floor(Math.random() * CHARACTERS.length)]
    ).join('');
  }, []);

  // フィットネス計算(正しい文字の数)
  const calculateFitness = useCallback((individual, target) => {
    let matches = 0;
    for (let i = 0; i < Math.min(individual.length, target.length); i++) {
      if (individual[i] === target[i]) matches++;
    }
    return matches;
  }, []);

  // 突然変異
  const mutate = useCallback((individual, mutationRate) => {
    return individual.split('').map(char => {
      if (Math.random() < mutationRate) {
        return CHARACTERS[Math.floor(Math.random() * CHARACTERS.length)];
      }
      return char;
    }).join('');
  }, []);

  // 初期化
  const initialize = useCallback(() => {
    const initialPop = Array.from({ length: populationSize }, () => 
      generateRandomString(target.length)
    );
    
    const populationWithFitness = initialPop.map(individual => ({
      string: individual,
      fitness: calculateFitness(individual, target)
    }));
    
    populationWithFitness.sort((a, b) => b.fitness - a.fitness);
    
    setPopulation(populationWithFitness);
    setBestIndividual(populationWithFitness[0].string);
    setBestFitness(populationWithFitness[0].fitness);
    setCurrentGeneration(0);
    setFitnessHistory([populationWithFitness[0].fitness]);
    setIsComplete(populationWithFitness[0].fitness === target.length);
  }, [target, populationSize, generateRandomString, calculateFitness]);

  // 一世代の進化
  const evolveOneGeneration = useCallback(() => {
    if (population.length === 0) return;

    // 親の選択(上位個体を選択)
    const parent = population[0].string;
    
    // 子個体群の生成
    const newPopulation = Array.from({ length: populationSize }, () => {
      const child = mutate(parent, mutationRate);
      return {
        string: child,
        fitness: calculateFitness(child, target)
      };
    });

    // 親も含める
    newPopulation.push({
      string: parent,
      fitness: population[0].fitness
    });

    // フィットネスでソート
    newPopulation.sort((a, b) => b.fitness - a.fitness);
    
    // 上位個体のみ保持
    const survivors = newPopulation.slice(0, populationSize);
    
    setPopulation(survivors);
    setBestIndividual(survivors[0].string);
    setBestFitness(survivors[0].fitness);
    setCurrentGeneration(prev => prev + 1);
    setFitnessHistory(prev => [...prev.slice(-99), survivors[0].fitness]);
    
    if (survivors[0].fitness === target.length) {
      setIsComplete(true);
      setIsRunning(false);
    }
  }, [population, populationSize, mutationRate, target, calculateFitness, mutate]);

  // 自動実行
  useEffect(() => {
    if (isRunning && !isComplete) {
      intervalRef.current = setInterval(evolveOneGeneration, 1000 / speed);
    } else {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
        intervalRef.current = null;
      }
    }

    return () => {
      if (intervalRef.current) {
        clearInterval(intervalRef.current);
      }
    };
  }, [isRunning, isComplete, evolveOneGeneration, speed]);

  // 初期化(マウント時とターゲット変更時)
  useEffect(() => {
    initialize();
  }, [initialize]);

  const handleStart = () => {
    if (isComplete) {
      initialize();
    }
    setIsRunning(true);
  };

  const handlePause = () => {
    setIsRunning(false);
  };

  const handleReset = () => {
    setIsRunning(false);
    initialize();
  };

  const handleStep = () => {
    if (!isComplete) {
      evolveOneGeneration();
    }
  };

  const fitnessPercentage = target.length > 0 ? (bestFitness / target.length) * 100 : 0;

  return (
    <div className="min-h-screen bg-gradient-to-br from-purple-900 via-blue-900 to-indigo-900 p-6">
      <div className="max-w-6xl mx-auto">
        <div className="text-center mb-8">
          <h1 className="text-4xl font-bold text-white mb-2">
            🧬 Weasel Program Evolution Simulator
          </h1>
          <p className="text-purple-200">
            Richard Dawkinsの進化シミュレーション - ランダムから目標文字列への進化
          </p>
        </div>

        <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
          {/* メインディスプレイ */}
          <div className="lg:col-span-2 space-y-6">
            {/* 現在の最良個体 */}
            <div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 border border-white/20">
              <h2 className="text-xl font-semibold text-white mb-4 flex items-center gap-2">
                <TrendingUp className="w-5 h-5" />
                最良個体(第{currentGeneration}世代)
              </h2>
              <div className="space-y-4">
                <div className="bg-black/30 rounded-lg p-4 font-mono text-lg">
                  <div className="text-gray-400 text-sm mb-2">目標:</div>
                  <div className="text-green-400 mb-3">{target}</div>
                  <div className="text-gray-400 text-sm mb-2">現在:</div>
                  <div className="text-white">
                    {bestIndividual.split('').map((char, i) => (
                      <span
                        key={i}
                        className={char === target[i] ? 'text-green-400 bg-green-400/20' : 'text-red-400'}
                      >
                        {char}
                      </span>
                    ))}
                  </div>
                </div>
                <div className="flex justify-between items-center">
                  <div className="text-white">
                    適合度: <span className="font-bold text-green-400">{bestFitness}</span>/{target.length}
                  </div>
                  <div className="text-white">
                    進捗: <span className="font-bold text-blue-400">{fitnessPercentage.toFixed(1)}%</span>
                  </div>
                </div>
                <div className="w-full bg-gray-700 rounded-full h-3">
                  <div
                    className="bg-gradient-to-r from-blue-500 to-green-500 h-3 rounded-full transition-all duration-300"
                    style={{ width: `${fitnessPercentage}%` }}
                  ></div>
                </div>
              </div>
            </div>

            {/* 制御パネル */}
            <div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 border border-white/20">
              <div className="flex flex-wrap gap-3 justify-center">
                <button
                  onClick={isRunning ? handlePause : handleStart}
                  disabled={isComplete && bestFitness === target.length}
                  className="flex items-center gap-2 bg-gradient-to-r from-green-500 to-blue-500 text-white px-6 py-3 rounded-xl font-semibold hover:from-green-600 hover:to-blue-600 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  {isRunning ? <Pause className="w-5 h-5" /> : <Play className="w-5 h-5" />}
                  {isRunning ? '一時停止' : isComplete ? '再開始' : '開始'}
                </button>
                <button
                  onClick={handleStep}
                  disabled={isRunning || isComplete}
                  className="flex items-center gap-2 bg-gradient-to-r from-purple-500 to-pink-500 text-white px-6 py-3 rounded-xl font-semibold hover:from-purple-600 hover:to-pink-600 transition-all disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  ステップ実行
                </button>
                <button
                  onClick={handleReset}
                  className="flex items-center gap-2 bg-gradient-to-r from-orange-500 to-red-500 text-white px-6 py-3 rounded-xl font-semibold hover:from-orange-600 hover:to-red-600 transition-all"
                >
                  <RotateCcw className="w-5 h-5" />
                  リセット
                </button>
                <button
                  onClick={() => setShowSettings(!showSettings)}
                  className="flex items-center gap-2 bg-gradient-to-r from-gray-500 to-gray-600 text-white px-6 py-3 rounded-xl font-semibold hover:from-gray-600 hover:to-gray-700 transition-all"
                >
                  <Settings className="w-5 h-5" />
                  設定
                </button>
              </div>
            </div>

            {/* フィットネス履歴グラフ */}
            <div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 border border-white/20">
              <h3 className="text-lg font-semibold text-white mb-4">適合度の推移</h3>
              <div className="h-40 relative bg-black/30 rounded-lg p-4">
                <svg width="100%" height="100%" className="overflow-visible">
                  {fitnessHistory.length > 1 && (
                    <polyline
                      fill="none"
                      stroke="url(#gradient)"
                      strokeWidth="2"
                      points={fitnessHistory.map((fitness, i) => {
                        const x = (i / (fitnessHistory.length - 1)) * 100;
                        const y = 100 - (fitness / target.length) * 100;
                        return `${x},${y}`;
                      }).join(' ')}
                      vectorEffect="non-scaling-stroke"
                      transform="scale(2.4,1.2)"
                    />
                  )}
                  <defs>
                    <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
                      <stop offset="0%" stopColor="#3b82f6" />
                      <stop offset="100%" stopColor="#10b981" />
                    </linearGradient>
                  </defs>
                </svg>
              </div>
            </div>
          </div>

          {/* サイドパネル */}
          <div className="space-y-6">
            {/* 統計情報 */}
            <div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 border border-white/20">
              <h3 className="text-lg font-semibold text-white mb-4">統計情報</h3>
              <div className="space-y-3 text-white">
                <div className="flex justify-between">
                  <span>世代数:</span>
                  <span className="font-bold text-blue-400">{currentGeneration}</span>
                </div>
                <div className="flex justify-between">
                  <span>個体数:</span>
                  <span className="font-bold text-purple-400">{populationSize}</span>
                </div>
                <div className="flex justify-between">
                  <span>突然変異率:</span>
                  <span className="font-bold text-pink-400">{(mutationRate * 100).toFixed(1)}%</span>
                </div>
                <div className="flex justify-between">
                  <span>実行速度:</span>
                  <span className="font-bold text-green-400">{speed}x</span>
                </div>
                {isComplete && (
                  <div className="mt-4 p-3 bg-green-500/20 rounded-lg border border-green-500/30">
                    <div className="text-green-400 font-bold text-center">
                      🎉 進化完了!
                    </div>
                  </div>
                )}
              </div>
            </div>

            {/* 設定パネル */}
            {showSettings && (
              <div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 border border-white/20">
                <h3 className="text-lg font-semibold text-white mb-4">パラメータ設定</h3>
                <div className="space-y-4">
                  <div>
                    <label className="block text-white text-sm mb-2">目標文字列:</label>
                    <input
                      type="text"
                      value={target}
                      onChange={(e) => setTarget(e.target.value.toUpperCase())}
                      className="w-full bg-black/30 text-white border border-white/30 rounded-lg px-3 py-2 focus:border-blue-500 focus:outline-none"
                      disabled={isRunning}
                    />
                  </div>
                  <div>
                    <label className="block text-white text-sm mb-2">
                      個体数: {populationSize}
                    </label>
                    <input
                      type="range"
                      min="20"
                      max="200"
                      value={populationSize}
                      onChange={(e) => setPopulationSize(Number(e.target.value))}
                      className="w-full"
                      disabled={isRunning}
                    />
                  </div>
                  <div>
                    <label className="block text-white text-sm mb-2">
                      突然変異率: {(mutationRate * 100).toFixed(1)}%
                    </label>
                    <input
                      type="range"
                      min="0.01"
                      max="0.2"
                      step="0.01"
                      value={mutationRate}
                      onChange={(e) => setMutationRate(Number(e.target.value))}
                      className="w-full"
                      disabled={isRunning}
                    />
                  </div>
                  <div>
                    <label className="block text-white text-sm mb-2">
                      実行速度: {speed}x
                    </label>
                    <input
                      type="range"
                      min="1"
                      max="500"
                      value={speed}
                      onChange={(e) => setSpeed(Number(e.target.value))}
                      className="w-full"
                    />
                  </div>
                </div>
              </div>
            )}

            {/* アルゴリズム説明 */}
            <div className="bg-white/10 backdrop-blur-md rounded-2xl p-6 border border-white/20">
              <h3 className="text-lg font-semibold text-white mb-4">アルゴリズム</h3>
              <div className="text-purple-200 text-sm space-y-2">
                <p>1. ランダムな文字列を生成</p>
                <p>2. 最も適合度の高い個体を選択</p>
                <p>3. その個体を親として子個体を生成</p>
                <p>4. 突然変異を適用</p>
                <p>5. 目標に到達するまで繰り返し</p>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
};

export default WeaselProgramSimulator;

コメントを残す

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