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> |