OverviewCode › R113
Code · blind round

R113 · Predator and prey on a shared field

blind round 8/11 local models answered

Every answer below carries the name of the model that wrote it. Blind refers to the scoring: the review was done without knowing which model produced which answer — the published result names them.

2 of the 11 local models delivered nothing through our test harness in this round — for reasons that lie with our setup, not with the models. Those cards are marked DNF like any other, but they are not evidence about those models — the reason is noted on the card itself.

Show task
Create ONE self-contained HTML file (STRICT LIMIT: max 7000 characters in total — this is a budget on characters, not on lines, so removing line breaks does not help) that simulates predators and prey on a <canvas>: prey graze on regrowing food and multiply where food is plentiful, predators chase nearby prey, eat them, lose energy over time and multiply when well fed. Draw food, prey and predators in distinct colours and let the two populations visibly oscillate against each other. Show both population counts. Smooth requestAnimationFrame animation, NO user input, starts immediately and keeps running (restart with a fresh random instance when finished). No external libraries, no comments needed. Output ONLY the HTML file content, nothing else.

The answers

Local models (Brain cluster) — identical prompt, shuffled order (the sequence is not a ranking)
qwen3:14bERRBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html><head><title>Predator-Prey Simulation</title></head><body style="display:flex;justify-content:center;align-items:center;background:#333;"><canvas id="gameCanvas" width="800" height="500" style="border:1px solid #ccc;"></canvas><script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

let food = [];
let prey = [];
let predators = [];
let score = { P: 0, R: 0 };
let animationId;

const CANVAS_W = 800;
const CANVAS_H = 500;

// --- Object Definitions ---
class Food { constructor(x, y) { this.x = x; this.y = y; this.r = 3; } draw() { ctx.fillStyle='#4CAF50'; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); ctx.fill(); } }
class Prey { constructor(x, y) { this.x = x; this.y = y; this.r = 5; this.energy = 100; this.maxEnergy = 100; this.moveSpeed = Math.random() * 1 + 0.8; } update() { this.energy -= 0.2; if (this.energy <= 0) return false; let dx = (Math.random() - 0.5) * 2; let dy = (Math.random() - 0.5) * 2; this.x += dx * this.moveSpeed; this.y += dy * this.moveSpeed; if (this.x < 0 || this.x > CANVAS_W || this.y < 0 || this.y > CANVAS_H) {this.x = Math.random() * CANVAS_W; this.y = Math.random() * CANVAS_H;} return true; } draw() { ctx.fillStyle='#FFD700'; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); ctx.fill(); } }
class Predator { constructor(x, y) { this.x = x; this.y = y; this.r = 7; this.energy = 150; this.maxEnergy = 150; this.moveSpeed = 3; } update() { this.energy -= 0.4; if (this.energy <= 0) return false; let targetPrey = prey.reduce((best, p) => {
    const distA = Math.hypot(p.x - this.x, p.y - this.y);
    return best ? (distA < best.dist) ? p : best : p;
}, null).filter(Boolean)[0]; if (!targetPrey) return true; let angle = Math.atan2(targetPrey.y - this.y, targetPrey.x - this.x); let speed = this.moveSpeed * (this.energy / this.maxEnergy); this.x += Math.cos(angle) * speed; this.y += Math.sin(angle) * speed; if (this.x < 0 || this.x > CANVAS_W || this.y < 0 || this.y > CANVAS_H) {this.x = Math.random() * CANVAS_W; this.y = Math.random() * CANVAS_H;} return true; } draw() { ctx.fillStyle='#FF6347'; ctx.beginPath(); ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2); ctx.fill(); } }

// --- Interaction Functions ---
function checkFoodInteraction(p) {
    for (let i = food.length - 1; i >= 0; i--) {
        const f = food[i];
        if (Math.hypot(f.x - p.x, f.y - p.y) < p.r + f.r * 0.8) {
            p.energy = Math.min(p.maxEnergy, p.energy + 15);
            food.splice(i, 1);
        }
    }
}

function checkPreyInteraction(predator) {
    let consumed = false;
    for (let i = prey.length - 1; i >= 0; i--) {
        const p = prey[i];
        if (Math.hypot(p.x - predator.x, p.y - predator.y) < predator.r + p.r * 0.8) {
            predator.energy = Math.min(predator.maxEnergy, predator.energy + 50);
            prey.splice(i, 1);
            consumed = true;
        }
    }
    return consumed;
}

function attemptReproduction() {
    // Prey reproduction (high food/low energy)
    if (prey.length > 2 && Math.random() < 0.005) {
        const p = prey[Math.floor(Math.random() * prey.length)];
        if (p.energy > 120) { // Must be well fed to reproduce
            prey.splice(prey.indexOf(p), 1);
            prey.push(new Prey(p.x + Math.random() * 5, p.y + Math.random() * 5));
        }
    }

    // Predator reproduction (high energy)
    if (predators.length < 20 && Math.random() < 0.01) {
        const pred = predators[Math.floor(Math.random() * predators.length)];
        if (pred.energy > 160) { // Must be well fed to reproduce
            prey.push(new Prey(pred.x + Math.random() * 5, pred.y + Math.random() * 5)); // Sometimes reproduces by "finding" food
            predators.push(new Predator(pred.x - 10, pred.y - 10));
        }
    }
}

// --- Simulation Step ---
function updateSimulation() {
    // 1. Food Growth (Regrowth)
    if (Math.random() < 0.5 && food.length < 300) {
        food.push(new Food(Math.random() * CANVAS_W, Math.random() * CANVAS_H));
    }

    // 2. Prey Update & Interaction
    let nextPrey = [];
    for (const p of prey) {
        if (p.update()) {
            checkFoodInteraction(p);
            nextPrey.push(p);
        } else {
            score.P--;
        }
    }
    prey = nextPrey;

    // 3. Predator Update & Interaction
    let nextPredators = [];
    for (const pred of predators) {
        if (pred.update()) {
            checkPreyInteraction(pred);
            nextPredators.push(pred);
        } else {
            score.R--;
        }
    }
    predators = nextPredators;

    // 4. Reproduction and Cleanup
    attemptReproduction();

    // 5. Score Update (Populations)
    score.P = prey.length;
    score.R = predators.length;
}

// --- Drawing Functions ---
function drawSimulation() {
    ctx.clearRect(0, 0, CANVAS_W, CANVAS_H);

    // Draw Food (Green)
    food.forEach(f => f.draw());

    // Draw Prey (Yellow/Gold)
    prey.forEach(p => p.draw());

    // Draw Predators (Red/Orange)
    predators.forEach(p => p.draw());
}

function loop() {
    updateSimulation();
    drawSimulation();

    // Display Stats
    const stats = document.createElement('div');
    stats.style.position = 'absolute';
    stats.style.top = '10px';
    stats.style.left = '150px';
    stats.innerHTML = `
        <h3 style="color:#4CAF50;">Food: ${food.length}</h3>
        <h3 style="color:#FFD700;">Prey ($P$): ${score.P}</h3>
        <h3 style="color:#FF6347;">Predators ($R$): ${score.R}</h3>
    `;
    document.body.appendChild(stats); // Simplistic way to ensure display

    animationId = requestAnimationFrame(loop);
}

function init() {
    // Reset and initialize populations randomly
    food = [];
    prey = [];
    predators = [];
    score = { P: 0, R: 0 };

    for (let i = 0; i < 150; i++) food.push(new Food(Math.random() * CANVAS_W, Math.random() * CANVAS_H));
    for (let i = 0; i < 40; i++) prey.push(new Prey(Math.random() * CANVAS_W, Math.random() * CANVAS_H));
    for (let i = 0; i < 5; i++) predators.push(new Predator(Math.random() * CANVAS_W, Math.random() * CANVAS_H));

    // Start the loop
    if (animationId) cancelAnimationFrame(animationId);
    loop();
}

init();
</script></body></html>
```
gemma4:26bharness
No answer reached us (THIN) — and the reason lies with our setup, not with the model: reasoning consumed the entire token budget (3 min 28 s, zero characters of answer); larger budgets are refused by the gateway Counted as a did-not-finish, but it is not evidence about this model.
qwen3.5:9bBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head>
<title>Predator-Prey Simulation</title>
<style>
body {background: #111; display: flex; justify-content: center; align-items: center; margin: 0;}
canvas {border: 2px solid #333; background: #000; }
#stats {color: white; font-family: monospace; position: absolute; top: 10px; left: 50%; transform: translateX(-50%); padding: 10px; background: rgba(0,0,0,0.7); border-radius: 5px;}
</style>
</head>
<body>

<canvas id="gameCanvas" width="800" height="600"></canvas>
<div id="stats"></div>

<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const statsDiv = document.getElementById('stats');

let W = canvas.width;
let H = canvas.height;

let prey = [];
let predators = [];
let food = [];

// Constants
const MAX_PREY = 150;
const MIN_PREY = 20;
const INITIAL_PREDATORS = 7;

const PREDATOR_ENERGY_DECAY = 0.03;
const PREY_FOOD_GAIN = 5;
const PREY_REPRO_COST = 10;
const PREDATOR_REPRO_COST = 20;
const FOOD_SPAWN_RATE = 0.01;

// Utility function for distance squared (faster than actual distance)
function distSq(p1, p2) {
    return Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2);
}

// Object Definitions
class Food {
    constructor() {
        this.x = Math.random() * W;
        this.y = Math.random() * H;
        this.radius = 3 + Math.random() * 2;
    }
}

class Prey {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.vx = (Math.random() - 0.5) * 1.5;
        this.vy = (Math.random() - 0.5) * 1.5;
        this.energy = 10;
        this.radius = 3;
    }

    update() {
        this.energy -= 0.02; // Base decay
        if (this.energy <= 0) return false;

        // Find nearest food patch
        let nearestFood = null;
        let minDistSq = Infinity;
        for (const f of food) {
            const dSq = distSq(this, f);
            if (dSq < minDistSq) {
                minDistSq = dSq;
                nearestFood = f;
            }
        }

        // Movement logic
        let targetX = this.x + Math.sign(Math.random() - 0.5) * 2;
        let targetY = this.y + Math.sign(Math.random() - 0.5) * 2;

        if (nearestFood && distSq(this, nearestFood) < 10000) { // If food is close enough
            targetX = nearestFood.x;
            targetY = nearestFood.y;
        } else if (Math.random() < 0.05) { // Random wander otherwise
             targetX += Math.cos(Date.now()/1000)*2;
             targetY += Math.sin(Date.now()/1000)*2;
        }

        const dx = targetX - this.x;
        const dy = targetY - this.y;
        const dist = Math.sqrt(dx*dx + dy*dy);

        if (dist > 0) {
            this.vx = (dx / dist) * 1.5;
            this.vy = (dy / dist) * 1.5;
        }
        
        // Apply movement and boundary checks
        this.x += this.vx;
        this.y += this.vy;

        if (this.x < 0 || this.x > W) { this.vx *= -1; this.x = Math.max(0, Math.min(W, this.x)); }
        if (this.y < 0 || this.y > H) { this.vy *= -1; this.y = Math.max(0, Math.min(H, this.y)); }

        return true;
    }
}

class Predator {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.vx = 0;
        this.vy = 0;
        this.energy = 40;
        this.radius = 5;
    }

    update() {
        this.energy -= PREDATOR_ENERGY_DECAY;
        if (this.energy <= 0) return false;

        // Target nearest prey
        let targetPrey = null;
        let minDistSq = Infinity;
        for (const p of prey) {
            const dSq = distSq(this, p);
            if (dSq < minDistSq) {
                minDistSq = dSq;
                targetPrey = p;
            }
        }

        // Movement logic
        let dx = 0 - this.x;
        let dy = 0 - this.y;

        if (targetPrey && distSq(this, targetPrey) < 500000) { // If prey is in range
            dx = targetPrey.x - this.x;
            dy = targetPrey.y - this.y;
        } else {
            // Random drift if no prey nearby
            dx += (Math.random() - 0.5);
            dy += (Math.random() - 0.5);
        }

        const dist = Math.sqrt(dx*dx + dy*dy);
        if (dist > 0) {
            this.vx = (dx / dist) * 1.2;
            this.vy = (dy / dist) * 1.2;
        } else {
             this.vx = (Math.random() - 0.5) * 0.5;
             this.vy = (Math.random() - 0.5) * 0.5;
        }

        // Apply movement and boundary checks
        this.x += this.vx;
        this.y += this.vy;

        if (this.x < 0 || this.x > W) { this.vx *= -1; this.x = Math.max(0, Math.min(W, this.x)); }
        if (this.y < 0 || this.y > H) { this.vy *= -1; this.y = Math.max(0, Math.min(H, this.y)); }

        return true;
    }
}


// Initialization Functions
function initPopulations() {
    prey = [];
    predators = [];
    food = [];

    for (let i = 0; i < MIN_PREY + Math.floor(Math.random() * 30); i++) {
        prey.push(new Prey(Math.random() * W, Math.random() * H));
    }
    for (let i = 0; i < INITIAL_PREDATORS; i++) {
        predators.push(new Predator(Math.random() * W, Math.random() * H));
    }
    food = Array(50).fill(null).map(() => new Food());
}

// Interaction Logic (Called during update cycle)
function handleInteractions() {
    let nextPrey = [];
    let nextPredators = [];
    let consumedFoodIndices = {};
    let preyConsumedByPredator = new Set();

    // 1. Predator-Prey Hunting
    for (const p of predators) {
        if (!p.update()) continue;
        
        let targetIndex = -1;
        let minDSq = Infinity;

        // Find the closest non-consumed prey
        for(let i=0; i < prey.length; i++) {
            const p_obj = prey[i];
            if (!preyConsumedByPredator.has(p_obj)) {
                const dSq = distSq(p, p_obj);
                if (dSq < minDSq) {
                    minDSq = dSq;
                    targetIndex = i;
                }
            }
        }

        if (targetIndex !== -1 && Math.sqrt(distSq(p, prey[targetIndex])) < p.radius + 5 + 2) { // Collision range check
            const target = prey[targetIndex];
            // Attack successful
            p.energy += 20;
            preyConsumedByPredator.add(target);
        } else if (Math.random() < 0.01) {
             // Simulate minor random movement towards the target's general area
             const
qwen3:8bharness
No answer reached us (ERR) — and the reason lies with our setup, not with the model: reasoning consumed the entire token budget and the answer stayed empty; the gateway rejects budgets above 3000 tokens Counted as a did-not-finish, but it is not evidence about this model.
llama3.1:8bSTATFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Predator Prey Simulation</title>
<style>
body {
  background-color: #f2f2f2;
}
canvas {
  border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let w = canvas.width;
let h = canvas.height;
let food = [];
for (let i = 0; i < 100; i++) {
  food.push({x: Math.random() * w, y: Math.random() * h});
}
let prey = [{x: Math.random() * w, y: Math.random() * h}];
let predators = [{x: Math.random() * w, y: Math.random() * h}];
function drawFood() {
  ctx.fillStyle = 'green';
  ctx.beginPath();
  for (const f of food) {
    ctx.arc(f.x, f.y, 2, 0, 2 * Math.PI);
  }
  ctx.fill();
}
function drawPrey() {
  ctx.fillStyle = 'blue';
  ctx.beginPath();
  for (const p of prey) {
    ctx.arc(p.x, p.y, 4, 0, 2 * Math.PI);
  }
  ctx.fill();
}
function drawPredators() {
  ctx.fillStyle = 'red';
  ctx.beginPath();
  for (const p of predators) {
    ctx.arc(p.x, p.y, 6, 0, 2 * Math.PI);
  }
  ctx.fill();
}
function updatePrey() {
  for (let i = prey.length - 1; i >= 0; i--) {
    const p = prey[i];
    let closestFood;
    let minDist = Infinity;
    for (const f of food) {
      const dist = Math.sqrt((p.x - f.x) ** 2 + (p.y - f.y) ** 2);
      if (dist < minDist) {
        minDist = dist;
        closestFood = f;
      }
    }
    if (minDist > 10 && Math.random() < 0.1) {
      prey.splice(i, 1);
    } else if (closestFood) {
      p.x += (p.x - closestFood.x) / 10;
      p.y += (p.y - closestFood.y) / 10;
      food.splice(food.indexOf(closestFood), 1);
      if (Math.random() < 0.05) {
        prey.push({x: Math.random() * w, y: Math.random() * h});
      }
    }
  }
}
function updatePredators() {
  for (let i = predators.length - 1; i >= 0; i--) {
    const p = predators[i];
    let closestPrey;
    let minDist = Infinity;
    for (const preyAnimal of prey) {
      const dist = Math.sqrt((p.x - preyAnimal.x) ** 2 + (p.y - preyAnimal.y) ** 2);
      if (dist < minDist) {
        minDist = dist;
        closestPrey = preyAnimal;
      }
    }
    if (minDist > 20 && Math.random() < 0.1) {
      predators.splice(i, 1);
    } else if (closestPrey) {
      p.x += (p.x - closestPrey.x) / 10;
      p.y += (p.y - closestPrey.y) / 10;
      prey.splice(prey.indexOf(closestPrey), 1);
      let energy = Math.sqrt((p.x - closestPrey.x) ** 2 + (p.y - closestPrey.y) ** 2) > 5 ? 0.8 : 1;
      if (Math.random() < energy) {
        predators.push({x: Math.random() * w, y: Math.random() * h});
      }
    } else {
      if (Math.random() < 0.05) {
        predators.push({x: Math.random() * w, y: Math.random() * h});
      }
    }
  }
}
function drawStats() {
  ctx.fillStyle = 'black';
  ctx.font = '16px Arial';
  ctx.fillText('Prey: ' + prey.length.toLocaleString(), 10, 20);
  ctx.fillText('Predators: ' + predators.length.toLocaleString(), 10, 40);
}
setInterval(() => {
  if (predators.length === 0 && prey.length > 100) {
    food = [];
    for (let i = 0; i < 100; i++) {
      food.push({x: Math.random() * w, y: Math.random() * h});
    }
    prey = [{x: Math.random() * w, y: Math.random() * h}];
    predators = [{x: Math.random() * w, y: Math.random() * h}];
  }
  ctx.clearRect(0, 0, w, h);
  drawFood();
  updatePrey();
  drawPrey();
  updatePredators();
  drawPredators();
  drawStats();
}, 1000 / 60);
</script>
</body>
</html>
```
mistral-small:24bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Predator-Prey Simulation</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
#info { position: absolute; top: 10px; left: 10px; color: white; font-family: Arial, sans-serif; background: rgba(0, 0, 0, 0.5); padding: 10px; }
</style>
</head>
<body>
<canvas id="simulationCanvas" width="800" height="600"></canvas>
<div id="info">Prey: <span id="preyCount">0</span> Predators: <span id="predatorCount">0</span></div>
<script>
const canvas = document.getElementById('simulationCanvas');
const ctx = canvas.getContext('2d');
const info = document.getElementById('info');
const preyCountElem = document.getElementById('preyCount');
const predatorCountElem = document.getElementById('predatorCount');

class Entity {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  draw() {}
}

class Food extends Entity {
  constructor(x, y) {
    super(x, y);
    this.energy = Math.random() * 10 + 5;
  }
  draw() { ctx.fillStyle = 'green'; ctx.fillRect(this.x, this.y, 5, 5); }
}

class Prey extends Entity {
  constructor(x, y) {
    super(x, y);
    this.energy = Math.random() * 10 + 5;
    this.direction = Math.random() * 2 * Math.PI;
  }
  draw() { ctx.fillStyle = 'blue'; ctx.beginPath(); ctx.arc(this.x, this.y, 3, 0, 2 * Math.PI); ctx.fill(); }
}

class Predator extends Entity {
  constructor(x, y) {
    super(x, y);
    this.energy = Math.random() * 10 + 5;
    this.direction = Math.random() * 2 * Math.PI;
  }
  draw() { ctx.fillStyle = 'red'; ctx.beginPath(); ctx.arc(this.x, this.y, 4, 0, 2 * Math.PI); ctx.fill(); }
}

const foods = [];
const preys = [];
const predators = [];

function createFood() {
  for (let i = 0; i < 50; i++) {
    const x = Math.random() * canvas.width;
    const y = Math.random() * canvas.height;
    foods.push(new Food(x, y));
  }
}

function spawnPrey(count) {
  for (let i = 0; i < count; i++) {
    const x = Math.random() * canvas.width;
    const y = Math.random() * canvas.height;
    preys.push(new Prey(x, y));
  }
}

function spawnPredators(count) {
  for (let i = 0; i < count; i++) {
    const x = Math.random() * canvas.width;
    const y = Math.random() * canvas.height;
    predators.push(new Predator(x, y));
  }
}

function updatePrey(prey) {
  prey.direction += (Math.random() - 0.5) * 0.1;
  prey.x += Math.cos(prey.direction);
  prey.y += Math.sin(prey.direction);

  if (prey.x < 0) prey.x = canvas.width;
  if (prey.x > canvas.width) prey.x = 0;
  if (prey.y < 0) prey.y = canvas.height;
  if (prey.y > canvas.height) prey.y = 0;

  const nearbyFood = foods.find(f => Math.hypot(prey.x - f.x, prey.y - f.y) < 10);
  if (nearbyFood) {
    nearbyFood.energy -= 1;
    if (nearbyFood.energy <= 0) {
      foods.splice(foods.indexOf(nearbyFood), 1);
    }
    prey.energy += 2;
  } else {
    prey.energy -= 0.5;
  }

  if (prey.energy <= 0) {
    preys.splice(preys.indexOf(prey), 1);
  } else if (Math.random() < prey.energy / 100 && preys.length < 200) {
    spawnPrey(1);
  }
}

function updatePredator(predator) {
  const nearbyPrey = preys.find(p => Math.hypot(predator.x - p.x, predator.y - p.y) < 30);
  if (nearbyPrey) {
    predator.direction += (Math.atan2(nearbyPrey.y - predator.y, nearbyPrey.x - predator.x) - predator.direction + 5 * Math.PI) % (2 * Math.PI) - Math.PI;
    predator.x += Math.cos(predator.direction);
    predator.y += Math.sin(predator.direction);

    if (Math.hypot(predator.x - nearbyPrey.x, predator.y - nearbyPrey.y) < 4) {
      preys.splice(preys.indexOf(nearbyPrey), 1);
      predator.energy += 5;
    }
  } else {
    predator.direction += (Math.random() - 0.5) * 0.2;
    predator.x += Math.cos(predator.direction);
    predator.y += Math.sin(predator.direction);
  }

  if (predator.x < 0) predator.x = canvas.width;
  if (predator.x > canvas.width) predator.x = 0;
  if (predator.y < 0) predator.y = canvas.height;
  if (predator.y > canvas.height) predator.y = 0;

  predator.energy -= 1;
  if (predator.energy <= 0) {
    predators.splice(predators.indexOf(predator), 1);
  } else if (Math.random() < predator.energy / 50 && predators.length < 50) {
    spawnPredators(1);
  }
}

function update() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  for (const food of foods) { food.draw(); }

  preys.forEach(prey => {
    updatePrey(prey);
    prey.draw();
  });

  predators.forEach(predator => {
    updatePredator(predator);
    predator.draw();
  });

  preyCountElem.textContent = preys.length;
  predatorCountElem.textContent = predators.length;

  if (preys.length === 0 && predators.length === 0) resetSimulation();

  requestAnimationFrame(update);
}

function resetSimulation() {
  foods.length = 0;
  preys.length = 0;
  predators.length = 0;
  createFood();
  spawnPrey(10);
  spawnPredators(5);
  update();
}

createFood();
spawnPrey(10);
spawnPredators(5);
update();
</script>
</body>
</html>
```
No usable answer reached the harness (ERR). Counted as a did-not-finish.
qwen3-coder:30bBLANKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Predator Prey Simulation</title>
    <style>
        body { margin: 0; background: #111; display: flex; justify-content: center; align-items: center; min-height: 100vh; }
        canvas { border: 2px solid #333; background: #000; }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 800;
        canvas.height = 600;

        let food = [];
        let prey = [];
        let predators = [];
        let frameCount = 0;

        // --- Configuration Constants ---
        const FOOD_GROWTH_RATE = 15; // Per frame, how many new food patches appear
        const MAX_FOOD = 400;
        const PREY_MAX = 120;
        const PREDATOR_MAX = 30;

        const EAT_AMOUNT = 50;
        const ENERGY_LOSS = 0.05;

        // --- Objects/Classes (Simplified for brevity) ---

        class Food {
            constructor(x, y, size) {
                this.x = x;
                this.y = y;
                this.size = size;
                this.energy = 1;
            }
            draw() {
                ctx.fillStyle = 'rgba(70, 255, 70, 0.8)'; // Green food
                ctx.fillRect(this.x - this.size / 2, this.y - this.size / 2, this.size, this.size);
            }
        }

        class Agent {
            constructor(x, y, radius, color) {
                this.x = x;
                this.y = y;
                this.radius = radius;
                this.color = color;
                this.vx = (Math.random() - 0.5) * 1.5;
                this.vy = (Math.random() - 0.5) * 1.5;
                this.energy = Math.random() * 100 + 50;
            }

            update() {
                this.x += this.vx;
                this.y += this.vy;

                // Boundary checks
                if (this.x < 0 || this.x > canvas.width) { this.vx *= -1; this.x = Math.max(0, Math.min(canvas.width, this.x)); }
                if (this.y < 0 || this.y > canvas.height) { this.vy *= -1; this.y = Math.max(0, Math.min(canvas.height, this.y)); }

                // Energy loss
                this.energy -= ENERGY_LOSS;
            }

            draw() {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                ctx.fillStyle = this.color;
                ctx.fill();
            }
        }

        class Prey extends Agent {
            constructor(x, y) {
                super(x, y, 4, 'rgba(100, 100, 255, 0.8)'); // Blue prey
                this.moveTarget = null;
                this.acceleration = 0.1;
            }

            findNearestFood() {
                if (food.length === 0) return null;
                let minDistSq = Float32Array.prototype.includes(null);
                for(const f of food) {
                    const distSq = (this.x - f.x)**2 + (this.y - f.y)**2;
                    if (!minDistSq || distSq < minDistSq) {
                        minDistSq = distSq;
                        this.moveTarget = f;
                    }
                }
            }

            update() {
                let targetX, targetY;
                if (this.moveTarget) {
                    targetX = this.moveTarget.x;
                    targetY = this.moveTarget.y;
                } else {
                    // Wander if no food is nearby
                    this.vx += (Math.random() - 0.5) * 0.1;
                    this.vy += (Math.random() - 0.5) * 0.1;
                }

                let dx = targetX - this.x;
                let dy = targetY - this.y;
                let dist = Math.sqrt(dx*dx + dy*dy);

                if (dist < 3 || !this.moveTarget) { // Reached or no target
                    this.moveTarget = null;
                    this.vx += (Math.random() - 0.5) * 0.1;
                    this.vy += (Math.random() - 0.5) * 0.1;
                } else {
                    // Steer towards target
                    let angle = Math.atan2(dy, dx);
                    let desiredSpeed = 2; 
                    this.vx = Math.cos(angle) * desiredSpeed + (Math.random() - 0.5) * 0.1;
                    this.vy = Math.sin(angle) * desiredSpeed + (Math.random() - 0.5) * 0.1;
                }

                // Standard movement update
                super.update();

                // Check for food consumption
                for (let i = food.length - 1; i >= 0; i--) {
                    const f = food[i];
                    const d = Math.hypot(this.x - f.x, this.y - f.y);
                    if (d < f.size) {
                        this.energy = Math.min(150, this.energy + EAT_AMOUNT * 0.5);
                        food.splice(i, 1); // Remove eaten food
                        break;
                    }
                }

                // Reproduction
                if (this.energy > 200 && Math.random() < 0.02) {
                    this.energy -= 80;
                    prey.push(new Prey(this.x + Math.random()*5 - 2, this.y + Math.random()*5 - 2));
                }
            }
        }

        class Predator extends Agent {
            constructor(x, y) {
                super(x, y, 6, 'rgba(255, 100, 100, 0.9)'); // Red predator
                this.target = null;
                this.sightRangeSq = 400 * 400;
            }

            findNearestPrey() {
                let minDistSq = Infinity;
                let nearestIndex = -1;

                for (let i = 0; i < prey.length; i++) {
                    const p = prey[i];
                    const distSq = (this.x - p.x)**2 + (this.y - p.y)**2;

                    if (distSq < minDistSq && distSq < this.sightRangeSq) {
                        minDistSq = distSq;
                        nearestIndex = i;
                    }
                }
                this.target = nearestIndex !== -1 ? prey[nearestIndex] : null;
            }

            update() {
                let target = this.target;

                if (!target || (Math.random() < 0.01 && Math.hypot(this.x - target.x, this.y - target.y) > 60)) {
                    // Lose target or too far away, search for a new one
                    this.findNearestPrey();
                    target = this.target;
                }

                if (target) {
                    let dx = target.x - this.x;
                    let dy = target.y - this.y;
                    let distSq = dx*dx + dy*dy;

                    // If close enough, eat
                    if (distSq < 100) { // Close range for attack
                        this.energy = Math.min(300, this.energy + EAT_AMOUNT * 2);
                        prey.splice(prey.indexOf(target), 1);
                        this.target = null; // Must find new target after success
                    } else {
                        // Chase prey (Steer)
                        let angle = Math.atan2(dy, dx);
                        let desiredSpeed = 3;
                        this.vx = Math.cos(angle) * desiredSpeed + (Math.random() - 0.5) * 0.1;
                        this.vy = Math.sin(angle) * desiredSpeed + (Math.random() - 0.5) * 0.1;
                    }
                } else {
                     // Wander if no target
                    this.vx += (Math.random() - 0.5) * 0.05;
                    this.vy += (Math.random() - 0.5) * 0.05;
                }

                super.update();

                // Reproduction
                if (this.energy > 250 && Math.random() < 0.015) {
                    this.energy -= 100;
                    predators.push(new Predator(this.x + Math.random()*10 - 5, this.y + Math.random()*10 - 5));
                }

                // Death check (Starvation/Energy depletion)
                if (this.energy <= 0) {
                    return false; // Mark for removal
                }
                return true;
            }
        }


        // --- Simulation Management Functions ---

        function spawnFood() {
            let count = food.length;
            while (count < MAX_FOOD && Math.random() < 0.3) {
                const x = Math.random() * canvas.width;
                const y = Math.random() * canvas.height;
                food.push(new Food(x, y, 8));
                count++;
            }
        }

        function initializeSimulation() {
            prey = [];
            predators = [];
            food = [];
            frameCount = 0;

            // Initial populations
            for (let i = 0; i < 30; i++) {
                prey.push(new Prey(Math.random() * canvas.width, Math.random() * canvas.height));
            }
            for (let i = 0; i < 5; i++) {
                predators.push(new Predator(Math.random() * canvas.width, Math.random() * canvas.height));
            }
            for (let i = 0; i < 100; i++) {
                food.push(new Food(Math.random() * canvas.width, Math.random() * canvas.height, 8));
            }
        }

        function updateSimulation() {
            // 1. Spawn/Regrow Food
            spawnFood();

            // 2. Update Prey (Targeting food and reproducing)
            for (const p of prey) {
                p.findNearestFood();
                p.update();
            }
            prey = prey.filter(p => p.energy > -50); // Remove dead/stalled prey

            // 3. Update Predators (Targeting prey and reproducing)
            let nextPredators = [];
            for (const p of predators) {
                if (p.update()) {
                    nextPredators.push(p);
                }
            }
            predators = nextPredators;

            // 4. Check
deepseek-r1:32bERRBLANKMINIFIEDFORMAT
Show code
```html
<!DOCTYPE html><html><body style="background:#000;display:flex;flex-direction:column;height:100vh;margin:0;padding:0;">
<canvas id=c width=800 height=600></canvas>
<div id=pop style="color:white;font-family:sans-serif;padding:10px;">Prey: 0 Predators: 0</div><script>
class Food{constructor(x,y){this.x=x;this.y=y;this.energy=5}update(){if(this.energy<5)this.energy+=0.02}}class Prey{constructor(x,y){this.x=x;this.y=y;this.dir=Math.random()*Math.PI*2;this.energy=10;this.speed=3;this.size=8}update(foods,predators){let nearestFood=null,nearestDist=Infinity;foods.forEach(f=>{const dx=f.x-this.x,dx=f.y-this.y;let dist=Math.sqrt(dx*dx+dy*dy);if(dist<50&&dist<nearestDist){nearestFood=f;nearestDist=dist}});if(nearestFood){this.dir=Math.atan2(nearestFood.y-this.y,nearestFood.x-this.x)}this.x+=(Math.cos(this.dir)*this.speed)*(1/(1+predators.length/20));this.y+=(Math.sin(this.dir)*this.speed)*(1/(1+predators.length/20));if(this.x<0||this.x>800||this.y<0||this.y>600){this.energy-=5}else{foods.forEach(f=>{const dx=f.x-this.x,dy=f.y-this.y;let dist=Math.sqrt(dx*dx+dy*dy);if(dist<15){this.energy+=f.energy*f.energy/200;f.energy=0}})}this.energy-=0.5;if(this.energy>30&&Math.random()<0.02){preys.push(new Prey(this.x,this.y));this.energy-=10}return this.energy>0}draw(ctx){ctx.beginPath();ctx.arc(this.x,this.y,Math.max(4,this.size*(this.energy/30)),0,Math.PI*2);ctx.fillStyle='#FFD700';ctx.fill()}}class Predator{constructor(x,y){this.x=x;this.y=y;this.dir=0;this.energy=50;this.speed=2.5}update(preys){let nearestPrey=null,nearestDist=Infinity;preys.forEach(p=>{const dx=p.x-this.x,dy=p.y-this.y;let dist=Math.sqrt(dx*dx+dy*dy);if(dist<100&&dist<nearestDist){nearestPrey=p;nearestDist=dist}});if(nearestPrey){this.dir=Math.atan2(nearestPrey.y-this.y,nearestPrey.x-this.x)}else{this.dir+=Math.random()-0.5}this.x+=(Math.cos(this.dir)*this.speed)*(1/(1+preys.length/20));this.y+=(Math.sin(this.dir)*this.speed)*(1/(1+preys.length/20));if(this.x<0||this.x>800||this.y<0||this.y>600){this.energy-=5}preys.forEach(p=>{const dx=p.x-this.x,dy=p.y-this.y;let dist=Math.sqrt(dx*dx+dy*dy);if(dist<25&&this.energy<70){this.energy+=p.energy/2;p.energy=0}})this.energy-=0.3;if(this.energy>40&&Math.random()<0.015){predators.push(new Predator(this.x,this.y));this.energy-=10}return this.energy>0}draw(ctx){ctx.beginPath();ctx.arc(this.x,this.y,7,0,Math.PI*2);ctx.fillStyle='#FF0000';ctx.fill()}}let foods=[],preys=[],predators=[];function init(){foods.length=0;preys.length=0;predators.length=0;for(let i=0;i<50;i++)foods.push(new Food(Math.random()*800,Math.random()*600));for(let i=0;i<20;i++)preys.push(new Prey(Math.random()*800,Math.random()*600));for(let i=0;i<5;i++)predators.push(new Predator(Math.random()*800,Math.random()*600)}}function update(){foods.forEach(f=>f.update());preys=preys.filter(p=>p.update(foods,predators));predators=predators.filter(pd=>pd.update(preys));document.getElementById('pop').textContent=`Prey: ${preys.length} Predators: ${predators.length}`;if(preys.length<1||predators.length<1)init()}function draw(){const ctx=c.getContext('2d');ctx.fillStyle='#000';ctx.fillRect(0,0,800,600);foods.forEach(f=>{ctx.beginPath();ctx.arc(f.x,f.y,3,0,Math.PI*2);ctx.fillStyle=`hsl(${f.energy/5*180 + 90},70%,80%)`;ctx.fill()});preys.forEach(p=>p.draw(ctx));predators.forEach(pd=>pd.draw(ctx))}function animate(){update();draw();requestAnimationFrame(animate)}init();animate();
</script></body></html>
```
command-r:35bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Predators and Prey Simulation</title>
    <style>
        body { margin: 0; }
        canvas { border: 2px solid black; display: block; }
    </style>
</head>
<body>
    <canvas id="world"></canvas>
    <script>
        const WORLD = document.getElementById('world');
        const SIM = WORLD.getContext('2d');

        let FOOD, PREY, PREDATORS;
        let FOOD_GROWTH = 0.5; 
        let FOOD_SPEED = 1;
        let PREY_REPRODUCTION_RATE = 0.3;
        let PREDATOR_HUNGER_RATE = 0.8;
        let PREDATOR_SPEED = 2;

        const WORLD_WIDTH = WORLD.width = window.innerWidth; 
        const WORLD_HEIGHT = WORLD.height = window.innerHeight;

        function init() {
            FOOD = []; 
            PREY = []; 
            PREDATORS = []; 

            for (let i=0; i<WORLD_WIDTH*WORLD_HEIGHT/5000; i++) 
                FOOD.push({ x: Math.random()*WORLD_WIDTH, y: Math.random()*WORLD_HEIGHT });
            
            spawnPrey();
            spawnPredators(3);
        }

        function spawnPrey() { 
            for (let i=PREY.length; i<Math.min(FOOD.length/10, WORLD_WIDTH*WORLD_HEIGHT/2500) && PREY.length < 500; i++) 
                PREY.push({ x: FOOD[i].x - 30 + Math.random()*60, y: FOOD[i].y - 30 + Math.random()*60 });
        }

        function spawnPredators(n) {
            for (let i=PREDATORS.length; i<Math.min(PREY.length/10, n); i++) 
                PREDATORS.push({ x: Math.random() * WORLD_WIDTH, y: Math.random() * WORLD_HEIGHT });
        }

        function updateFood() { 
            FOOD = FOOD.map((f) => {
                f.x += (Math.random()-0.5)*FOOD_SPEED; 
                f.y += (Math.random()-0.5)*FOOD_SPEED; 
                if (f.x < 0 || f.x > WORLD_WIDTH || f.y < 0 || f.y > WORLD_HEIGHT)
                    return { x: Math.random()*WORLD_WIDTH, y: Math.random()*WORLD_HEIGHT };
                else 
                    return f;
            });

            for (let i=0; i<Math.round(PREY.length*FOOD_GROWTH); i++) 
                FOOD.push({ x: Math.random() * WORLD_WIDTH, y: Math.random() * WORLD_HEIGHT });
        }

        function updatePrey() {
            PREY = PREY.map((p) => {
                const targetFood = closest(FOOD, p); 

                p.x += (targetFood.x - p.x)*0.1; 
                p.y += (targetFood.y - p.y)*0.1;

                if (PREDATORS.some((pd) => distance(p, pd) < 30)) 
                    return null;
                else
                    return p;
            }).filter((p) => p !== null);

            for (let i=0; i<Math.round(PREY.length*PREY_REPRODUCTION_RATE); i++) 
                PREY.push({ x: PREY[i].x, y: PREY[i].y });
        }

        function updatePredators() {
            PREDATORS = PREDATORS.map((pd) => {
                const targetPrey = closest(PREY, pd); 

                if (targetPrey) { 
                    pd.x += (targetPrey.x - pd.x)*0.5;
                    pd.y += (targetPrey.y - pd.y)*0.5;
                } else {
                    pd.hunger += PREDATOR_HUNGER_RATE;
                }

                if (pd.hunger > 1) 
                    return null;
                else 
                    return pd;
            }).filter((p) => p !== null);

            for (let i=0; i<Math.round(PREDATORS.length*PREY_REPRODUCTION_RATE); i++) 
                spawnPredators(1);
        }

        function distance(a, b) { 
            return Math.sqrt(((a.x-b.x)**2)+((a.y-b.y)**2)); 
        }
        
        function closest(arr, obj) {
            let minDist = Infinity; 
            let closestObj = null;
            arr.forEach((o) => {
                const dist = distance(obj, o); 
                if (dist < minDist) {
                    minDist = dist; 
                    closestObj = o;
                }
            });

            return closestObj;
        }

        function update() {
            SIM.clearRect(0, 0, WORLD_WIDTH, WORLD_HEIGHT); 

            FOOD.forEach((f) => drawCircle(f.x, f.y, 5, 'lime')); 
            PREY.forEach((p) => drawCircle(p.x, p.y, 4, 'blueviolet')); 
            PREDATORS.forEach((pd) => {
                SIM.fillStyle = pd.hunger > 1 ? '#f00' : '#ff7'; 
                drawCircle(pd.x, pd.y, 8, SIM.fillStyle);
            });

            updateFood(); 
            updatePrey(); 
            spawnPrey(); 
            updatePredators(); 

            requestAnimationFrame(update);
        }

        function drawCircle(x, y, r, color) { 
            SIM.beginPath(); 
            SIM.arc(x, y, r, 0, Math.PI*2, false); 
            SIM.fillStyle = color; 
            SIM.fill(); 
        }

        init(); 
        requestAnimationFrame(update);
    </script>
</body>
</html>
```
qwq:32bOKFORMAT
Show code
<think>

Okay, I need to create a self-contained HTML file that simulates predators and prey on a canvas. Let me start by understanding the requirements. The user wants prey to graze on regrowing food, multiply where food is plentiful, predators to chase nearby prey, eat them, lose energy over time, and multiply when well-fed. The populations should oscillate, and I have to show both counts. The animation should use requestAnimationFrame, no user input, starts immediately, and restarts when finished. No external libraries, and the code must be under 7000 characters.

First, I'll set up the basic HTML structure with a canvas element. I'll need a head section with a title and a body with the canvas. The canvas will be the main area for the simulation.

Next, the JavaScript part. I'll start by getting the canvas context and setting up some constants. The canvas size can be set to 800x600 for visibility. I'll define the colors for food (green), prey (blue), predators (red). The food should regrow over time, so maybe a grid where each cell has a food value that increases over time up to a max, but is eaten by prey.

For the entities (prey and predators), I'll create objects with properties like position, energy, and maybe direction or velocity. Prey should move randomly, eat food, gain energy, and reproduce when energy is high enough. Predators need to seek prey, move towards them, eat them to gain energy, and reproduce when energy is sufficient.

The food grid can be a 2D array. Each cell's food value decreases when prey are nearby, and increases over time. The prey and predators will check their position to affect the food.

The animation loop will involve updating each entity's position, energy, interactions with food and each other, then redrawing everything. Each tick, the food regrows slightly. Prey and predators are moved and checked for energy levels. If they run out of energy, they die. Reproduction happens when energy reaches a threshold.

I need to manage the populations. Arrays for prey and predators. When an entity dies, remove it from the array.繁殖时,创造一个新个体并添加到数组中。

Drawing: Clear the canvas each frame, draw food, then prey and predators. The food can be small dots or rectangles. Maybe using ctx.fillStyle and small circles for each food cell. Prey and predators can be circles with different colors and sizes based on energy levels?

Population counts are displayed in the canvas as text. Maybe at the top left corner, updating each frame.

The restart functionality: when the simulation ends (maybe when both populations die out?), reset everything. But how to detect that? Perhaps check if the prey and predator arrays are empty for several frames, then trigger a restart. Or maybe after a certain time period? Hmm, maybe set a flag and restart automatically when the populations are low enough?

Wait, the user said to restart when finished, so I need to determine when to restart. Maybe when the prey and predator populations reach zero. But that might not happen. Alternatively, set a timer for a fixed period and restart. Hmm, perhaps after a certain number of frames or when the populations have been decreasing for a while. Alternatively, to simplify, just restart the simulation after a fixed period of time, say 10,000 frames (~2 minutes if 60 FPS). Or when the population counts go below a certain threshold for a while?

Alternatively, to make it restart automatically when both populations die, but that might not happen unless predators overhunt or prey overgraze. So perhaps the system will oscillate, but eventually might stabilize? Maybe the best approach is to restart after a certain number of frames. Let's think of setting a frame counter, and after 5000 frames (around 83 seconds at 60fps), restart. That should give enough time for the oscillations to be seen.

For the initial setup, randomize the starting positions and energy levels of prey and predators. Maybe start with some initial counts, say 50 prey and 10 predators, and 0.1 initial food in each cell.

Now, code structure:

- Canvas setup
- Variables for food grid, prey array, predator array, frame counter
- Functions:
   - drawFood()
   - drawEntities()
   - updateFood()
   - updatePrey()
   - updatePredators()
   - checkRestart()
   - reset()

The main loop function (using requestAnimationFrame) will handle all updates and drawing.

Food grid: Maybe a 2D array with the same dimensions as the canvas divided by a cell size. Let's say each cell is 10x10 pixels, so 80x60 cells for an 800x600 canvas. So foodGrid[80][60].

Each frame, for each cell, food increases by a small amount (like 0.1 per frame) up to a max (like 5). When prey are nearby, they consume food, so the cell's food decreases by some factor (maybe 0.5 per prey in that cell, but need to distribute properly).

Wait, maybe each prey consumes food from the cell it is in. So each prey's current cell (determined by their position) has its food reduced by some amount (like 0.5 per prey per frame). Similarly, when a prey eats, it gains energy.

Predators don't eat food but prey. So when a predator is near a prey, it can chase them, and when they catch them, the prey's energy is transferred to the predator, and the prey dies.

Hmm, collision detection between predators and prey. Predators move towards the nearest prey. To find nearby prey, maybe each predator checks all prey within a certain radius (like 20 pixels) and moves towards the closest one.

Movement: Prey move in a random direction each frame, but with some randomness to their direction. Predators have a direction towards the nearest prey.

Energy management: Prey lose a small amount of energy each frame, but gain from eating. If their energy drops to zero, they die. Predators lose energy faster (since they have to move more?) and gain energy by eating prey.

Reproduction: When an entity's energy reaches a high enough threshold (like 100), they split into two, creating a new entity with half the energy, and the original keeps some.

Now, coding steps:

Initialize the food grid with foodGrid = Array(80).fill().map(() => Array(60).fill(0.1));

Wait, actually, in JavaScript, to create a 2D array, need to use loops. Maybe:

const foodWidth = 80; // Canvas width / 10
const foodHeight = 60; // Canvas height /10
const foodGrid = [];
for (let x = 0; x < foodWidth; x++) {
    foodGrid[x] = [];
    for (let y = 0; y < foodHeight; y++) {
        foodGrid[x][y] = 0.1;
    }
}

But this might be slow in the loop. Alternatively, during setup, but need to do it in the code.

For entities, prey and predators can be objects with x, y coordinates (floats?), energy, direction (angle?), or velocity components.

Alternatively, to simplify, each prey has a velocity vector that is updated each frame with some randomness. Maybe:

Prey:
- x, y (position)
- vx, vy (velocity components)
- energy: number

Predators similarly, but their velocity is influenced by nearest prey.

For prey movement:

Each prey's direction is slightly randomized. Maybe each frame, their velocity is adjusted by a small random angle and speed. Or their velocity is a vector that is rotated randomly each frame.

Alternatively, each prey's direction is a random angle each frame with some persistence.

Hmm, maybe for prey:

prey.vx += (Math.random() * 2 - 1) * 0.1;
prey.vy += (Math.random() * 2 - 1) * 0.1;
Then normalize their speed to a certain maximum.

Predators:

For each predator, find the closest prey within a certain radius. If found, calculate the direction towards it and move towards it. Otherwise, wander randomly.

The radius could be 50 pixels. So for each predator, loop through all prey and find the closest one within 50 pixels.

Once a prey is within reach (distance < some threshold, like 5), the predator eats it. The predator gains energy, the prey dies.

Drawing:

For food, each cell's food value can be represented by the brightness of green. So, the higher the food, the greener it is. Each cell is a rectangle of 10x10 pixels. So:

ctx.fillStyle = `rgb(0, ${food * 50}, 0)`;
ctx.fillRect(x*10, y*10, 10, 10);

Wait, but 0.1 to 5 would give 0-250, but maybe clamp the color to 0-255. So if food is up to 5, multiply by 51 to get 5*51=255.

Alternatively, use a scale like (food * 50). So maximum food of 5 gives 250, which is okay.

Drawing prey and predators as circles. Prey could be blue circles, predators red. Maybe the size scales with energy? Not sure. Alternatively, fixed size, but color brightness varies with energy. Or just a fixed size.

Prey could be drawn with:

ctx.fillStyle = 'blue';
ctx.beginPath();
ctx.arc(x, y, 2, 0, Math.PI*2);
ctx.fill();

Predators as red with maybe slightly bigger radius (3px?)

Now, the steps in the animation loop:

1. Update the food grid:

For each cell, add a small amount (e.g., 0.1) to the food, up to a max (e.g., 5). Then, subtract any consumption from prey in that cell.

Wait, how to model consumption: each prey in a cell reduces the cell's food. So for each prey, determine which cell they're in (x_cell = Math.floor(x / 10), y_cell = Math.floor(y /10)), then subtract 0.5 per prey in that cell? Or maybe accumulate all prey in each cell and subtract accordingly.

Alternatively, for each prey:

let cellX = Math.floor(prey.x / 10);
let cellY = Math.floor(prey.y / 10);
foodGrid[cellX][cellY] = Math.max(0, foodGrid[cellX][cellY] - 0.5);

But if multiple prey are in the same cell, this would subtract 0.5 per prey. But this might be computationally expensive for many prey. Alternatively, for each cell, track how much prey are consuming, but that might be complex.

Alternatively, each prey consumes 0.5 per frame from their current cell. So during the prey update step:

for each prey in preys {
  let x = prey.x, y = prey.y;
  let cellX = Math.floor(x / 10);
  let cellY = Math.floor(y /10);
  if (foodGrid[cellX][cellY] > 0) {
    prey.energy += 0.5; // gain energy from food
    foodGrid[cellX][cellY] = Math.max(0, foodGrid[cellX][cellY] - 0.5);
  }
}

Wait, but that's per prey. So if two prey are in the same cell, they each subtract 0.5, reducing the food by 1.0.

But then the prey gains energy from the food. Maybe 1 unit of food gives 0.5 energy? Or just the prey gains energy equal to the food consumed. Hmm, need to balance the energy levels.

Alternatively, prey eat food in their cell. For each prey, the food in their cell is decreased by 0.1, and prey gains 0.1 energy (assuming food is a resource). But this might need to be adjusted.

The prey's energy decreases over time, so each frame, prey lose some energy (like 0.1) and gain from food.

Predators lose more energy (maybe 0.2 per frame?) and gain energy by eating prey.

Predator eating:

When a predator catches a prey, the predator gains the prey's energy, and the prey is removed.

Predator movement towards prey:

For each predator, find the closest prey within a certain distance. Then move towards that prey.

The code for finding the closest prey:

let closest = null;
let closestDist = Infinity;
for (let i=0; i<preys.length; i++) {
  let p = preys[i];
  let dx = p.x - pred.x;
  let dy = p.y - pred.y;
  let dist = dx*dx + dy*dy;
  if (dist < closestDist && dist < 2500) { // 50^2
    closestDist = dist;
    closest = p;
  }
}
if (closest) {
  // move towards closest
  let dx = closest.x - pred.x;
  let dy = closest.y - pred.y;
  let dist = Math.sqrt(dx*dx + dy*dy);
  if (dist < 5) { // within 5 pixels, eat
    pred.energy += closest.energy;
    // remove the prey
    preys.splice(i, 1);
  } else {
    // adjust velocity towards prey
    pred.vx += dx / dist * 0.1;
    pred.vy += dy / dist * 0.1;
  }
} else {
  // wander
  pred.vx += (Math.random() * 2 -1)*0.1;
  pred.vy += (Math.random() * 2 -1)*0.1;
}

Wait, but looping through preys each time could be slow if there are many preys and predators. Maybe optimize later.

Now, for the reproduction:

When an entity's energy exceeds a threshold, it splits into two. For prey, say when energy >= 100, they can reproduce. When they do, create a new prey with half the energy, subtract 50 from the original.

Similarly for predators, but maybe higher threshold (150?), so they reproduce less often.

The reproduction could be checked each frame:

for (let prey of preys) {
  if (prey.energy >= 100) {
    let newPrey = { ...prey };
    newPrey.x += Math.random() * 10 -5; // offset to spread
    newPrey.y += Math.random() * 10 -5;
    newPrey.energy = prey.energy / 2;
    preys.push(newPrey);
    prey.energy = newPrey.energy;
  }
}

Wait, but maybe better to have a random direction offset. Alternatively, split energy and then push the new prey.

But this needs to be coded efficiently.

Now putting all together.

Variables:

const canvas = document.getElementById('sim');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;

Constants:

const CELL_SIZE = 10;
const FOOD_WIDTH = 80; // 800/10
const FOOD_HEIGHT = 60; // 600/10
const MAX_FOOD = 5;

const MAX_PREY_ENERGY = 100;
const MAX_PREDATOR_ENERGY = 150;

const FOOD_GROWTH_RATE = 0.1;

let foodGrid = Array(FOOD_WIDTH).fill().map(() => Array(FOOD_HEIGHT).fill(0.1));

// Initialize prey and predators
let preys = [];
let predators = [];

// Frame counter for restart
let frameCount = 0;

// Functions
function reset() {
  foodGrid.forEach((row, x) => {
    row.forEach((_, y) => {
      foodGrid[x][y] = 0.1;
    });
  });
  preys = [];
  predators = [];
  // Initialize with some starting entities
  for (let i=0; i<50; i++) {
    preys.push({
      x: Math.random() * 800,
      y: Math.random() * 600,
      vx: (Math.random() * 2 - 1)*2,
      vy: (Math.random() * 2 - 1)*2,
      energy: 50
    });
  }
  for (let i=0; i<10; i++) {
    predators.push({
      x: Math.random() * 800,
      y: Math.random() * 600,
      vx: 0,
      vy: 0,
      energy: 75
    });
  }
  frameCount = 0;
}

function drawFood() {
  ctx.fillStyle = '#008000';
  for (let x=0; x<FOOD_WIDTH; x++) {
    for (let y=0; y<FOOD_HEIGHT; y++) {
      let food = foodGrid[x][y];
      ctx.fillStyle = `rgb(0, ${food * 50}, 0)`;
      ctx.fillRect(x*10, y*10, 10, 10);
    }
  }
}

function drawEntities() {
  ctx.fillStyle = 'blue';
  preys.forEach(p => {
    ctx.beginPath();
    ctx.arc(p.x, p.y, 2, 0, Math.PI*2);
    ctx.fill();
  });
  ctx.fillStyle = 'red';
  predators.forEach(pred => {
    ctx.beginPath();
    ctx.arc(pred.x, pred.y, 3, 0, Math.PI*2);
    ctx.fill();
  });
}

function updateFood() {
  for (let x=0; x<FOOD_WIDTH; x++) {
    for (let y=0; y<FOOD_HEIGHT; y++) {
      foodGrid[x][y] = Math.min(MAX_FOOD, foodGrid[x][y] + FOOD_GROWTH_RATE);
    }
  }
}

function updatePrey() {
  for (let i=0; i<preys.length; i++) {
    let p = preys[i];
    // Calculate cell
    let cellX = Math.floor(p.x / 10);
    let cellY = Math.floor(p.y / 10);
    // Consume food
    if (foodGrid[cellX][cellY] > 0) {
      p.energy += 0.5;
      foodGrid[cellX][cellY] = Math.max(0, foodGrid[cellX][cellY] - 0.5);
    }
    // Lose energy
    p.energy -= 0.1;
    // Move
    p.x += p.vx;
    p.y += p.vy;
    // Bounce off edges
    if (p.x < 0 || p.x > 800) p.vx *= -0.5;
    if (p.y < 0 || p.y > 600) p.vy *= -0.5;
    // Random movement
    p.vx += (Math.random() * 2 -1)*0.1;
    p.vy += (Math.random() * 2 -1)*0.1;
    // Reproduce
    if (p.energy >= MAX_PREY_ENERGY) {
      let newPrey = {...p};
      newPrey.x += Math.random() * 10 -5;
      newPrey.y += Math.random() * 10 -5;
      newPrey.energy = p.energy / 2;
      // Add new prey
      preys.push(newPrey);
      p.energy = newPrey.energy;
    }
    // Remove if energy too low
    if (p.energy <= 0) {
      preys.splice(i, 1);
      i--;
    }
  }
}

function updatePredators() {
  for (let i=0; i<predators.length; i++) {
    let pred = predators[i];
    // Lose energy
    pred.energy -= 0.2;
    // Find prey
    let closest = null;
    let closestDist = Infinity;
    for (let j=0; j<preys.length; j++) {
      let p = preys[j];
      let dx = p.x - pred.x;
      let dy = p.y - pred.y;
      let dist_sq = dx*dx + dy*dy;
      if (dist_sq < closestDist && dist_sq < 2500) { // within 50 units
        closestDist = dist_sq;
        closest = p;
      }
    }
    if (closest) {
      let dx = closest.x - pred.x;
      let dy = closest.y - pred.y;
      let dist = Math.sqrt(closestDist);
      // Move towards
      pred.vx += dx / dist * 0.3;
      pred.vy += dy / dist * 0.3;
      // If close enough, eat
      if (dist < 5) { // within 5 units
        pred.energy += closest.energy;
        // Remove prey
        preys.splice(j, 1); // but need correct index
        // Wait, need j here, but loop is over predators
        // Hmm, this might be tricky, perhaps need to track j
        let preyIndex = preys.indexOf(closest);
        if (preyIndex > -1) {
          preys.splice(preyIndex, 1);
        }
      }
    } else {
      // Wander
      pred.vx += (Math.random() - 0.5) * 0.2;
      pred.vy += (Math.random() - 0.5) * 0.2;
    }
    // Move
    pred.x += pred.vx;
    pred.y += pred.vy;
    // Bounce edges
    if (pred.x < 0 || pred.x > 800) pred.vx *= -0.5;
    if (pred.y < 0 || pred.y > 600) pred.vy *= -0.5;
    // Reproduce
    if (pred.energy >= MAX_PREDATOR_ENERGY) {
      let newPred = {...pred};
      newPred.x += Math.random() * 10 -5;
      newPred.y += Math.random() * 10 -5;
      newPred.energy = pred.energy / 2;
      predators.push(newPred);
      pred.energy = newPred.energy;
    }
    // Remove if energy too low
    if (pred.energy <=0 ) {
      predators.splice(i, 1);
      i--;
    }
  }
}

function drawStats() {
  ctx.fillStyle = 'white';
  ctx.fillText(`Prey: ${preys.length} Predators: ${predators.length}`, 10, 20);
}

function animate() {
  ctx.clearRect(0,0,800,600);
  updateFood();
  updatePrey();
  updatePredators();
  drawFood();
  drawEntities();
  drawStats();
  
  frameCount++;
  if (frameCount > 5000) reset(); // Arbitrary high number for demo

  requestAnimationFrame(animate);
}

reset();
animate();

Wait, but in the predator update function, when eating, the prey is spliced, but the index j was from the preys array. Since we're inside a loop over predators[i], and j is over preys[j], when removing preys[j], the indices shift. Maybe better to find the index and remove.

Alternatively, in code:

if (dist <5) {
  pred.energy += closest.energy;
  let index = preys.indexOf(closest);
  if (index != -1) preys.splice(index,1);
}

This is safer.

Testing this code, but in the initial setup.

Now, possible issues:

1. The predator's velocity might accumulate too much, making them move too fast. The 0.3 multiplier might be too large.

2. The energy consumption and reproduction thresholds may need tuning.

3. The foodGrid is initialized with 0.1, which might be too low, causing prey to starve quickly.

4. The prey and predators may not have enough initial energy.

Potential adjustments:

- Increase MAX_FOOD to 10, so food can be more abundant.

- Lower the energy consumption rates. Maybe prey lose 0.05 per frame instead of 0.1.

- Let predators lose 0.1 instead of 0.2.

- Start prey with higher energy, like 75 instead of 50.

- Reproduction energy thresholds: 150 for prey, 200 for predators.

Also, in the prey movement:

The vx and vy are added with random, but maybe better to apply a small random nudge each frame.

Testing this, but since we need to present the code, proceed with the current structure.

Now, packaging all this into a complete HTML file with <canvas>:

Here's the code:

```html
<!DOCTYPE html>
<html>
<body>
<canvas id="sim" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('sim');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 600;

const CELL_SIZE = 10;
const FOOD_WIDTH = 80; // 800/10
const FOOD_HEIGHT = 60; // 600/10
const MAX_FOOD = 5;

const MAX_PREY_ENERGY = 100;
const MAX_PREDATOR_ENERGY = 150;

const FOOD_GROWTH_RATE = 0.1;

let foodGrid = Array(FOOD_WIDTH).fill().map(() => Array(FOOD_HEIGHT).fill(0.1));

let preys = [];
let predators = [];
let frameCount = 0;

function reset() {
  foodGrid.forEach((row, x) => {
    row.forEach((_, y) => {
      foodGrid[x][y] = 0.1;
    });
  });
  preys = [];
  predators = [];
  for (let i=0; i<50; i++) {
    preys.push({
      x: Math.random() * 800,
      y: Math.random() * 600,
      vx: (Math.random() * 2 - 1)*2,
      vy: (Math.random() * 2 - 1)*2,
      energy: 50
    });
  }
  for (let i=0; i<10; i++) {
    predators.push({
      x: Math.random() * 800,
      y: Math.random() * 600,
      vx: 0,
      vy: 0,
      energy: 75
    });
  }
  frameCount = 0;
}

function drawFood() {
  ctx.fillStyle = '#008000';
  for (let x=0; x<FOOD_WIDTH; x++) {
    for (let y=0; y<FOOD_HEIGHT; y++) {
      let food = foodGrid[x][y];
      ctx.fillStyle = `rgb(0, ${food * 50}, 0)`;
      ctx.fillRect(x*10, y*10, 10, 10);
    }
  }
}

function drawEntities() {
  ctx.fillStyle = 'blue';
  preys.forEach(p => {
    ctx.beginPath();
    ctx.arc(p.x, p.y, 2, 0, Math.PI*2);
    ctx.fill();
  });
  ctx.fillStyle = 'red';
  predators.forEach(pred => {
    ctx.beginPath();
    ctx.arc(pred.x, pred.y, 3, 0, Math.PI*2);
    ctx.fill();
  });
}

function updateFood() {
  for (let x=0; x<FOOD_WIDTH; x++) {
    for (let y=0; y<FOOD_HEIGHT; y++) {
      foodGrid[x][y] = Math.min(MAX_FOOD, foodGrid[x][y] + FOOD_GROWTH_RATE);
    }
  }
}

function updatePrey() {
  for (let i = preys.length - 1; i >= 0; i--) {
    const p = preys[i];
    const xCell = Math.floor(p.x / CELL_SIZE);
    const yCell = Math.floor(p.y / CELL_SIZE);
    let foodAtCell = foodGrid[xCell] ? foodGrid[xCell][yCell] : 0;
    
    if (foodAtCell > 0) {
      p.energy += 0.5;
      foodGrid[xCell][yCell] = Math.max(0, foodAtCell - 0.5);
    }
    
    p.energy -= 0.1;
    p.x += p.vx;
    p.y += p.vy;
    
    // Bounce off edges
    if (p.x < 0 || p.x > 800) p.vx *= -0.5;
    if (p.y < 0 || p.y > 600) p.vy *= -0.5;
    
    // Random movement
    p.vx += (Math.random() - 0.5) * 0.2;
    p.vy += (Math.random() - 0.5) * 0.2;
    
    // Reproduction
    if (p.energy >= MAX_PREY_ENERGY) {
      const newPrey = { ...p };
      newPrey.x += Math.random() * 10 - 5;
      newPrey.y += Math.random() * 10 - 5;
      newPrey.energy = p.energy / 2;
      preys.push(newPrey);
      p.energy = newPrey.energy;
    }
    
    // Remove if energy too low
    if (p.energy <= 0) {
      preys.splice(i, 1);
    }
  }
}

function updatePredators() {
  for (let i = predators.length - 1; i >= 0; i--) {
    const pred = predators[i];
    pred.energy -= 0.2;
    
    let closestPrey = null;
    let closestDist = Infinity;
    
    for (const p of preys) {
      const dx = p.x - pred.x;
      const dy = p.y - pred.y;
      const distSq = dx * dx + dy * dy;
      if (distSq < closestDist && distSq < 2500) {
        closestDist = distSq;
        closestPrey = p;
      }
    }
    
    if (closestPrey) {
      const dx = closestPrey.x - pred.x;
      const dy = closestPrey.y - pred.y;
      const dist = Math.sqrt(closestDist);
      pred.vx += dx / dist * 0.3;
      pred.vy += dy / dist * 0.3;
      
      if (dist < 5) {
        pred.energy += closestPrey.energy;
        const preyIndex = preys.indexOf(closestPrey);
        if (preyIndex !== -1) {
          preys.splice(preyIndex, 1);
        }
      }
    } else {
      pred.vx += (Math.random() - 0.5) * 0.2;
      pred.vy += (Math.random() - 0.5) * 0.2;
    }
    
    pred.x += pred.vx;
    pred.y += pred.vy;
    
    // Bounce edges
    if (pred.x < 0 || pred.x > 800) pred.vx *= -0.5;
    if (pred.y < 0 || pred.y > 600) pred.vy *= -0.5;
    
    // Reproduction
    if (pred.energy >= MAX_PREDATOR_ENERGY) {
      const newPred = { ...pred };
      newPred.x += Math.random() * 10 - 5;
      newPred.y += Math.random() * 10 - 5;
      newPred.energy = pred.energy / 2;
      predators.push(newPred);
      pred.energy = newPred.energy;
    }
    
    // Remove if energy too low
    if (pred.energy <= 0) {
      predators.splice(i, 1);
    }
  }
}

function drawStats() {
  ctx.fillStyle = 'white';
  ctx.fillText(`Prey: ${preys.length} Predators: ${predators.length}`, 10, 20);
}

function animate() {
  ctx.clearRect(0, 0, 800, 600);
  updateFood();
  updatePrey();
  updatePredators();
  drawFood();
  drawEntities();
  drawStats();
  frameCount++;
  if (frameCount > 5000) reset();
  requestAnimationFrame(animate);
}

reset();
animate();
</script>
</body>
</html>
```

This should create an ecosystem simulation with prey and predators, food cells, and basic behavior like movement, energy consumption, reproduction, and predation. The stats are displayed in the top-left corner. Users can observe how the populations interact over time.
Outside the Brain cluster — same task, same character budget, collected through their own tooling (response times not comparable)
Show code
<!doctype html><html><head><meta charset=utf-8><title>Predator Prey</title><style>html,body{margin:0;height:100%;overflow:hidden;background:#111;color:#eee;font:16px system-ui}canvas{display:block}#p{position:fixed;left:12px;top:10px;background:#0008;padding:8px 10px;border-radius:6px}</style></head><body><canvas id=c></canvas><div id=p></div><script>
let c=document.getElementById("c"),x=c.getContext("2d"),p=document.getElementById("p"),W,H,G=36,gw,gh,food,prey,pred,t=0;
function R(n){return Math.random()*n}
function S(){W=c.width=innerWidth;H=c.height=innerHeight;gw=Math.ceil(W/G);gh=Math.ceil(H/G)}
onresize=S;S();
function start(){food=Array(gw*gh).fill(0).map(_=>.25+R(.7));prey=[];pred=[];for(let i=0;i<70;i++)prey.push({x:R(W),y:R(H),e:9+R(5),a:R(7)});for(let i=0;i<18;i++)pred.push({x:R(W),y:R(H),e:28+R(10),a:R(7)})}
function wrap(o){if(o.x<0)o.x+=W;if(o.x>W)o.x-=W;if(o.y<0)o.y+=H;if(o.y>H)o.y-=H}
function step(){
 t++;
 for(let i=0;i<food.length;i++)food[i]=Math.min(1,food[i]+.0028);
 for(let q of prey){
  let gx=Math.max(0,Math.min(gw-1,q.x/G|0)),gy=Math.max(0,Math.min(gh-1,q.y/G|0)),best=gy*gw+gx,b=food[best];
  for(let yy=-1;yy<2;yy++)for(let xx=-1;xx<2;xx++){let nx=gx+xx,ny=gy+yy;if(nx>=0&&ny>=0&&nx<gw&&ny<gh){let k=ny*gw+nx;if(food[k]>b){b=food[k];best=k}}}
  let tx=(best%gw+.5)*G,ty=((best/gw|0)+.5)*G,dx=tx-q.x,dy=ty-q.y,d=Math.hypot(dx,dy)||1;
  q.a+=R(.6)-.3;q.x+=dx/d*.45+Math.cos(q.a)*.7;q.y+=dy/d*.45+Math.sin(q.a)*.7;wrap(q);
  let k=(Math.min(gh-1,q.y/G|0))*gw+Math.min(gw-1,q.x/G|0),eat=Math.min(food[k],.035);food[k]-=eat;q.e+=eat*20-.028;
  if(q.e>16&&food[k]>.45&&prey.length<420){q.e*=.55;prey.push({x:q.x+R(20)-10,y:q.y+R(20)-10,e:q.e,a:R(7)})}
 }
 prey=prey.filter(q=>q.e>0);
 for(let r of pred){
  let n=null,bd=150;
  for(let q of prey){let dx=q.x-r.x,dy=q.y-r.y,d=Math.hypot(dx,dy);if(d<bd){bd=d;n=q}}
  if(n){let dx=n.x-r.x,dy=n.y-r.y,d=Math.hypot(dx,dy)||1;r.x+=dx/d*2.25;r.y+=dy/d*2.25;if(d<7){n.e=-1;r.e+=18}}
  else{r.a+=R(.7)-.35;r.x+=Math.cos(r.a)*1.4;r.y+=Math.sin(r.a)*1.4}
  r.e-=.082;wrap(r);
  if(r.e>55&&pred.length<120){r.e*=.55;pred.push({x:r.x+R(30)-15,y:r.y+R(30)-15,e:r.e,a:R(7)})}
 }
 prey=prey.filter(q=>q.e>0);pred=pred.filter(r=>r.e>0);
 if(t>900&&(prey.length<4||pred.length<2||prey.length>390))start()
}
function draw(){
 x.fillStyle="#111";x.fillRect(0,0,W,H);
 for(let y=0;y<gh;y++)for(let z=0;z<gw;z++){let f=food[y*gw+z];if(f>.08){x.fillStyle="rgba(70,170,70,"+(f*.55)+")";x.fillRect(z*G,y*G,G,G)}}
 x.fillStyle="#58c7ff";for(let q of prey){x.beginPath();x.arc(q.x,q.y,3.1,0,7);x.fill()}
 x.fillStyle="#ff5a4d";for(let r of pred){x.beginPath();x.moveTo(r.x+6,r.y);x.lineTo(r.x-5,r.y-4);x.lineTo(r.x-5,r.y+4);x.fill()}
 p.textContent="Prey: "+prey.length+"  Predators: "+pred.length
}
function loop(){step();draw();requestAnimationFrame(loop)}
start();loop();
</script></body></html>
Show code
<!DOCTYPE html><html><head><meta charset="utf-8"><title>Predator-Prey</title><style>html,body{margin:0;overflow:hidden;background:#0b1210}canvas{display:block}</style></head><body><canvas id="c"></canvas><script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d');
let W,H,cols,rows,cell=14,food,prey,pred;
function initSim(){
W=cv.width=innerWidth;H=cv.height=innerHeight;
cols=Math.floor(W/cell);rows=Math.floor(H/cell);
food=new Float32Array(cols*rows);
for(let i=0;i<food.length;i++)food[i]=Math.random();
prey=[];pred=[];
for(let i=0;i<130;i++)prey.push({x:Math.random()*W,y:Math.random()*H,vx:0,vy:0,e:50});
for(let i=0;i<18;i++)pred.push({x:Math.random()*W,y:Math.random()*H,vx:0,vy:0,e:80});
}
initSim();
function fIdx(x,y){let cx=Math.min(cols-1,Math.max(0,(x/cell)|0));let cy=Math.min(rows-1,Math.max(0,(y/cell)|0));return cy*cols+cx;}
function step(){
for(let i=0;i<food.length;i++)food[i]=Math.min(1,food[i]+0.0016);
for(let p of prey){
let fx=0,fy=0;
for(let q of pred){let dx=p.x-q.x,dy=p.y-q.y,d2=dx*dx+dy*dy;if(d2<7000){let d=Math.sqrt(d2)||1;fx+=dx/d;fy+=dy/d;}}
p.vx+=(Math.random()-0.5)*0.6+fx*0.9;
p.vy+=(Math.random()-0.5)*0.6+fy*0.9;
let sp=Math.hypot(p.vx,p.vy);if(sp>1.6){p.vx=p.vx/sp*1.6;p.vy=p.vy/sp*1.6;}
p.x+=p.vx;p.y+=p.vy;
if(p.x<0)p.x+=W;if(p.x>=W)p.x-=W;if(p.y<0)p.y+=H;if(p.y>=H)p.y-=H;
let fi=fIdx(p.x,p.y);
if(food[fi]>0.2){let g=food[fi]*0.5;p.e+=g*20;food[fi]-=g;}
p.e-=0.15;
}
prey=prey.filter(p=>p.e>0);
let babies=[];
for(let p of prey)if(p.e>140&&prey.length+babies.length<320){p.e*=0.5;babies.push({x:p.x,y:p.y,vx:0,vy:0,e:p.e});}
prey.push(...babies);
for(let q of pred){
let target=null,best=1e9;
for(let p of prey){if(p.dead)continue;let dx=p.x-q.x,dy=p.y-q.y,d2=dx*dx+dy*dy;if(d2<best){best=d2;target=p;}}
if(target){
let dx=target.x-q.x,dy=target.y-q.y,d=Math.hypot(dx,dy)||1;
q.vx+=(dx/d)*0.55;q.vy+=(dy/d)*0.55;
if(d<11){target.dead=true;q.e+=42;}
}else{q.vx+=(Math.random()-0.5)*0.5;q.vy+=(Math.random()-0.5)*0.5;}
let sp=Math.hypot(q.vx,q.vy);if(sp>2.1){q.vx=q.vx/sp*2.1;q.vy=q.vy/sp*2.1;}
q.x+=q.vx;q.y+=q.vy;
if(q.x<0)q.x+=W;if(q.x>=W)q.x-=W;if(q.y<0)q.y+=H;if(q.y>=H)q.y-=H;
q.e-=0.26;
}
prey=prey.filter(p=>!p.dead);
pred=pred.filter(q=>q.e>0);
let pbabies=[];
for(let q of pred)if(q.e>160&&pred.length+pbabies.length<100){q.e*=0.5;pbabies.push({x:q.x,y:q.y,vx:0,vy:0,e:q.e});}
pred.push(...pbabies);
}
function draw(){
ctx.fillStyle='#0b1210';ctx.fillRect(0,0,W,H);
for(let y=0;y<rows;y++)for(let x=0;x<cols;x++){let f=food[y*cols+x];if(f>0.06){ctx.fillStyle='rgba(60,200,90,'+(f*0.5)+')';ctx.fillRect(x*cell,y*cell,cell,cell);}}
ctx.fillStyle='#3fa9ff';for(let p of prey){ctx.beginPath();ctx.arc(p.x,p.y,3,0,7);ctx.fill();}
ctx.fillStyle='#ff4d4d';for(let q of pred){ctx.beginPath();ctx.arc(q.x,q.y,5,0,7);ctx.fill();}
ctx.fillStyle='#fff';ctx.font='16px monospace';
ctx.fillText('Prey: '+prey.length,14,24);
ctx.fillText('Predators: '+pred.length,14,44);
}
function loop(){
step();draw();
if(prey.length===0||pred.length===0)initSim();
requestAnimationFrame(loop);
}
loop();
</script></body></html>
Show code
<!DOCTYPE html><html><head><meta charset="utf-8"><title>Predator-Prey</title><style>html,body{margin:0;background:#000;height:100%;overflow:hidden}canvas{position:absolute;inset:0;width:100vw;height:100vh}#h{position:fixed;top:8px;left:10px;color:#fff;font:13px monospace;z-index:1;text-shadow:0 0 4px #000}</style></head><body><canvas id="c"></canvas><div id="h"></div><script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d'),hud=document.getElementById('h');
const W=480,H=320;cv.width=W;cv.height=H;
const CS=8,GW=W/CS,GH=H/CS;
let food,prey,pred,step;
const rnd=(a,b)=>a+Math.random()*(b-a);
function reset(){food=new Float32Array(GW*GH);
for(let i=0;i<food.length;i++)food[i]=Math.random();
prey=[];pred=[];
for(let i=0;i<160;i++)prey.push({x:rnd(0,W),y:rnd(0,H),a:rnd(0,6.28),e:rnd(4,8)});
for(let i=0;i<16;i++)pred.push({x:rnd(0,W),y:rnd(0,H),a:rnd(0,6.28),e:rnd(8,14)});
step=0;}
reset();
function cell(x,y){return ((y/CS)|0)*GW+((x/CS)|0);}
function frame(){
for(let i=0;i<food.length;i++)food[i]=Math.min(1,food[i]+0.0022);
for(const p of prey){
p.a+=rnd(-0.35,0.35);
p.x=(p.x+Math.cos(p.a)*1.2+W)%W;p.y=(p.y+Math.sin(p.a)*1.2+H)%H;
const c=cell(p.x,p.y),eat=Math.min(food[c],0.09);
food[c]-=eat;p.e+=eat*6-0.05;
if(p.e>10&&prey.length<700&&Math.random()<0.05){p.e/=2;prey.push({x:p.x,y:p.y,a:rnd(0,6.28),e:p.e});}}
for(const q of pred){
let best=null,bd=90*90;
for(const p of prey){if(p.dead)continue;
const dx=p.x-q.x,dy=p.y-q.y,d=dx*dx+dy*dy;
if(d<bd){bd=d;best=p;}}
if(best){const ta=Math.atan2(best.y-q.y,best.x-q.x);
let da=ta-q.a;da=Math.atan2(Math.sin(da),Math.cos(da));
q.a+=Math.max(-0.3,Math.min(0.3,da));
if(bd<49){best.dead=true;q.e+=7;}}
else q.a+=rnd(-0.3,0.3);
q.x=(q.x+Math.cos(q.a)*1.7+W)%W;q.y=(q.y+Math.sin(q.a)*1.7+H)%H;
q.e-=0.065;
if(q.e>22&&pred.length<150&&Math.random()<0.04){q.e/=2;pred.push({x:q.x,y:q.y,a:rnd(0,6.28),e:q.e});}}
prey=prey.filter(p=>!p.dead&&p.e>0);
pred=pred.filter(q=>q.e>0);
ctx.fillStyle='#020402';ctx.fillRect(0,0,W,H);
for(let gy=0;gy<GH;gy++)for(let gx=0;gx<GW;gx++){
const f=food[gy*GW+gx];
if(f>0.05){ctx.fillStyle='rgb(0,'+((20+f*110)|0)+',12)';ctx.fillRect(gx*CS,gy*CS,CS,CS);}}
ctx.fillStyle='#5cf';
for(const p of prey)ctx.fillRect(p.x-1.5,p.y-1.5,3,3);
ctx.fillStyle='#f43';
for(const q of pred)ctx.fillRect(q.x-2.5,q.y-2.5,5,5);
step++;
hud.textContent='prey: '+prey.length+'   predators: '+pred.length+'   step: '+step;
if(prey.length===0||pred.length===0||step>9000)reset();
requestAnimationFrame(frame);}
frame();
</script></body></html>
Show code
<!DOCTYPE html><html><head><title>Predator Prey</title></head><body style="margin:0;background:#000;display:flex;justify-content:center;align-items:center;height:100vh"><canvas id="c"></canvas><div id="i" style="position:absolute;top:10px;left:10px;color:#0f0;font-family:mono;font-size:10px"></div><script>
const c=document.getElementById('c'),x=c.getContext('2d'),i=document.getElementById('i');c.width=c.height=400;
let pr=[],pd=[],gr=[];for(let j=0;j<300;j++){pr.push({x:Math.random()*400,y:Math.random()*400,e:50});}for(let j=0;j<50;j++){pd.push({x:Math.random()*400,y:Math.random()*400,e:100});}for(let j=0;j<500;j++){gr.push({x:Math.random()*400,y:Math.random()*400});}
function d(){x.fillStyle='#1a3a1a';x.fillRect(0,0,400,400);for(let g of gr){x.fillStyle='#0a0';x.fillRect(g.x-2,g.y-2,4,4);}if(Math.random()<0.01){gr.push({x:Math.random()*400,y:Math.random()*400});}for(let p of pr){p.e-=0.1;p.x+=Math.random()*2-1;p.y+=Math.random()*2-1;p.x=Math.max(0,Math.min(400,p.x));p.y=Math.max(0,Math.min(400,p.y));for(let j=0;j<gr.length;j++){if(Math.hypot(p.x-gr[j].x,p.y-gr[j].y)<5){p.e+=10;gr.splice(j,1);break;}}if(Math.random()<0.01&&p.e>60){pr.push({x:p.x+Math.random()*10-5,y:p.y+Math.random()*10-5,e:40});}}pr=pr.filter(x=>x.e>0);for(let p of pd){p.e-=0.2;p.x+=Math.random()*3-1.5;p.y+=Math.random()*3-1.5;p.x=Math.max(0,Math.min(400,p.x));p.y=Math.max(0,Math.min(400,p.y));for(let j=0;j<pr.length;j++){if(Math.hypot(p.x-pr[j].x,p.y-pr[j].y)<8){p.e+=30;pr.splice(j,1);break;}}if(Math.random()<0.01&&p.e>120){pd.push({x:p.x+Math.random()*10-5,y:p.y+Math.random()*10-5,e:80});}}pd=pd.filter(x=>x.e>0);x.fillStyle='#080';for(let p of pr)x.fillRect(p.x-3,p.y-3,6,6);x.fillStyle='#f00';for(let p of pd)x.fillRect(p.x-4,p.y-4,8,8);i.textContent=`Prey: ${pr.length} | Predators: ${pd.length}`;}(function a(){d();requestAnimationFrame(a);})();
</script></body></html>
Results at a glance— every model in this round with score, response time and status.

Who wrote what

ModelBlind scoreLatencyStatus
qwen3:14b 69.4 sOK
gemma4:26b harness
qwen3.5:9b 69.5 sOK
qwen3:8b harness
llama3.1:8b 24.9 sOK
mistral-small:24b 82.9 sOK
deepseek-r1:14b DNF
qwen3-coder:30b 38.6 sOK
deepseek-r1:32b 150.9 sOK
command-r:35b 36.6 sOK
qwq:32b 232.6 sOK