156 lines
4.8 KiB
HTML
156 lines
4.8 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;
|
|
}
|
|
|
|
if (data.ants) {
|
|
data.ants.forEach(ant => {
|
|
const ax = ant[0] * cellSize;
|
|
const ay = ant[1] * cellSize;
|
|
const speed = ant[2];
|
|
|
|
let color = "orange";
|
|
if (speed > 1.3) color = `rgb(255, ${255 - (speed*80)}, 0)`;
|
|
else if (speed < 0.9) color = `rgb(${speed*100}, ${speed*100}, 255)`;
|
|
|
|
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> |