Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Interactive Genetic Algorithm</title> | |
| <style> | |
| body { | |
| font-family: 'Helvetica Neue', Arial, sans-serif; | |
| text-align: center; | |
| margin: 0; | |
| padding: 0; | |
| background: linear-gradient(135deg, #ffefba, #ffffff); | |
| color: #333; | |
| } | |
| h1 { | |
| color: #4a4e69; | |
| } | |
| p { | |
| color: #9a8c98; | |
| } | |
| canvas { | |
| border: 2px solid #c9ada7; | |
| background: #f2e9e4; | |
| margin: 20px auto; | |
| display: block; | |
| box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); | |
| } | |
| .controls { | |
| margin: 20px auto; | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| gap: 20px; | |
| flex-wrap: wrap; | |
| } | |
| .controls label { | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| color: #6c5b7b; | |
| } | |
| .controls input, .controls button { | |
| padding: 10px 20px; | |
| font-size: 16px; | |
| border: none; | |
| border-radius: 5px; | |
| cursor: pointer; | |
| transition: background 0.3s, transform 0.3s; | |
| } | |
| .controls input { | |
| width: 100px; | |
| background: #f2e9e4; | |
| border: 1px solid #c9ada7; | |
| color: #6c5b7b; | |
| } | |
| .controls button { | |
| background: #a29bfe; | |
| color: white; | |
| } | |
| .controls button:hover { | |
| background: #6c5b7b; | |
| transform: scale(1.05); | |
| } | |
| .controls button:disabled { | |
| background: #c9ada7; | |
| cursor: not-allowed; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1> Genetic Algorithm</h1> | |
| <p>Click on the canvas to set a target position. Adjust settings and evolve the population!</p> | |
| <div class="controls"> | |
| <label>Population Size: <input id="populationSize" type="number" value="50" min="10" max="200"></label> | |
| <label>Mutation Rate: <input id="mutationRate" type="number" value="1" min="0" max="100">%</label> | |
| <button id="startButton">Start Evolution</button> | |
| <button id="stepButton">Step</button> | |
| <button id="resetButton">Reset</button> | |
| </div> | |
| <canvas id="gaCanvas" width="800" height="600"></canvas> | |
| <script> | |
| const canvas = document.getElementById('gaCanvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const populationSizeInput = document.getElementById('populationSize'); | |
| const mutationRateInput = document.getElementById('mutationRate'); | |
| const startButton = document.getElementById('startButton'); | |
| const stepButton = document.getElementById('stepButton'); | |
| const resetButton = document.getElementById('resetButton'); | |
| let running = false; | |
| let targetX = 400; | |
| let targetY = 300; | |
| let population = []; | |
| let generation = 0; | |
| class Creature { | |
| constructor(x, y) { | |
| this.x = x || Math.random() * canvas.width; | |
| this.y = y || Math.random() * canvas.height; | |
| } | |
| getFitness() { | |
| const dx = this.x - targetX; | |
| const dy = this.y - targetY; | |
| return 1 / (1 + Math.sqrt(dx * dx + dy * dy)); | |
| } | |
| mutate(mutationRate) { | |
| if (Math.random() < mutationRate) { | |
| this.x += (Math.random() - 0.5) * 50; | |
| this.y += (Math.random() - 0.5) * 50; | |
| } | |
| } | |
| draw() { | |
| ctx.fillStyle = `rgba(94, 135, 243, ${this.getFitness()})`; | |
| ctx.beginPath(); | |
| ctx.arc(this.x, this.y, 8, 0, Math.PI * 2); | |
| ctx.fill(); | |
| ctx.strokeStyle = 'rgba(0, 0, 0, 0.2)'; | |
| ctx.stroke(); | |
| } | |
| } | |
| function generatePopulation(size) { | |
| const population = []; | |
| for (let i = 0; i < size; i++) { | |
| population.push(new Creature()); | |
| } | |
| return population; | |
| } | |
| function selectParents(population) { | |
| const sorted = population.sort((a, b) => b.getFitness() - a.getFitness()); | |
| return sorted.slice(0, Math.floor(population.length / 2)); | |
| } | |
| function crossover(parent1, parent2) { | |
| const childX = (parent1.x + parent2.x) / 2; | |
| const childY = (parent1.y + parent2.y) / 2; | |
| return new Creature(childX, childY); | |
| } | |
| function evolvePopulation(population, mutationRate) { | |
| const parents = selectParents(population); | |
| const newPopulation = []; | |
| newPopulation.push(parents[0]); | |
| while (newPopulation.length < population.length) { | |
| const parent1 = parents[Math.floor(Math.random() * parents.length)]; | |
| const parent2 = parents[Math.floor(Math.random() * parents.length)]; | |
| const child = crossover(parent1, parent2); | |
| child.mutate(mutationRate); | |
| newPopulation.push(child); | |
| } | |
| return newPopulation; | |
| } | |
| function visualizePopulation(population, generation) { | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| ctx.fillStyle = 'red'; | |
| ctx.beginPath(); | |
| ctx.arc(targetX, targetY, 10, 0, Math.PI * 2); | |
| ctx.fill(); | |
| population.forEach(creature => creature.draw()); | |
| ctx.fillStyle = 'black'; | |
| ctx.font = '16px Arial'; | |
| ctx.fillText(`Generation: ${generation}`, 10, 20); | |
| } | |
| canvas.addEventListener('click', (event) => { | |
| const rect = canvas.getBoundingClientRect(); | |
| targetX = event.clientX - rect.left; | |
| targetY = event.clientY - rect.top; | |
| }); | |
| startButton.addEventListener('click', () => { | |
| running = true; | |
| startButton.disabled = true; | |
| stepButton.disabled = true; | |
| resetButton.disabled = true; | |
| const evolutionInterval = setInterval(() => { | |
| if (!running) { | |
| clearInterval(evolutionInterval); | |
| startButton.disabled = false; | |
| stepButton.disabled = false; | |
| resetButton.disabled = false; | |
| return; | |
| } | |
| const populationSize = parseInt(populationSizeInput.value); | |
| const mutationRate = parseInt(mutationRateInput.value) / 100; | |
| if (population.length === 0) { | |
| population = generatePopulation(populationSize); | |
| } | |
| visualizePopulation(population, generation); | |
| population = evolvePopulation(population, mutationRate); | |
| generation++; | |
| }, 200); | |
| }); | |
| stepButton.addEventListener('click', () => { | |
| if (population.length === 0) { | |
| const populationSize = parseInt(populationSizeInput.value); | |
| population = generatePopulation(populationSize); | |
| } | |
| const mutationRate = parseInt(mutationRateInput.value) / 100; | |
| visualizePopulation(population, generation); | |
| population = evolvePopulation(population, mutationRate); | |
| generation++; | |
| }); | |
| resetButton.addEventListener('click', () => { | |
| population = []; | |
| generation = 0; | |
| visualizePopulation(population, generation); | |
| }); | |
| </script> | |
| </body> | |
| </html> |