OverviewCode › R115
Code · blind round

R115 · Crowd leaving through a bottleneck

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.

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 a crowd on a <canvas>: several hundred people head for a single narrow exit, each steered by a force towards the door plus a repulsion from neighbours and walls, so they visibly pile up into an arch in front of the bottleneck and drain through it in bursts. Refill the room once it has emptied. Show how many are still inside and the flow rate through the door. 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)
llama3.1:8bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Crowd Simulation</title>
<style>
body {
  margin: 0;
  background-color: #f2f2f2;
}
canvas {
  border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="crowd" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('crowd');
const ctx = canvas.getContext('2d');

let people = [];
for (let x = 0; x < canvas.width; x += Math.random() * 10 + 1) {
  for (let y = 0; y < canvas.height; y += Math.random() * 10 + 1) {
    people.push({
      x: x,
      y: y,
      vx: Math.cos(Math.PI * 2 * Math.random()) * 1.5,
      vy: Math.sin(Math.PI * 2 * Math.random()) * 1.5
    });
  }
}

const exit = {x: canvas.width - 20, y: canvas.height / 2};
const doorWidth = 10;

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (let i = people.length - 1; i >= 0; i--) {
    const p = people[i];
    p.x += p.vx;
    p.y += p.vy;
    if (Math.hypot(p.x - exit.x, p.y - exit.y) < doorWidth / 2) {
      people.splice(i, 1);
      continue;
    }
    if (p.x + 10 > canvas.width || p.x < 0) {
      p.vx *= -1;
    }
    if (p.y + 10 > canvas.height || p.y < 0) {
      p.vy *= -1;
    }
    const distanceToExit = Math.hypot(p.x - exit.x, p.y - exit.y);
    const normalX = (exit.x - p.x) / distanceToExit;
    const normalY = (exit.y - p.y) / distanceToExit;
    const forceTowardsDoor = 0.1 * (normalX * (p.x - exit.x) + normalY * (p.y - exit.y));
    const repulsionFromNeighbours = people.reduce((acc, other) => {
      if (other !== p && Math.hypot(p.x - other.x, p.y - other.y) < 50) {
        const dx = p.x - other.x;
        const dy = p.y - other.y;
        const distanceSquared = dx * dx + dy * dy;
        const force = 100 / (distanceSquared + 1);
        acc += force * dx / Math.hypot(dx, dy) * normalX + force * dy / Math.hypot(dx, dy) * normalY;
      }
      return acc;
    }, 0);
    p.vx += forceTowardsDoor + repulsionFromNeighbours * normalX;
    p.vy += forceTowardsDoor + repulsionFromNeighbours * normalY;
    ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
    ctx.beginPath();
    ctx.arc(p.x, p.y, 10, 0, Math.PI * 2);
    ctx.fill();
  }
  document.title = people.length + ' people left';
  const flowRate = 1 / (canvas.width * canvas.height) * people.length;
  document.getElementById('flow-rate').textContent = `Flow rate: ${flowRate.toFixed(2)} people/s`;
}

let lastTime;
function animate() {
  if (!lastTime) lastTime = performance.now();
  const now = performance.now();
  const dt = (now - lastTime) / 1000;
  draw();
  lastTime = now;
  requestAnimationFrame(animate);
}
requestAnimationFrame(animate);

const button = document.createElement('button');
button.textContent = 'Restart';
document.body.appendChild(button);
button.onclick = () => {
  people = [];
  for (let x = 0; x < canvas.width; x += Math.random() * 10 + 1) {
    for (let y = 0; y < canvas.height; y += Math.random() * 10 + 1) {
      people.push({
        x: x,
        y: y,
        vx: Math.cos(Math.PI * 2 * Math.random()) * 1.5,
        vy: Math.sin(Math.PI * 2 * Math.random()) * 1.5
      });
    }
  }
};
document.body.appendChild(document.createElement('br'));
document.body.appendChild(document.createTextNode('Flow rate:'));
const flowElement = document.createElement('span');
flowElement.id = 'flow-rate';
document.body.appendChild(flowElement);
</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-coder:30bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Crowd Simulation</title>
    <style>body {margin:0;overflow:hidden;background:#111}canvas {display:block;border-bottom:2px solid #333;}#info {color:#ccc;font-family:monospace;padding:5px 20px;}</style>
</head>
<body>
    <canvas id="c"></canvas>
    <div id="info">People Inside: 0 | Flow Rate: 0/s</div>

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

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

        let particles = [];
        const NUM_PEOPLE = 300;
        const EXIT_X = canvas.width * 0.85;
        const EXIT_Y = canvas.height / 2;
        const EXIT_WIDTH = 15;
        const MAX_SPEED = 2;
        const REPULSION_RADIUS = 40;
        const ATTRACTION_STRENGTH = 0.02;
        const REFILL_RATE = 3;

        class Particle {
            constructor() {
                this.x = Math.random() * canvas.width * 0.1 + 20;
                this.y = Math.random() * canvas.height;
                this.vx = (Math.random() - 0.5) * 0.5;
                this.vy = (Math.random() - 0.5) * 0.5;
                this.radius = 4 + Math.random() * 3;
            }

            applyForce(fx, fy) {
                this.vx += fx * 0.1;
                this.vy += fy * 0.1;
            }

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

                let totalFx = 0;
                let totalFy = 0;
                let count = 0;

                for (const other of particles) {
                    if (other === this) continue;
                    let dx = this.x - other.x;
                    let dy = this.y - other.y;
                    let distSq = dx * dx + dy * dy;
                    let dist = Math.sqrt(distSq);

                    // Repulsion force
                    if (dist < REPULSION_RADIUS && dist > 1) {
                        let overlap = REPULSION_RADIUS - dist;
                        totalFx += (dx / dist) * overlap * 0.5;
                        totalFy += (dy / dist) * overlap * 0.5;
                    }
                }

                // Attraction force towards exit
                let dxExit = EXIT_X - this.x;
                let dyExit = EXIT_Y - this.y;
                let distToExitSq = dxExit * dxExit + dyExit * dyExit;
                
                if (distToExitSq > 1) {
                    // Stronger attraction when far from exit, weaker near exit center
                    let strengthFactor = Math.min(1, Math.sqrt(distToExitSq) / (canvas.width * canvas.height));
                    totalFx += dxExit * ATTRACTION_STRENGTH * strengthFactor;
                    totalFy += dyExit * ATTRACTION_STRENGTH * strengthFactor;
                }

                // Boundary/Wall repulsion
                if (this.x - this.radius <= 0 || this.x + this.radius >= canvas.width) {
                    totalFx -= Math.sign(this.x - this.radius) * 0.5;
                }
                if (this.y - this.radius <= 0 || this.y + this.radius >= canvas.height) {
                    totalFy -= Math.sign(this.y - this.radius) * 0.5;
                }

                // Check if particle is exiting the door area
                let isInDoor = (Math.abs(this.x - EXIT_X) < EXIT_WIDTH / 2 && 
                                Math.abs(this.y - EXIT_Y) < canvas.height * 0.5);
                
                if (isInDoor && this.vx > 1 || this.vy > 1) {
                    // Simulate drain/exit speed boost
                    totalFx *= 1.2;
                    totalFy *= 1.2;
                }

                this.applyForce(totalFx, totalFy);

                // Update position
                this.x += this.vx * MAX_SPEED;
                this.y += this.vy * MAX_SPEED;
            }

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

        function initialize() {
            particles = [];
            for (let i = 0; i < NUM_PEOPLE; i++) {
                particles.push(new Particle());
            }
            // Set exit door appearance
            canvas.style.borderBottom = `4px solid red`; 
        }

        function updateSimulation() {
            for (let p of particles) {
                p.update();
            }

            // Handle particle exiting the room (draining)
            const remainingParticles = [];
            let exitedCount = 0;
            for(let i=0; i < particles.length; i++) {
                const p = particles[i];
                // Check if particle has passed far enough through the exit area
                if ((p.x > canvas.width * 0.8 + EXIT_WIDTH/2 && Math.abs(p.y - EXIT_Y) < canvas.height * 0.5)) {
                    exitedCount++;
                } else if (p.x < -10 || p.x > canvas.width + 10 || p.y < -10 || p.y > canvas.height + 10) {
                    // Completely off screen, remove it
                } else {
                    remainingParticles.push(p);
                }
            }
            particles = remainingParticles;

            // Refill room if empty or low count (to restart cycle)
            if (Math.random() < 0.05 && particles.length < NUM_PEOPLE * 0.2) {
                 for(let i=0; i < REFILL_RATE; i++) {
                    particles.push(new Particle());
                }
            }

            // Calculate stats
            const countInside = particles.length;
            const flowRate = exitedCount > 0 ? Math.max(1, parseFloat((exitedCount / 60).toFixed(1))) : 0; // Approximation per second/frame rate dependent

            infoDiv.innerHTML = `People Inside: ${countInside} | Flow Rate: ${flowRate}/${NUM_PEOPLE}/s`;
        }


        function animate() {
            // Clear canvas background (dark mode)
            ctx.fillStyle = 'rgba(17, 17, 17, 0.4)'; // Trail effect
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            updateSimulation();

            for (let p of particles) {
                p.draw();
            }

            requestAnimationFrame(animate);
        }

        // Initial setup and start
        window.addEventListener('resize', () => {
             canvas.width = window.innerWidth;
             canvas.height = window.innerHeight - 40;
             initialize(); // Re-initializes particles on resize to fit new bounds
        });
        
        initialize();
        animate();

    </script>
</body>
</html>
```
mistral-small:24bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Crowd Simulation</title>
<style>
body { margin: 0; overflow: hidden; }
canvas { display: block; }
#stats { position: absolute; top: 10px; left: 10px; color: white; font-size: 24px; }
</style>
<script>
function simulate() {
    const canvas = document.getElementById('crowd');
    const ctx = canvas.getContext('2d');
    const width = canvas.width;
    const height = canvas.height;
    let people = [];
    let insideCount = 0;
    const doorX = width - 50;
    const doorY = height / 2;
    const doorWidth = 30;
    const peopleCount = 500;
    const maxSpeed = 2;
    const repulsionForce = 1.5;
    const wallRepulsion = 1;

    function Person(x, y) {
        this.x = x;
        this.y = y;
        this.vx = (Math.random() - 0.5) * 2;
        this.vy = (Math.random() - 0.5) * 2;
        this.update = function () {
            let fx = 0, fy = 0;
            for (let p of people) {
                if (p !== this && dist(this.x, this.y, p.x, p.y) < 30) {
                    let dx = p.x - this.x;
                    let dy = p.y - this.y;
                    let d = Math.sqrt(dx * dx + dy * dy);
                    fx += (dx / d) * repulsionForce / d;
                    fy += (dy / d) * repulsionForce / d;
                }
            }
            if(this.x < 10 || this.x > width - 10){
                this.vx *= -wallRepulsion
            }else{
                this.vx -= wallRepulsion*(this.x - doorX)/width-2*wallRepulsion;
            }
            if(this.y < 10 || this.y > height - 10){
                this.vy *= -wallRepulsion
            }else{
                this.vy -= wallRepulsion*(this.y - doorY)/height-2*wallRepulsion;
            }

            fx += (doorX - this.x) * 0.05 ;
            fy += (doorY - this.y) * 0.05 ;

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

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

        };
    }

    function dist(x1, y1, x2, y2) {
        return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    }

    function updatePeople() {
        for (let p of people) {
            if(p.x<=doorX+doorWidth&&p.x>=doorX-30){if(Math.abs((p.y-doorY))<40)p.x=width+50;
            p.update();
            }
        }
        insideCount = people.length;

    }

    function drawPeople() {
        ctx.clearRect(0, 0, width, height);
        for (let p of people) {
            ctx.beginPath();
            ctx.arc(p.x, p.y, 5, 0, Math.PI * 2);
            ctx.fillStyle = 'red';
            ctx.fill();
            ctx.closePath();
        }
    }

    function drawDoor() {
        ctx.beginPath();
        ctx.rect(doorX - doorWidth / 2, doorY - 10, doorWidth, 20);
        ctx.fillStyle = 'blue';
        ctx.fill();
        ctx.closePath();
    }

    function animate() {
        updatePeople();
        drawPeople();
        drawDoor();
        document.getElementById('stats').innerText = `Inside: ${insideCount} Flow Rate: ${peopleCount - insideCount}`;
        if (insideCount === 0) {
            people = [];
            for (let i = 0; i < peopleCount; i++) {
                let x = Math.random() * width;
                let y = Math.random() * height;
                people.push(new Person(x, y));
            }
        }
        requestAnimationFrame(animate);
    }

    function init() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        for (let i = 0; i < peopleCount; i++) {
            let x = Math.random() * width;
            let y = Math.random() * height;
            people.push(new Person(x, y));
        }

        animate();
    }
    init();
}
</script>
</head>
<body onload="simulate()">
<canvas id="crowd"></canvas>
<div id="stats"></div>
</body>
</html>
```
deepseek-r1:14bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head>
<canvas id="c"></canvas><div id="info" style="position:absolute;top:10;left:10;"></div>
<style>canvas{position:absolute;top:0;left:0;width:100%;height:100%}</style>
</head>
<body>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const info = document.getElementById('info');

const cellSize = 20;
const numPeople = 500;
const doorX = canvas.width / 2 - 10;
const doorY = canvas.height * 0.8;
const wallThickness = 40;

let particles = [];
let count = numPeople;
let flowRate = 0;
let needsRefill = false;

class Particle {
  constructor() {
    this.x = Math.random() * (canvas.width - cellSize*2) + cellSize;
    this.y = canvas.height - cellSize;
    this.targetX = doorX + (Math.random() * 60 - 30);
    this.targetY = doorY;
    this.dx = 0;
    this.dy = 0;
    this.radius = cellSize/2;
  }
}

function initPeople() {
  particles.length = 0;
  count = numPeople;
  needsRefill = false;
  flowRate = 0;
  
  for(let i=0; i<numPeople; i++) {
    const p = new Particle();
    p.targetX += Math.random() * (canvas.width - cellSize*2);
    particles.push(p);
  }
}

function updatePositions() {
  particles.forEach(p => {
    p.x += p.dx;
    p.y += p.dy;
    
    if(p.y > doorY - p.radius) {
      const dx = p.targetX - p.x;
      const dy = p.targetY - p.y;
      p.dx *= 0.95; p.dy *= 0.95;
      p.dx += (dx * 0.1);
      p.dy += (dy * 0.1);
    }
    
    if(p.x < wallThickness || p.x > canvas.width - wallThickness) {
      p.dx *= -1;
    }
    if(p.y < wallThickness || p.y > canvas.height - wallThickness) {
      p.dy *= -1;
    }
    
    if(p.y > doorY - p.radius && p.x > doorX - 30 && p.x < doorX + 30) {
      particles.push(new Particle());
      flowRate++;
      needsRefill = true;
    }
  });
  
  for(let i=particles.length-1; i>=0; i--) {
    const p = particles[i];
    
    if(p.y > canvas.height - wallThickness) {
      particles.splice(i, 1);
      count--;
    }
    
    for(let j=i-1; j>=0; j--) {
      const q = particles[j];
      if(Math.hypot(q.x - p.x, q.y - p.y) < cellSize*2) {
        const dx = q.x - p.x;
        const dy = q.y - p.y;
        const dist = Math.hypot(dx, dy);
        const force = (cellSize*2 - dist)/dist * 0.3;
        
        p.dx += dx * force / 2;
        p.dy += dy * force / 2;
        q.dx -= dx * force / 2;
        q.dy -= dy * force / 2;
      }
    }
  }
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  
  // Draw walls
  ctx.fillStyle = '#333';
  ctx.fillRect(0, 0, wallThickness, canvas.height);
  ctx.fillRect(canvas.width - wallThickness, 0, wallThickness, canvas.height);
  ctx.fillRect(0, 0, canvas.width, wallThickness);
  ctx.fillRect(0, canvas.height - wallThickness, canvas.width, wallThickness);
  
  // Draw door
  ctx.fillStyle = 'white';
  ctx.fillRect(doorX - 30, doorY - cellSize*2, 60, cellSize*4);
  
  // Draw people
  particles.forEach(p => {
    ctx.beginPath();
    ctx.arc(p.x, p.y, cellSize/2, 0, Math.PI * 2);
    ctx.fillStyle = '#f00';
    ctx.fill();
    
    if(Math.random() > 0.98) {
      ctx.beginPath();
      ctx.moveTo(p.x - cellSize/4, p.y + cellSize/4);
      ctx.lineTo(p.x + cellSize/4, p.y + cellSize/4);
      ctx.strokeStyle = '#fff';
      ctx.stroke();
    }
  });
  
  // Update info
  info.textContent = `Count: ${count} | Flow Rate: ${flowRate}`;
}

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

initPeople();
animate();

// Refill when empty
setInterval(() => {
  if(needsRefill && particles.length === 0) {
    initPeople();
    flowRate = 0;
    needsRefill = false;
  }
}, 1000);
</script>
</body>
</html>
```
qwen3:14bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Crowd Flow Simulation</title>
    <style>
        body { margin: 0; background: #111; display: flex; justify-content: center; align-items: center; height: 100vh; }
        canvas { border: 2px solid #333; background: #222; }
    </style>
</head>
<body>
    <canvas id="crowdCanvas"></canvas>
    <script>
        const canvas = document.getElementById('crowdCanvas');
        const ctx = canvas.getContext('2d');

        let W, H;
        let particles = [];
        let exitCenter = { x: 0, y: 0 };
        let particleCount = 300;
        let flowRate = 0;
        let simulationRunning = true;

        function resize() {
            W = canvas.width = window.innerWidth * 0.8;
            H = canvas.height = window.innerHeight * 0.8;
            exitCenter.x = W / 2;
            exitCenter.y = H / 2;
        }
        window.addEventListener('resize', resize);
        resize();

        class Particle {
            constructor(x, y) {
                this.x = x;
                this.y = y;
                this.vx = (Math.random() - 0.5) * 1;
                this.vy = (Math.random() - 0.5) * 1;
                this.r = Math.random() * 3 + 2;
                this.ax = 0;
                this.ay = 0;
            }

            applyForce(fx, fy) {
                this.ax += fx;
                this.ay += fy;
            }

            update() {
                // Reset acceleration
                this.ax *= 0.8;
                this.ay *= 0.8;
                if (this.ax > 0.5) this.ax = 0.5;
                if (this.ay > 0.5) this.ay = 0.5;

                // Apply force and update velocity/position
                this.vx += this.ax / 2;
                this.vy += this.ay / 2;
                this.x += this.vx;
                this.y += this.vy;
            }

            draw() {
                ctx.beginPath();
                ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
                ctx.fillStyle = '#66ccff';
                ctx.fill();
            }

            isDead() {
                return (this.x < 0 || this.x > W || this.y < 0 || this.y > H) && !(Math.abs(this.x - exitCenter.x) < 15 && Math.abs(this.y - exitCenter.y) < 15);
            }
        }

        const COALESCENCE_RADIUS = 40;
        const REPULSION_STRENGTH = 0.2;
        const ATTRACTION_STRENGTH = 0.005;
        const WALL_REPULSION = 1.5;
        let lastFrameCount = 0;

        function handlePhysics() {
            // 1. Clear and Filter dead particles
            particles = particles.filter(p => !p.isDead());

            // 2. Apply forces (Attraction, Wall, Repulsion)
            for (let i = 0; i < particles.length; i++) {
                let p = particles[i];
                p.ax = 0;
                p.ay = 0;

                // A. Attraction to Exit
                let dx_att = exitCenter.x - p.x;
                let dy_att = exitCenter.y - p.y;
                let dist_att = Math.sqrt(dx_att * dx_att + dy_att * dy_att);
                if (dist_att > 1) {
                    p.applyForce(dx_att / dist_att * ATTRACTION_STRENGTH, dy_att / dist_att * ATTRACTION_STRENGTH);
                }

                // B. Wall Repulsion
                let rx = p.r + WALL_REPULSION;
                let ry = p.r + WALL_REPULSION;
                if (p.x < rx) { p.applyForce(1, 0); }
                if (p.x > W - rx) { p.applyForce(-1, 0); }
                if (p.y < ry) { p.applyForce(0, 1); }
                if (p.y > H - ry) { p.applyForce(0, -1); }

                // C. Neighbor Repulsion
                for (let j = i + 1; j < particles.length; j++) {
                    let q = particles[j];
                    let dx = p.x - q.x;
                    let dy = p.y - q.y;
                    let distSq = dx * dx + dy * dy;
                    let min_distSq = 100; // Minimum separation squared
                    let dist = Math.sqrt(distSq);

                    if (dist < COALESCENCE_RADIUS && dist > 1) {
                        let forceFactor = REPULSION_STRENGTH * ((COALESCENCE_RADIUS / dist) - 1);
                        p.applyForce(dx / dist * forceFactor, dy / dist * forceFactor);
                        q.applyForce(-dx / dist * forceFactor, -dy / dist * forceFactor);
                    }
                }
            }

            // 3. Update positions and draw
            for (let p of particles) {
                p.update();
                p.draw();
            }
        }

        function updateFlowRate() {
            const now = performance.now();
            if (!lastFrameCount) return;

            // Simple flow rate calculation based on the difference in particle count over time
            let delta = particles.length - lastFrameCount;
            flowRate = (flowRate * 0.9 + (delta / 60) * 0.1); // Decay and update
        }


        function spawnParticles() {
            // Fill the room at random points away from the exit
            const startX = Math.random() * W;
            const startY = Math.random() * H;

            if (Math.sqrt((startX - exitCenter.x)**2 + (startY - exitCenter.y)**2) > 100) {
                particles.push(new Particle(startX, startY));
            }
        }

        function restartSimulation(initialFill = true) {
            if (initialFill && particles.length === 0) {
                 for(let i=0; i<300; i++) spawnParticles();
            } else if (!initialFill) {
                // If empty, and simulation is supposed to continue, we just wait for the next cycle
            }
        }

        function animate() {
            ctx.clearRect(0, 0, W, H);
            handlePhysics();
            updateFlowRate();

            const currentCount = particles.length;

            // Check simulation state and handle refill/restart logic
            if (currentCount < 5 && Math.random() < 0.1) { // If almost empty, chance to spawn new people
                spawnParticles();
            } else if (currentCount === 0 && lastFrameCount > 0) {
                 // Completely empty and simulating for a moment -> Restart
                 restartSimulation(true);
             }

            requestAnimationFrame(animate);
        }

        let frameCounter = 0;
        setInterval(() => {
            frameCounter++;
            if (frameCounter % 60 === 0) {
                // Display stats
                const statusDiv = document.createElement('div');
                statusDiv.style.position = 'absolute';
                statusDiv.style.bottom = '20px';
                statusDiv.innerHTML = `People Inside: ${Math.max(0, Math.floor(particles.length))}<br>Flow Rate (Est): ${Math.max(0, Math.round(flowRate * 10) / 10)}/s`;
                document.body.appendChild(statusDiv);
            }
        }, 100);


        // Initial setup and run
        restartSimulation(true);
        animate();

    </script>
</body>
</html>
```
qwen3.5:9bOKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Crowd Simulation</title>
    <style>
        body { margin: 0; overflow: hidden; background: #111; }
        canvas { display: block; }
    </style>
</head>
<body>
    <canvas id="crowdCanvas"></canvas>
    <script>
        const canvas = document.getElementById('crowdCanvas');
        const ctx = canvas.getContext('2d');
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        let agents = [];
        let goal = { x: canvas.width * 0.15, y: canvas.height / 2 }; // Narrow exit location
        const AGENT_COUNT = 400;
        const REPULSION_DIST = 30;
        const ATTRACTION_STRENGTH = 0.005;
        const MAX_SPEED = 2.5;
        const REFILL_INTERVAL = 100; // Frames until refill attempt

        let flowRateCount = 0;
        let lastRefreshTime = performance.now();
        let frameCounter = 0;

        function initAgents() {
            agents = [];
            for (let i = 0; i < AGENT_COUNT; i++) {
                agents.push({
                    x: Math.random() * canvas.width,
                    y: Math.random() * canvas.height,
                    vx: (Math.random() - 0.5) * 1,
                    vy: (Math.random() - 0.5) * 1,
                    r: 4
                });
            }
        }

        function updateStats(deltaTime) {
            let insideCount = 0;
            let throughput = 0;

            agents.forEach(a => {
                if (a.x > canvas.width * 0.85 || a.y < 0 || a.y > canvas.height) {
                    // Off screen or passed the exit area boundary for simplicity
                    return;
                }
                insideCount++;

                // Check passage through the narrow goal area (simple line check)
                if (a.x <= goal.x && Math.abs(a.y - goal.y) < 20 && a.vx > 0 && !a.passed) {
                    throughput++;
                    a.passed = true; // Mark as passed this frame
                }
            });

            // Simple flow rate calculation (per second estimate)
            const timeElapsed = deltaTime / 1000;
            if (timeElapsed >= 1) {
                 let rateChange = throughput * (timeElapsed - lastRefreshTime/1000);
                 flowRateCount = Math.min(30, flowRateCount + rateChange * 2); // Cap at 30 per second
            }

            return { inside: insideCount, flow: flowRateCount };
        }

        function applyForces() {
            for (let i = 0; i < agents.length; i++) {
                const a1 = agents[i];
                a1.vx *= 0.95; // Damping
                a1.vy *= 0.95;

                // Wall repulsion
                if (a1.x - a1.r < 0 || a1.x + a1.r > canvas.width) {
                    a1.vx -= Math.sign(a1.x - a1.r < 0 ? 0 : canvas.width - a1.x - a1.r);
                }
                if (a1.y - a1.r < 0 || a1.y + a1.r > canvas.height) {
                    a1.vy -= Math.sign(a1.y - a1.r < 0 ? 0 : canvas.height - a1.y - a1.r);
                }

                // Goal attraction (force towards the center of the exit line)
                const dxG = goal.x - a1.x;
                const dyG = goal.y - a1.y;
                let distG = Math.sqrt(dxG * dxG + dyG * dyG);

                if (distG > 0) {
                    a1.vx += dxG / distG * ATTRACTION_STRENGTH;
                    a1.vy += dyG / distG * ATTRACTION_STRENGTH;
                }

                // Repulsion from neighbors
                for (let j = i + 1; j < agents.length; j++) {
                    const a2 = agents[j];
                    const dx = a2.x - a1.x;
                    const dy = a2.y - a1.y;
                    let distSq = dx * dx + dy * dy;

                    if (distSq < REPULSION_DIST * REPULSION_DIST && distSq > 0) {
                        let force = (REPULSION_DIST * REPULSION_DIST / Math.sqrt(distSq)) * 0.5;
                        a1.vx -= dx / Math.sqrt(distSq) * force;
                        a1.vy -= dy / Math.sqrt(distSq) * force;

                        a2.vx += dx / Math.sqrt(distSq) * force;
                        a2.vy += dy / Math.sqrt(distSq) * force;
                    }
                }
            }
        }

        function updatePositions() {
            for (let i = 0; i < agents.length; i++) {
                const a = agents[i];
                a.x += a.vx;
                a.y += a.vy;
            }
        }

        function drawAgents() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            agents.forEach(a => {
                ctx.fillStyle = '#FFF';
                ctx.beginPath();
                ctx.arc(a.x, a.y, a.r, 0, Math.PI * 2);
                ctx.fill();
            });
        }

        function simulationLoop(timestamp) {
            const deltaTime = timestamp - (window.lastTimestamp || timestamp);
            window.lastTimestamp = timestamp;

            // Step 1: Apply forces and calculate new velocities
            applyForces();

            // Step 2: Update positions based on velocities
            updatePositions();

            // Step 3: Draw everything
            drawAgents();

            // Step 4: Calculate stats (passing through the goal)
            const { inside, flow } = updateStats(deltaTime);

            // Status display
            ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
            ctx.font = '16px monospace';
            ctx.fillText(`Inside: ${inside} | Flow Rate: ${Math.round(flow)}/s`, 10, 30);

            // Refill logic
            if (inside < AGENT_COUNT * 0.1 && frameCounter >= REFILL_INTERVAL) {
                initAgents();
                frameCounter = 0;
                lastRefreshTime = timestamp;
            }

            requestAnimationFrame(simulationLoop);
        }

        // Initialization
        window.onload = () => {
            initAgents();
            window.lastTimestamp = performance.now();
            requestAnimationFrame(simulationLoop);
        };

    </script>
</body>
</html>
```
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.
qwq:32bOKFORMAT
Show code
<think>

Okay, I need to create an HTML file that simulates a crowd moving towards a narrow exit with forces acting on them. Let me think through the steps.

First, the HTML structure. I'll have a canvas element and a few divs to display the count and flow rate. The canvas will handle the animation. Since the user wants it self-contained, all code has to be inline.

Next, the JavaScript part. I need to model each person as an object with position, velocity, and maybe acceleration. Each person should have a force towards the door and repulsion from others and walls.

The door is a single narrow exit, so maybe the bottom edge of the canvas? Let me define the door position. The people should be attracted to the door's center, perhaps with a gravitational force. The repulsion from others can be calculated using distance between each pair of people. Also, walls are the edges of the canvas, so people repel away from them when too close.

I'll need arrays to store the people and track the ones inside. The simulation should refill the room once emptied. The flow rate is the number leaving per second, so I can track time and calculate it based on the number that exited in a frame.

For the animation loop using requestAnimationFrame. Each frame, update each person's forces, apply velocity and position, check if they've exited, and update the counters. Repopulate when all are gone.

Wait, how to calculate forces? Maybe for each person, compute a vector towards the door, scaled by some attraction strength. Then for repulsion, loop through all others and compute a repulsion vector when they are too close. Also, walls: check distance to edges and add force when near.

To prevent excessive computation, maybe optimize the repulsion by not checking every pair, but that might be too hard. Since it's several hundred people, maybe 500, a double loop for repulsion might be slow. Hmm, but the user specified several hundred, so maybe 500 is manageable?

Let me outline the steps per frame:

1. For each person in the array:
   a. Compute attraction to door (maybe direction towards door center, scaled by a constant)
   b. Compute repulsion from others: for every other person, if distance < threshold, add a repulsion force proportional to inverse distance squared or something.
   c. Compute repulsion from walls: if near any edge (left/right/top/bottom), add a force away from the edge.
   d. Sum all forces, then update acceleration, velocity, position with Euler integration (or simple step? Maybe velocity += force * delta time, but need to manage time steps properly).

Wait, time management: using delta time between frames would be better to avoid speed differences, but since requestAnimationFrame gives a timestamp, maybe calculate delta time and use that for velocity updates. Or maybe just use a constant time step since it's a simulation and the effect might not need exact physics.

Alternatively, maybe the forces can be calculated per unit time, multiplied by delta time for each frame. Let's see.

Variables needed:

- canvas context
- array of people (each with x,y,vx,vy, etc.)
- door position (maybe centered at bottom edge)
- count of remaining people
- total flowed count
- time for flow rate calculation
- a flag to know when to refill

Initialization steps:

- Populate the array with N people (like 500) randomly placed in the room (maybe top left? Or spread out initially? Wait, the user says "each steered by a force towards the door", so initial positions might be spread around the room. Or maybe they start in some area, but need to be initially inside the room.)

Wait, the door is the exit, so initial positions need to be inside the room. Maybe the room is the entire canvas, with the door being the lower edge's middle point.

Wait, the door is a single narrow exit, perhaps a small rectangle at the bottom center. So the exit is a gate, and when a person's position crosses the door, they exit.

So first, define the door as a rectangle: let's say the bottom edge's center with some width, maybe 50px wide? So the door is at the bottom edge, centered, 50px wide. When a person's y is above the door's y (so door is at the bottom edge?), wait maybe the door is at the very bottom, so the exit is when their y is below a certain point, but that might complicate.

Alternatively, the door is a rectangle at bottom center, and when the person's position enters that rectangle, they are considered to have exited.

But perhaps simpler: the door is a point at (cx, cy) at the bottom edge. People are attracted to that point. When their distance to the door point is less than a threshold, like 30px, they exit? Or perhaps when their y coordinate reaches the bottom edge.

Hmm, maybe the door is at the bottom center (cx, cy = canvas.width/2, canvas.height). The exit is when the person's y reaches the bottom of the canvas (cy), and they move towards that point. So the attraction is towards (cx, cy). But to exit, they need to be near that point and moving down. Alternatively, once they reach the bottom edge, they are removed.

But then the repulsion from the door would be tricky. Maybe the attraction is towards the door's center, but once they reach the door's area, they get through. Hmm, perhaps better to have the door as a rectangle, and once a person is inside, they exit.

Alternatively, when a person's y coordinate is at least (canvas.height - 5), they exit. So the door is the lower edge. The attraction is to the center (canvas.width/2, canvas.height). Then, the repulsion from the bottom edge would be when they are too close to the edge (but maybe they can move through it once they are close enough).

Wait, but the repulsion from the walls should prevent them from going beyond the edges. Unless the door is part of the wall but allows exiting when they reach it.

Hmm, perhaps the walls are the top, left, right, and bottom edges except near the door. The door is a region in the bottom where they can exit.

Alternatively, the attraction is to the door center, and when they reach the door's area (like within a certain radius), they are removed from the array and counted as exited.

So the steps for each person:

- Compute attraction force towards door point (cx, cy)
- Compute repulsion from other people
- Compute repulsion from walls (left/right/top)
- Sum all forces, apply to velocity
- Update position
- Check if they are near door (within exit area) to remove them

Now, the repulsion from walls: when a person is within a certain distance (like 50px) from the walls (left, right, top), they get a repulsion force pushing them away. The bottom is the exit, so maybe no repulsion there except near the door? Or maybe the bottom's repulsion is only active outside the door area.

Alternatively, the bottom edge is part of the repulsion except the door region. Not sure, perhaps easier to have repulsion from walls (left/right/top edges) but not the bottom.

Wait, the door is on the bottom edge. So, the bottom edge is the exit, so people can move towards it. Repulsion from walls would be left, right, top edges, but bottom is open except that the door is there. Hmm.

Alternatively, the repulsion from walls is for all edges, but the door region allows them to pass through. Maybe when they approach the door area, the repulsion from the bottom edge is disabled, allowing them to go through. But this could complicate.

Alternatively, just have the walls be left, right, top edges. The bottom edge is open, so no repulsion there. The attraction to the door (bottom center) would pull them down, but once they reach the bottom, they exit.

Hmm, perhaps that's simpler. Let me define:

Walls are left (x=0), right (x=canvas.width), top (y=0). The bottom (y=canvas.height) is the exit edge. The door is the entire bottom edge, so when a person's y reaches the bottom, they exit. Wait, but then how do they get out? They need to reach the bottom. So the attraction is to the center (cx, cy) of the bottom edge.

So attraction force towards (cx, cy). Each person's velocity is influenced by this, plus repulsion from others and walls.

When their y coordinate is equal to cy (the bottom edge), they are removed.

But in code, since pixels are integers, perhaps check if their y is >= (canvas.height - 5) or something to account for movement.

But maybe it's better to have the door as a point, and when they reach that point, they exit. Not sure. Alternatively, when their position is within a small radius of the door point, then exit.

Alternatively, for the exit condition, when their y is at the bottom edge (y >= canvas.height - 1), and their x is near the door's center (within some range). For example, the door is a 100px wide exit in the center, so if their x is between (cx -50, cx +50) and y is at the bottom, then they can exit.

This way, the bottleneck is enforced because only those in that region can exit.

Hmm, that might be better. So the door is a horizontal line segment in the center of the bottom edge, with a width. People can only exit through that segment.

So the exit condition is: if the person's y is greater than (canvas.height - 5) and their x is within (cx - doorWidth/2) to (cx + doorWidth/2), then they exit (removed from array).

This creates a bottleneck because only those in that horizontal strip can exit, others have to maneuver into that position.

So, door parameters:

doorX = canvas.width / 2

doorWidth = 100 (so from doorX -50 to doorX +50)

doorY = canvas.height (the bottom edge)

So exit when: y >= doorY - 2 (to account for movement) and x between (doorX - doorWidth/2) and (doorX + doorWidth/2)

Once they meet that, they leave the room, so removed from the array.

Now, the forces:

Attract to door center (doorX, doorY). The attraction force can be a vector pointing towards that point, with magnitude depending on distance.

Repulsion from other people: each person exerts a repulsion force on others when they are too close. The repulsion is proportional to 1/distance² (or something like that) so that when they are close, the force is strong.

Repulsion from walls: when a person is near the left, right, or top edges (bottom is the exit, so no repulsion there?), the force pushes them away.

Now, the forces need to be calculated for each particle each frame.

Let me think about each particle's forces:

For attraction to door:

dx = doorX - person.x

dy = doorY - person.y

distance = sqrt(dx*dx + dy*dy)

if distance > 0:

    force_x = (dx / distance) * attraction_strength

    force_y = (dy / distance) * attraction_strength

But maybe attraction_strength is a constant, like 0.1, so the force is proportional to the unit vector towards the door.

Alternatively, attraction could be stronger when further away, but maybe linear.

Then, repulsion from others:

for each other in people:

    dx = other.x - person.x

    dy = other.y - person.y

    dist_sq = dx*dx + dy*dy

    if dist_sq < min_dist_sq (to prevent division by zero):

        continue

    strength = repulsion_strength / dist_sq

    force_x += (dx / sqrt(dist_sq)) * strength

    force_y += (dy / sqrt(dist_sq)) * strength

Wait, but sqrt is needed for unit vector? Alternatively, the repulsion could be proportional to 1/distance^2, and direction is away from the other person. So:

if distance is small, the repulsion is strong, pushing away.

But calculating this for every pair could be computationally heavy for 500 people. Since 500 people, that's 500*500 = 250,000 calculations per frame, which might be too much. Hmm.

But maybe the user says "several hundred", so perhaps 500 is manageable? Or maybe we can optimize by not checking every pair? Like, only check neighbors within a certain radius.

Alternatively, reduce the repulsion strength, but the user wants them to pile up, so the repulsion is necessary.

Alternatively, use a threshold distance beyond which repulsion is ignored. Like, if distance is more than 100px, no repulsion.

Wait, in the problem statement, the people should be repelled by their neighbors, so the repulsion is strongest when close, which is exactly what that formula does. But with 500 particles, this could be slow. Maybe need to find a way to optimize.

Alternatively, for each particle, only check a subset of others, like in a grid? Not sure, but given time constraints, perhaps proceed with the double loop and hope it's okay.

Next, walls' repulsion:

For the left wall (x=0):

if person.x < wall_repulsion_distance, then

force_x += (wall_repulsion_strength) * (wall_repulsion_distance - person.x) / wall_repulsion_distance

Wait, but better to compute the distance to the wall and apply force.

Left wall: distance to left is person.x. If person.x < repulsion_distance, the repulsion is towards increasing x.

So the force_x += (repulsion_strength / (person.x)^2 ) ?

Wait, similar to repulsion between particles.

Alternatively, a repulsion force proportional to (repulsion_distance - distance)^3, but perhaps simpler to just a force pushing away when near the edges.

Alternatively, the repulsion from walls could be calculated as follows:

for left wall (x=0):

dist = person.x

if dist < repulsion_distance:

    // push to the right

    force_x += (repulsion_strength / (dist * dist)) * (repulsion_distance - dist)

Wait, not sure, perhaps the repulsion from walls is:

for each edge:

left edge: if x < repulsionDistance, then add to force_x a value proportional to (repulsionDistance - x)

Similarly for right edge (x > width - repulsionDistance): add to force_x a negative value pushing to the left.

Top edge (y < repulsionDistance): push down?

Wait, the top wall is at y=0. So if the person's y is less than repulsionDistance, then their y is near the top edge, so repulsion pushes down.

Bottom edge (the exit area) is okay, so no repulsion there.

So for each wall:

Left wall:

if (person.x < repulsionDistance) {

    force_x += repulsion_strength * (repulsionDistance - person.x);

}

Similarly,

Right wall:

if (person.x > (canvas.width - repulsionDistance)) {

    force_x -= repulsion_strength * (person.x - (canvas.width - repulsionDistance));

}

Top wall:

if (person.y < repulsionDistance) {

    force_y += repulsion_strength * (repulsionDistance - person.y);

}

This way, the closer to the wall, the stronger the repulsion.

The repulsion_strength for walls might need to be higher than for people, to prevent them from getting stuck in the walls.

Now, putting it all together.

Variables:

- const canvas = document.getElementById('myCanvas');

- ctx = canvas.getContext('2d');

- people array: each has x, y, vx, vy.

Constants:

- doorX = canvas.width / 2,

- doorY = canvas.height,

- doorWidth = 100;

- attractionStrength = 0.2;

- repulsionStrengthPeople = 0.001;

- repulsionDistance = 15; // distance from wall to start repelling

- repulsionStrengthWall = 0.4;

- friction = 0.95; // velocity damping, to prevent infinite speed

Wait, maybe also include a friction term to slow them down over time. So in each step, velocity is multiplied by friction, to simulate some damping.

Alternatively, the forces can include a friction term. Hmm.

Now, the steps in the animation loop:

function animate() {

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

    let exitedCount = 0;

    for (let i = people.length - 1; i >= 0; i--) {

        let p = people[i];

        // Compute forces

        let forceX = 0, forceY = 0;

        // Attraction to door

        let dx = doorX - p.x;

        let dy = doorY - p.y;

        let distance = Math.sqrt(dx*dx + dy*dy);

        if (distance > 0) {

            forceX += (dx / distance) * attractionStrength;

            forceY += (dy / distance) * attractionStrength;

        }

        // Repulsion from walls

        // Left wall

        if (p.x < repulsionDistance) {

            let delta = repulsionDistance - p.x;

            forceX += delta * repulsionStrengthWall;

        }

        // Right wall

        if (p.x > canvas.width - repulsionDistance) {

            let delta = p.x - (canvas.width - repulsionDistance);

            forceX -= delta * repulsionStrengthWall;

        }

        // Top wall

        if (p.y < repulsionDistance) {

            let delta = repulsionDistance - p.y;

            forceY += delta * repulsionStrengthWall;

        }

        // Repulsion from other people

        for (let j = 0; j < people.length; j++) {

            if (i === j) continue;

            let other = people[j];

            let dx = other.x - p.x;

            let dy = other.y - p.y;

            let dist_sq = dx*dx + dy*dy;

            if (dist_sq < 1) continue; // avoid division by zero

            let invDist_sq = 1 / dist_sq;

            let invDist = Math.sqrt(invDist_sq); // sqrt(1/d^2) = 1/d

            // Strength is proportional to 1/d^2 ?

            let strength = repulsionStrengthPeople * invDist_sq; 

            forceX += (dx * strength);

            forceY += (dy * strength);

        }

        // Apply forces to velocity

        // Let's say acceleration is force, so velocity += force * delta_time?

        // Assuming delta_time is 1 (since we're in animation frame?)

        // Maybe introduce a scaling factor to control speed.

        const accelerationScale = 0.1;

        p.vx += forceX * accelerationScale;

        p.vy += forceY * accelerationScale;

        // Apply friction (damping)

        p.vx *= friction;

        p.vy *= friction;

        // Update position

        p.x += p.vx;

        p.y += p.vy;

        // Check exit condition

        let exitXMin = doorX - doorWidth/2;

        let exitXMax = doorX + doorWidth/2;

        if (p.y >= doorY - 5 && p.x >= exitXMin && p.x <= exitXMax) {

            // exited!

            exitedCount++;

            people.splice(i, 1); // remove from array

        }

    }

    // Draw all remaining people

    ctx.fillStyle = 'blue';

    for (let p of people) {

        ctx.beginPath();

        ctx.arc(p.x, p.y, 3, 0, 2*Math.PI);

        ctx.fill();

    }

    // Update UI elements: exitedCount, current population, etc.

    document.getElementById('exited').textContent = exitedCount;

    document.getElementById('current').textContent = people.length;

    // If all people have exited, reset and start again?

    // Not sure yet, maybe have a timer.

    requestAnimationFrame(animate);

}

Wait, but in this code, exitedCount is the number of people who exited in this frame, but the total exited should be tracked. Maybe a separate variable.

Also, initial setup: when starting, the people are placed randomly in the canvas except near the exit.

Wait, initially, perhaps the people are placed in the top left or somewhere not too close to the door.

So in the setup:

function init() {

    people = [];

    for (let i=0; i<500; i++) {

        let x = Math.random() * (canvas.width - 200) + 100; // not too near edges?

        let y = Math.random() * (canvas.height - 200) + 100;

        // Ensure not in exit area initially?

        // door is at the bottom center, so avoid that region

        while (y > canvas.height - 100) {

            y = Math.random() * (canvas.height - 200) + 100;

        }

        people.push({

            x: x,

            y: y,

            vx: 0,

            vy: 0

        });

    }

}

But this might be too much code. Let's think about constants and how to structure it.

Additionally, the problem mentions creating the simulation, but the user might need code that runs in a browser, using canvas.

Another thing: to make the people pile up, the attraction should be towards the exit, but the repulsion between them creates a jam.

Maybe the parameters need to be tuned: attraction strength, repulsion strengths, friction, etc.

Testing this code might require tweaking these values.

Now, putting all together in a HTML page:

But since the user asked for the code, perhaps present the JavaScript part with necessary variables and functions.

Wait, but the user wants the code to create the simulation.

Let me structure the code properly, using canvas, and with all the parameters.

Also, when all people have exited, perhaps reset the scene after a delay.

But the user didn't specify, so maybe just loop continuously.

Now, the full code:

```html
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="800" height="600"></canvas>
<div id="status">
    Exited: <span id="exited">0</span>
    Current: <span id="current">500</span>
</div>

<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const doorX = canvas.width / 2;
const doorY = canvas.height; // bottom edge
const doorWidth = 100;
const attractionStrength = 0.1;
const repulsionStrengthPeople = 0.002;
const repulsionDistance = 20; // distance from wall to start repelling
const repulsionStrengthWall = 0.5;
const friction = 0.9; // velocity damping

let people = [];
let exitedCount = 0;

function init() {
    people = [];
    exitedCount = 0;
    document.getElementById('exited').textContent = 0;
    document.getElementById('current').textContent = 500;
    for (let i = 0; i < 500; i++) {
        let x = Math.random() * (canvas.width - 50) + 25; // avoid edges
        let y = Math.random() * (canvas.height - 200) + 50; // not near the bottom
        people.push({
            x: x,
            y: y,
            vx: 0,
            vy: 0
        });
    }
}

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

    for (let i = people.length - 1; i >= 0; i--) {
        const p = people[i];
        let forceX = 0, forceY = 0;

        // Attraction to door
        const dx = doorX - p.x;
        const dy = doorY - p.y;
        const distance = Math.sqrt(dx * dx + dy * dy);
        if (distance > 0) {
            forceX += (dx / distance) * attractionStrength;
            forceY += (dy / distance) * attractionStrength;
        }

        // Repulsion from walls
        if (p.x < repulsionDistance) {
            forceX += (repulsionDistance - p.x) * repulsionStrengthWall;
        } else if (p.x > canvas.width - repulsionDistance) {
            forceX -= (p.x - (canvas.width - repulsionDistance)) * repulsionStrengthWall;
        }
        if (p.y < repulsionDistance) {
            forceY += (repulsionDistance - p.y) * repulsionStrengthWall;
        }

        // Repulsion from other people
        for (let j = 0; j < people.length; j++) {
            if (i === j) continue;
            const other = people[j];
            const dx_p = other.x - p.x;
            const dy_p = other.y - p.y;
            const dist_sq = dx_p * dx_p + dy_p * dy_p;
            if (dist_sq < 1) continue;
            const invDist_sq = 1 / dist_sq;
            const strength = repulsionStrengthPeople * invDist_sq;
            forceX += dx_p * strength;
            forceY += dy_p * strength;
        }

        // Update velocity with forces
        p.vx += forceX * 0.1; // scaling factor
        p.vy += forceY * 0.1;

        // Apply friction
        p.vx *= friction;
        p.vy *= friction;

        // Update position
        p.x += p.vx;
        p.y += p.vy;

        // Check exit condition
        const exitXMin = doorX - doorWidth / 2;
        const exitXMax = doorX + doorWidth / 2;
        if (p.y >= doorY - 5 && p.x >= exitXMin && p.x <= exitXMax) {
            // exited
            people.splice(i, 1);
            exitedCount++;
            document.getElementById('exited').textContent = exitedCount;
            document.getElementById('current').textContent = people.length;
        }
    }

    // Draw people
    ctx.fillStyle = 'blue';
    ctx.beginPath();
    for (const p of people) {
        ctx.moveTo(p.x, p.y);
        ctx.arc(p.x, p.y, 3, 0, Math.PI * 2);
    }
    ctx.fill();

    requestAnimationFrame(animate);
}

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

This is a rough implementation. It might need some tuning of constants to see the piling effect. The parameters like attractionStrength, repulsionStrengthPeople, and friction can be adjusted. Also, the initial positions need to be such that they start away from the exit.

Potential issues to check:

- The repulsion between particles might not be strong enough; increasing repulsionStrengthPeople could help.

- The attraction to the door might be too weak; increasing attractionStrength.

- Friction too high or low. Friction set to 0.9 means 10% velocity loss each frame.

- The exit condition uses doorY which is the bottom of the canvas (600px if height is 600). The condition p.y >= doorY -5 would be when they're near the bottom edge.

- The exit area is a horizontal strip in the center.

The code uses canvas to draw blue dots, and shows the count of exited and current people.

I think this should work, though it might require some tweaking of values to see the desired effect of people piling up near the exit.
deepseek-r1:32bERRBLANKFORMAT
Show code
```html
<!DOCTYPE html><html><body style="background:#1a1a1a;margin:0;display:flex;flex-direction:column;align-items:center"><canvas id=c width=640 height=360></canvas><div style="color:white;font-family:sans-serif">Inside: <span id=n>500</span><br>Flow rate: <span id=f>0</span>/s</div><script>
const c=document.getElementById('c'),ctx=c.getContext('2d')
const W=640,H=360,EXIT_W=100,EXIT_H=20,REFILL=500
let people=[],count=0,width=W,height=H,exitX=W/2-exitW/2,exitY=H-50,iterations=0,lastReset=0,flowRate=0

class Person{
constructor(x,y){
this.x=x;this.y=y;this.vx=0;this.vy=0
this.fx=0;this.fy=0;this.radius=10
}
update(){
let forceX=0,forceY=0
// Attraction to exit
let dx=exitX+EXIT_W/2 - this.x
let dy=exitY - this.y
forceX += dx*.5
forceY += dy*.5

// Repulsion from walls
if(this.x < this.radius){forceX += (this.radius - this.x)*.5}
if(this.y < this.radius){forceY += (this.radius - this.y)*.5}
if(this.x > W - this.radius){forceX -= (W - this.radius - this.x)*.5}
if(this.y > H - 100 - this.radius){forceY += (H - 100 - this.radius - this.y)*2}

// Apply forces
this.fx=forceX/5;this.fy=forceY/5

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

// Simple damping
this.vx *= .98
this.vy *= .98

// Check exit
if(this.y < exitY && this.x > exitX && this.x < exitX + EXIT_W){
people.splice(people.indexOf(this),1)
count--
}
}

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

function init(){
people=[];count=REFILL;lastReset=Date.now()
for(let i=0;i<REFILL;i++){
let x=Math.random()*(W/2-50)+100
let y=Math.random()*(H/2-50)+100
while(people.some(p=>Math.hypot(x-p.x,y-p.y)<p.radius*2)){
x=Math.random()*(W/2-50)+100
y=Math.random()*(H/2-50)+100
}
people.push(new Person(x,y))
}
}

function animate(){
iterations++
if(iterations%60===0){
let now=Date.now()
flowRate=(REFILL - count)/((now-lastReset)/1000)
document.getElementById('f').innerHTML=Math.round(flowRate).toFixed(1)
}
if(count<=0&&iterations>500){
init()
return
}

ctx.clearRect(0,0,W,H)

// Update and draw people
for(let p of people){
p.update()

// Collision detection
people.forEach(other=>{
if(other===p)return
let dx=p.x-other.x
let dy=p.y-other.y
let dist=Math.hypot(dx,dy)
if(dist<p.radius+other.radius){
let overlap=(p.radius + other.radius - dist)/2
p.x-=dx/overlap*.5
p.y-=dy/overlap*.5
}
})
}

// Draw exit
ctx.fillStyle='#0f0'
ctx.fillRect(exitX,exitY,EXIT_W,-EXIT_H)

people.forEach(p=>p.draw())
document.getElementById('n').innerHTML=count

requestAnimationFrame(animate)
}

init()
animate()
</script></body></html>
```
command-r:35bOKFORMAT
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>Crowd Simulation</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background-color: #111;
        }
        canvas {
            display: block;
        }
    </style>
</head>
<body>
    <canvas id="simulationCanvas"></canvas>
    <script>
        const canvas = document.getElementById('simulationCanvas');
        const ctx = canvas.getContext('2d');
        
        let people = [];
        let MAX_PEOPLE = 300;
        let roomWidth = 400;
        let roomHeight = 400;
        let exitX = roomWidth - 50;
        let doorWidth = 100;

        function createPeople() {
            for (let i = 0; i < MAX_PEOPLE; i++) {
                people.push({
                    x: Math.random() * roomWidth,
                    y: Math.random() * roomHeight,
                    vx: 0,
                    vy: 0,
                    radius: 15,
                    color: `hsl(${Math.random()*360}, 100%, 80%)`
                });
            }
        }

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

            people.forEach((person) => {
                // Apply forces
                let exitForceX = (exitX - person.x) * 0.1;
                let exitForceY = (roomHeight/2 - person.y) * 0.05;
                let repulsionStrength = 0.08;

                people.forEach((otherPerson) => {
                    if (person === otherPerson) return;
                    const dX = person.x - otherPerson.x;
                    const dY = person.y - otherPerson.y;
                    const distance = Math.sqrt(dX * dX + dY * dY);
                    if (distance > 0 && distance < 60) {
                        let forceX = dX / distance * repulsionStrength;
                        let forceY = dY / distance * repulsionStrength;
                        person.vx -= forceX;
                        person.vy -= forceY;
                    }
                });

                const wallRepulsion = 4;
                if (person.x - person.radius < wallRepulsion) {
                    person.vx += wallRepulsion - (person.x - person.radius);
                } else if (person.x + person.radius > roomWidth - wallRepulsion) {
                    person.vx -= wallRepulsion + (person.x + person.radius) - roomWidth;
                }

                person.vx += exitForceX * 0.15;
                person.vy += exitForceY * 0.15;

                // Update position and bounce off walls
                person.x += person.vx;
                person.y += person.vy;
                if (person.x - person.radius < 0) {
                    person.x = person.radius;
                    person.vx *= -1;
                } else if (person.x + person.radius > roomWidth) {
                    person.x = roomWidth - person.radius;
                    person.vx *= -1;
                }
                if (person.y - person.radius < 0) {
                    person.y = person.radius;
                    person.vy *= -1;
                } else if (person.y + person.radius > roomHeight) {
                    person.y = roomHeight - person.radius;
                    person.vy *= -1;
                }

                // Draw the person
                ctx.beginPath();
                ctx.arc(person.x, person.y, person.radius, 0, Math.PI * 2);
                ctx.fillStyle = person.color;
                ctx.fill();
            });

            // Handle exit and refill room
            let exitingPeople = people.filter(p => p.x > MAX_PEOPLE && p.vx > 0);
            for (let i = 0, len = exitingPeople.length; i < len; i++) {
                if (!people.includes(exitingPeople[i])) continue; // safety check
                let index = people.indexOf(exitingPeople[i]);
                people.splice(index, 1);
            }

            if (people.length === 0) createPeople();
            
            requestAnimationFrame(updateAndDraw);
        }

        window.onload = function() {
            canvas.width = roomWidth;
            canvas.height = roomHeight;
            createPeople();
            updateAndDraw();
        };
    </script>
</body>
</html>
```
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>Crowd Exit</title><style>html,body{margin:0;height:100%;overflow:hidden;background:#111;color:#ddd;font:15px system-ui}canvas{display:block;width:100vw;height:100vh}#h{position:fixed;left:14px;top:12px;background:#0009;padding:8px 10px;border-radius:6px}</style></head><body><canvas id=c></canvas><div id=h></div><script>
let c=document.getElementById("c"),x=c.getContext("2d"),h=document.getElementById("h"),W,H,S,door,ps=[],gone=0,last=0,rate=0,t0=0;
function R(a,b){return a+Math.random()*(b-a)}
function reset(){
 W=c.width=innerWidth*devicePixelRatio;H=c.height=innerHeight*devicePixelRatio;x.setTransform(devicePixelRatio,0,0,devicePixelRatio,0,0);W=innerWidth;H=innerHeight;S=Math.min(W,H);door={x:W/2,w:S*.085,y:24};ps=[];gone=0;last=0;rate=0;t0=performance.now();
 let n=Math.max(360,Math.min(720,(W*H/1900)|0));
 for(let i=0;i<n;i++)ps.push({x:R(40,W-40),y:R(H*.28,H-35),vx:R(-.4,.4),vy:R(-.3,.3),r:R(2.6,3.6),out:0});
}
onresize=reset;reset();
function step(T){
 let dt=Math.min(.033,(T-last||16)/1000);last=T;
 x.fillStyle="#151719";x.fillRect(0,0,W,H);
 x.fillStyle="#2a2d30";x.fillRect(22,22,W-44,H-44);
 x.fillStyle="#101214";x.fillRect(28,28,W-56,H-56);
 x.fillStyle="#58d68d";x.fillRect(door.x-door.w/2,0,door.w,30);
 x.fillStyle="#444";x.fillRect(22,22,door.x-door.w/2-22,10);x.fillRect(door.x+door.w/2,22,W-door.x-door.w/2-22,10);
 let cell=13,g=new Map(),alive=0,passed=0;
 for(let p of ps)if(!p.out){let k=((p.x/cell)|0)+","+((p.y/cell)|0);(g.get(k)||g.set(k,[]).get(k)).push(p)}
 for(let p of ps){
  if(p.out){p.y-=70*dt;if(p.y<-10)p.out=2;continue}
  alive++;
  let dx=door.x-p.x,dy=door.y-p.y,d=Math.hypot(dx,dy)||1,fx=dx/d*72,fy=dy/d*72;
  let cx=(p.x/cell)|0,cy=(p.y/cell)|0;
  for(let ix=-1;ix<=1;ix++)for(let iy=-1;iy<=1;iy++){let a=g.get(cx+ix+","+ (cy+iy));if(a)for(let q of a)if(q!==p){let ox=p.x-q.x,oy=p.y-q.y,dd=Math.hypot(ox,oy)||1,m=p.r+q.r+4;if(dd<m){let f=(m-dd)*42/dd;fx+=ox*f;fy+=oy*f}}}
  let l=31,r=W-31,top=31,bot=H-31;
  if(p.x<l+16)fx+=(l+16-p.x)*70;if(p.x>r-16)fx-=(p.x-r+16)*70;if(p.y>bot-16)fy-=(p.y-bot+16)*70;
  if(p.y<top+18&&(p.x<door.x-door.w/2||p.x>door.x+door.w/2))fy+=(top+18-p.y)*90;
  p.vx=(p.vx+fx*dt)*.88;p.vy=(p.vy+fy*dt)*.88;
  let sp=Math.hypot(p.vx,p.vy),mx=95;if(sp>mx){p.vx=p.vx/sp*mx;p.vy=p.vy/sp*mx}
  p.x+=p.vx*dt;p.y+=p.vy*dt;
  if(p.y<25&&Math.abs(p.x-door.x)<door.w/2){p.out=1;gone++;passed++}
  x.beginPath();x.fillStyle=p.y<90?"#f6c85f":"#70a1ff";x.arc(p.x,p.y,p.r,0,7);x.fill()
 }
 if(T-t0>1000){rate=gone/((T-t0)/1000)}
 h.textContent="inside "+alive+"   flow "+rate.toFixed(1)+"/s";
 if(alive<1)reset();
 requestAnimationFrame(step)
}
requestAnimationFrame(step)
</script></body></html>
Show code
<!DOCTYPE html><html><head><meta charset="utf-8"><title>Crowd Exit</title>
<style>html,body{margin:0;overflow:hidden;background:#0b0d12}canvas{display:block}</style>
</head><body><canvas id="c"></canvas><script>
const cv=document.getElementById('c'),x=cv.getContext('2d');
let W,H;
function resize(){W=cv.width=innerWidth;H=cv.height=innerHeight}
resize();addEventListener('resize',resize);
function bounds(){return{L:W*0.15,R:W*0.85,T:H*0.1,B:H*0.8,dc:W*0.5,dh:Math.max(16,W*0.018)}}
let people=[],exits=[],drained=0,last=0;
function spawn(n){
  people=[];
  const b=bounds();
  for(let i=0;i<n;i++){
    people.push({
      x:b.L+10+Math.random()*(b.R-b.L-20),
      y:b.T+10+Math.random()*((b.B-b.T)*0.75),
      vx:0,vy:0
    });
  }
}
spawn(260+Math.floor(Math.random()*140));
const ACC=260,REP=2000,WF=9,MAXSPD=150,RAD=4,MIND=9;
function tick(t){
  if(!last)last=t;
  const dt=Math.min(0.033,(t-last)/1000);
  last=t;
  x.fillStyle='#0b0d12';x.fillRect(0,0,W,H);
  const b=bounds();
  const n=people.length;
  const ax=new Float32Array(n),ay=new Float32Array(n);
  const tx=b.dc,ty=b.B+50;
  for(let i=0;i<n;i++){
    const p=people[i];
    let dx=tx-p.x,dy=ty-p.y,d=Math.hypot(dx,dy)||1;
    ax[i]+=dx/d*ACC;ay[i]+=dy/d*ACC;
    if(p.x-b.L<20)ax[i]+=(20-(p.x-b.L))*WF;
    if(b.R-p.x<20)ax[i]-=(20-(b.R-p.x))*WF;
    if(p.y-b.T<20)ay[i]+=(20-(p.y-b.T))*WF;
    if(Math.abs(p.x-b.dc)>b.dh&&p.y<b.B&&b.B-p.y<20)ay[i]-=(20-(b.B-p.y))*WF;
  }
  for(let i=0;i<n;i++)for(let j=i+1;j<n;j++){
    const p=people[i],q=people[j];
    let dx=p.x-q.x,dy=p.y-q.y,d=Math.hypot(dx,dy)||0.01;
    if(d<MIND){
      const f=REP*(MIND-d)/MIND/d;
      ax[i]+=dx*f;ay[i]+=dy*f;
      ax[j]-=dx*f;ay[j]-=dy*f;
    }
  }
  x.strokeStyle='#5b6472';x.lineWidth=4;
  x.beginPath();
  x.moveTo(b.L,b.B);x.lineTo(b.L,b.T);x.lineTo(b.R,b.T);x.lineTo(b.R,b.B);
  x.stroke();
  x.beginPath();x.moveTo(b.L,b.B);x.lineTo(b.dc-b.dh,b.B);x.stroke();
  x.beginPath();x.moveTo(b.dc+b.dh,b.B);x.lineTo(b.R,b.B);x.stroke();
  x.strokeStyle='#3ad16f';x.lineWidth=6;
  x.beginPath();x.moveTo(b.dc-b.dh,b.B);x.lineTo(b.dc+b.dh,b.B);x.stroke();
  for(let i=n-1;i>=0;i--){
    const p=people[i];
    p.vx=(p.vx+ax[i]*dt)*0.9;
    p.vy=(p.vy+ay[i]*dt)*0.9;
    const sp=Math.hypot(p.vx,p.vy);
    if(sp>MAXSPD){p.vx=p.vx/sp*MAXSPD;p.vy=p.vy/sp*MAXSPD}
    p.x+=p.vx*dt;p.y+=p.vy*dt;
    if(p.y>b.B+40){people.splice(i,1);drained++;exits.push(t)}
  }
  exits=exits.filter(e=>t-e<1000);
  x.fillStyle='#ffcf4a';
  for(const p of people){
    x.beginPath();x.arc(p.x,p.y,RAD,0,6.3);x.fill();
  }
  if(people.length===0){spawn(250+Math.floor(Math.random()*160));drained=0}
  x.fillStyle='#e8ecf1';x.font='18px sans-serif';
  x.fillText('Inside: '+people.length,20,30);
  x.fillText('Flow: '+exits.length+'/s',20,54);
  requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
</script></body></html>
Show code
<!DOCTYPE html><html><head><title>Crowd</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 ppl=[];for(let j=0;j<200;j++){ppl.push({x:Math.random()*300+50,y:Math.random()*300+50,vx:0,vy:0});}let out=0;
function d(){x.fillStyle='#111';x.fillRect(0,0,400,400);x.strokeStyle='#444';x.lineWidth=2;x.strokeRect(20,20,360,360);x.strokeStyle='#f00';x.lineWidth=3;x.strokeRect(185,350,30,20);for(let p of ppl){let fx=0,fy=0;fx+=(185-p.x)*0.002;fy+=(350-p.y)*0.002;for(let q of ppl){if(p===q)continue;const dx=q.x-p.x,dy=q.y-p.y,d=Math.hypot(dx,dy);if(d<15&&d>0){fx-=(dx/d)*0.5;fy-=(dy/d)*0.5;}}if(p.x<30)fx+=0.5;if(p.x>370)fx-=0.5;if(p.y<30)fy+=0.5;if(p.y>370)fy-=0.5;p.vx=p.vx*0.9+fx*0.1;p.vy=p.vy*0.9+fy*0.1;p.x+=p.vx;p.y+=p.vy;p.x=Math.max(20,Math.min(380,p.x));p.y=Math.max(20,Math.min(370,p.y));if(p.y>360&&p.x>180&&p.x<210){out++;ppl.splice(ppl.indexOf(p),1);}}if(Math.random()<0.02&&ppl.length<200){ppl.push({x:Math.random()*300+50,y:Math.random()*100+50,vx:0,vy:0});}x.fillStyle='#0f0';for(let p of ppl)x.fillRect(p.x-2,p.y-2,4,4);i.textContent=`Inside: ${ppl.length} | Flow: ${out}`;}(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
llama3.1:8b 166.3 sOK
gemma4:26b harness
qwen3-coder:30b 27.6 sOK
mistral-small:24b 178.0 sOK
deepseek-r1:14b 182.9 sOK
qwen3:14b 32.8 sOK
qwen3.5:9b 37.8 sOK
qwen3:8b harness
qwq:32b 194.2 sOK
deepseek-r1:32b 39.1 sOK
command-r:35b 60.1 sOK