Overview › Code › R77
Code · blind round

R77 · Crowd leaving a room, cell by cell

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.

A frontier reference answered the same task (Claude Opus 5) — outside the field and deliberately unscored, further down the page.

Show task
Create ONE self-contained HTML file (STRICT LIMIT: max 120 lines total) that simulates 60 people leaving a room through one exit on a 40x30 CELL GRID drawn on a <canvas>. Each step, every person moves one cell towards the exit along a precomputed distance field, and may not enter an occupied cell, so congestion and queues form at the door. Work strictly cell by cell — no floating-point positions, no velocities. Show how many have left and the step 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)
llama3.1:8bBLANKFORMAT
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>Cell Exit</title>
<style>
body { margin: 0; }
canvas { border: 1px solid black; }
</style>
</head>
<body>
<canvas id="c" width="400" height="300"></canvas>
<script>
const c = document.getElementById('c');
const ctx = c.getContext('2d');
let grid, exit, people;
function randomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }
function getDistance(x0, y0, x1, y1) {
  const dx = Math.abs(x1-x0);
  const dy = Math.abs(y1-y0);
  if (dx > dy) return { d: dx, u: [x1 - x0 < 0 ? -1 : 1, 0] };
  else return { d: dy, u: [0, y1 - y0 < 0 ? -1 : 1] };
}
function draw(x, y) {
  ctx.fillStyle = 'black';
  ctx.fillRect(x*10, y*10, 10, 10);
}
function step() {
  const nleft = people.filter(p => p.x == exit[0]).length;
  if (nleft > 0 || people.length == 0) {
    console.log(nleft + ' left in ' + stepcount++ + ' steps');
    window.location.reload();
  }
  for (const p of people) {
    const {d, u} = getDistance(p.x, p.y, exit[1], exit[2]);
    if (p.x < exit[1]) p.x += u[0];
    else if (p.y < exit[2]) p.y += u[1];
  }
}
let stepcount = 0;
grid = Array(40).fill().map(() => Array(30).fill(false));
exit = [20, 19, 29]; // x,y exit row
people = Array(60).fill().map(() => ({x: randomInt(0,39), y: randomInt(0,29)}));
for (const p of people) {
  if (grid[p.x][p.y]) p.x = randomInt(0,39);
  else grid[p.x][p.y] = true;
}
requestAnimationFrame(function anon() {
  ctx.fillStyle = 'white';
  ctx.fillRect(0, 0, c.width, c.height);
  people.forEach(draw);
  step();
  requestAnimationFrame(anon);
});
</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.
mistral-small:24bOKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Evacuation Simulation</title>
    <style>
        body { margin: 0; display: flex; justify-content: center; align-items: center; height: 100vh; background-color: #f0f0f0; }
        canvas { border: 1px solid black; }
        #info { position: absolute; top: 20px; left: 20px; font-family: Arial, sans-serif; color: black; }
    </style>
</head>
<body>
    <div id="info">Step: 0 | Left: 0/60</div>
    <canvas id="simulation" width="800" height="600"></canvas>
    <script>
        const canvas = document.getElementById('simulation');
        const ctx = canvas.getContext('2d');
        const info = document.getElementById('info');

        const gridWidth = 40;
        const gridHeight = 30;
        const cellSize = 20;
        const exitX = 19; // X-coordinate of the exit
        const exitY = 29; // Y-coordinate of the exit

        let stepCount = 0;
        let peopleLeft = 60;

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

            move() {
                if (this.x === exitX && this.y === exitY - 1) {
                    return true; // Person has left
                }
                const directions = [
                    { dx: 0, dy: 1 },
                    { dx: 1, dy: 0 },
                    { dx: -1, dy: 0 },
                    { dx: 0, dy: -1 }
                ];
                for (const dir of directions) {
                    const nx = this.x + dir.dx;
                    const ny = this.y + dir.dy;
                    if (nx === exitX && ny === exitY) {
                        return true; // Person has left
                    }
                    if (!grid[nx][ny] && !isOccupied(nx, ny)) {
                        grid[this.x][this.y] = false;
                        this.x = nx;
                        this.y = ny;
                        grid[this.x][this.y] = this;
                        break;
                    }
                }
                return false;
            }
        }

        function isOccupied(x, y) {
            for (const person of people) {
                if (person.x === x && person.y === y) {
                    return true;
                }
            }
            return false;
        }

        function drawGrid() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            for (let x = 0; x < gridWidth; x++) {
                for (let y = 0; y < gridHeight; y++) {
                    if (grid[x][y]) {
                        ctx.fillStyle = 'red';
                        ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
                    } else {
                        ctx.strokeRect(x * cellSize, y * cellSize, cellSize, cellSize);
                    }
                }
            }
        }

        function updateInfo() {
            info.textContent = `Step: ${stepCount} | Left: ${peopleLeft}/60`;
        }

        function animate() {
            stepCount++;
            people.forEach((person, index) => {
                if (person.move()) {
                    people.splice(index, 1);
                    peopleLeft--;
                }
            });

            drawGrid();
            updateInfo();

            if (people.length === 0) {
                setTimeout(() => location.reload(), 2000); // Restart after 2 seconds
                return;
            }

            requestAnimationFrame(animate);
        }

        const grid = Array.from({ length: gridWidth }, () =>
            Array(gridHeight).fill(false)
        );

        const people = [];
        for (let i = 0; i < 60; i++) {
            let x, y;
            do {
                x = Math.floor(Math.random() * gridWidth);
                y = Math.floor(Math.random() * gridHeight);
            } while (grid[x][y]);
            grid[x][y] = new Person(x, y);
            people.push(grid[x][y]);
        }

        animate();
    </script>
</body>
</html>
```
qwen3-coder:30bOKLIM
Show code
<!DOCTYPE html>
<html><head><title>Crowd Simulation</title></head><style>body{background:#333;margin:0;display:flex;justify-content:center;align-items:center;height:100vh;color:white}canvas{border:2px solid #666}</style><body><canvas id="c"></canvas><script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');

const COLS = 40;
const ROWS = 30;
const CELL_SIZE = 15;
canvas.width = COLS * CELL_SIZE;
canvas.height = ROWS * CELL_SIZE;

let people = [];
let stepCount = 0;
let leavingCount = 0;

function initializePeople() {
    people = [];
    for (let i = 0; i < 60; i++) {
        const startX = Math.floor(Math.random() * (COLS - 5)) + 2;
        const startY = Math.floor(Math.random() * (ROWS - 10)) + 5;
        people.push({ x: startX, y: startY, active: true });
    }
}

function drawGrid() {
    ctx.fillStyle = '#222';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    ctx.strokeStyle = '#333';
    for (let i = 0; i <= COLS; i++) ctx.strokeRect(i * CELL_SIZE, 0, CELL_SIZE, 1);
    for (let j = 0; j <= ROWS; j++) ctx.strokeRect(0, j * CELL_SIZE, 1, CELL_SIZE);
}

function drawPeople() {
    ctx.fillStyle = 'rgba(255, 100, 0, 0.8)'; // Orange for people
    people.forEach(p => {
        if (p.active) {
            const x = p.x * CELL_SIZE + 2;
            const y = p.y * CELL_SIZE + 2;
            ctx.fillRect(x, y, CELL_SIZE - 4, CELL_SIZE - 4);
        }
    });
}

function updateSimulation() {
    stepCount++;
    let occupiedCells = new Set();
    
    // Mark all current positions as occupied
    people.forEach(p => {
        if (p.active) {
            occupiedCells.add(`${p.x},${p.y}`);
        }
    });

    const nextPositions = people.map(p => ({ x: p.x, y: p.y })); 

    // Determine moves for all people sequentially to handle collisions/queuing
    people.forEach((p, i) => {
        if (!p.active) return;

        let targetX = Math.max(0, p.x - (p.x > 2 ? 1 : 0)); // Prioritize moving left (towards exit at X=0)
        let targetY = p.y;
        let moved = false;

        // Check if the primary move is blocked or leads out
        if (targetX < 0 || occupiedCells.has(`${targetX},${targetY}`)) {
            // If blocked, try moving vertically (Y-axis)
            let fallbackTargetY = p.y + Math.floor(Math.random() * 3) - 1; // Try adjacent row
            fallbackTargetY = Math.max(0, Math.min(ROWS - 1, fallbackTargetY));

            if (!occupiedCells.has(`${p.x},${fallbackTargetY}`)) {
                targetX = p.x;
                targetY = fallbackTargetY;
                moved = true;
            } else if (targetX < 0) { // Edge case: stuck at exit column, try vertical movement
                 if (!occupiedCells.has(`${p.x},${fallbackTargetY}`)) {
                    targetX = p.x;
                    targetY = fallbackTargetY;
                    moved = true;
                }
            }
        } else {
             // Primary move is clear and possible (moving left)
             targetX -= 1;
        }

        // Check final safety before committing the move
        if (targetX >= 0 && targetY >= 0 && targetX < COLS && targetY < ROWS && !occupiedCells.has(`${targetX},${targetY}`)) {
            nextPositions[i].x = targetX;
            nextPositions[i].y = targetY;
        } else if (Math.abs(parseFloat(p.x) - parseFloat(targetX)) > 0.1 || Math.abs(parseFloat(p.y) - parseFloat(targetY)) > 0.1){
             // If the calculated move is invalid or blocked, stay put
            nextPositions[i].x = p.x;
            nextPositions[i].y = p.y;
        }

    });

    // Apply moves and check for exit
    let newOccupiedCells = new Set();
    people.forEach((p, i) => {
        const nextP = nextPositions[i];
        if (!p.active) return;

        let exited = false;
        // Check if the target cell is outside the grid boundary (exit at X=-1 conceptually)
        if (nextP.x < 0 && p.x === 0) {
            exited = true;
        } else {
             p.x = nextP.x;
             p.y = nextP.y;
        }

        if (exited) {
            p.active = false;
            leavingCount++;
        } else {
            newOccupiedCells.add(`${p.x},${p.y}`);
        }
    });
}


function animate() {
    drawGrid();
    drawPeople();

    if (leavingCount < 60) {
        updateSimulation();
    }

    requestAnimationFrame(animate);
}

initializePeople();
animate();
</script></body></html>
qwen3.5:9bERRBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head>
<title>Crowd Simulation</title>
<style>body {display:flex;justify-content:center;align-items:center;height:100vh;background:#333;color:white;}canvas {border:2px solid #ccc;}</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');

let WIDTH = 40 * 15;
let HEIGHT = 30 * 15;
canvas.width = WIDTH;
canvas.height = HEIGHT;

const COORDS_W = 40;
const COORDS_H = 30;
const CELL_SCALE = 15;
const NUM_PEOPLE = 60;
let people = [];
let stepCount = 0;

function initializePeople() {
    people = [];
    for (let i = 0; i < NUM_PEOPLE; i++) {
        people.push({
            x: Math.floor(Math.random() * (COORDS_W - 10)) + 5,
            y: Math.floor(Math.random() * (COORDS_H - 10)) + 5,
            left: false
        });
    }
    stepCount = 0;
}

function getTarget(x, y) {
    if (x === 39 && y === 2) return null; // Already at exit
    let dx = Math.abs(x - 39);
    let dy = Math.abs(y - 2);
    let nextX, nextY;

    if (dx > dy) {
        nextX = x + Math.sign(39 - x);
        nextY = y;
    } else if (dy > dx) {
        nextX = x;
        nextY = y + Math.sign(2 - y);
    } else {
        nextX = x + Math.sign(39 - x);
        nextY = y + Math.sign(2 - y);
    }

    return {x: nextX, y: nextY};
}

function draw() {
    ctx.fillStyle = '#1a1a1a';
    ctx.fillRect(0, 0, WIDTH, HEIGHT);
    
    let occupiedCells = {};
    people.forEach(p => {
        if (!p.left) {
            const key = `${Math.floor(p.x)}_${Math.floor(p.y)}`;
            occupiedCells[key] = true;
            ctx.fillStyle = '#4CAF50';
            ctx.fillRect(p.x * CELL_SCALE, p.y * CELL_SCALE, CELL_SCALE - 1, CELL_SCALE - 1);
        }
    });

    ctx.fillStyle = 'red';
    ctx.fillText('Exit (39, 2)', WIDTH - 100, 20);
}

function update() {
    stepCount++;
    let stillMoving = false;
    const newPeople = [];

    for (let p of people) {
        if (p.left) {
            newPeople.push(p);
            continue;
        }

        stillMoving = true;
        let target = getTarget(p.x, p.y);
        let nextCellKey = `${target.x}_${target.y}`;
        let canMove = !occupiedCells[nextCellKey];

        if (canMove) {
            p.x = target.x;
            p.y = target.y;
            if (p.x === 39 && p.y === 2) {
                p.left = true;
            }
        }
        newPeople.push(p);
    }

    people = newPeople;
    draw();
    document.getElementById('stats').innerHTML = `Steps: ${stepCount}<br>Left: ${people.filter(p => p.left).length}/${NUM_PEOPLE}`;
}

function animate() {
    if (people.every(p => p.left)) {
        initializePeople();
    } else {
        update();
    }
    requestAnimationFrame(animate);
}

document.body.innerHTML = '<canvas id="c"></canvas><div id="stats" style="position:absolute;top:20px;right:20px;">Steps: 0<br>Left: 0/60</div>';
initializePeople();
animate();
</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.
deepseek-r1:14bHANGFORMAT
Show code
```html
<!DOCTYPE html>
<html><body style="margin:0;display:flex;justify-content:center;align-items:center;height:100vh">
<canvas id=c width=200 height=150></canvas>
<div id=s>Step 0, Left 0</div>
<script>
const c=document.getElementById('c'), ctx=c.getContext('2d');
const w=40,h=30;const cellSize=5;
let grid=[],people=[],left=0,step=0;

// Initialize grid
for(let y=0;y<h;++y){
    grid[y]=new Array(w).fill();
}

// Create people and their targets
function initializePeople(){
    people=[]
    for(let i=0;i<60;++i){
        let x=Math.floor(Math.random()*(w/2)),y=Math.floor(Math.random()*(h/2));
        while(grid[y]?.[x])x=Math.floor(Math.random()*(w/2)),y=Math.floor(Math.random()*(h/2));
        grid[y][x]={}
        people.push({x,y,target:getTarget(x,y)})
    }
}

function getTarget(ex, ey){
    let target=null;
    let queue=[[w-1,h-1]],dist=0;
    while(queue.length>0){
        const next=[];
        for(let d=queue.length;d>0;--d){
            const [x,y]=queue[d-1];
            if(x===ex && y===ey){target=dist;break;}
            const dirs=[[x+1,y],[x-1,y],[x,y+1],[x,y-1]];
            for(const [nx,ny] of dirs){
                if(nx>=0&&nx<w&&ny>=0&&ny<h&&!grid[ny][nx]){
                    grid[ny][nx]=dist+1;
                    next.push([nx,ny]);
                }
            }
        }
        queue=next;
        dist++;
    }
    return target;
}

function updateGrid(){
    const moved=false;
    for(let i=people.length-1;i>=0;--i){
        const p=people[i];
        if(!p.target) continue;
        const nextX=p.x+((p.target.x-p.x)/Math.abs(p.target.x-p.x||1));
        const nextY=p.y+((p.target.y-p.y)/Math.abs(p.target.y-p.y||1));
        if(nextX>=0&&nextX<w&&nextY>=0&&nextY<h&&!grid[nextY][nextX]){
            grid[p.y][p.x]=null;
            p.x=nextX;p.y=nextY;
            if(nextX===w-1&&nextY===h-1){
                left++;
                people.splice(i,1);
            }
        }
    }
}

function drawGrid(){
    ctx.fillStyle='rgb(250,250,250)';
    ctx.fillRect(0,0,c.width,c.height);
    for(let y=0;y<h;++y){
        for(let x=0;x<w;++x){
            if(grid[y]?.[x]) {
                ctx.fillStyle='#ff4444';
                ctx.fillRect(x*cellSize,y*cellSize,(x+1)*cellSize,(y+1)*cellSize);
            }
        }
    }
    ctx.fillStyle='#44ff44';
    ctx.fillRect((w-1)*cellSize, (h-1)*cellSize, cellSize, cellSize);
}

function animate(){
    if(people.length>0){
        updateGrid();
        drawGrid();
        step++;
        document.getElementById('s').textContent=`Step ${step}, Left ${left}`;
        requestAnimationFrame(animate);
    }else{
        step=0;left=0;
        initializePeople();
        animate();
    }
}

initializePeople();
animate();
</script>
</body></html>
```
qwen3:14bOKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head>
<title>Cell Grid Simulation</title>
<style>body {background:#222;display:flex;justify-content:center;align-items:center;height:100vh;margin:0;}canvas {border:1px solid #444;}</style>
</head>
<body>
<canvas id="gridCanvas" width="600" height="300"></canvas>
<script>
const canvas = document.getElementById('gridCanvas');
const ctx = canvas.getContext('2d');

const W = 40; // Grid width (cells)
const H = 30; // Grid height (cells)
const CELL_SIZE = 15;
const NUM_PEOPLE = 60;
const EXIT_X = 39;
const EXIT_Y = Math.floor(H / 2);

let people = [];
let running = true;
let stepCount = 0;

function initPeople() {
    people = [];
    for (let i = 0; i < NUM_PEOPLE; i++) {
        let x, y;
        do {
            x = Math.floor(Math.random() * W);
            y = Math.floor(Math.random() * H);
        } while (x === EXIT_X && y === EXIT_Y);
        people.push({ id: i, x: x, y: y, active: true });
    }
}

function drawGrid() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    for (let y = 0; y < H; y++) {
        for (let x = 0; x < W; x++) {
            ctx.fillStyle = 'rgba(30, 30, 50, 0.1)';
            ctx.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
        }
    }
    ctx.fillStyle = '#8B0000'; // Red exit marker
    ctx.fillRect(EXIT_X * CELL_SIZE + 1, (EXIT_Y - 1) * CELL_SIZE + 1, 2 * CELL_SIZE, 2 * CELL_SIZE);
}

function getTargetDirection(x, y) {
    let dx = Math.sign(EXIT_X - x);
    let dy = Math.sign(EXIT_Y - y);
    if (dx === 0 && dy === 0) return null;
    if (Math.random() > 0.5) { // Prioritize horizontal move slightly randomly
        return [x + dx, y];
    } else {
        return [x, y + dy];
    }
}

function updateSimulation() {
    stepCount++;
    let peopleLeft = 0;
    let nextPeopleState = [];
    const occupiedCells = {};

    // Pass 1: Determine intended moves and identify blockages
    for (const p of people) {
        if (!p.active) continue;
        
        const target = getTargetDirection(p.x, p.y);
        let newX = p.x;
        let newY = p.y;

        if (target) {
            newX = Math.min(Math.max(target[0], 0), W - 1);
            newY = Math.min(Math.max(target[1], 0), H - 1);
        } else {
             // At exit point, just wait until cleared
        }

        p.nextX = newX;
        p.nextY = newY;
    }

    // Pass 2: Resolve collisions and update positions (Queue logic)
    for (const p of people) {
        if (!p.active) continue;

        let proposedCellKey = `${Math.min(p.x + Math.sign(EXIT_X - p.x), Math.max(0, W-1))},${Math.min(p.y + Math.sign(EXIT_Y - p.y), Math.max(0, H-1))}`;
        let actualTargetKey = `${p.nextX},${p.nextY}`;

        // Check if the target cell is occupied by another person who *will* move there (collision detection)
        let collision = false;
        for (const other of people) {
            if (other === p || !other.active) continue;
             // If two people try to occupy the same spot, only one gets it randomly/first in loop order wins.
            if (other.nextX === p.nextX && other.nextY === p.nextY) {
                collision = true;
                break;
            }
        }

        // Simple queue logic: If target is occupied, stay put unless at exit
        let moveSuccessful = !p.nextX || (p.nextX !== p.x && p.nextY !== p.y);

        if (collision) {
             moveSuccessful = false; // Blocked by another person
        } else if (Math.abs(EXIT_X - p.x) < 2 && Math.abs(EXIT_Y - p.y) < 2) {
            // Special handling for exit: If we are at the exit, we leave immediately.
             if (!p.hasLeft) {
                 peopleLeft++;
                 p.active = false;
                 p.hasLeft = true; // Mark as left
                 continue;
             }
        }


        // Final update based on success
        if (moveSuccessful && p.nextX !== p.x || moveSuccessful && p.nextY !== p.y) {
            p.x = p.nextX;
            p.y = p.nextY;
        } else if (!moveSuccessful) {
             // Stay put due to congestion or logic block
        }

        nextPeopleState.push(p);
    }
    people = nextPeopleState;

    // Check termination condition: All people have left (or are marked inactive/left)
    if (people.every(p => !p.active)) {
        running = false;
        setTimeout(() => { stepCount = 0; initPeople(); }, 2500); // Restart after delay
    }

    drawGrid();
    for (const p of people) {
        if (p.active) {
            ctx.fillStyle = 'rgba(173, 216, 230, 0.9)'; // Light Blue person
            ctx.fillRect(p.x * CELL_SIZE + 5, p.y * CELL_SIZE + 5, CELL_SIZE - 10, CELL_SIZE - 10);
        } else if (p.hasLeft) {
             // Mark as departed
              ctx.fillStyle = 'rgba(60, 60, 60, 0.4)'; 
              ctx.fillRect(p.x * CELL_SIZE + 5, p.y * CELL_SIZE + 5, CELL_SIZE - 10, CELL_SIZE - 10);
        }
    }

    // Status display (simplified output)
    if (!document.getElementById('status')) {
        const statusDiv = document.createElement('div');
        statusDiv.id = 'status';
        statusDiv.style.cssText = 'color:white; position:absolute; top:10px; left:10px; font-family:monospace; background:rgba(0,0,0,0.5); padding:10px; border-radius:5px;';
        document.body.appendChild(statusDiv);
    }
    document.getElementById('status').innerHTML = `
Steps: ${stepCount}<br>
Left: ${NUM_PEOPLE - people.filter(p => p.active).length}`;

    requestAnimationFrame(updateSimulation);
}

initPeople();
requestAnimationFrame(updateSimulation);
</script>
</body>
</html>
```
command-r:35bERRBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>People Leaving Room</title>
    <style>
        body { margin: 0; overflow: hidden }
        canvas { image-rendering: pixelated }
    </style>
</head>
<body>

    <canvas></canvas>

    <script>

        let W = window, D = W.document, C = D.querySelector('canvas'),
            X = C.getContext('2d'), T = 0, F = [], S = []

        function R(n) { return Math.floor(Math.random() * n) }
        function M(a, b) { return a[R(a.length)] + b }
        
        for (let i=0; i < 60; i++) F.push([M('1234', '5'), M('6789', '')])

        function P() {
            let [x, y] = S[T % S.length] 
            X.fillStyle = '#' + (D.body.style.background === '#fff' ? '000' : 'f80')
            X.fillRect(x * 16, y * 16, 16, 16)
        }

        function L() {
            let f = F.shift(), d = [], p = [f[0]], i=2

            while (p.length < i++) {
                if (!F.length || !d.includes(p)) p = M(F.pop(), '') 
                else {
                    let j = R(i) + 1, c = p.charAt(R(j)), n = f[1]

                    if (c === '5') d.push(M([n, '8'], '')) 
                    else if (c !== '6' && c !== '') f[0] += c
                    else {
                        d.push(f)
                        p = [n + c]
                    }
                }
            }

            F.unshift(d.reverse())
        }

        function G() {
            let r = R, g = S.length / 40

            for (let x=0; x < 40; x++) {
                for (let y=g; y--; ) 
                    if (!S[T++ % S.length] && !((x + y) % 2)) 
                        S.push([x * 16, g * 16 - y * 16])

                P()
            }

            L()
        }

        C.width = D.body.clientWidth
        C.height = D.body.clientHeight / 3 * 2
        X.fillStyle = '#08f'

        for (let i=0; i < S.length; i++) 
            P()
            
        W.requestAnimationFrame(G)

    </script>
</body>
</html>
```
qwq:32bSTATMINIFIED
Show code
<think>

Okay, let's see. I need to create an HTML file that simulates 60 people leaving a room through an exit. The grid is 40x30 cells, and each step, everyone moves towards the exit based on a distance field. They can't enter occupied cells, so congestion forms. The output has to be self-contained, under 120 lines, and use requestAnimationFrame. Alright.

First, structure the HTML. The canvas tag with some width and height, but since it's a grid of 40x30, maybe set it to 800x600 pixels (20px per cell) for visibility. But the user said the grid is 40x30 cells. Hmm, so the cells can be 20x20 each. Wait, but the user might not specify pixel size. Maybe just set the canvas to 40x30 cells but scaled up. Wait, better to make sure each cell is a pixel? No, because then it would be very small. Maybe 20px per cell, so canvas is 800x600.

Wait, but the user says "cell grid drawn on a canvas". The exact pixel size isn't specified, so perhaps I can choose a reasonable size. Let's go with 40 cells wide, 30 tall. So maybe 400x300 pixels, each cell 10x10. That's manageable. So the canvas element would have width 400 and height 300, with a 10px per cell scaling.

Now the main elements: the canvas, and some text to show the step count and how many have exited.

The simulation needs a grid. Each cell has a distance to the exit. The exit is probably at the bottom right, but need to set it as a specific cell. Let's say the exit is at (39,29), the bottom-right corner. Wait, indexes start at 0, so maybe exit is at (39,29).

The distance field is precomputed. So first, compute for each cell (x,y) the distance to the exit, but moving step by step. Wait, but distance field can be computed as BFS from the exit. So the distance for each cell is the minimum steps needed to reach the exit, considering walls or not? Since it's a room, maybe the grid is all open except the exit is the target. Wait, the problem says "one exit", so the exit is just a single cell which people can leave from.

Wait, perhaps the exit is a door at the right side, but the user says 'one exit', so maybe the exit is a specific cell, and when people reach it, they leave. So the distance field is computed as the shortest path from each cell to the exit. So the distance field would be a 2D array where each cell's value is the steps needed to reach the exit. We can compute this using BFS.

So first step: set up the grid. The canvas size is 40x30 cells. The exit is at (39,29) (since it's 0-based). Wait, but maybe the exit is at the bottom-right corner, so that people have to move towards it. Alternatively, maybe the exit is on a wall, but the exit cell is the last before leaving. Hmm, perhaps the exit is at the end of the grid, so that the distance field is computed as the minimal steps to reach that point.

So first, create the distance field. Initialize a 2D array (40x30) with all values as undefined or infinity. Then set the exit cell's distance to 0. Then perform BFS to propagate the distances.

Wait, the BFS approach would be:

Initialize the exit cell's distance to 0. Then, for each cell in the queue, look at its neighbors and set their distance to current distance +1, if not set yet. Proceed until all cells are filled.

Yes. So the distance field is computed once at the start.

Then, the people are placed randomly in the grid, except the exit cell and maybe adjacent cells.

Wait, the initial positions need to be on cells that are not the exit. Also, each person is on a different cell, so when placing 60 people, we need to make sure they don't start on the same cell. Let's think: 40x30 is 1200 cells. 60 is small, so randomly placing them is okay.

Each step:

For each person, determine the direction towards the exit based on the distance field. The direction is the direction to the neighbor cell (up, down, left, right) which has the smallest distance. But since the distance field is precomputed, each cell has its best direction.

Wait, the direction is the direction towards the exit, so for a cell (x,y), the next cell is the one among its four neighbors (if exist) that has the smallest distance. If multiple have the same distance, can choose one direction? Or maybe pick the first one.

Wait, the distance field is such that each cell's distance is exactly one more than the next cell. So the direction to move is to the neighbor cell with distance exactly one less. So for each cell, there should be exactly one direction (or maybe multiple) that gives the next step.

Wait, actually, the distance field would have for each cell, the distance is 1 + min of neighbors. So each cell has a unique path to the exit? Not necessarily, but the direction can be any direction that reduces the distance. Hmm. To make it deterministic, perhaps for each cell, there is a preferred direction (like the right direction first, then down, etc.)?

Alternatively, for each cell, the direction is the direction towards the neighbor with the smallest distance. Since the distance field is such that each cell's distance is exactly one less than the previous, so you can choose any adjacent cell with distance = current distance - 1. So for movement, each person can look at all four adjacent cells, and pick the one with the smallest distance (which should be exactly one less). Among those, perhaps choose the direction that's closest to the target.

Alternatively, to make it simple, for each cell, the direction can be determined by comparing the four neighbors and choosing the direction with the smallest distance. Let's code that.

So for a person at (x,y), the next cell is the direction with distance equal to distance[y][x] - 1. So check all four directions. For each direction (dx, dy), check if the next cell's distance is one less. Then pick one direction (maybe the first one found? Or the direction that's towards the exit's general direction?)

Alternatively, in code, for each direction in order of priority (like right, down, left, up), and pick the first direction towards a cell with distance one less.

Hmm, perhaps to keep it simple, for each direction in order of priority (maybe right, down, left, up?), and then pick the first direction that leads closer.

Alternatively, we can precompute for each cell the direction (dx, dy) that leads to the next step. For each cell, store the direction to move. This would be more efficient.

Yes, maybe during the BFS, when computing the distance, we can also store the direction to move for each cell. So when building the distance field, for each cell, when we set its distance from a neighbor, we can note the direction from the neighbor. Wait, maybe not. Alternatively, for each cell, once the distance is known, the direction can be
deepseek-r1:32bBLANKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html><body style="background:#1a1a1a;display:flex;flex-direction:column;align-items:center;">
<canvas id=c></canvas>
<div style="color:white;font-family:sans-serif;">People left: <span id=p>60</span>, Steps: <span id=s>0</span></div>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const GRID_W = 40;
const GRID_H = 30;
const EXIT_X = GRID_W - 1;
const EXIT_Y = GRID_H - 1;
const CELL_SIZE = 8;
const RADIUS = CELL_SIZE * 0.4;
canvas.width = GRID_W * CELL_SIZE;
canvas.height = GRID_H * CELL_SIZE;

let grid = [];
let people = [];
let step = 0;

function init() {
    grid = Array(GRID_H).fill().map(() => Array(GRID_W).fill(0));
    // Add obstacles
    for(let y = 0; y < GRID_H; y++) {
        for(let x = 0; x < GRID_W; x++) {
            if(y === 0 || y === GRID_H -1 || x === 0 || x === GRID_W -1) grid[y][x] = 1;
            else if((y === 8 && (x >5 && x <15)) ||
                    (y ===16 && (x>20 && x<30))) grid[y][x] = 1;
        }
    }
    
    people = [];
    for(let i=0; i<60; i++) {
        let x, y;
        do {
            x = Math.floor(Math.random() * GRID_W);
            y = Math.floor(Math.random() * GRID_H);
        } while(grid[y][x] === 1 || (y === EXIT_Y && x === EXIT_X));
        people.push({x,y,lastX:x,lastY:y});
    }
    
    // Precompute distance field
    let dist = Array(GRID_H).fill().map(() => Array(GRID_W).fill(Infinity));
    let queue = [];
    dist[EXIT_Y][EXIT_X] = 0;
    queue.push([EXIT_Y, EXIT_X]);
    
    while(queue.length) {
        let [y,x] = queue.shift();
        for(let dy=-1; dy<=1; dy++) {
            for(let dx=-1; dx<=1; dx++) {
                if(dy ===0 && dx ===0) continue;
                let ny = y + dy;
                let nx = x + dx;
                if(ny >=0 && ny < GRID_H && nx >=0 && nx < GRID_W && grid[ny][nx] !== 1 && dist[ny][nx] > dist[y][x] +1) {
                    dist[ny][nx] = dist[y][x] +1;
                    queue.push([ny,nx]);
                }
            }
        }
    }
    
    // For each person, find direction towards exit
    for(let p of people) {
        let minDist = Infinity;
        let dir = null;
        for(let dy=-1; dy<=1; dy++) {
            for(let dx=-1; dx<=1; dx++) {
                if(dy ===0 && dx ===0) continue;
                let ny = p.y + dy;
                let nx = p.x + dx;
                if(ny >=0 && ny < GRID_H && nx >=0 && nx < GRID_W && grid[ny][nx] !== 1 && dist[ny][nx] < minDist) {
                    minDist = dist[ny][nx];
                    dir = {x:dx,y:dy};
                }
            }
        }
        p.dir = dir;
    }
}

function update() {
    let allExited = people.every(p => p.y === EXIT_Y && p.x === EXIT_X);
    if(allExited) {
        step = 0;
        document.getElementById('p').textContent = '60';
        init();
        return;
    }
    
    for(let p of people) {
        if(p.y !== EXIT_Y || p.x !== EXIT_X) {
            let targetX = p.x + (p.dir?.x || 0);
            let targetY = p.y + (p.dir?.y || 0);
            
            // Check if target cell is within bounds and not blocked
            if(targetX >=0 && targetX < GRID_W && targetY >=0 && targetY < GRID_H &&
               grid[targetY][targetX] !== 1) {
                
                // Check if target cell is not occupied by another person
                let canMove = people.every(other => 
                    !(other.x === targetX && other.y === targetY && other !== p)
                );
                
                if(canMove) {
                    p.lastX = p.x;
                    p.lastY = p.y;
                    p.x = targetX;
                    p.y = targetY;
                }
            }
        }
    }
    
    step++;
    document.getElementById('s').textContent = step;
    document.getElementById('p').textContent = people.filter(p => !(p.y === EXIT_Y && p.x === EXIT_X)).length;
}

function draw() {
    ctx.fillStyle = '#1a1a1a';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    // Draw grid
    ctx.strokeStyle = '#33
Outside the Brain cluster — same task, same character budget, collected through their own tooling (response times not comparable)
GPT-5.5 (Codex)frontier referenceOK
Show code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Evacuation Grid</title>
<style>
html,body{margin:0;height:100%;background:#111;color:#eee;font:16px system-ui;display:grid;place-items:center}
#wrap{width:min(96vw,960px)}
#hud{display:flex;justify-content:space-between;margin:0 0 8px}
canvas{width:100%;aspect-ratio:4/3;background:#181818;display:block}
</style>
</head>
<body>
<div id="wrap">
<div id="hud"><span id="left"></span><span id="step"></span></div>
<canvas id="c" width="800" height="600"></canvas>
</div>
<script>
const W=40,H=30,N=60,exit={x:39,y:15},c=document.getElementById("c"),ctx=c.getContext("2d");
const left=document.getElementById("left"),stepEl=document.getElementById("step"),cw=c.width/W,ch=c.height/H;
let dist,people,steps,gone,last=0,delay=90;
function field(){
  dist=Array.from({length:H},()=>Array(W).fill(1e9));
  let q=[[exit.x,exit.y]],i=0;dist[exit.y][exit.x]=0;
  while(i<q.length){
    let [x,y]=q[i++],d=dist[y][x]+1;
    for(let [nx,ny] of [[x+1,y],[x-1,y],[x,y+1],[x,y-1]])
      if(nx>=0&&nx<W&&ny>=0&&ny<H&&d<dist[ny][nx]){dist[ny][nx]=d;q.push([nx,ny])}
  }
}
function start(){
  field();people=[];steps=gone=0;
  let used=new Set([exit.x+","+exit.y]);
  while(people.length<N){
    let x=1+Math.floor(Math.random()*(W-5)),y=1+Math.floor(Math.random()*(H-2)),k=x+","+y;
    if(!used.has(k)){used.add(k);people.push({x,y})}
  }
}
function shuffle(a){
  for(let i=a.length-1;i>0;i--){let j=Math.floor(Math.random()*(i+1)),t=a[i];a[i]=a[j];a[j]=t}
}
function tick(){
  steps++;
  people=people.filter(p=>!(p.x==exit.x&&p.y==exit.y&&(gone++,1)));
  let occ=new Set(people.map(p=>p.x+","+p.y)),order=[...people];shuffle(order);
  for(let p of order){
    let opts=[];
    for(let [nx,ny] of [[p.x+1,p.y],[p.x-1,p.y],[p.x,p.y+1],[p.x,p.y-1]])
      if(nx>=0&&nx<W&&ny>=0&&ny<H&&dist[ny][nx]<dist[p.y][p.x]&&!occ.has(nx+","+ny))opts.push([nx,ny]);
    if(opts.length){
      let [nx,ny]=opts[Math.floor(Math.random()*opts.length)];
      occ.delete(p.x+","+p.y);p.x=nx;p.y=ny;occ.add(nx+","+ny);
    }
  }
  if(gone==N)start();
}
function draw(){
  ctx.fillStyle="#181818";ctx.fillRect(0,0,c.width,c.height);
  ctx.strokeStyle="#2b2b2b";ctx.lineWidth=1;
  for(let x=0;x<=W;x++){ctx.beginPath();ctx.moveTo(x*cw,0);ctx.lineTo(x*cw,c.height);ctx.stroke()}
  for(let y=0;y<=H;y++){ctx.beginPath();ctx.moveTo(0,y*ch);ctx.lineTo(c.width,y*ch);ctx.stroke()}
  ctx.fillStyle="#39d98a";ctx.fillRect(exit.x*cw,exit.y*ch,cw,ch);
  ctx.fillStyle="#ffcc4d";
  for(let p of people)ctx.fillRect(p.x*cw+2,p.y*ch+2,cw-4,ch-4);
  left.textContent="Left: "+gone+" / "+N;
  stepEl.textContent="Steps: "+steps;
}
function loop(t){
  if(t-last>delay){tick();last=t}
  draw();requestAnimationFrame(loop);
}
start();requestAnimationFrame(loop);
</script>
</body>
</html>
Claude Sonnet 5frontier referenceOK
Show code
<!doctype html>
<html><head><meta charset="utf-8"><title>Room Evacuation Grid</title>
<style>html,body{margin:0;background:#0d0f14;overflow:hidden;height:100%}canvas{display:block}</style>
</head><body>
<canvas id="c"></canvas>
<script>
const cv=document.getElementById('c'),ctx=cv.getContext('2d');
function resize(){cv.width=innerWidth;cv.height=innerHeight;}
resize();addEventListener('resize',resize);
const COLS=40,ROWS=30,CS=16,OX=20,OY=20,NP=60;
let exitX,exitY,dist,cellCol,persons,occupied,leftCount,stepCount,waitTimer,frameCounter;
const STEPI=8;
function idx(x,y){return y*COLS+x}
function isWall(x,y){return (x===0||x===COLS-1||y===0||y===ROWS-1)&&!(x===exitX&&y===exitY);}
function bfs(){
  dist=new Int16Array(COLS*ROWS).fill(-1);
  const q=[[exitX,exitY]];dist[idx(exitX,exitY)]=0;let h=0;
  while(h<q.length){
    const[cx,cy]=q[h++];const d=dist[idx(cx,cy)];
    const nb=[[cx-1,cy],[cx+1,cy],[cx,cy-1],[cx,cy+1]];
    for(const[nx,ny]of nb){
      if(nx<0||nx>=COLS||ny<0||ny>=ROWS)continue;
      if(isWall(nx,ny))continue;
      if(dist[idx(nx,ny)]!==-1)continue;
      dist[idx(nx,ny)]=d+1;q.push([nx,ny]);
    }
  }
}
function initColors(){
  let maxD=1;
  for(let i=0;i<dist.length;i++)if(dist[i]>maxD)maxD=dist[i];
  cellCol=new Array(COLS*ROWS);
  for(let y=0;y<ROWS;y++)for(let x=0;x<COLS;x++){
    const i=idx(x,y);
    if(isWall(x,y)){cellCol[i]='#2a2f3a';continue;}
    const t=dist[i]<0?0:dist[i]/maxD;
    const g=Math.round(30+t*40),b=Math.round(50+t*70);
    cellCol[i]='rgb(20,'+g+','+b+')';
  }
}
function init(){
  exitX=COLS-1;exitY=4+Math.floor(Math.random()*(ROWS-8));
  bfs();initColors();
  occupied=new Uint8Array(COLS*ROWS);
  persons=[];
  while(persons.length<NP){
    const x=1+Math.floor(Math.random()*(COLS-2));
    const y=1+Math.floor(Math.random()*(ROWS-2));
    if(x===exitX&&y===exitY)continue;
    if(occupied[idx(x,y)])continue;
    occupied[idx(x,y)]=1;persons.push({x,y,px:x,py:y});
  }
  leftCount=0;stepCount=0;waitTimer=0;frameCounter=0;
}
init();
function step(){
  for(let i=persons.length-1;i>=0;i--){
    const p=persons[i];
    if(p.x===exitX&&p.y===exitY){occupied[idx(p.x,p.y)]=0;persons.splice(i,1);leftCount++;}
  }
  const order=persons.map((_,i)=>i);
  for(let i=order.length-1;i>0;i--){const j=Math.floor(Math.random()*(i+1));[order[i],order[j]]=[order[j],order[i]];}
  for(const oi of order){
    const p=persons[oi];
    p.px=p.x;p.py=p.y;
    const cur=dist[idx(p.x,p.y)];
    const nb=[[p.x-1,p.y],[p.x+1,p.y],[p.x,p.y-1],[p.x,p.y+1]];
    let best=null,bestD=cur;
    for(const[nx,ny]of nb){
      if(nx<0||nx>=COLS||ny<0||ny>=ROWS)continue;
      if(isWall(nx,ny))continue;
      const nd=dist[idx(nx,ny)];
      if(nd<0||nd>=cur)continue;
      if(occupied[idx(nx,ny)])continue;
      if(nd<bestD){bestD=nd;best=[nx,ny];}
    }
    if(best){occupied[idx(p.x,p.y)]=0;p.x=best[0];p.y=best[1];occupied[idx(p.x,p.y)]=1;}
  }
  stepCount++;
  if(persons.length===0){waitTimer++;if(waitTimer>60)init();}
}
function draw(){
  ctx.fillStyle='#0d0f14';ctx.fillRect(0,0,cv.width,cv.height);
  for(let y=0;y<ROWS;y++)for(let x=0;x<COLS;x++){
    ctx.fillStyle=cellCol[idx(x,y)];
    ctx.fillRect(OX+x*CS,OY+y*CS,CS-1,CS-1);
  }
  ctx.fillStyle='#4f8';
  ctx.fillRect(OX+exitX*CS,OY+exitY*CS,CS-1,CS-1);
  ctx.fillStyle='#ffb648';
  const t=(frameCounter%STEPI)/STEPI;
  for(const p of persons){
    const dx=p.px+(p.x-p.px)*t,dy=p.py+(p.y-p.py)*t;
    ctx.beginPath();
    ctx.arc(OX+dx*CS+CS/2,OY+dy*CS+CS/2,CS*0.35,0,7);
    ctx.fill();
  }
  ctx.fillStyle='#eef';ctx.font='16px monospace';ctx.textAlign='left';
  ctx.fillText('Room Evacuation - Distance Field (40x30 grid)',OX,OY+ROWS*CS+28);
  ctx.font='13px monospace';ctx.fillStyle='#9cf';
  ctx.fillText('Left: '+leftCount+' / '+NP,OX,OY+ROWS*CS+50);
  ctx.fillText('Step: '+stepCount,OX,OY+ROWS*CS+70);
}
function loop(){
  frameCounter++;
  if(frameCounter%STEPI===0)step();
  draw();
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script>
</body></html>
Claude Haiku 4.5frontier referenceERRBLANK
Show code
<!DOCTYPE html><html><head><title>r77</title></head><body><canvas id="c"></canvas><script>
let c=document.getElementById('c'),x=c.getContext('2d');c.width=800;c.height=600;
let W=40,H=30,ppl=Array(60).fill(0).map(()=>({x:Math.floor(Math.random()*W),y:Math.floor(Math.random()*H),left:false}));
let g=Array(H).fill(0).map((,i)=>Array(W).fill(999));
// Distance field from exit (37, H/2)
for(let i=0;i<H;i++)g[i][W-1]=Math.abs(i-Math.floor(H/2));
for(let r=W-2;r>=0;r--)for(let i=0;i<H;i++){
  g[i][r]=Math.min(g[i][r],Math.min(g[i][r+1],i>0?g[i-1][r+1]:999,i<H-1?g[i+1][r+1]:999)+1);
}
let left=0,step=0;
function draw(){
  x.fillStyle="#fff";x.fillRect(0,0,800,600);
  let s=Math.floor(750/W);
  // Heatmap
  for(let i=0;i<H;i++)for(let j=0;j<W;j++){
    let v=Math.min(g[i][j]/W*255,255);x.fillStyle=`rgb(${255-v},${v/2},${v/2})`;
    x.fillRect(j*s+10,i*s+10,s,s);
  }
  // Move people
  let occ=Array(H).fill(0).map(()=>Array(W).fill(false));
  ppl.forEach(p=>{if(!p.left&&Math.random()>0.3){
    let best=null,bestd=999;
    for(let[dx,dy]of[[1,0],[-1,0],[0,1],[0,-1]]){
      let nx=p.x+dx,ny=p.y+dy;
      if(nx>=0&&nx<W&&ny>=0&&ny<H&&g[ny][nx]<bestd){best=[nx,ny];bestd=g[ny][nx];}
    }
    if(best&&!occ[best[1]][best[0]]){p.x=best[0];p.y=best[1];}
  }
  if(p.x===W-1)p.left=true;else occ[p.y][p.x]=true;
  if(p.left)left++;});
  // Draw people
  ppl.forEach(p=>{if(!p.left){x.fillStyle="#f00";x.fillRect(p.x*s+10+2,p.y*s+10+2,s-4,s-4);}});
  // Exit
  x.fillStyle="#0f0";x.fillRect(W*s+10,Math.floor(H/2)*s+10,s,s*3);
  step++;
  x.fillStyle="#000";x.font="14px mono";x.fillText("Left:"+left+" Step:"+step,500,50);
  requestAnimationFrame(draw);
}draw();
</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 —126.1 sOK
gemma4:26b ——harness
mistral-small:24b —126.0 sOK
qwen3-coder:30b —25.8 sOK
qwen3.5:9b —47.7 sOK
qwen3:8b ——harness
deepseek-r1:14b —69.3 sOK
qwen3:14b —30.1 sOK
command-r:35b —137.2 sOK
qwq:32b —140.6 sOK
deepseek-r1:32b —140.2 sOK

Frontier reference — outside the blind field

These models answered the identical prompt outside the blind field. They are deliberately not scored and not part of the blind comparison — they are there so you can see where a frontier model lands on the same task.

Collected differently from the blind field: the local models run through a plain API harness, the frontier references through a context-free agent, one shot, no retries. Response times are therefore not comparable and are not shown. On two English tasks the reference answer came back in German — an artefact of that harness, flagged on the affected rounds.
Claude Opus 5frontier reference
<meta charset="utf-8">
<title>Room Evacuation — 60 agents, one exit</title>
<style>
html,body{height:100%;margin:0;background:#0d1017;color:#dfe6f2;
font:13px/1.5 ui-monospace,SFMono-Regular,Menlo,monospace;
display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px}
#hud{display:flex;gap:26px;letter-spacing:.06em;text-transform:uppercase;font-size:11px;color:#7c8aa5}
#hud b{color:#eaf1ff;font-size:15px;font-weight:600;letter-spacing:0}
canvas{background:#11151e;border-radius:6px;box-shadow:0 18px 50px #0006}
</style>
<canvas id=c width=640 height=480></canvas>
<div id=hud><span>escaped <b id=vl>0</b>/60</span><span>inside <b id=vi>60</b></span><span>step <b id=vs>0</b></span></div>
<script>
const W=40,H=30,S=16,N=60,EX=W-1,EY=H>>1,D=[[1,0],[-1,0],[0,1],[0,-1]];
const c=document.getElementById('c'),g=c.getContext('2d');
const ix=(x,y)=>y*W+x;
let wall,dist,occ,people,left,step,acc,last,hold;
function init(){
  wall=new Uint8Array(W*H);dist=new Int32Array(W*H).fill(-1);occ=new Uint8Array(W*H);
  for(let x=0;x<W;x++){wall[ix(x,0)]=1;wall[ix(x,H-1)]=1}
  for(let y=0;y<H;y++){wall[ix(0,y)]=1;wall[ix(W-1,y)]=1}
  for(let k=0;k<7;k++){
    const bx=2+(Math.random()*(W-9)|0),by=2+(Math.random()*(H-8)|0),
          bw=2+(Math.random()*4|0),bh=2+(Math.random()*4|0);
    for(let y=by;y<by+bh&&y<H-1;y++)for(let x=bx;x<bx+bw&&x<W-1;x++)wall[ix(x,y)]=1;
  }
  for(let y=EY-2;y<=EY+2;y++)for(let x=W-5;x<W-1;x++)wall[ix(x,y)]=0;
  wall[ix(EX,EY)]=0;
  const q=[ix(EX,EY)];dist[q[0]]=0;
  for(let h=0;h<q.length;h++){
    const p=q[h],x=p%W,y=p/W|0;
    for(const[dx,dy]of D){
      const nx=x+dx,ny=y+dy;if(nx<0||ny<0||nx>=W||ny>=H)continue;
      const n=ix(nx,ny);if(wall[n]||dist[n]>=0)continue;dist[n]=dist[p]+1;q.push(n);
    }
  }
  people=[];
  while(people.length<N){
    const x=1+(Math.random()*(W-3)|0),y=1+(Math.random()*(H-2)|0),i=ix(x,y);
    if(dist[i]<1||occ[i])continue;
    occ[i]=1;people.push({x,y,w:0,h:190+Math.random()*90|0});
  }
  left=0;step=0;acc=0;hold=0;
}
function sim(){
  people.sort((a,b)=>dist[ix(a.x,a.y)]-dist[ix(b.x,b.y)]);
  const rest=[];
  for(const p of people){
    const cur=ix(p.x,p.y);let best=-1,bd=dist[cur],o=Math.random()*4|0;
    for(let k=0;k<4;k++){
      const d=D[(k+o)&3],n=ix(p.x+d[0],p.y+d[1]);
      if(dist[n]<0||occ[n])continue;
      if(dist[n]<bd){bd=dist[n];best=n}
    }
    if(best>=0){occ[cur]=0;p.x=best%W;p.y=best/W|0;occ[best]=1;p.w=0}else p.w++;
    if(p.x===EX&&p.y===EY){occ[ix(p.x,p.y)]=0;left++}else rest.push(p);
  }
  people=rest;step++;
}
function draw(){
  g.fillStyle='#11151e';g.fillRect(0,0,640,480);
  let mx=1;for(let i=0;i<W*H;i++)if(dist[i]>mx)mx=dist[i];
  for(let y=0;y<H;y++)for(let x=0;x<W;x++){
    const i=ix(x,y);
    if(wall[i]){g.fillStyle='#232b3b'}
    else if(dist[i]<0){g.fillStyle='#151a24'}
    else{const t=1-dist[i]/mx;g.fillStyle='hsl(212,'+(14+t*22|0)+'%,'+(11+t*9|0)+'%)'}
    g.fillRect(x*S,y*S,S-1,S-1);
  }
  g.fillStyle='#ffca5c';g.fillRect(EX*S,EY*S,S-1,S-1);
  g.fillStyle='rgba(255,202,92,.18)';g.fillRect((EX-1)*S,(EY-1)*S,S*2,S*3);
  for(const p of people){
    const jam=Math.min(p.w,6)/6;
    g.fillStyle='hsl('+(p.h-jam*160)+','+(55+jam*30|0)+'%,'+(66-jam*8|0)+'%)';
    g.beginPath();g.arc(p.x*S+S/2-.5,p.y*S+S/2-.5,S*.36,0,6.284);g.fill();
  }
  document.getElementById('vl').textContent=left;
  document.getElementById('vi').textContent=people.length;
  document.getElementById('vs').textContent=step;
}
function frame(t){
  if(!last)last=t;
  acc+=Math.min(t-last,200);last=t;
  while(acc>=85){
    acc-=85;
    if(people.length)sim();
    else if(++hold>45){init();break}
  }
  draw();requestAnimationFrame(frame);
}
init();requestAnimationFrame(frame);
</script>