OverviewCode › R164
Code · blind round

R164 · Boids flocking with separation, alignment, cohesion and a predator

blind round 9/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.

1 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 about 60 boids on a <canvas>, each drawn as a small triangle pointing in its current direction of travel, governed by the three classic flocking rules acting together every frame: separation (steer away from boids that are too close), alignment (steer toward the average heading of nearby boids) and cohesion (steer toward the average position of nearby boids), with boids wrapping around when they cross a screen edge. Add one additional point that wanders slowly and randomly around the screen acting as a predator: any boid that senses it within a moderate radius adds a strong steering force away from it on top of the three flocking rules, so nearby flocks visibly scatter and swerve around the predator before regrouping once it has moved on. Draw the predator as a clearly distinct marker so it stands out from the boids. Show the current boid count. 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.5:9bOKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Boids Simulation</title>
    <style>body {margin:0;overflow:hidden;background:#111}canvas {display:block;border:1px solid #333;}</style>
</head>
<body>

<canvas id="boidCanvas"></canvas>

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

let W, H;
let NUM_BOIDS = 60;
let MAX_SPEED = 3;
let NEIGHBOR_RADIUS = 50;
let SEPARATION_DISTANCE = 15;
let COHESION_WEIGHT = 1.0;
let ALIGNMENT_WEIGHT = 1.0;
let SEPARATION_WEIGHT = 2.0;

class Vector {
    constructor(x, y) {
        this.x = x || 0;
        this.y = y || 0;
    }
    add(v) { return new Vector(this.x + v.x, this.y + v.y); }
    sub(v) { return new Vector(this.x - v.x, this.y - v.y); }
    mult(s) { return new Vector(this.x * s, this.y * s); }
    magSq() { return this.x * this.x + this.y * this.y; }
    mag() { return Math.sqrt(this.magSq()); }
    normalize() {
        const m = this.mag();
        return m > 0 ? this.mult(1 / m) : new Vector(0, 0);
    }
    limit(max) {
        if (this.magSq() > max * max) {
            const ratio = max / Math.sqrt(this.magSq());
            return this.mult(ratio);
        }
        return this;
    }
    set(x, y) { this.x = x; this.y = y; return this; }
}

class Boid {
    constructor(x, y) {
        this.pos = new Vector(x, y);
        this.vel = new Vector((Math.random() - 0.5) * 2, (Math.random() - 0.5) * 2);
        this.acc = new Vector(0, 0);
    }

    applyForce(force) {
        this.acc = this.acc.add(force);
    }

    steer(target, strength) {
        let desired = target.sub(this.pos).normalize();
        desired = desired.mult(MAX_SPEED);
        let steer = desired.sub(this.vel);
        steer = steer.limit(strength);
        return steer;
    }

    flock(boids, predator) {
        this.acc = new Vector(0, 0);

        // 1. Separation (Avoid crowding nearby boids)
        let separation = this.separate(boids).mult(SEPARATION_WEIGHT);
        this.applyForce(separation);

        // 2. Alignment (Steer toward average heading)
        let alignment = this.align(boids).mult(ALIGNMENT_WEIGHT);
        this.applyForce(alignment);

        // 3. Cohesion (Steer toward center of mass)
        let cohesion = this.cohere(boids).mult(COHESION_WEIGHT);
        this.applyForce(cohesion);
        
        // Predator avoidance force
        if (predator) {
            let predatorAvoidance = this.avoidPredator(predator).mult(3.0); // Stronger force
            this.applyForce(predatorAvoidance);
        }
    }

    separate(boids) {
        let separationVector = new Vector(0, 0);
        let count = 0;

        for (const other of boids) {
            if (other === this) continue;
            let d = this.pos.sub(other.pos).mag();
            if (d < SEPARATION_DISTANCE && d > 0) {
                let diff = this.pos.sub(other.pos);
                diff = diff.normalize().mult(1 / d); // Weight inversely proportional to distance
                separationVector = separationVector.add(diff);
                count++;
            }
        }

        if (count > 0) {
            separationVector = separationVector.mult(1 / count).normalize().mult(MAX_SPEED);
        }
        return separationVector;
    }

    align(boids) {
        let avgVelocity = new Vector(0, 0);
        let count = 0;

        for (const other of boids) {
            if (other === this) continue;
            let d = this.pos.sub(other.pos).mag();
            if (d < NEIGHBOR_RADIUS && d > 0) {
                avgVelocity = avgVelocity.add(other.vel);
                count++;
            }
        }

        if (count > 0) {
            let average = avgVelocity.mult(1 / count).normalize().mult(MAX_SPEED);
            return this.steer(average, 0.0); // Use strength 0.0 as desired force is already normalized/limited by MAX_SPEED
        }
        return new Vector(0, 0);
    }

    cohere(boids) {
        let centerOfMass = new Vector(0, 0);
        let count = 0;

        for (const other of boids) {
            if (other === this) continue;
            let d = this.pos.sub(other.pos).mag();
            if (d < NEIGHBOR_RADIUS && d > 0) {
                centerOfMass = centerOfMass.add(other.pos);
                count++;
            }
        }

        if (count > 0) {
            let averagePos = centerOfMass.mult(1 / count).normalize().mult(MAX_SPEED);
            return this.steer(averagePos, 0.0);
        }
        return new Vector(0, 0);
    }

    avoidPredator(pred) {
        let d = this.pos.sub(pred.pos).mag();
        if (d < NEIGHBOR_RADIUS * 1.5 && d > 0) { // Larger radius for predator
            let diff = this.pos.sub(pred.pos).normalize();
            return diff; // Direct vector away from the predator
        }
        return new Vector(0, 0);
    }

    update() {
        this.vel = this.vel.add(this.acc);
        this.acc = new Vector(0, 0);
        
        // Apply drag to prevent infinite speed buildup
        this.vel = this.vel.mult(0.98); 

        this.pos = this.pos.add(this.vel);

        // Wrapping logic
        if (this.pos.x < 0) this.pos.x += W;
        else if (this.pos.x > W) this.pos.x -= W;
        if (this.pos.y < 0) this.pos.y += H;
        else if (this.pos.y > H) this.pos.y -= H;
    }

    draw() {
        ctx.fillStyle = 'cyan';
        ctx.save();
        ctx.translate(this.pos.x, this.pos.y);
        ctx.rotate(Math.atan2(this.vel.y, this.vel.x));
        ctx.beginPath();
        ctx.moveTo(10, 0); // Tip of the triangle
        ctx.lineTo(-10, -8); // Bottom left
        ctx.lineTo(-10, 8); // Bottom right
        ctx.closePath();
        ctx.fill();
        ctx.restore();
    }
}

class Predator {
    constructor() {
        this.pos = new Vector(Math.random() * W, Math.random() * H);
        this.speed = 1.5;
        this.targetX = this.pos.x + (Math.random() - 0.5) * W * 0.8;
        this.targetY = this.pos.y + (Math.random() - 0.5) * H * 0.8;
    }

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

        if (dist < 5) {
            this.targetX = this.pos.x + (Math.random() - 0.5) * W * 1.6;
            this.targetY = this.pos.y + (Math.random() - 0.5) * H * 1.6;
        }

        let angle = Math.atan2(dy, dx);
        this.pos.x += Math.cos(angle) * this.speed;
        this.pos.y += Math.sin(angle) * this.speed;

        // Wrapping logic for predator too
        if (this.pos.x < 0) this.pos.x += W;
        else if (this.pos.x > W) this.pos.x -= W;
        if (this.pos.y < 0) this.pos.y += H;
        else if (this.pos.y > H) this.pos.y -= H;
    }

    draw() {
        ctx.fillStyle = 'red';
        ctx.beginPath();
        ctx.arc(this.pos.x, this.pos.y, 8, 0, Math.PI * 2);
        ctx.fill();
    }
}


let boids = [];
let predator = new Predator();

function init() {
    W = canvas.width = window.innerWidth * 0.8;
    H = canvas.height = window.innerHeight * 0.9;
    
    if (boids.length === 0) {
        boids = [];
        for (let i = 0; i < NUM_BOIDS; i++) {
            boids.push(new Boid(Math.random() * W, Math.random() * H));
        }
    }
}

function loop() {
    // Clear canvas and draw background
    ctx.fillStyle = 'rgba(17, 17, 17, 0.3)'; // Slight trail effect
    ctx.fillRect(0, 0, W, H);
    
    predator.update();
    boids.forEach(b => b.update());

    // Flocking and Predator logic
    boids.forEach(b => b.flock(boids, predator));

    // Drawing phase
    ctx.globalAlpha = 0.9; // Slightly transparent drawing for trails
    for (let i = 0; i < boids.length; i++) {
        boids[i].draw();
    }
    ctx.globalAlpha = 1.0;

    predator.draw();

    // Display count
    const countDisplay = document.getElementById('boidCount');
    if (countDisplay) {
        countDisplay.textContent = `Boids: ${boids.length}`;
    } else {
        let div = document.createElement('div');
        div.id = 'boidCount';
        div.style.position = 'absolute';
        div.style.top = '10px';
        div.style.left = '10px';
        div.style.color = '#AAA';
        document.body.appendChild(div);
    }

    requestAnimationFrame(loop);
}

window.addEventListener('resize', () => {
    init();
});

// Initial setup and start
init();
loop();
</script>
<div id="boidCount" style="position: fixed; top: 10px; left: 10px; color: #AAA;">Boids: ${NUM_BOIDS}</div>

</body>
</html>
```
llama3.1:8bERRBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head>
<style>
#c { border: 1px solid black; }
</style>
</head>
<body>
<canvas id='c' width=800 height=600></canvas>
<script>
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');

// constants
var NUM_BOIDS = 60;
var PREDATOR_RADIUS = 20;

// boid properties
function Boid(x, y) {
  this.x = x || Math.floor(Math.random() * (canvas.width - 10));
  this.y = y || Math.floor(Math.random() * (canvas.height - 10));
  this.velX = Math.random()*2-1;
  this.velY = Math.random()*2-1;
}

// predator properties
function Predator(x, y) {
  this.x = x || Math.floor(Math.random() * (canvas.width - PREDATOR_RADIUS*2));
  this.y = y || Math.floor(Math.random() * (canvas.height - PREDATOR_RADIUS*2));
  this.velX = Math.random()*0.5-0.25;
  this.velY = Math.random()*0.5-0.25;
}

// flock properties
function Flock(boids) {
  this.boids = boids || [];
}

Flock.prototype.count = function() { return this.boids.length; }

Boid.prototype.display = function(ctx) {
  ctx.save();
  ctx.translate(this.x, this.y);
  ctx.rotate(Math.atan2(this.velY,this.velX));
  ctx.beginPath();
  ctx.moveTo(-5, -3);
  ctx.lineTo(0,-1);
  ctx.lineTo(5, -3);
  ctx.stroke();
  ctx.restore();
}

Boid.prototype.update = function(flock) {
  this.x += this.velX;
  this.y += this.velY;

  var closeBoids = flock.boids.filter(function(boid){
    return boid !== this && Math.hypot(this.x-boid.x,this.y-boid.y)<10
  }.bind(this));

  if (closeBoids.length) {
    var avgVelX = closeBoids.reduce(function(sum,boid){return sum+boid.velX},0)/closeBoids.length;
    var avgVelY = closeBoids.reduce(function(sum,boid){return sum+boid.velY},0)/closeBoids.length;

    this.velX += (avgVelX-this.velX)*0.1;
    this.velY += (avgVelY-this.velY)*0.1;
  }

  if (!closeBoids.length || Math.hypot(this.x-closeBoids[0].x,this.y-closeBoids[0].y)>10) {
    var targetX = closeBoids.reduce(function(sum,boid){return sum+boid.x},0)/closeBoids.length;
    var targetY = closeBoids.reduce(function(sum,boid){return sum+boid.y},0)/closeBoids.length;

    this.velX += (targetX-this.x)*0.01;
    this.velY += (targetY-this.y)*0.01;
  }

  if (Math.hypot(this.x+this.velX*10,this.y+this.velY*10)>canvas.width || Math.hypot(this.x-10,this.y+this.velY*10)>canvas.height || Math.hypot(this.x-10,this.y-this.velY*10)>canvas.height)
    this.x =canvas.width/2, this.y=canvas.height/2;

  var predator = flock.predator;
  if (Math.hypot(this.x-predator.x,PREDATOR_RADIUS,this.y-predator.y,PREDATOR_RADIUS)<PREDATOR_RADIUS) {
    var avgVelX = closeBoids.reduce(function(sum,boid){return sum+boid.velX},0)/closeBoids.length;
    var avgVelY = closeBoids.reduce(function(sum,boid){return sum+boid.velY},0)/closeBoids.length;

    this.velX += (avgVelX-this.velX)*-0.1;
    this.velY += (avgVelY-this.velY)*-0.1;
  }
}

Predator.prototype.display = function(ctx) {
  ctx.save();
  ctx.fillStyle="red";
  ctx.beginPath();
  ctx.arc(this.x,this.y,PREDATOR_RADIUS,0,2*Math.PI);
  ctx.fill();
  ctx.restore();
}

function draw(flock) {
  canvas.width=canvas.offsetWidth;
  canvas.height=canvas.offsetHeight;

  ctx.clearRect(0,0,canvas.width,canvas.height);

  flock.boids.forEach(function(boid){
    boid.update(flock);
    boid.display(ctx);
  });

  flock.predator.update();
  flock.predator.display(ctx);

  ctx.font="12px Arial";
  ctx.fillStyle="#000";
  ctx.textAlign="left";
  ctx.textBaseline="top";
  ctx.fillText("Boids: "+flock.count(),10,10);
}

function init() {
  var boids = new Array(NUM_BOIDS).fill(0).map(function(){return new Boid()});
  var predator = new Predator();
  var flock = new Flock({boids:boids,predator:predator});
  (function animloop(){
    draw(flock);
    requestAnimationFrame(animloop)
  })();
}

init()

</script>
</body>
</html>
```
qwen3-coder:30bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>Flocking Simulation</title></head><body style="margin:0;background:#000;"><canvas id="c"></canvas><script>
const c = document.getElementById('c');
const ctx = c.getContext('2d');
let W, H;
let boids = [];
let predator = { x: 0, y: 0, vx: 0, vy: 0 };

function init() {
    W = window.innerWidth * 0.95;
    H = window.innerHeight * 0.85;
    c.width = W;
    c.height = H;
    boids = [];
    for (let i = 0; i < 60; i++) {
        boids.push({ x: Math.random() * W, y: Math.random() * H, vx: Math.cos(Math.random() * Math.PI) * 1 + 0.5, vy: Math.sin(Math.random() * Math.PI) * 1 + 0.5, maxForce: 1, maxSpeed: 2, sepWeight: 1.5, alignWeight: 1.0, cohWeight: 1.0 });
    }
    predator = { x: W / 2, y: H / 2, vx: (Math.random() - 0.5) * 0.1, vy: (Math.random() - 0.5) * 0.1 };
}

function limit(v, max) { return Math.min(Math.max(v, -max), max); }
function distSq(x1, y1, x2, y2) { return (x1-x2)**2 + (y1-y2)**2; }

const N = 60; // Number of boids
const SEPARATION_RADIUS = 35;
const NEIGHBOR_RADIUS = 80;
const PREDATOR_RADIUS = 150;
const STEERING_FORCE = 0.05;


function wrap(v, max) { return v > max ? v - max * 2 : (v < -max ? v + max * 2 : v); }

function applyForce(boid, fX, fY) {
    boid.vx += fX;
    boid.vy += fY;
}

function getSteer(currentVX, currentVY, targetVX, targetVY) {
    let dx = targetVX - currentVX;
    let dy = targetVY - currentVY;
    return Math.sqrt(dx*dx + dy*dy);
}

function calculateFlockForce(boid, allBoids, rule) {
    let totalX = 0, totalY = 0, count = 0;
    const maxSepDistSq = SEPARATION_RADIUS * SEPARATION_RADIUS;
    const neighborLimitSq = NEIGHBOR_RADIUS * NEIGHBOR_RADIUS;

    for (const other of allBoids) {
        if (boid === other) continue;
        let dSq = distSq(boid.x, boid.y, other.x, other.y);
        if (rule === 'separation' && dSq < maxSepDistSq) {
            let dx = boid.x - other.x;
            let dy = boid.y - other.y;
            let dist = Math.sqrt(dSq);
            let strength = 1 / dist;
            totalX += (dx / dist) * strength;
            totalY += (dy / dist) * strength;
        } else if ((rule === 'alignment' || rule === 'cohesion') && dSq < neighborLimitSq) {
            totalX += other.vx;
            totalY += other.vy;
            count++;
        }
    }

    let forceX = 0, forceY = 0;

    if (rule === 'separation') {
        let avgForce = Math.sqrt(totalX*totalX + totalY*totalY) / SEPARATION_RADIUS;
        return { x: totalX * boid.sepWeight, y: totalY * boid.sepWeight };
    } else if (rule === 'alignment' && count > 0) {
        let avgVX = totalX / count;
        let avgVY = totalY / count;
        return { x: avgVX - boid.vx, y: avgVY - boid.vy };
    } else if (rule === 'cohesion' && count > 0) {
        let center = { x: totalX / count, y: totalY / count };
        // Steering towards the average position
        return { x: (center.x - boid.x), y: (center.y - boid.y) };
    }
    return { x: 0, y: 0 };
}

function applyPredatorForce(boid) {
    let dSq = distSq(boid.x, boid.y, predator.x, predator.y);
    if (dSq < PREDATOR_RADIUS * PREDATOR_RADIUS && dSq > 50) {
        let dx = boid.x - predator.x;
        let dy = boid.y - predator.y;
        let dist = Math.sqrt(dSq);
        // Strong repulsion force inverse to distance squared
        let strength = (PREDATOR_RADIUS*PREDATOR_RADIUS / dSq) * 0.5;

        return { x: dx * strength, y: dy * strength };
    }
    return { x: 0, y: 0 };
}


function update() {
    // Update Predator position
    predator.x += predator.vx;
    predator.y += predator.vy;

    if (Math.random() < 0.01) { // Random change in velocity direction
        predator.vx += (Math.random() - 0.5) * 0.02;
        predator.vy += (Math.random() - 0.5) * 0.02;
    }

    // Keep predator within bounds
    if (predator.x < 0 || predator.x > W) { predator.vx *= -1; }
    if (predator.y < 0 || predator.y > H) { predator.vy *= -1; }


    for (let i = 0; i < N; i++) {
        const boid = boids[i];

        // Accumulate forces: Separation + Alignment + Cohesion
        let fx = calculateFlockForce(boid, boids, 'separation').x;
        let fy = calculateFlockForce(boid, boids, 'separation').y;
        let fA = calculateFlockForce(boid, boids, 'alignment');
        let fB = calculateFlockForce(boid, boids, 'cohesion');

        fx += fA.x * 0.5 + fB.x * 0.8;
        fy += fA.y * 0.5 + fB.y * 0.8;

        // Add Predator force (strong repulsion)
        let pForce = applyPredatorForce(boid);
        fx += pForce.x * 1.2;
        fy += pForce.y * 1.2;


        // Apply the total steering force and limit speed
        let newVX = boid.vx + fx * STEERING_FORCE;
        let newVY = boid.vy + fy * STEERING_FORCE;

        boid.vx = limit(newVX, boid.maxSpeed);
        boid.vy = limit(newVY, boid.maxSpeed);


        // Update position with wrapping logic
        boid.x += boid.vx;
        if (boid.x < 0) boid.x += W; else if (boid.x > W) boid.x -= W;

        boid.y += boid.vy;
        if (boid.y < 0) boid.y += H; else if (boid.y > H) boid.y -= H;
    }
}


function draw() {
    ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
    ctx.fillRect(0, 0, W, H);

    // Draw Boids
    for (const boid of boids) {
        let angle = Math.atan2(boid.vy, boid.vx);
        let size = 3;

        ctx.fillStyle = '#4CAF50';
        ctx.beginPath();
        ctx.moveTo(boid.x + size * Math.cos(angle - Math.PI / 6), boid.y + size * Math.sin(angle - Math.PI / 6));
        ctx.lineTo(boid.x + size * (Math.cos(angle) + 0.5) * Math.cos(angle - Math.PI / 6), boid.y + size * (Math.sin(angle) + 0.5) * Math.sin(angle - Math.PI / 6));
        ctx.lineTo(boid.x + size * Math.cos(angle + Math.PI / 6), boid.y + size * Math.sin(angle + Math.PI / 6));
        ctx.closePath();
        ctx.fill();
    }

    // Draw Predator (Red circle)
    ctx.fillStyle = '#FF0000';
    ctx.beginPath();
    ctx.arc(predator.x, predator.y, 5, 0, Math.PI * 2);
    ctx.fill();

    // Display Boid count
    ctx.fillStyle = '#FFF';
    ctx.font = '14px sans-serif';
    ctx.fillText(`Boids: ${boids.length}`, 10, 20);
}

function loop() {
    update();
    draw();
    requestAnimationFrame(loop);
}

window.addEventListener('resize', () => {
    W = window.innerWidth * 0.95;
    H = window.innerHeight * 0.85;
    c.width = W;
    c.height = H;
});

init();
loop();
</script></body></html>
```
gemma4:26bharness
No answer reached us (ERR) — 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.
mistral-small:24bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Boids Simulation</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="boidCanvas"></canvas>
<script>
const canvas = document.getElementById('boidCanvas');
const ctx = canvas.getContext('2d');
const boids = [];
const predator = { x: Math.random() * canvas.width, y: Math.random() * canvas.height };
const predatorRadius = 50;
let boidCount = 60;

canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

function Boid(x, y) {
    this.x = x;
    this.y = y;
    this.vx = (Math.random() - 0.5) * 2;
    this.vy = (Math.random() - 0.5) * 2;
    this.maxSpeed = 2;
    this.perceptionRadius = 50;

    this.update = function() {
        const sep = this.separate(boids);
        const ali = this.align(boids);
        const coh = this.cohere(boids);
        const pred = this.flee(predator);

        this.vx += (sep.x + ali.x + coh.x + pred.x) * 0.1;
        this.vy += (sep.y + ali.y + coh.y + pred.y) * 0.1;

        if (this.vx > this.maxSpeed) this.vx = this.maxSpeed;
        else if (this.vx < -this.maxSpeed) this.vx = -this.maxSpeed;
        if (this.vy > this.maxSpeed) this.vy = this.maxSpeed;
        else if (this.vy < -this.maxSpeed) this.vy = -this.maxSpeed;

        this.x += this.vx;
        this.y += this.vy;

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

    this.separate = function(boids) {
        let sepX = 0, sepY = 0;
        const dist = this.perceptionRadius / 2;
        boids.forEach(b => {
            const dx = b.x - this.x;
            const dy = b.y - this.y;
            const d = Math.sqrt(dx * dx + dy * dy);
            if (d < dist && d > 0) {
                sepX += dx / d;
                sepY += dy / d;
            }
        });
        return { x: sepX, y: sepY };
    }

    this.align = function(boids) {
        let avgVx = 0, avgVy = 0;
        boids.forEach(b => {
            if (this != b && Math.sqrt(Math.pow(b.x - this.x, 2) + Math.pow(b.y - this.y, 2)) < this.perceptionRadius) {
                avgVx += b.vx;
                avgVy += b.vy;
            }
        });
        const count = boids.length - (this != null ? 1 : 0);
        return { x: avgVx / count, y: avgVy / count };
    }

    this.cohere = function(boids) {
        let avgX = 0, avgY = 0;
        boids.forEach(b => {
            if (this != b && Math.sqrt(Math.pow(b.x - this.x, 2) + Math.pow(b.y - this.y, 2)) < this.perceptionRadius) {
                avgX += b.x;
                avgY += b.y;
            }
        });
        const count = boids.length - (this != null ? 1 : 0);
        return { x: (avgX / count) - this.x, y: (avgY / count) - this.y };
    }

    this.flee = function(predator) {
        if (Math.sqrt(Math.pow(predator.x - this.x, 2) + Math.pow(predator.y - this.y, 2)) < predatorRadius * 3) {
            const dx = this.x - predator.x;
            const dy = this.y - predator.y;
            return { x: dx / predatorRadius, y: dy / predatorRadius };
        }
        return { x: 0, y: 0 };
    }

    this.draw = function() {
        ctx.beginPath();
        ctx.moveTo(this.x, this.y);
        const angle = Math.atan2(this.vy, this.vx);
        const dx = Math.cos(angle) * 10;
        const dy = Math.sin(angle) * 10;
        ctx.lineTo(this.x + dx, this.y + dy);
        ctx.lineTo(this.x - dy, this.y + dx);
        ctx.closePath();
        ctx.fillStyle = 'blue';
        ctx.fill();
    }
}

for (let i = 0; i < boidCount; i++) {
    boids.push(new Boid(Math.random() * canvas.width, Math.random() * canvas.height));
}

function updatePredator() {
    predator.x += (Math.random() - 0.5) * 2;
    predator.y += (Math.random() - 0.5) * 2;

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

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    boids.forEach(b => b.update());
    boids.forEach(b => b.draw());

    ctx.beginPath();
    ctx.arc(predator.x, predator.y, predatorRadius / 2, 0, Math.PI * 2);
    ctx.fillStyle = 'red';
    ctx.fill();

    updatePredator();
}

function animate() {
    draw();
    requestAnimationFrame(animate);
}

function restartSimulation() {
    boids.length = 0;
    for (let i = 0; i < boidCount; i++) {
        boids.push(new Boid(Math.random() * canvas.width, Math.random() * canvas.height));
    }
    animate();
}

canvas.addEventListener('click', restartSimulation);
animate();
</script>
</body>
</html>
```
qwen3:8bERRBLANKMINIFIED
Show code
<!DOCTYPE html><html><body><canvas id=c></canvas><div id=cnt>60</div><script>const c=document.getElementById('c'),ctx=c.getContext('2d'),w=c.width=800,h=c.height=600;let boids=[],predator={x:Math.random()*w,y:Math.random()*h,vx:0,vy:0},cnt=60;function init(){for(let i=0;i<cnt;i++)boids.push({x:Math.random()*w,y:Math.random()*h,vx:Math.random()*2-1,vy:Math.random()*2-1,heading:Math.atan2(vy,vx)})}function update(){predator.vx+=(Math.random()*0.01-0.005);predator.vy+=(Math.random()*0.01-0.005);predator.x+=predator.vx;predator.y+=predator.vy;predator.x=(predator.x%w+w)%w;predator.y=(predator.y%h+h)%h;for(let b of boids){let steer={x:0,y:0},sep={x:0,y:0},align={x:0,y:0},cohesion={x:0,y:0},pred={x:0,y:0},neighborCount=0;for(let other of boids){let dx=other.x-b.x,dy=other.y-b.y,dist=Math.hypot(dx,dy);if(dist<50&&dist>0){neighborCount++;let force={x:-dx/dist,y:-dy/dist};force.x/=dist;force.y/=dist;sep.x+=force.x;sep.y+=force.y;align.x+=other.vx;align.y+=other.vy;cohesion.x+=other.x;cohesion.y+=other.y}}if(neighborCount>0){sep.x/=neighborCount;sep.y/=neighborCount;align.x/=neighborCount;align.y/=neighborCount;align.x/=0.01;align.y/=0.01;cohesion.x/=neighborCount;cohesion.y/=neighborCount;cohesion.x-=b.x;cohesion.y-=b.y}let pdist=Math.hypot(predator.x-b.x,predator.y-b.y);if(pdist<100){let force={x:predator.x-b.x,y:predator.y-b.y};force.x/=pdist;force.y/=pdist;force.x*=-10;force.y*=-10;steer.x+=force.x;steer.y+=force.y}steer.x+=sep.x+align.x+cohesion.x;steer.y+=sep.y+align.y+cohesion.y;let mag=Math.hypot(steer.x,steer.y);if(mag>1){steer.x/=mag;steer.y/=mag}b.vx+=steer.x;b.vy+=steer.y;mag=Math.hypot(b.vx,b.vy);if(mag>2){b.vx/=mag;b.vy/=mag}b.x+=b.vx;b.y+=b.vy;b.x=(b.x%w+w)%w;b.y=(b.y%h+h)%h;b.heading=Math.atan2(b.vy,b.vx)}}}function draw(){ctx.clearRect(0,0,w,h);ctx.fillStyle='red';ctx.beginPath();ctx.arc(predator.x,predator.y,10,0,Math.PI*2);ctx.fill();ctx.fillStyle='black';for(let b of boids){ctx.save();ctx.translate(b.x,b.y);ctx.rotate(b.heading);ctx.beginPath();ctx.moveTo(0,-5);ctx.lineTo(-3,3);ctx.lineTo(3,3);ctx.closePath();ctx.fill();ctx.restore()}document.getElementById('cnt').textContent=cnt;requestAnimationFrame(draw)}init();draw();</script></body></html>
qwen3:14bOKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Boid Simulation</title>
    <style>body {margin:0;overflow:hidden;background:#111;}canvas {display:block;}</style>
</head>
<body>
    <canvas id="c"></canvas>
    <script>
        const canvas = document.getElementById('c');
        const ctx = canvas.getContext('2d');

        let WIDTH = window.innerWidth * 0.95;
        let HEIGHT = window.innerHeight * 0.85;
        ctx.canvas.width = WIDTH;
        ctx.canvas.height = HEIGHT;

        const NUM_BOIDS = 60;
        const MAX_FORCE = 1.0;
        const NEIGHBOR_RADIUS = 75;
        const SEPARATION_DISTANCE = 20;
        
        let boids = [];
        let predator = { x: WIDTH * 0.3, y: HEIGHT * 0.3, vx: 0, vy: 0 };

        function Boid(x, y) {
            this.x = x;
            this.y = y;
            this.vx = (Math.random() - 0.5) * 2;
            this.vy = (Math.random() - 0.5) * 2;
            this.maxSpeed = 3;

            this.seek = function(targetX, targetY, steerFactor = 1.0) {
                let dx = targetX - this.x;
                let dy = targetY - this.y;
                let dist = Math.sqrt(dx * dx + dy * dy);
                if (dist === 0) return { ax: 0, ay: 0 };

                let desiredVx = (dx / dist) * this.maxSpeed;
                let desiredVy = (dy / dist) * this.maxSpeed;

                let ax = (desiredVx - this.vx) * steerFactor * 0.15;
                let ay = (desiredVy - this.vy) * steerFactor * 0.15;
                return { ax, ay };
            };

            this.applyForce = function(ax, ay) {
                this.vx += ax;
                this.vy += ay;
            };

            this.update = function() {
                // Apply friction/drag
                this.vx *= 0.98;
                this.vy *= 0.98;

                // Limit speed
                let mag = Math.sqrt(this.vx * this.vx + this.vy * this.vy);
                if (mag > this.maxSpeed) {
                    this.vx = (this.vx / mag) * this.maxSpeed;
                    this.vy = (this.vy / mag) * this.maxSpeed;
                }

                this.x += this.vx;
                this.y += this.vy;

                // Wrap boundaries
                if (this.x < 0) this.x = WIDTH;
                if (this.x > WIDTH) this.x = 0;
                if (this.y < 0) this.y = HEIGHT;
                if (this.y > HEIGHT) this.y = 0;
            };

            this.calculateFlockForce = function(allBoids) {
                let accelX = 0, accelY = 0;
                let count = 0;
                let separationList = [];
                let alignmentSum = { x: 0, y: 0 };
                let cohesionSum = { x: 0, y: 0 };

                for (const other of allBoids) {
                    if (other === this) continue;

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

                    // Separation
                    if (dist < SEPARATION_DISTANCE && dist > 0) {
                        let strength = 1 / dist;
                        separationList.push({ ax: -dx * strength, ay: -dy * strength });
                        count++;
                    }
                    // Alignment
                    alignmentSum.x += other.vx;
                    alignmentSum.y += other.vy;
                    count++;
                    // Cohesion
                    cohesionSum.x += other.x;
                    cohesionSum.y += other.y;
                }

                if (count === 0) return { ax: 0, ay: 0 };

                // 1. Separation Force (Strong repulsion when too close)
                let sepX = 0, sepY = 0;
                for (const s of separationList) {
                    sepX += s.ax * MAX_FORCE * 0.8;
                    sepY += s.ay * MAX_FORCE * 0.8;
                }

                // 2. Alignment Force (Steer toward average heading)
                let avgVx = alignmentSum.x / count;
                let avgVy = alignmentSum.y / count;
                let alignForce = this.seek(this.x + avgVx * WIDTH/NUM_BOIDS, this.y + avgVy * HEIGHT/NUM_BOIDS, 1.0);

                // 3. Cohesion Force (Steer toward average position)
                let avgX = cohesionSum.x / count;
                let avgY = cohesionSum.y / count;
                let cohereForce = this.seek(avgX, avgY, 1.0);
                
                // Combine forces
                accelX = (sepX + alignForce.ax * 0.5 + cohereForce.ax * 0.5) / NUM_BOIDS;
                accelY = (sepY + alignForce.ay * 0.5 + cohereForce.ay * 0.5) / NUM_BOIDS;

                return { ax: accelX, ay: accelY };
            };

            this.calculatePredatorForce = function() {
                let dx = this.x - predator.x;
                let dy = this.y - predator.y;
                let distSq = dx * dx + dy * dy;
                const P_RADIUS = 150; // Moderate radius for sensing

                if (distSq < P_RADIUS * P_RADIUS && distSq > 0) {
                    // Strong repulsive force away from the predator
                    let strength = Math.sqrt(P_RADIUS * P_RADIUS - distSq);
                    let ax = (dx / Math.sqrt(distSq)) * 1.5 * strength;
                    let ay = (dy / Math.sqrt(distSq)) * 1.5 * strength;
                    return { ax, ay };
                }
                return { ax: 0, ay: 0 };
            };


            this.steer = function() {
                // Base flocking forces
                let { ax: f_ax, ay: f_ay } = this.calculateFlockForce(boids);

                // Predator force (overrides/adds)
                let { ax: p_ax, ay: p_ay } = this.calculatePredatorForce();

                return { 
                    ax: f_ax + p_ax * 1.5, // Predator is stronger than flocking rules
                    ay: f_ay + p_ay * 1.5 
                };
            };
        }

        function init() {
            boids = [];
            for (let i = 0; i < NUM_BOIDS; i++) {
                boids.push(new Boid(Math.random() * WIDTH, Math.random() * HEIGHT));
            }
        }

        function updatePredator() {
            predator.x += predator.vx * 0.01;
            predator.y += predator.vy * 0.01;

            // Simple sine wave motion for wandering effect
            predator.vx = Math.sin(Date.now() / 6000) * 0.5 + (Math.random() - 0.5) * 0.1;
            predator.vy = Math.cos(Date.now() / 7000) * 0.5 + (Math.random() - 0.5) * 0.1;

            // Keep predator contained roughly within the center area
            if (predator.x < WIDTH * 0.1 || predator.x > WIDTH * 0.9) {
                predator.vx *= -1;
            }
        }

        function updateBoids() {
            for (const b of boids) {
                let { ax, ay } = b.steer();
                b.applyForce(ax, ay);
                b.update();
            }
        }

        function drawBoid(b) {
            ctx.save();
            ctx.translate(b.x, b.y);
            // Calculate angle based on velocity vector
            let angle = Math.atan2(b.vy, b.vx); 
            ctx.rotate(angle);

            ctx.fillStyle = `rgba(0, 150, 255, 0.8)`;
            ctx.beginPath();
            // Draw triangle pointing right (due to rotation)
            ctx.moveTo(10, 0); // Tip
            ctx.lineTo(-10, -10); // Bottom left
            ctx.lineTo(-10, 10);  // Top left
            ctx.closePath();
            ctx.fill();
            ctx.restore();
        }

        function drawPredator() {
            ctx.fillStyle = 'rgba(255, 50, 50, 1)'; // Distinct red color
            ctx.beginPath();
            ctx.arc(predator.x, predator.y, 8, 0, Math.PI * 2);
            ctx.fill();
        }

        function loop() {
            // Clear canvas with slight fade effect for trails
            ctx.fillStyle = 'rgba(17, 17, 17, 0.3)';
            ctx.fillRect(0, 0, WIDTH, HEIGHT);

            updatePredator();
            updateBoids();

            boids.forEach(drawBoid);
            drawPredator();

            // Display boid count (optional but good for debugging/requirement fulfillment)
            ctx.fillStyle = 'white';
            ctx.font = '14px Arial';
            ctx.fillText(`Boids: ${NUM_BOIDS}`, 10, 20);


            requestAnimationFrame(loop);
        }

        window.addEventListener('resize', () => {
            WIDTH = window.innerWidth * 0.95;
            HEIGHT = window.innerHeight * 0.85;
            ctx.canvas.width = WIDTH;
            ctx.canvas.height = HEIGHT;
        });

        init();
        loop();
    </script>
</body>
</html>
```
deepseek-r1:14bSTATFORMAT
Show code
```html
<!DOCTYPE html>
<html><body style="margin:0;padding:0;overflow:hidden;background-color:black;">
<canvas id=c></canvas>
<div id=i style="position:absolute;top:10px;left:10px;color:white;font-family:Arial;">Boids: <span id=n>60</span></div>

<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
let width = canvas.width, height = canvas.height;

class Boid {
  constructor() {
    this.x = Math.random()*width;
    this.y = Math.random()*height;
    this.vx = (Math.random()-0.5)*4;
    this.vy = (Math.random()-0.5)*4;
    this.color = `hsl(${Math.random()*360}, 100%, 75%)`;
  }
}

class Predator {
  constructor() {
    this.x = width/2;
    this.y = height/2;
    this.radius = 20;
    this.speed = 2;
    this.direction = Math.random()*Math.PI*2;
    this.wanderAngle = 0;
  }

  move() {
    this.direction += (Math.sin(this.wanderAngle) * 0.1);
    this.wanderAngle += 0.03;
    
    this.x += Math.cos(this.direction)*this.speed;
    this.y += Math.sin(this.direction)*this.speed;

    if(this.x < -this.radius) this.x = width + this.radius;
    else if(this.x > width + this.radius) this.x = -this.radius;
    if(this.y < -this.radius) this.y = height + this.radius;
    else if(this.y > height + this.radius) this.y = -this.radius;
  }

  draw() {
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2);
    ctx.strokeStyle = 'red';
    ctx.lineWidth = 2;
    ctx.stroke();
  }
}

let boids = [];
let predator = new Predator();
let frameCount = 0;

function initBoids() {
  boids = [];
  for(let i=0;i<60;i++) boids.push(new Boid());
  frameCount = 0;
}

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

  // Update positions
  boids.forEach(b => {
    b.x += b.vx;
    b.y += b.vy;

    // Wrap around edges
    if(b.x < -25) b.x = width + 25;
    else if(b.x > width+25) b.x = -25;
    if(b.y < -25) b.y = height + 25;
    else if(b.y > height+25) b.y = -25;

    // Add forces
    let sepForce = {x:0,y:0};
    let alignForce = {x:0,y:0};
    let cohesionForce = {x:0,y:0};
    let count = 0;

    // Check nearby boids for separation
    for(let i=0;i<boids.length;i++) {
      if(i === b) continue;
      let dx = b.x - boids[i].x;
      let dy = b.y - boids[i].y;
      let dist = Math.sqrt(dx*dx + dy*dy);
      if(dist < 50) {
        sepForce.x += (boids[i].x - b.x)/dist;
        sepForce.y += (boids[i].y - b.y)/dist;
      }
    }

    // Find nearby boids for alignment and cohesion
    let avgDir = {x:0,y:0}, center = {x:0,y:0};
    for(let i=0;i<boids.length;i++) {
      if(i === b) continue;
      let dx = boids[i].x - b.x;
      let dy = boids[i].y - b.y;
      let dist = Math.sqrt(dx*dx + dy*dy);
      if(dist < 100) {
        avgDir.x += boids[i].vx;
        avgDir.y += boids[i].vy;
        center.x += boids[i].x;
        center.y += boids[i].y;
        count++;
      }
    }

    // Apply forces
    if(count > 0) {
      alignForce = {x:avgDir.x/count, y:avgDir.y/count};
      cohesionForce = {x:(center.x - b.x)/count*3, y:(center.y - b.y)/count*3};
    }

    // Add predator avoidance
    let dx = b.x - predator.x;
    let dy = b.y - predator.y;
    if(dx*dx + dy*dy < 400) {
      sepForce.x += (b.x - predator.x)*1.5;
      sepForce.y += (b.y - predator.y)*1.5;
    }

    // Apply forces to velocity
    b.vx += (sepForce.x * 0.3 + alignForce.x * 0.5 + cohesionForce.x) * 0.1;
    b.vy += (sepForce.y * 0.3 + alignForce.y * 0.5 + cohesionForce.y) * 0.1;

    // Limit speed
    let speed = Math.sqrt(b.vx*b.vx + b.vy*b.vy);
    if(speed > 4) {
      b.vx *= 4/speed;
      b.vy *= 4/speed;
    }
  });

  // Move predator
  predator.move();
}

function draw() {
  ctx.fillStyle = 'black';
  ctx.fillRect(0,0,width,height);

  boids.forEach(b => {
    ctx.beginPath();
    ctx.fillStyle = b.color;
    ctx.translate(b.x, b.y);
    ctx.rotate(b.vx * Math.PI / 180);
    ctx.lineTo(-5, -3);
    ctx.lineTo(10, -3);
    ctx.lineTo(0, 7);
    ctx.fill();

    // Draw movement indicator
    ctx.beginPath();
    ctx.strokeStyle = 'white';
    ctx.arc(b.x, b.y, 1, 0, Math.PI*2);
    ctx.stroke();
  });

  predator.draw();
}

function animate() {
  updateBoids();
  draw();
  frameCount++;
  if(frameCount % 60 == 0) initBoids();

  requestAnimationFrame(animate);
}

// Handle window resize
window.addEventListener('resize', () => {
  width = canvas.width = window.innerWidth;
  height = canvas.height = window.innerHeight;
  initBoids();
});

initBoids();
animate();
</script>
</body></html>
```
No usable answer reached the harness (ERR). Counted as a did-not-finish.
qwq:32bBLANKLIMFORMAT
Show code
<think>

Okay, so I need to create an HTML file that simulates about 60 boids with the classic flocking rules and a predator. Let's start by recalling the three rules of boids: separation, alignment, and cohesion. Each boid should adjust its velocity based on these rules by steering towards or away from other boids. Also, the predator adds an extra steering force to nearby boids.

First, I'll structure the HTML with a canvas element and a script tag. The canvas will be the area where everything is drawn. The JavaScript code will handle the simulation and animation.

I need to set up the canvas context and define the initial variables. The boids will be objects with position, velocity, acceleration, and other properties. The predator is another object that moves slowly around the screen.

For the boids, each one should check other boids within a certain radius for separation, alignment, and cohesion. The separation is steering away from nearby boids, alignment is matching the average heading, and cohesion is moving towards the average position of nearby boids. These forces are added together and then normalized to keep the speed constant.

The predator needs to wander randomly but slowly. Maybe use a simple random walk with a small step size. The boids should detect the predator within a larger radius and steer away from it if it's close.

I'll need to wrap the boids around the screen edges, so when they go off one side, they come back on the opposite. That means their position is modulo the canvas width and height.

The animation should use requestAnimationFrame for smooth updates. Each frame, all boids update their acceleration based on the flocking rules and predator avoidance, then update their velocity and position. Then everything is redrawn.

Including the boid count display is straightforward: add a div element in the HTML and update its innerHTML each frame.

Now, let's outline the steps in code:

1. Initialize the canvas and context.
2. Create an array to hold boid objects.
3. Define the Predator object with position and velocity.
4. Implement the update functions for boids and predator.
5. The flocking rules functions: separate, align, cohesion, predatorAvoid.
6. The main loop function that updates and draws everything.
7. Event listeners to start the animation.

Wait, the user said no user input, so maybe a start() function that's called automatically when the page loads. Using window.onload or putting the initialization in the script.

Variables needed:

- canvas width and height (maybe set to innerWidth and innerHeight for fullscreen? Or fixed values? Probably fixed for simplicity, like 800x600)
- Boid count (60)
- Parameters for separation (distance, strength), alignment, cohesion (radius, weight)
- Predator's speed, wander rate, etc.
- Max speed and force for boids.

In the boid structure, each boid has:

- pos: {x,y}
- vel: {x,y}
- acc: {x,y}
- r (radius for sensing), maxSpeed, maxForce.

Wait, maybe better to have some global parameters for separationDist, alignmentDist, cohesionDist, predatorRadius. Also, the weights for each steering force (like 1.0 for each, but maybe adjustment).

The separation function would calculate the steering vector by summing the difference in position between the current boid and others within separationDist, then invert that direction. The alignment calculates the average heading of nearby boids. Cohesion averages their positions and steers towards that point.

The predatorAvoid function checks if any boid is within predatorRadius, then adds a steering force away from it.

The predator's movement: every frame, add a random small vector to its velocity, but with damping so it doesn't move too fast. Or, maybe just a small step in a slightly random direction each frame.

Drawing: each boid as a small triangle pointing in the direction of their velocity. The predator is a different color, maybe red, and a circle or cross.

Now, code structure:

HTML:

<!DOCTYPE html>
<html>
<head>
  <title>Boids Simulation</title>
</head>
<body>
  <canvas id="simCanvas"></canvas>
  <div id="count">Boids: 60</div>
  <script>
    // JS code here
  </script>
</body>
</html>

In the JavaScript:

- Get the canvas context, set size.
- Initialize variables: boids array, predator, etc.
- Functions:

function Boid() {
  this.pos = {x: Math.random() * width, y: Math.random() * height};
  this.vel = {x: (Math.random()-0.5)*2, y: (Math.random()-0.5)*2};
  this.acc = {x:0, y:0};
  this.maxSpeed = 2;
  this.maxForce = 0.05;
}

But need to have the separation distance and other parameters as global or local variables.

Wait, the predator is a separate object:

var predator = {
  pos: {x: width/2, y: height/2},
  vel: {x:0, y:0},
  speed: 0.2,
  wander: 0.01 // or something
};

Then, in the update loop for predator:

predator.vel.x += (Math.random()-0.5)*predator.wander;
predator.vel.y += (Math.random()-0.5)*predator.wander;
// Apply damping? maybe multiply by 0.9 to slow down over time
predator.vel.x *= 0.9;
predator.vel.y *= 0.9;
predator.pos.x += predator.vel.x * predator.speed;
predator.pos.y += predator.vel.y * predator.speed;

But that might make it move smoothly. Alternatively, just move in a random direction each frame with a small step.

Wait, maybe the predator has a velocity that is adjusted each frame by a small random vector, then clamped to a max speed.

Hmm.

Now, for the boid's steering functions:

function separate(boid) {
  let desiredSeperation = 25;
  let steer = {x:0, y:0};
  let count = 0;
  for (let other of boids) {
    if (other == boid) continue;
    let d = dist(boid.pos, other.pos);
    if (d > 0 && d < desiredSeperation) {
      let diff = {x: boid.pos.x - other.pos.x, y: boid.pos.y - other.pos.y};
      diff.x /= (d*d);
      diff.y /= (d*d);
      steer.x += diff.x;
      steer.y += diff.y;
      count++;
    }
  }
  if (count > 0) {
    steer.x /= count;
    steer.y /= count;
  }
  if (steer.x != 0 || steer.y != 0) {
    steer = normalize(steer);
    steer.x *= boid.maxSpeed;
    steer = sub(steer, boid.vel);
    steer = limit(steer, boid.maxForce);
  }
  return steer;
}

Wait, better to have helper functions for vector operations. Like add, sub, normalize, etc.

Alternatively, implement those inline.

Wait, perhaps I should implement helper functions first.

Wait, the code will need to have functions for vector operations. Let's define them:

function dist(a, b) {
  return Math.sqrt( (a.x - b.x)**2 + (a.y - b.y)**2 );
}

function limit(v, max) {
  let mag = Math.sqrt(v.x**2 + v.y**2);
  if (mag > max) {
    v.x = (v.x / mag) * max;
    v.y = (v.y / mag) * max;
  }
  return v;
}

function normalize(v) {
  let mag = Math.sqrt(v.x**2 + v.y**2);
  if (mag == 0) return {x:0,y:0};
  return {x: v.x/mag, y: v.y/mag};
}

But maybe better to inline these for brevity, but it might get too long. Alternatively, keep the functions.

Hmm, given the character limit, I should try to minimize code. Maybe inlining some operations.

Another thing: the boids' acceleration is the sum of all steering forces (separate, align, cohesion, predatorAvoid). Then, the velocity is updated by adding acceleration, but clamped to maxSpeed.

Wait, the standard process is:

Each boid calculates the steering force (acceleration) based on the rules, then:

boid.vel.x += steering.x;
boid.vel.y += steering.y;
Then limit the velocity to maxSpeed.

Wait, no, acceleration is added, then velocity is updated with acceleration.

Wait, in the boid's update step:

boid.acc = separate(boid) + align(boid) + cohesion(boid) + predatorAvoid(boid);
then, boid.vel += boid.acc;
then limit vel to maxSpeed.

Wait, but how to add vectors? Maybe I need a vector add function.

Alternatively, in the steering functions, return a vector that is already multiplied by some factor, and then the total acceleration is the sum of these.

Hmm. Let's see.

The predatorAvoid function would check the distance to the predator, if within radius, steer away.

Putting all together:

In each frame:

- Clear the canvas.
- Update each boid's acceleration based on rules.
- Update each boid's velocity and position, wrapping around edges.
- Update predator's position and velocity.
- Draw everything.

Now, the draw function: for each boid, draw a triangle pointing in their direction. The triangle can be a small equilateral triangle. The direction is their velocity vector.

For drawing a triangle, we can use the context's beginPath, moveTo, lineTo, etc.

For example:

ctx.beginPath();
ctx.moveTo(x, y);
// points of the triangle in the direction of velocity
const triangleSize = 4;
const dir = normalize(boid.vel);
const perp = {x: -dir.y, y: dir.x}; // perpendicular vector for triangle points
ctx.moveTo(boid.pos.x, boid.pos.y);
ctx.lineTo(boid.pos.x + dir.x * triangleSize * 2, boid.pos.y + dir.y * triangleSize * 2);
ctx.lineTo(boid.pos.x + (dir.x - perp.x) * triangleSize, boid.pos.y + (dir.y - perp.y) * triangleSize);
ctx.closePath();
ctx.fill();

Wait, perhaps a simpler way. Maybe a triangle with three points: the tip in the direction, and two sides.

Alternatively, maybe just a line pointing in the direction, but the user wants triangles.

Alternatively, using a rotated rectangle, but that might be complex.

Alternatively, code for a simple triangle:

function drawBoid(boid) {
  ctx.save();
  ctx.translate(boid.pos.x, boid.pos.y);
  const angle = Math.atan2(boid.vel.y, boid.vel.x);
  ctx.rotate(angle);
  ctx.beginPath();
  ctx.moveTo(0, -3);
  ctx.lineTo(-2, 3);
  ctx.lineTo(2, 3);
  ctx.closePath();
  ctx.fill();
  ctx.restore();
}

This way, the triangle is rotated to face the direction of the velocity. The points are relative to the center.

The predator is drawn as a red circle, maybe with a line through it for visibility.

Now, putting all together in code.

Wait, the predator's position should also wrap around the canvas edges? Probably yes, to make it consistent with the boids.

The parameters like separation distance, alignment and cohesion distances need to be set. Let me think:

Separation distance: maybe 25 pixels.

Alignment and cohesion distance: 50 pixels?

The predator radius could be around 100 pixels.

Max speed for boids: maybe 2.5 or so. Max force around 0.05.

Predator speed: 0.2 per frame, but with some random direction.

Now, coding this step by step.

First, in the HTML script:

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

Wait, but the user didn't specify the size. Maybe using the full window size. But if I set to 800x600, it's manageable. Or maybe using innerWidth and innerHeight, but that might complicate the code.

Alternatively, leave the canvas at default size but set it in the code. Maybe better fixed for simplicity.

Then, the boids array:

let boids = [];
for (let i = 0; i < 60; i++) {
  boids.push(new Boid());
}

Then the Boid constructor:

function Boid() {
  this.pos = {x: Math.random() * width, y: Math.random() * height};
  this.vel = {x: (Math.random() - 0.5)*2, y: (Math.random() - 0.5)*2};
  this.acc = {x:0, y:0};
  this.maxSpeed = 2;
  this.maxForce = 0.05;
}

Then the predator:

var predator = {
  pos: {x: width/2, y: height/2},
  vel: {x:0, y:0},
  speed: 0.2,
  wander: 0.01 // per frame velocity adjustment
};

Then the functions:

function updateBoids() {
  for (let boid of boids) {
    boid.acc.x = 0;
    boid.acc.y = 0;
    
    let sep = separate(boid);
    let ali = align(boid);
    let coh = cohesion(boid);
    let pred = predatorAvoid(boid);
    
    boid.acc.x += sep.x + ali.x + coh.x + pred.x;
    boid.acc.y += sep.y + ali.y + coh.y + pred.y;
    
    // Update velocity
    boid.vel.x += boid.acc.x;
    boid.vel.y += boid.acc.y;
    boid.vel = limit(boid.vel, boid.maxSpeed);
    
    // Update position
    boid.pos.x += boid.vel.x;
    boid.pos.y += boid.vel.y;
    
    // Wrap around
    if (boid.pos.x < 0) boid.pos.x += width;
    if (boid.pos.x > width) boid.pos.x -= width;
    if (boid.pos.y < 0) boid.pos.y += height;
    if (boid.pos.y > height) boid.pos.y -= height;
  }
}

Wait, but in the code, the acceleration is the steering force. Wait, normally steering force is the acceleration, so the velocity is added by the acceleration * deltaTime, but in this case since it's using requestAnimationFrame which is variable time step, but maybe assuming fixed step for simplicity, and just adding the acceleration directly to velocity each frame. But perhaps better to use acceleration as the steering force, then:

Wait, maybe I should clarify:

The steering force (from the rules) is added to the acceleration, which then affects the velocity. But in code, perhaps the steering force is directly added to velocity, scaled by delta time? Hmm, maybe it's getting too complicated.

Alternatively, each steering function returns a force (acceleration), and the total acceleration is the sum of those, then:

boid.vel.x += boid.acc.x * dt;
boid.vel.y += boid.acc.y * dt;

But without delta time, maybe the code uses a fixed step, so it's okay to just add the acceleration directly.

Alternatively, maybe the code is simplified by treating the steering as acceleration directly added to velocity, but clamped to maxSpeed.

Wait, in the boid's update, the acc is the sum of all steering forces (each steering function returns a vector which is the force/acceleration).

So:

boid.acc = sep + ali + coh + pred;

then

boid.vel += boid.acc;

then limit to maxSpeed.

Wait, but in code, that would be:

boid.vel.x += boid.acc.x;

Yes, but the acceleration is the steering force. So each steering function returns a vector which is the acceleration to apply.

Hmm, perhaps it's better to separate the functions into returning the desired steering vector (acceleration).

Now, implementing the separation function:

function separate(boid) {
  let steer = {x:0, y:0};
  let count = 0;
  let desiredSeperation = 25;
  for (let other of boids) {
    if (other == boid) continue;
    let d = dist(boid.pos, other.pos);
    if (d < desiredSeperation && d > 0) {
      let diff = {x: boid.pos.x - other.pos.x, y: boid.pos.y - other.pos.y};
      diff.x /= (d*d);
      diff.y /= (d*d);
      steer.x += diff.x;
      steer.y += diff.y;
      count++;
    }
  }
  if (count > 0) {
    steer.x /= count;
    steer.y /= count;
  }
  if (steer.x != 0 || steer.y != 0) {
    steer = normalize(steer);
    steer.x *= boid.maxSpeed;
    steer = sub(steer, boid.vel); // desired - current velocity
    steer = limit(steer, boid.maxForce);
  }
  return steer;
}

Wait, that seems a bit off. Because the steering force is supposed to be the direction to turn in. Maybe the standard approach is:

The separation steering is calculated as the average direction away from the nearby boids. The code above is adding the inverse of the direction to other.boid's position, normalized.

Alternatively, perhaps the direction should be the normalized average of the vectors pointing away from the other boids.

Wait, perhaps I should re-express it:

The desired vector is to go away from the others. So for each nearby boid, the direction is (current position - other's position), then sum those vectors, normalize and scale to maxForce.

Wait, in the code above, the diff is (boid.pos - other.pos), which points away from the other boid. Then divided by d squared (so closer boids have more influence).

Summing those gives the desired direction.

Hmm, but then steer is the average of these, then normalize to maxSpeed, then desired - current vel, then clamped to maxForce?

This is getting a bit confusing. Maybe it's better to refer to the classic boids algorithm.

In the classic implementation, the separation is calculated as:

for each nearby boid:
   vector away from it (current - other)
sum all these vectors
divide by count (average)
normalize and scale to maxForce.

So in code:

function separate(boid) {
    let steering = {x:0, y:0};
    let count = 0;
    let desiredSeperation = 25;
    for (let other of boids) {
        if (other == boid) continue;
        let d = dist(boid.pos, other.pos);
        if (d < desiredSeperation && d > 0) {
            let diff = {x: boid.pos.x - other.pos.x, y: boid.pos.y - other.pos.y};
            diff.x /= (d * d);
            diff.y /= (d * d);
            steering.x += diff.x;
            steering.y += diff.y;
            count++;
        }
    }
    if (count > 0) {
        steering.x /= count;
        steering.y /= count;
    }
    steering = limit(steering, boid.maxForce);
    return steering;
}

Wait, perhaps that's better. Each nearby boid contributes a vector pointing away from them, weighted by 1/d² (so closer ones are stronger). Then sum all, divide by count (average), then limit to maxForce.

Hmm, maybe that's better.

Similarly, alignment is the average velocity of nearby boids.

Cohesion is the average position of nearby boids, then steer towards that center.

PredatorAvoid is to steer away from the predator if within radius.

Okay, let's code alignment:

function align(boid) {
    let steering = {x:0, y:0};
    let count = 0;
    let neighborDist = 50;
    for (let other of boids) {
        if (other == boid) continue;
        let d = dist(boid.pos, other.pos);
        if (d > 0 && d < neighborDist) {
            steering.x += other.vel.x;
            steering.y += other.vel.y;
            count++;
        }
    }
    if (count > 0) {
        steering.x /= count;
        steering.y /= count;
        steering.x -= boid.vel.x;
        steering.y -= boid.vel.y;
        steering = limit(steering, boid.maxForce);
    } else {
        steering.x = 0;
        steering.y = 0;
    }
    return steering;
}

Wait, the alignment is trying to match the average velocity of neighbors. So the desired velocity is the average of neighbors' velocities, then steering is desired minus current velocity, clamped.

Hmm.

Cohesion:

function cohesion(boid) {
    let steering = {x:0, y:0};
    let count = 0;
    let neighborDist = 50;
    for (let other of boids) {
        if (other == boid) continue;
        let d = dist(boid.pos, other.pos);
        if (d > 0 && d < neighborDist) {
            steering.x += other.pos.x;
            steering.y += other.pos.y;
            count++;
        }
    }
    if (count > 0) {
        steering.x /= count;
        steering.y /= count;
        steering.x -= boid.pos.x;
        steering.y -= boid.pos.y;
        steering = normalize(steering);
        steering.x *= boid.maxSpeed;
        steering = sub(steering, boid.vel);
        steering = limit(steering, boid.maxForce);
    } else {
        steering.x = 0;
        steering.y = 0;
    }
    return steering;
}

Wait, not sure. The cohesion is to steer towards the average position. So the desired velocity is towards the center point. So the steering vector is (center - current pos) normalized and scaled to maxSpeed, then desired - current velocity.

Hmm, perhaps the code can be:

steering = (center - boid.pos).normalized * maxSpeed - currentVelocity.

But in code terms, perhaps:

if (count >0 ) {
    steering.x = (center.x - boid.pos.x);
    steering.y = (center.y - boid.pos.y);
    // normalize and scale to maxSpeed
    len = Math.hypot(steering.x, steering.y);
    if (len >0) {
        steering.x *= boid.maxSpeed / len;
        steering.y *= boid.maxSpeed / len;
    }
    // then subtract current velocity to get the acceleration
    steering.x -= boid.vel.x;
    steering.y -= boid.vel.y;
    steering = limit(steering, boid.maxForce);
}

Hmm, this is getting a bit tangled. Maybe better to write helper functions for vector operations.

Let me define these:

function add(v1, v2) {
    return {x: v1.x + v2.x, y: v1.y + v2.y};
}

function sub(v1, v2) {
    return {x: v1.x - v2.x, y: v1.y - v2.y};
}

function multScalar(v, s) {
    return {x: v.x * s, y: v.y * s};
}

function normalize(v) {
    const len = Math.hypot(v.x, v.y);
    if (len == 0) return {x: 0, y: 0};
    return {x: v.x/len, y: v.y/len};
}

function limit(v, max) {
    const len = Math.hypot(v.x, v.y);
    if (len > max) {
        const factor = max / len;
        v.x *= factor;
        v.y *= factor;
    }
    return v;
}

function dist(p1, p2) {
    return Math.hypot(p1.x - p2.x, p1.y - p2.y);
}

With these helper functions, the separation function becomes:

function separate(boid) {
    let steering = {x:0, y:0};
    let count =0;
    let desiredSeperation = 25;
    for (let other of boids) {
        if (other == boid) continue;
        let d = dist(boid.pos, other.pos);
        if (d >0 && d < desiredSeperation) {
            let diff = sub(boid.pos, other.pos);
            diff = multScalar(diff, 1 / (d*d));
            steering = add(steering, diff);
            count++;
        }
    }
    if (count >0 ) {
        steering = multScalar(steering, 1/count);
    }
    steering = limit(steering, boid.maxForce);
    return steering;
}

Similarly, alignment:

function align(boid) {
    let steering = {x:0, y:0};
    let count =0;
    let neighborDist = 50;
    for (let other of boids) {
        if (other == boid) continue;
        let d = dist(boid.pos, other.pos);
        if (d >0 && d < neighborDist) {
            steering = add(steering, other.vel);
            count++;
        }
    }
    if (count >0 ) {
        steering = multScalar(steering, 1/count);
        steering = sub(steering, boid.vel);
        steering = limit(steering, boid.maxForce);
    } else {
        steering = {x:0,y:0};
    }
    return steering;
}

Cohesion:

function cohesion(boid) {
    let steering = {x:0, y:0};
    let count =0;
    let neighborDist = 50;
    let center = {x:0,y:0};
    for (let other of boids) {
        if (other == boid) continue;
        let d = dist(boid.pos, other.pos);
        if (d >0 && d < neighborDist) {
            center.x += other.pos.x;
            center.y += other.pos.y;
            count++;
        }
    }
    if (count >0 ) {
        center.x /= count;
        center.y /= count;
        steering = sub(center, boid.pos);
        steering = normalize(steering);
        steering = multScalar(steering, boid.maxSpeed);
        steering = sub(steering, boid.vel);
        steering = limit(steering, boid.maxForce);
    } else {
        steering = {x:0,y:0};
    }
    return steering;
}

And predatorAvoid:

function predatorAvoid(boid) {
    let d = dist(boid.pos, predator.pos);
    let steering = {x:0,y:0};
    let avoidRadius = 100;
    if (d < avoidRadius && d > 0) {
        steering = sub(boid.pos, predator.pos);
        steering = normalize(steering);
        steering = multScalar(steering, boid.maxSpeed);
        steering = sub(steering, boid.vel);
        steering = limit(steering, boid.maxForce);
    }
    return steering;
}

Okay, that's more systematic.

Now, putting all together in the update function:

Each boid's steering is the sum of separation, alignment, cohesion, predatorAvoid.

Wait, actually in the classic boids, the three behaviors are separation, alignment, cohesion. The predatorAvoid is an added behavior here.

So in code:

function update() {
    for (let boid of boids) {
        let sep = separate(boid);
        let ali = align(boid);
        let coh = cohesion(boid);
        let pred = predatorAvoid(boid);
        let steering = add(sep, ali);
        steering = add(steering, coh);
        steering = add(steering, pred);
        // apply steering
        boid.vel = add(boid.vel, steering);
        // limit velocity
        boid.vel = limit(boid.vel, boid.maxSpeed);
        // move
        boid.pos = add(boid.pos, boid.vel);
        // wrap around
        if (boid.pos.x > width) boid.pos.x = 0;
        if (boid.pos.x <0) boid.pos.x = width;
        if (boid.pos.y > height) boid.pos.y =0;
        if (boid.pos.y <0) boid.pos.y = height;
    }
}

But need to setup the predator's movement.

Wait, maybe the predator should move towards the boids.

Alternatively, perhaps the predator is stationary or moves in some pattern.

But since the user's question is to create the system, perhaps the predator is just a point that the boids avoid.

Alternatively, maybe the predator chases the boids. Let's say the predator moves towards the center of the boids.

So in the code:

function updatePredator() {
    let center = {x:0,y:0};
    let count = boids.length;
    if (count ==0) return;
    for (let boid of boids) {
        center.x += boid.pos.x;
        center.y += boid.pos.y;
    }
    center.x /= count;
    center.y /= count;
    let desired = sub(center, predator.pos);
    let d = Math.hypot(desired.x, desired.y);
    if (d >0) {
        desired = normalize(desired);
        desired = multScalar(desired, predator.maxSpeed);
    }
    predator.vel = desired;
    predator.pos = add(predator.pos, predator.vel);
    // wrap around
    // same as boids
}

But this requires defining a predator object with pos and vel.

So in initialization:

let predator = {
    pos: {x: 200, y: 200},
    vel: {x:0, y:0},
    maxSpeed: 4
};

Then in the main loop, call updatePredator() each frame.

Putting all together, the full code would be:

But since this is getting too long, perhaps I should outline the steps.

But the user asked to "Create a system where entities (boids) avoid a predator", so I need to provide the code.

But in the context of a text answer, perhaps pseudo-code or code snippets.

Alternatively, here's the JavaScript code for p5.js:

Here's a possible implementation:

```javascript
let boids = [];
let predator;

function setup() {
  createCanvas(640, 480);
  for (let i = 0; i < 100; i++) {
    boids.push(new Boid(random(width), random(height)));
  }
  predator = new Predator(width/2, height/2);
}

function draw() {
  background(51);
  predator.update();
  predator.show();
  for (let b of boids) {
    b.run(boids);
    b.show();
  }
}

class Boid {
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.vel = p5.Vector.random2D();
    this.acc = createVector(0, 0);
    this.maxForce = 0.05;
    this.maxSpeed = 3;
  }

  run(boids) {
    this.flock(boids);
    this.update();
    this.borders();
  }

  flock(boids) {
    let sep = this.separate(boids);
    let ali = this.align(boids);
    let coh = this.cohesion(boids);
    let pred = this.predatorAvoid(predator);
    
    // Arbitrarily weight these forces
    sep.mult(1.5);
    ali.mult(1);
    coh.mult(1);
    
    this.acc.add(sep);
    this.acc.add(ali);
    this.acc.add(coh);
    this.acc.add(pred);
  }

  update() {
    this.vel.add(this.acc);
    this.vel.limit(this.maxSpeed);
    this.pos.add(this.vel);
    this.acc.mult(0);
  }

  borders() {
    if (this.pos.x < -50) this.pos.x = width + 50;
    if (this.pos.x > width + 50) this.pos.x = -50;
    if (this.pos.y < -50) this.pos.y = height + 50;
    if (this.pos.y > height + 50) this.pos.y = -50;
  }

  separate(boids) {
    let desiredSeperation = 25.0;
    let steer = createVector(0, 0);
    let count = 0;
    for (let other of boids) {
      let d = this.pos.dist(other.pos);
      if ((d > 0) && (d < desiredSeperation)) {
        let diff = p5.Vector.sub(this.pos, other.pos);
        diff.normalize();
        diff.div(d);
        steer.add(diff);
        count++;
      }
    }
    if (count > 0) {
      steer.div(count);
    }
    if (steer.mag() > 0) {
      steer.normalize();
      steer.mult(this.maxSpeed);
      steer.sub(this.vel);
      steer.limit(this.maxForce);
    }
    return steer;
  }

  align(boids) {
    let neighborDist = 50;
    let steer = createVector(0, 0);
    let count = 0;
    for (let other of boids) {
      let d = this.pos.dist(other.pos);
      if ((d > 0) && (d < neighborDist) && (other != this)) {
        steer.add(other.vel);
        count++;
      }
    }
    if (count > 0) {
      steer.div(count);
      steer.normalize();
      steer.mult(this.maxSpeed);
      steer.sub(this.vel);
      steer.limit(this.maxForce);
    } else {
      steer = createVector(0,0);
    }
    return steer;
  }

  cohesion(boids) {
    let neighborDist = 50;
    let sum = createVector(0, 0);
    let count = 0;
    for (let other of boids) {
      let d = this.pos.dist(other.pos);
      if ((d > 0) && (d < neighborDist) && (other != this)) {
        sum.add(other.pos);
        count++;
      }
    }
    if (count > 0) {
      sum.div(count);
      return this.seek(sum);
    } else {
      return createVector(0,0);
    }
  }

  seek(target) {
    let desired = p5.Vector.sub(target, this.pos);
    desired.normalize();
    desired.mult(this.maxSpeed);
    let steer = p5.Vector.sub(desired, this.vel);
    steer.limit(this.maxForce);
    return steer;
  }

  predatorAvoid(predator) {
    let d = this.pos.dist(predator.pos);
    if (d > 100) return createVector(0,0); // ignore if too far
    let desired = p5.Vector.sub(this.pos, predator.pos);
    desired.normalize();
    desired.mult(this.maxSpeed);
    let steer = p5.Vector.sub(desired, this.vel);
    steer.limit(this.maxForce);
    return steer;
  }

  show() {
    let theta = this.vel.heading() + PI/2;
    fill(255);
    stroke(200);
    push();
    translate(this.pos.x, this.pos.y);
    rotate(theta);
    beginShape();
    vertex(0, -5);
    vertex(-15, 5);
    vertex(-10,0);
    vertex(-15, -5);
    endShape(CLOSE);
    pop();
  }
}

class Predator {
  constructor(x, y) {
    this.pos = createVector(x, y);
    this.vel = createVector(0, 0);
    this.maxSpeed = 2;
    this.maxForce = 0.2;
  }

  update() {
    // Move towards the center of boids
    let center = createVector(0,0);
    let count = 0;
    for (let b of boids) {
      center.add(b.pos);
      count++;
    }
    if (count >0) {
      center.div(count);
      let desired = p5.Vector.sub(center, this.pos);
      desired.normalize();
      desired.mult(this.maxSpeed);
      this.vel = desired;
    }
    this.pos.add(this.vel);
    this.borders();
  }

  borders() {
    if (this.pos.x < 0) this.pos.x = 0;
    if (this.pos.x > width) this.pos.x = width;
    if (this.pos.y < 0) this.pos.y = 0;
    if (this.pos.y > height) this.pos.y = height;
  }

  show() {
    fill(255, 0, 0);
    ellipse(this.pos.x, this.pos.y, 12, 12);
  }
}
```

This is a p5.js sketch implementing Boids with predator avoidance. The Boid class includes separation, alignment, cohesion, and predatorAvoid methods. The predator moves towards the center of the boids and applies a repulsive force to the boids when within a certain distance.
deepseek-r1:32bERRSTATFORMAT
Show code
```html
<!DOCTYPE html>
<html><title>Boid Flocking Simulation</title><body>
<canvas id=c width=800 height=600></canvas>
<script>
const c=document.getElementById('c'),ctx=c.getContext('2d');let w=800,h=600,boids=[],predator={x:400,y:300,target:{x:400,y:300},radius:50,speed:0.5};const maxBoids=60,visionRadius=50,maxSpeed=2,separationWeight=1.5,alignmentWeight=1.2,cohesionWeight=1,predatorAvoidanceWeight=4;
class Boid{
constructor(){this.x=Math.random()*w;this.y=Math.random()*h;this.vx=(Math.random()-0.5)*maxSpeed;this.vy=(Math.random()-0.5)*maxSpeed}
update(boids,predator){let sepX=0,sepY=0,alignX=0,alignY=0,cohX=0,cohY=0,nearby=0;
for(let b of boids){
let dx=b.x-this.x,dy=b.y-this.y,d=Math.sqrt(dx*dx+dy*dy);
if(d<visionRadius&&d>1){
sepX+=dx/d;d>25?sepX-=dx/d:sepX-=(dx)/Math.pow(d,2);
sepY+=dy/d;d>25?sepY-=dy/d:sepY-=(dy)/Math.pow(d,2);
alignX+=b.vx;alignY+=b.vy;
cohX+=b.x;cohY+=b.y;nearby++;
}
}if(nearby){
sepX*=-separationWeight;nearby>1?(sepY*=-separationWeight,alignX/=nearby,alignY/=nearby,cohX/=nearby,cohY/=nearby):sepY*=-separationWeight;
this.vx+=sepX+alignmentWeight*(alignX-this.vx)+cohesionWeight*(cohX-this.x);
this.vy+=sepY+alignmentWeight*(alignY-this.vy)+cohesionWeight*(cohY-this.y);
}let dx=predator.x-this.x,dy=predator.y-this.y,d=Math.sqrt(dx*dx+dy*dy);
if(d<predator.radius){
dx/=d;dy/=d;
this.vx-=predatorAvoidanceWeight*dx;
this.vy-=predatorAvoidanceWeight*dy;
}let speed=Math.sqrt(this.vx*this.vx+this.vy*vy);
if(speed>maxSpeed||speed<-maxSpeed){
this.vx*=maxSpeed/speed;
this.vy*=maxSpeed/speed;
}dx=predator.target.x-predator.x;dy=predator.target.y-predator.y;d=Math.sqrt(dx*dx+dy*dy);
if(d>predator.speed){let ratio=predator.speed/d;predator.x+=dx*ratio;predator.y+=dy*ratio}else{predator.target={x:Math.random()*w,y:Math.random()*h}};
this.x=(this.x+w)%w;this.y=(this.y+h)%h;
}draw(){let dir=this.angle=Math.atan2(this.vy,this.vx)+Math.PI/2;
let len=10,mag=5,pt1={x:this.x+len*Math.cos(dir),y:this.y+len*Math.sin(dir)},pt2={x:this.x+mag*Math.cos(dir-Math.PI/4),y:this.y+mag*Math.sin(dir-Math.PI/4)},pt3={x:this.x+mag*Math.cos(dir+Math.PI/4),y:this.y+mag*sin(dir+Math.PI/4)};
ctx.beginPath();ctx.moveTo(pt1.x,pt1.y);ctx.lineTo(pt2.x,pt2.y);ctx.lineTo(pt3.x,pt3.y);ctx.closePath();ctx.fillStyle='#00f';ctx.fill();}
}function init(){boids=[];for(let i=0;i<maxBoids;i++)boids.push(new Boid());predator={x:400,y:300,target:{x:Math.random()*w,y:Math.random()*h},radius:50,speed:1}}
function animate(){requestAnimationFrame(animate);ctx.clearRect(0,0,w,h);
ctx.fillStyle='#f00';ctx.beginPath();ctx.arc(predator.x,predator.y,predator.radius,0,2*Math.PI);ctx.stroke();
for(let b of boids){b.update(boids,predator);b.draw();}
ctx.fillStyle='black';ctx.fillText(`Boids: ${maxBoids}`,10,20)}
init();animate();
</script></body></html>
```
Outside the Brain cluster — same task, same character budget, collected through their own tooling (response times not comparable)
Claude Opus 5frontier referenceOK
Show code
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Flock &amp; Predator</title>
<style>html,body{margin:0;height:100%;background:#070b12;overflow:hidden}canvas{display:block}
#h{position:fixed;left:16px;top:14px;font:12px/1.5 ui-monospace,Menlo,monospace;color:#6fe0ff;letter-spacing:.18em;text-transform:uppercase;text-shadow:0 0 10px rgba(0,170,255,.7);pointer-events:none}
#h b{color:#fff;font-size:16px}#h i{color:#ff6a7a;font-style:normal}</style></head><body>
<canvas id="c"></canvas><div id="h">Boids <b id="n">0</b> &nbsp;·&nbsp; <i>1 predator</i></div>
<script>
var c=document.getElementById('c'),g=c.getContext('2d'),N=document.getElementById('n'),W,H,B,P,t;
function rs(){W=c.width=innerWidth;H=c.height=innerHeight}
addEventListener('resize',rs);rs();
function R(a,b){return a+Math.random()*(b-a)}
function init(){
 B=[];var n=54+(Math.random()*13|0);
 for(var i=0;i<n;i++){var a=R(0,6.2832),s=R(1.6,2.6);B.push({x:R(0,W),y:R(0,H),vx:Math.cos(a)*s,vy:Math.sin(a)*s,h:R(160,205)})}
 P={x:R(0,W),y:R(0,H),vx:0,vy:0,a:R(0,6.2832)};t=0;N.textContent=n;
}
init();
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 frame(){
 t++;if(t>2600)init();
 g.fillStyle='rgba(7,11,18,.26)';g.fillRect(0,0,W,H);
 P.a+=R(-.22,.22);P.vx+=Math.cos(P.a)*.13;P.vy+=Math.sin(P.a)*.13;
 var ps=Math.hypot(P.vx,P.vy);if(ps>2.1){P.vx*=2.1/ps;P.vy*=2.1/ps}
 P.x+=P.vx;P.y+=P.vy;wrap(P);
 var V=70,S=24,F=130,MX=3.1,i,j,b,o;
 for(i=0;i<B.length;i++){
  b=B[i];var sx=0,sy=0,ax=0,ay=0,cx=0,cy=0,k=0;
  for(j=0;j<B.length;j++){if(j===i)continue;o=B[j];
   var dx=o.x-b.x,dy=o.y-b.y,d=Math.hypot(dx,dy);
   if(d<V&&d>0){k++;ax+=o.vx;ay+=o.vy;cx+=o.x;cy+=o.y;
    if(d<S){sx-=dx/d/d*6;sy-=dy/d/d*6}}}
  var fx=0,fy=0;
  if(k){ax/=k;ay/=k;cx=cx/k-b.x;cy=cy/k-b.y;
   var al=Math.hypot(ax,ay);if(al>0){fx+=(ax/al*MX-b.vx)*.055;fy+=(ay/al*MX-b.vy)*.055}
   var cl=Math.hypot(cx,cy);if(cl>0){fx+=(cx/cl*MX-b.vx)*.035;fy+=(cy/cl*MX-b.vy)*.035}}
  var sl=Math.hypot(sx,sy);if(sl>0){fx+=(sx/sl*MX-b.vx)*.11;fy+=(sy/sl*MX-b.vy)*.11}
  var px=b.x-P.x,py=b.y-P.y,pd=Math.hypot(px,py);b.p=0;
  if(pd<F&&pd>0){var w=(1-pd/F);b.p=w;fx+=(px/pd*MX*2.4-b.vx)*.34*w;fy+=(py/pd*MX*2.4-b.vy)*.34*w}
  b.vx+=fx;b.vy+=fy;
  var sp=Math.hypot(b.vx,b.vy),m=b.p>.15?MX*1.55:MX;
  if(sp>m){b.vx*=m/sp;b.vy*=m/sp}else if(sp<1.2&&sp>0){b.vx*=1.2/sp;b.vy*=1.2/sp}
  b.x+=b.vx;b.y+=b.vy;wrap(b);
 }
 for(i=0;i<B.length;i++){b=B[i];
  g.save();g.translate(b.x,b.y);g.rotate(Math.atan2(b.vy,b.vx));
  var hu=b.p>.05?(b.h+(30-b.h)*b.p):b.h;
  g.fillStyle='hsl('+hu+',95%,'+(58+b.p*14)+'%)';
  g.shadowColor='hsla('+hu+',100%,60%,.9)';g.shadowBlur=9;
  g.beginPath();g.moveTo(9,0);g.lineTo(-6,4.4);g.lineTo(-3.4,0);g.lineTo(-6,-4.4);g.closePath();g.fill();
  g.restore();}
 g.save();g.translate(P.x,P.y);g.shadowColor='#ff2d55';g.shadowBlur=22;
 g.strokeStyle='rgba(255,60,90,.22)';g.lineWidth=1.4;g.beginPath();g.arc(0,0,F,0,6.2832);g.stroke();
 g.strokeStyle='rgba(255,90,120,.85)';g.lineWidth=2;
 g.beginPath();g.arc(0,0,13+Math.sin(t*.09)*2,0,6.2832);g.stroke();
 g.beginPath();g.moveTo(-20,0);g.lineTo(-7,0);g.moveTo(7,0);g.lineTo(20,0);
 g.moveTo(0,-20);g.lineTo(0,-7);g.moveTo(0,7);g.lineTo(0,20);g.stroke();
 g.fillStyle='#ff2d55';g.beginPath();g.arc(0,0,5.5,0,6.2832);g.fill();
 g.restore();
 requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
</script></body></html>
GPT-5.5 (Codex)frontier referenceOK
Show code
<!doctype html><html><head><meta charset=utf-8><title>Boids</title><style>html,body{margin:0;height:100%;overflow:hidden;background:#101316;color:#e8eef2;font:16px system-ui}canvas{display:block}#n{position:fixed;left:12px;top:10px;background:#0008;padding:6px 10px;border-radius:6px}</style></head><body><canvas id=c></canvas><div id=n></div><script>
const c=document.getElementById("c"),x=c.getContext("2d"),n=document.getElementById("n"),N=60,B=[],P={x:0,y:0,vx:1,vy:1};let W,H;
function R(a=1){return Math.random()*a}
function S(){W=c.width=innerWidth;H=c.height=innerHeight}onresize=S;S();
function boot(){B.length=0;for(let i=0;i<N;i++){let a=R(6.283);B.push({x:R(W),y:R(H),vx:Math.cos(a)*2,vy:Math.sin(a)*2})}P.x=R(W);P.y=R(H);P.vx=R(2)-1;P.vy=R(2)-1}boot();
function wrap(o){o.x=(o.x+W)%W;o.y=(o.y+H)%H}
function lim(o,m){let s=Math.hypot(o.vx,o.vy);if(s>m)o.vx=o.vx/s*m,o.vy=o.vy/s*m}
function near(a,b){let dx=b.x-a.x,dy=b.y-a.y;if(dx>W/2)dx-=W;if(dx<-W/2)dx+=W;if(dy>H/2)dy-=H;if(dy<-H/2)dy+=H;return[dx,dy,dx*dx+dy*dy]}
function step(){
x.fillStyle="#101316";x.fillRect(0,0,W,H);
P.vx+=R(.12)-.06;P.vy+=R(.12)-.06;lim(P,1.25);P.x+=P.vx;P.y+=P.vy;wrap(P);
for(let b of B){
let sx=0,sy=0,ax=0,ay=0,cx=0,cy=0,k=0;
for(let q of B)if(q!==b){let[d,e,z]=near(b,q);if(z<3600){k++;ax+=q.vx;ay+=q.vy;cx+=d;cy+=e;if(z<625){sx-=d/(z||1);sy-=e/(z||1)}}}
if(k){ax=ax/k-b.vx;ay=ay/k-b.vy;cx/=k;cy/=k}
let[px,py,pd]=near(b,P),rx=0,ry=0;if(pd<10000){rx=-px/(pd||1)*900;ry=-py/(pd||1)*900}
b.vx+=sx*.7+ax*.045+cx*.0007+rx;b.vy+=sy*.7+ay*.045+cy*.0007+ry;lim(b,3.2);b.x+=b.vx;b.y+=b.vy;wrap(b)}
x.fillStyle="#9fd7ff";
for(let b of B){let a=Math.atan2(b.vy,b.vx);x.beginPath();x.moveTo(b.x+9*Math.cos(a),b.y+9*Math.sin(a));x.lineTo(b.x+5*Math.cos(a+2.55),b.y+5*Math.sin(a+2.55));x.lineTo(b.x+5*Math.cos(a-2.55),b.y+5*Math.sin(a-2.55));x.closePath();x.fill()}
x.strokeStyle="#ff4d65";x.lineWidth=3;x.beginPath();x.arc(P.x,P.y,12,0,6.283);x.moveTo(P.x-17,P.y);x.lineTo(P.x+17,P.y);x.moveTo(P.x,P.y-17);x.lineTo(P.x,P.y+17);x.stroke();
n.textContent="Boids: "+B.length;requestAnimationFrame(step)}
requestAnimationFrame(step);
</script></body></html>
Claude Sonnet 5frontier referenceOK
Show code
<!DOCTYPE html>
<html><head><meta charset="utf-8"><title>Boids</title>
<style>html,body{margin:0;background:#0b0e14;overflow:hidden}canvas{display:block}#hud{position:fixed;top:8px;left:10px;color:#9fe;font:14px monospace;text-shadow:0 0 4px #000}</style>
</head><body>
<div id="hud"></div>
<canvas id="c"></canvas>
<script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d'),hud=document.getElementById('hud');
let W,H;
function resize(){W=cv.width=innerWidth;H=cv.height=innerHeight;}
addEventListener('resize',resize);resize();

const N=60;
const PERCEPT=70, SEPD=24, PREDR=140;
function rnd(a,b){return a+Math.random()*(b-a);}

function init(){
  const boids=[];
  for(let i=0;i<N;i++){
    boids.push({x:rnd(0,W),y:rnd(0,H),vx:rnd(-2,2),vy:rnd(-2,2)});
  }
  const pred={x:rnd(0,W),y:rnd(0,H),ang:rnd(0,6.28),vx:0,vy:0};
  return {boids,pred,t:0};
}
let state=init();

function wrap(b){
  if(b.x<0)b.x+=W; if(b.x>W)b.x-=W;
  if(b.y<0)b.y+=H; if(b.y>H)b.y-=H;
}

function step(){
  const boids=state.boids, pred=state.pred;
  state.t++;
  if(state.t%90===0 || (Math.abs(pred.vx)<0.01&&Math.abs(pred.vy)<0.01)){
    pred.ang+=rnd(-1,1);
  }
  pred.ang+=rnd(-0.15,0.15);
  pred.vx=pred.vx*0.9+Math.cos(pred.ang)*0.4;
  pred.vy=pred.vy*0.9+Math.sin(pred.ang)*0.4;
  const ps=Math.hypot(pred.vx,pred.vy)||1;
  const pmax=1.3;
  if(ps>pmax){pred.vx=pred.vx/ps*pmax;pred.vy=pred.vy/ps*pmax;}
  pred.x+=pred.vx; pred.y+=pred.vy;
  wrap(pred);

  const maxSpeed=3.2, minSpeed=1.4;

  for(const b of boids){
    let sepx=0,sepy=0,aliVx=0,aliVy=0,cohx=0,cohy=0,cnt=0;
    for(const o of boids){
      if(o===b)continue;
      let dx=o.x-b.x, dy=o.y-b.y;
      if(Math.abs(dx)>W/2) dx-=Math.sign(dx)*W;
      if(Math.abs(dy)>H/2) dy-=Math.sign(dy)*H;
      const d=Math.hypot(dx,dy);
      if(d<PERCEPT && d>0.0001){
        cnt++;
        aliVx+=o.vx; aliVy+=o.vy;
        cohx+=b.x+dx; cohy+=b.y+dy;
        if(d<SEPD){
          sepx-=dx/d/d*8; sepy-=dy/d/d*8;
        }
      }
    }
    let ax=0, ay=0;
    if(cnt>0){
      aliVx/=cnt; aliVy/=cnt;
      ax+=(aliVx-b.vx)*0.05; ay+=(aliVy-b.vy)*0.05;
      cohx/=cnt; cohy/=cnt;
      ax+=(cohx-b.x)*0.0025; ay+=(cohy-b.y)*0.0025;
    }
    ax+=sepx*0.06; ay+=sepy*0.06;

    let dxp=b.x-pred.x, dyp=b.y-pred.y;
    if(Math.abs(dxp)>W/2) dxp-=Math.sign(dxp)*W;
    if(Math.abs(dyp)>H/2) dyp-=Math.sign(dyp)*H;
    const dp=Math.hypot(dxp,dyp);
    if(dp<PREDR){
      const force=(PREDR-dp)/PREDR*1.4;
      ax+=dxp/(dp||1)*force;
      ay+=dyp/(dp||1)*force;
    }

    b.vx+=ax; b.vy+=ay;
    let sp=Math.hypot(b.vx,b.vy)||0.001;
    if(sp>maxSpeed){b.vx=b.vx/sp*maxSpeed;b.vy=b.vy/sp*maxSpeed;}
    if(sp<minSpeed){b.vx=b.vx/sp*minSpeed;b.vy=b.vy/sp*minSpeed;}
    b.x+=b.vx; b.y+=b.vy;
    wrap(b);
  }
}

function draw(){
  ctx.fillStyle='#0b0e14';
  ctx.fillRect(0,0,W,H);

  const pred=state.pred;
  ctx.save();
  ctx.translate(pred.x,pred.y);
  const grad=ctx.createRadialGradient(0,0,0,0,0,PREDR);
  grad.addColorStop(0,'rgba(255,60,60,0.12)');
  grad.addColorStop(1,'rgba(255,60,60,0)');
  ctx.fillStyle=grad;
  ctx.beginPath();ctx.arc(0,0,PREDR,0,6.283);ctx.fill();
  ctx.rotate(Math.atan2(pred.vy,pred.vx));
  ctx.fillStyle='#ff3b3b';
  ctx.beginPath();
  ctx.moveTo(14,0);ctx.lineTo(-10,8);ctx.lineTo(-4,0);ctx.lineTo(-10,-8);
  ctx.closePath();ctx.fill();
  ctx.strokeStyle='#fff';ctx.lineWidth=1.5;ctx.stroke();
  ctx.restore();

  ctx.fillStyle='#7fd4ff';
  for(const b of state.boids){
    const ang=Math.atan2(b.vy,b.vx);
    ctx.save();
    ctx.translate(b.x,b.y);
    ctx.rotate(ang);
    ctx.beginPath();
    ctx.moveTo(8,0);
    ctx.lineTo(-6,4);
    ctx.lineTo(-6,-4);
    ctx.closePath();
    ctx.fill();
    ctx.restore();
  }

  hud.textContent='Boids: '+state.boids.length;
}

let frames=0;
function loop(){
  step();
  draw();
  frames++;
  if(frames>100000){ state=init(); frames=0; }
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script>
</body></html>
Claude Fable 5frontier referenceOK
Show code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Boids with Predator</title>
<style>
html,body{margin:0;height:100%;overflow:hidden;background:#0b1020}
canvas{display:block}
#hud{position:fixed;top:10px;left:12px;color:#cfe3ff;font:14px/1.4 monospace;background:rgba(10,16,32,.6);padding:6px 10px;border-radius:6px;pointer-events:none}
</style>
</head>
<body>
<canvas id="c"></canvas>
<div id="hud"></div>
<script>
var cv=document.getElementById("c"),cx=cv.getContext("2d"),hud=document.getElementById("hud"),W,H;
function rs(){W=cv.width=innerWidth;H=cv.height=innerHeight}
rs();addEventListener("resize",rs);
var N=60,PER=100,SEP=26,PRED=120,MAXS=2.6,MAXF=0.06,boids,pred,t;
function reset(){
t=0;boids=[];
for(var i=0;i<N;i++){
var a=Math.random()*Math.PI*2;
boids.push({x:Math.random()*W,y:Math.random()*H,vx:Math.cos(a)*MAXS,vy:Math.sin(a)*MAXS});
}
pred={x:Math.random()*W,y:Math.random()*H,a:Math.random()*Math.PI*2,s:1.2};
}
function wrapD(d,m){if(d>m/2)d-=m;else if(d<-m/2)d+=m;return d}
function limit(o,px,py,m){
var l=Math.hypot(px,py);
if(l>m){px=px/l*m;py=py/l*m}
return[px,py];
}
function step(){
var i,j,b,o;
for(i=0;i<boids.length;i++){
b=boids[i];
var cxs=0,cys=0,axs=0,ays=0,sxs=0,sys=0,n=0,ns=0;
for(j=0;j<boids.length;j++){
if(i===j)continue;
o=boids[j];
var dx=wrapD(o.x-b.x,W),dy=wrapD(o.y-b.y,H),d=Math.hypot(dx,dy);
if(d<PER&&d>0){
cxs+=dx;cys+=dy;axs+=o.vx;ays+=o.vy;n++;
if(d<SEP){sxs-=dx/d;sys-=dy/d;ns++}
}
}
var fx=0,fy=0;
if(n>0){
var v=limit(0,cxs/n,cys/n,1);fx+=v[0]*MAXF;fy+=v[1]*MAXF;
var al=Math.hypot(axs,ays)||1;
fx+=(axs/al*MAXS-b.vx)*MAXF*0.9;fy+=(ays/al*MAXS-b.vy)*MAXF*0.9;
}
if(ns>0){fx+=sxs/ns*MAXS*MAXF*2.4;fy+=sys/ns*MAXS*MAXF*2.4}
var pdx=wrapD(b.x-pred.x,W),pdy=wrapD(b.y-pred.y,H),pd=Math.hypot(pdx,pdy);
if(pd<PRED&&pd>0){
var k=(1-pd/PRED);
fx+=pdx/pd*MAXS*MAXF*10*k;fy+=pdy/pd*MAXS*MAXF*10*k;
}
b.vx+=fx;b.vy+=fy;
var sp=Math.hypot(b.vx,b.vy)||1;
if(sp>MAXS){b.vx=b.vx/sp*MAXS;b.vy=b.vy/sp*MAXS}
if(sp<1.2){b.vx=b.vx/sp*1.2;b.vy=b.vy/sp*1.2}
}
for(i=0;i<boids.length;i++){
b=boids[i];
b.x+=b.vx;b.y+=b.vy;
if(b.x<0)b.x+=W;if(b.x>=W)b.x-=W;
if(b.y<0)b.y+=H;if(b.y>=H)b.y-=H;
}
pred.a+=(Math.random()-0.5)*0.25;
pred.x+=Math.cos(pred.a)*pred.s;
pred.y+=Math.sin(pred.a)*pred.s;
if(pred.x<0)pred.x+=W;if(pred.x>=W)pred.x-=W;
if(pred.y<0)pred.y+=H;if(pred.y>=H)pred.y-=H;
t++;
if(t>60*90)reset();
}
function draw(){
cx.fillStyle="#0b1020";
cx.fillRect(0,0,W,H);
cx.fillStyle="#7fd4ff";
for(var i=0;i<boids.length;i++){
var b=boids[i],a=Math.atan2(b.vy,b.vx);
cx.save();
cx.translate(b.x,b.y);
cx.rotate(a);
cx.beginPath();
cx.moveTo(8,0);
cx.lineTo(-5,4.5);
cx.lineTo(-5,-4.5);
cx.closePath();
cx.fill();
cx.restore();
}
cx.save();
cx.translate(pred.x,pred.y);
cx.strokeStyle="#ff5566";
cx.fillStyle="#ff5566";
cx.beginPath();
cx.arc(0,0,7,0,Math.PI*2);
cx.fill();
cx.lineWidth=2;
cx.beginPath();
cx.arc(0,0,13,0,Math.PI*2);
cx.stroke();
cx.beginPath();
cx.moveTo(-19,0);cx.lineTo(-9,0);
cx.moveTo(9,0);cx.lineTo(19,0);
cx.moveTo(0,-19);cx.lineTo(0,-9);
cx.moveTo(0,9);cx.lineTo(0,19);
cx.stroke();
cx.restore();
hud.textContent="Boids: "+boids.length+"  |  Predator: 1";
}
function loop(){
step();
draw();
requestAnimationFrame(loop);
}
reset();
loop();
</script>
</body>
</html>
Claude Haiku 4.5frontier referenceOKMINIFIED
Show code
<!DOCTYPE html><html><head><style>body{margin:0;background:#000}#d{position:fixed;top:10px;left:10px;color:#fff;font:14px monospace}</style></head><body><canvas id="c"></canvas><div id="d"></div><script>const c=document.getElementById('c'),x=c.getContext('2d'),w=c.width=innerWidth,h=c.height=innerHeight,d=document.getElementById('d');class B{constructor(){this.x=Math.random()*w;this.y=Math.random()*h;this.vx=(Math.random()-.5)*2;this.vy=(Math.random()-.5)*2}update(bs,p){let s={x:0,y:0},a={x:0,y:0},o={x:0,y:0},n=0;for(let b of bs){if(b!==this){let dx=b.x-this.x,dy=b.y-this.y,r=Math.hypot(dx,dy);r<50&&(s.x-=dx,s.y-=dy);r<100&&(a.x+=b.vx,a.y+=b.vy,o.x+=b.x,o.y+=b.y,n++)}}if(n){a.x/=n;a.y/=n;o.x/=n;o.y/=n;this.vx+=a.x*.01+s.x*.1+(o.x-this.x)*.001;this.vy+=a.y*.01+s.y*.1+(o.y-this.y)*.001}let r=Math.hypot(p.x-this.x,p.y-this.y);r<80&&(this.vx+=(this.x-p.x)/r*.2,this.vy+=(this.y-p.y)/r*.2);let m=Math.hypot(this.vx,this.vy);m>2&&(this.vx*=2/m,this.vy*=2/m);this.x+=this.vx;this.y+=this.vy;this.x<0?this.x+=w:this.x>w&&(this.x-=w);this.y<0?this.y+=h:this.y>h&&(this.y-=h)}draw(){let a=Math.atan2(this.vy,this.vx);x.save();x.translate(this.x,this.y);x.rotate(a);x.fillStyle='#0f0';x.beginPath();x.moveTo(4,0);x.lineTo(-3,3);x.lineTo(-2,0);x.lineTo(-3,-3);x.closePath();x.fill();x.restore()}}let bs=[];for(let i=0;i<60;i++)bs.push(new B());let p={x:w/2,y:h/2,vx:0,vy:0};!function e(){x.fillStyle='#000';x.fillRect(0,0,w,h);p.vx+=(Math.random()-.5)*.1;p.vy+=(Math.random()-.5)*.1;let s=Math.hypot(p.vx,p.vy);s>1&&(p.vx/=s,p.vy/=s);p.x+=p.vx;p.y+=p.vy;p.x<0?p.x+=w:p.x>w&&(p.x-=w);p.y<0?p.y+=h:p.y>h&&(p.y-=h);for(let b of bs)b.update(bs,p);for(let b of bs)b.draw();x.fillStyle='#f00';x.beginPath();x.arc(p.x,p.y,6,0,6.3);x.fill();d.textContent='Boids: '+bs.length;requestAnimationFrame(e)}();</script></body></html>
Results at a glance— every model in this round with score, response time and status.

Who wrote what

ModelBlind scoreLatencyStatus
qwen3.5:9b 69.2 sOK
llama3.1:8b 101.0 sOK
qwen3-coder:30b 34.2 sOK
gemma4:26b harness
mistral-small:24b 135.1 sOK
qwen3:8b 38.1 sOK
qwen3:14b 40.8 sOK
deepseek-r1:14b 36.9 sOK
command-r:35b DNF
qwq:32b 263.8 sOK
deepseek-r1:32b 76.9 sOK