OverviewCode › R77
Code · blind round

R77 · Crowd leaving a room, cell by cell

blind round 4/8 local models answered

Answers below are anonymized and shuffled. Read, judge, pick a favourite — then scroll down and reveal the models.

2 of the 8 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. Which ones, and why, is spelled out in the reveal.

The reveal also holds a frontier reference on the same task (Claude Opus 5) — kept out of sight here so it cannot steer your judgement.

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 — blind

Local models (Brain cluster) — identical prompt, anonymized order
MODEL Allama3.1:8bDNF
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
MODEL Bgemma4:26bDNF
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
MODEL Dqwen3-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>
MODEL Eqwen3.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>
```
MODEL Fqwen3:8bDNF
No usable answer reached the harness (ERR). Counted as a did-not-finish.
MODEL Gdeepseek-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>
```
MODEL Hqwen3: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>
```
Reveal the models— compare the answers first, then open. Names, blind scores and latencies are hidden until you do.

Who wrote what

Blind labelModelBlind scoreLatencyStatus
MODEL A llama3.1:8b DNF
MODEL B gemma4:26b harness
MODEL C mistral-small:24b DNF
MODEL D qwen3-coder:30b 25.8 sOK
MODEL E qwen3.5:9b 47.7 sOK
MODEL F qwen3:8b harness
MODEL G deepseek-r1:14b 69.3 sOK
MODEL H qwen3:14b 30.1 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>