AI_Zig/ant_viewer.html

163 lines
5.2 KiB
HTML

<!DOCTYPE html>
<html lang="it">
<head>
<meta charset="UTF-8">
<title>Hive Mind Viewer</title>
<style>
body {
margin: 0;
background-color: #111;
color: #eee;
font-family: monospace;
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
overflow: hidden;
}
#header {
width: 100%;
padding: 10px;
background: #222;
display: flex;
justify-content: space-between;
border-bottom: 1px solid #444;
box-sizing: border-box;
z-index: 10;
}
#container {
flex-grow: 1;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
canvas {
box-shadow: 0 0 50px rgba(0,0,0,0.8);
image-rendering: pixelated;
}
</style>
</head>
<body>
<div id="header">
<span><b>HIVE MIND AI</b></span>
<span>Episodio: <span id="episode">0</span></span>
<span>Epsilon: <span id="epsilon">0.00</span></span>
<span>Cibo: <span id="food-coords">?</span></span>
</div>
<div id="container">
<canvas id="gridCanvas"></canvas>
</div>
<script>
const canvas = document.getElementById('gridCanvas');
const ctx = canvas.getContext('2d');
const epEl = document.getElementById('episode');
const epsEl = document.getElementById('epsilon');
const foodEl = document.getElementById('food-coords');
let gridSize = 100;
function drawWorld(data) {
gridSize = data.grid_size;
const margin = 40;
const availableW = document.getElementById('container').clientWidth - margin;
const availableH = document.getElementById('container').clientHeight - margin;
const canvasSize = Math.min(availableW, availableH);
canvas.width = canvasSize;
canvas.height = canvasSize;
const cellSize = canvasSize / gridSize;
ctx.fillStyle = "#1a1a1a";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (cellSize > 4) {
ctx.strokeStyle = "#2a2a2a";
ctx.lineWidth = 1;
ctx.beginPath();
for(let i=0; i<=gridSize; i++) {
const pos = i * cellSize;
ctx.moveTo(pos, 0); ctx.lineTo(pos, canvas.height);
ctx.moveTo(0, pos); ctx.lineTo(canvas.width, pos);
}
ctx.stroke();
}
if (data.food) {
const fx = data.food[0] * cellSize;
const fy = data.food[1] * cellSize;
ctx.shadowBlur = 15;
ctx.shadowColor = "#0f0";
ctx.fillStyle = "#00ff00";
ctx.beginPath();
ctx.arc(fx + cellSize/2, fy + cellSize/2, cellSize/1.5, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
}
// 5. FORMICHE (Colorate in base alla velocità)
if (data.ants) {
data.ants.forEach(ant => {
// ant[0] = x, ant[1] = y, ant[2] = speed
const ax = ant[0] * cellSize;
const ay = ant[1] * cellSize;
const speed = ant[2];
// Interpolazione Colore
// Speed 0.5 (Lenta) -> Blu (0, 0, 255)
// Speed 1.0 (Media) -> Arancio (255, 165, 0)
// Speed 2.5 (Veloce) -> Rosso Fuoco (255, 0, 0)
let color = "orange";
if (speed > 1.3) color = `rgb(255, ${255 - (speed*80)}, 0)`; // Diventa rossa
else if (speed < 0.9) color = `rgb(${speed*100}, ${speed*100}, 255)`; // Diventa blu
ctx.fillStyle = color;
if (cellSize < 3) {
ctx.fillRect(ax, ay, cellSize, cellSize);
} else {
ctx.beginPath();
ctx.arc(ax + cellSize/2, ay + cellSize/2, cellSize/2, 0, Math.PI*2);
ctx.fill();
}
});
}
}
async function update() {
try {
const response = await fetch('ant_state.json?t=' + Date.now());
if (!response.ok) return;
const data = await response.json();
epEl.innerText = data.episode;
epsEl.innerText = data.epsilon;
if(data.food) foodEl.innerText = `[${data.food[0]}, ${data.food[1]}]`;
drawWorld(data);
} catch (e) {
console.error(e);
}
}
setInterval(update, 50);
window.addEventListener('resize', () => {
});
</script>
</body>
</html>