|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Ant Colony Optimization with Controls</title> |
|
<style> |
|
body { |
|
font-family: Arial, sans-serif; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
justify-content: center; |
|
height: 100vh; |
|
margin: 0; |
|
background: #f4f4f4; |
|
} |
|
canvas { |
|
border: 1px solid #000; |
|
background: #fff; |
|
margin-top: 20px; |
|
} |
|
#controls { |
|
margin-top: 20px; |
|
display: flex; |
|
flex-direction: column; |
|
align-items: center; |
|
} |
|
.control-group { |
|
margin: 10px 0; |
|
display: flex; |
|
align-items: center; |
|
} |
|
.control-group label { |
|
margin-right: 10px; |
|
} |
|
button { |
|
padding: 10px 20px; |
|
font-size: 16px; |
|
margin: 5px; |
|
cursor: pointer; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<h1>Ant Colony Optimization Simulation</h1> |
|
<canvas id="canvas" width="600" height="400"></canvas> |
|
<div id="controls"> |
|
<div class="control-group"> |
|
<label for="numAnts">Number of Ants:</label> |
|
<input type="number" id="numAnts" value="200" min="1" max="500"> |
|
</div> |
|
<div class="control-group"> |
|
<label for="evaporationRate">Evaporation Rate:</label> |
|
<input type="range" id="evaporationRate" min="0.8" max="0.99" step="0.01" value="0.95"> |
|
<span id="evaporationRateValue">0.95</span> |
|
</div> |
|
<div class="control-group"> |
|
<label for="pheromoneDeposit">Pheromone Deposit:</label> |
|
<input type="number" id="pheromoneDeposit" value="5" min="1" max="20"> |
|
</div> |
|
<div class="control-group"> |
|
<label for="gridSize">Grid Size:</label> |
|
<input type="number" id="gridSize" value="10" min="5" max="20"> |
|
</div> |
|
<button id="start">Start Simulation</button> |
|
<button id="reset">Reset</button> |
|
</div> |
|
|
|
<script> |
|
|
|
const canvas = document.getElementById('canvas'); |
|
const ctx = canvas.getContext('2d'); |
|
|
|
|
|
const numAntsInput = document.getElementById('numAnts'); |
|
const evaporationRateInput = document.getElementById('evaporationRate'); |
|
const pheromoneDepositInput = document.getElementById('pheromoneDeposit'); |
|
const gridSizeInput = document.getElementById('gridSize'); |
|
const evaporationRateValue = document.getElementById('evaporationRateValue'); |
|
|
|
|
|
let gridSize = parseInt(gridSizeInput.value); |
|
let gridWidth = canvas.width / gridSize; |
|
let gridHeight = canvas.height / gridSize; |
|
const nest = { x: 1, y: Math.floor(gridHeight / 2) }; |
|
const food = { x: gridWidth - 2, y: Math.floor(gridHeight / 2) }; |
|
let pheromoneGrid = Array.from({ length: gridWidth }, () => Array(gridHeight).fill(0)); |
|
let ants = []; |
|
let numAnts = parseInt(numAntsInput.value); |
|
let evaporationRate = parseFloat(evaporationRateInput.value); |
|
let pheromoneDeposit = parseInt(pheromoneDepositInput.value); |
|
|
|
|
|
function initializeAnts() { |
|
ants = []; |
|
for (let i = 0; i < numAnts; i++) { |
|
ants.push({ |
|
x: nest.x, |
|
y: nest.y, |
|
hasFood: false, |
|
}); |
|
} |
|
} |
|
|
|
|
|
function randomMove(ant) { |
|
const directions = [ |
|
{ dx: -1, dy: 0 }, |
|
{ dx: 1, dy: 0 }, |
|
{ dx: 0, dy: -1 }, |
|
{ dx: 0, dy: 1 }, |
|
]; |
|
const randomDirection = directions[Math.floor(Math.random() * directions.length)]; |
|
ant.x = Math.max(0, Math.min(gridWidth - 1, ant.x + randomDirection.dx)); |
|
ant.y = Math.max(0, Math.min(gridHeight - 1, ant.y + randomDirection.dy)); |
|
} |
|
|
|
|
|
function draw() { |
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
|
|
|
|
for (let x = 0; x < gridWidth; x++) { |
|
for (let y = 0; y < gridHeight; y++) { |
|
if (pheromoneGrid[x][y] > 0) { |
|
const intensity = pheromoneGrid[x][y] / 10; |
|
ctx.fillStyle = `rgba(0, 0, 255, ${intensity})`; |
|
ctx.fillRect(x * gridSize, y * gridSize, gridSize, gridSize); |
|
} |
|
} |
|
} |
|
|
|
|
|
ctx.fillStyle = 'green'; |
|
ctx.fillRect(nest.x * gridSize, nest.y * gridSize, gridSize, gridSize); |
|
ctx.fillStyle = 'red'; |
|
ctx.fillRect(food.x * gridSize, food.y * gridSize, gridSize, gridSize); |
|
|
|
|
|
ctx.fillStyle = 'black'; |
|
ants.forEach(ant => { |
|
ctx.beginPath(); |
|
ctx.arc((ant.x + 0.5) * gridSize, (ant.y + 0.5) * gridSize, gridSize / 4, 0, Math.PI * 2); |
|
ctx.fill(); |
|
}); |
|
} |
|
|
|
|
|
function moveAnts() { |
|
ants.forEach(ant => { |
|
randomMove(ant); |
|
|
|
|
|
if (ant.x === food.x && ant.y === food.y) { |
|
ant.hasFood = true; |
|
} |
|
if (ant.x === nest.x && ant.y === nest.y) { |
|
ant.hasFood = false; |
|
} |
|
|
|
|
|
if (ant.hasFood) { |
|
pheromoneGrid[ant.x][ant.y] += pheromoneDeposit; |
|
} |
|
}); |
|
} |
|
|
|
|
|
function evaporatePheromones() { |
|
for (let x = 0; x < gridWidth; x++) { |
|
for (let y = 0; y < gridHeight; y++) { |
|
pheromoneGrid[x][y] *= evaporationRate; |
|
} |
|
} |
|
} |
|
|
|
|
|
function updateGridSize() { |
|
gridSize = parseInt(gridSizeInput.value); |
|
gridWidth = canvas.width / gridSize; |
|
gridHeight = canvas.height / gridSize; |
|
pheromoneGrid = Array.from({ length: gridWidth }, () => Array(gridHeight).fill(0)); |
|
initializeAnts(); |
|
} |
|
|
|
|
|
function simulate() { |
|
moveAnts(); |
|
evaporatePheromones(); |
|
draw(); |
|
requestAnimationFrame(simulate); |
|
} |
|
|
|
|
|
document.getElementById('start').addEventListener('click', () => { |
|
updateGridSize(); |
|
simulate(); |
|
}); |
|
|
|
document.getElementById('reset').addEventListener('click', () => { |
|
updateGridSize(); |
|
pheromoneGrid.forEach((row, x) => row.fill(0)); |
|
draw(); |
|
}); |
|
|
|
numAntsInput.addEventListener('input', () => { |
|
numAnts = parseInt(numAntsInput.value); |
|
initializeAnts(); |
|
}); |
|
|
|
evaporationRateInput.addEventListener('input', () => { |
|
evaporationRate = parseFloat(evaporationRateInput.value); |
|
evaporationRateValue.textContent = evaporationRate.toFixed(2); |
|
}); |
|
|
|
pheromoneDepositInput.addEventListener('input', () => { |
|
pheromoneDeposit = parseInt(pheromoneDepositInput.value); |
|
}); |
|
|
|
gridSizeInput.addEventListener('input', () => { |
|
updateGridSize(); |
|
}); |
|
</script> |
|
</body> |
|
</html> |