Code · blind round
R96 · Force-directed graph settling
blind round
3/8 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 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 — 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 lays out a small graph on a <canvas> with a force simulation: about 25 nodes connected by edges, where every pair of nodes repels each other and every edge pulls its two nodes together like a spring, with damping so the layout comes to rest instead of oscillating. Draw edges and labelled nodes each frame while the tangle visibly untangles. Show the node count and the total energy, and restart with a fresh random graph once it has settled. 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)
▶ Play Show code ```html
<!DOCTYPE html>
<html>
<head>
<title>Force Simulation Graph</title>
<style>
body {margin:0;overflow:hidden;background:#111;}canvas {display:block;border:1px solid #333;}</style>
</head>
<body>
<canvas id="graphCanvas"></canvas>
<script>
(function() {
const canvas = document.getElementById('graphCanvas');
const ctx = canvas.getContext('2d');
let W, H;
let N = 25;
let nodes = [];
let edges = [];
let isRunning = true;
let FRAME_COUNT = 0;
// Physics constants
const K_SPRING = 0.01; // Spring constant (Attraction)
const REPULSION_COEFF = 2000; // Repulsion strength
const DAMPING = 0.98; // Velocity damping factor
const MAX_VELOCITY = 3;
function resizeCanvas() {
W = canvas.width = window.innerWidth * 0.95;
H = canvas.height = window.innerHeight * 0.85;
}
function initGraph() {
nodes = [];
edges = [];
for (let i = 0; i < N; i++) {
nodes.push({ x: Math.random() * W, y: Math.random() * H, vx: 0, vy: 0, fx: 0, fy: 0 });
}
// Generate edges (fully connected graph)
edges = [];
for (let i = 0; i < N; i++) {
for (let j = i + 1; j < N; j++) {
edges.push({ source: i, target: j });
}
}
isRunning = true;
}
function calculateForces() {
// Reset forces
nodes.forEach(n => { n.fx = 0; n.fy = 0; });
let totalEnergy = 0;
// 1. Calculate Repulsion (All pairs)
for (let i = 0; i < N; i++) {
for (let j = i + 1; j < N; j++) {
const n1 = nodes[i];
const n2 = nodes[j];
const dx = n1.x - n2.x;
const dy = n1.y - n2.y;
let distSq = dx * dx + dy * dy;
let dist = Math.sqrt(distSq);
if (dist === 0) { dist = 0.001; }
// Force magnitude: Inverse square law repulsion
const force = REPULSION_COEFF / distSq;
n1.fx += (dx / dist) * force;
n1.fy += (dy / dist) * force;
n2.fx -= (dx / dist) * force;
n2.fy -= (dy / dist) * force;
}
}
// 2. Calculate Attraction (Springs/Edges)
for (const edge of edges) {
const n1 = nodes[edge.source];
const n2 = nodes[edge.target];
const dx = n1.x - n2.x;
const dy = n1.y - n2.y;
let distSq = dx * dx + dy * dy;
let dist = Math.sqrt(distSq);
if (dist === 0) { dist = 0.001; }
// Spring force: F = k * x (Hooke's Law, using current distance for approximation)
const idealLength = W / N * 0.5; // Simple estimate for desired length
let displacement = Math.abs(dist) - idealLength;
let forceMagnitude = K_SPRING * displacement;
// Apply force components
const fX = (dx / dist) * forceMagnitude;
const fY = (dy / dist) * forceMagnitude;
n1.fx += fX;
n1.fy += fY;
n2.fx -= fX;
n2.fy -= fY;
}
// 3. Update positions and velocities (Integration)
for (let i = 0; i < N; i++) {
const n = nodes[i];
// Apply forces to acceleration proxy
n.vx += n.fx * 0.1;
n.vy += n.fy * 0.1;
// Apply damping and limit velocity
n.vx *= DAMPING;
n.vy *= DAMPING;
const speed = Math.sqrt(n.vx * n.vx + n.vy * n.vy);
if (speed > MAX_VELOCITY) {
n.vx = (n.vx / speed) * MAX_VELOCITY;
n.vy = (n.vy / speed) * MAX_VELOCITY;
}
// Update position
n.x += n.vx;
n.y += n.vy;
}
}
function draw() {
ctx.fillStyle = 'rgba(17, 17, 17, 0.4)';
ctx.fillRect(0, 0, W, H); // Fade effect for trailing motion
// Draw Edges
ctx.strokeStyle = '#666';
ctx.lineWidth = 1.5;
for (const edge of edges) {
const n1 = nodes[edge.source];
const n2 = nodes[edge.target];
ctx.beginPath();
ctx.moveTo(n1.x, n1.y);
ctx.lineTo(n2.x, n2.y);
ctx.stroke();
}
// Draw Nodes and Labels
for (let i = 0; i < N; i++) {
const n = nodes[i];
// Node circle
ctx.fillStyle = '#4CAF50';
ctx.beginPath();
ctx.arc(n.x, n.y, 3, 0, Math.PI * 2);
ctx.fill();
// Label
ctx.fillStyle = '#FFF';
ctx.font = '10px Arial';
ctx.fillText(`N${i}`, n.x + 5, n.y - 5);
}
}
function updateMetrics() {
const totalEnergy = Math.abs(nodes.reduce((sum, n) => sum + (n.fx * n.vx + n.fy * n.vy), 0));
const nodeCountText = `Nodes: ${N}`;
const energyText = `Energy Est.: ${totalEnergy.toFixed(2)}`;
const infoDiv = document.createElement('div');
infoDiv.style.position = 'absolute';
infoDiv.style.top = '10px';
infoDiv.style.left = '10px';
infoDiv.style.color = '#CCC';
infoDiv.innerHTML = `${nodeCountText}<br>${energyText}`;
let infoContainer = document.getElementById('info');
if (!infoContainer) {
infoContainer = document.createElement('div');
infoContainer.id = 'info';
document.body.appendChild(infoContainer);
}
infoContainer.innerHTML = `${nodeCountText}<br>${energyText}`;
}
function loop() {
if (!isRunning) {
// Check for settlement: if average speed is very low, restart
const avgSpeedSq = nodes.reduce((sum, n) => sum + (n.vx * n.vx + n.vy * n.vy), 0) / N;
if (avgSpeedSq < 0.01 && FRAME_COUNT > 300) { // Stay settled for a moment before restarting
initGraph();
FRAME_COUNT = 0;
} else if (Math.random() < 0.005) { // Small chance to restart even if settling slowly
initGraph();
FRAME_COUNT = 0;
}
}
calculateForces();
draw();
updateMetrics();
requestAnimationFrame(loop);
FRAME_COUNT++;
}
window.addEventListener('resize', () => {
resizeCanvas();
// Re-run init to keep nodes within bounds if resizing drastically changes W/H
nodes = [];
edges = [];
initGraph();
});
resizeCanvas();
initGraph();
loop();
})();
</script>
</body>
</html>
```
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.
▶ Playstarts, but throws a JavaScript error Show code ```html
<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>Force Graph Simulation</title></head><body style="background:#111;color:#fff;"><canvas id="graphCanvas" width="800" height="600" style="display:block;border:1px solid #333;"></canvas><div id="info" style="padding:10px;font-family:monospace;">Nodes: 0 | Energy: 0.0</div><script>
const canvas = document.getElementById('graphCanvas');
const ctx = canvas.getContext('2d');
const infoDiv = document.getElementById('info');
let nodes = [];
let edges = [];
let running = true;
let simulationRunning = false;
// --- Physics Constants ---
const K_SPRING = 0.015; // Spring constant (attraction)
const C_REPULSION = 500; // Repulsion constant (inverse square law influence)
const DAMPING = 0.95; // Drag/damping factor
const TARGET_GRAVITY = 0;
function createNode(x, y) {
return { x: x, y: y, vx: Math.random() * 2 - 1, vy: Math.random() * 2 - 1, mass: 1 };
}
function initGraph(N) {
nodes = [];
edges = [];
for (let i = 0; i < N; i++) {
nodes.push(createNode(Math.random() * canvas.width, Math.random() * canvas.height));
}
// Create a random sparse graph (ensuring connectedness is not strictly required but adds visual interest)
const maxEdges = N * 3; // Connect each node to ~3 others on average
let addedEdges = new Set();
while (edges.length < Math.min(maxEdges, N * (N - 1) / 2)) {
let i = Math.floor(Math.random() * N);
let j = Math.floor(Math.random() * N);
if (i === j) continue;
const pairKey = i < j ? `${i}-${j}` : `${j}-${i}`;
if (!addedEdges.has(pairKey)) {
edges.push({ u: i, v: j });
addedEdges.add(pairKey);
}
}
}
function calculateForces() {
let totalEnergy = 0;
// 1. Repulsion (N^2) and Spring Force Calculation
for (let i = 0; i < nodes.length; i++) {
const nA = nodes[i];
nA.fx = 0;
nA.fy = 0;
// Repulsion from all other nodes j > i
for (let j = i + 1; j < nodes.length; j++) {
const nB = nodes[j];
// Calculate distance vector and squared distance
const dx = nA.x - nB.x;
const dy = nA.y - nB.y;
const distSq = dx * dx + dy * dy;
let dist = Math.sqrt(distSq);
// Repulsion force (inverse square magnitude)
let forceRepel = C_REPULSION / distSq;
let fxR = (dx / dist) * forceRepel;
let fyR = (dy / dist) * forceRepel;
nA.fx += fxR;
nA.fy += fyR;
nB.fx -= fxR; // Action-reaction pair
nB.fy -= fyR;
// Spring Force (Hooke's Law: F = -k * x)
let forceSpring = K_SPRING * dist;
let fxS = -(dx / dist) * forceSpring;
let fyS = -(dy / dist) * forceSpring;
nA.fx += fxS;
nA.fy += fyS;
nB.fx -= fxS;
nB.fy -= fyS;
}
}
// 2. Apply forces and update positions (Euler Integration with Damping)
for (let i = 0; i < nodes.length; i++) {
const n = nodes[i];
// Update velocity: v(t+1) = v(t) * damping + a * dt
n.vx = n.vx * DAMPING + (n.fx / n.mass);
n.vy = n.vy * DAMPING + (n.fy / n.mass);
// Update position: p(t+1) = p(t) + v(t+1) * dt
n.x += n.vx;
n.y += n.vy;
}
return totalEnergy;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw Edges (Springs)
ctx.strokeStyle = '#555';
ctx.lineWidth = 1;
edges.forEach(edge => {
const nA = nodes[edge.u];
const nB = nodes[edge.v];
ctx.beginPath();
ctx.moveTo(nA.x, nA.y);
ctx.lineTo(nB.x, nB.y);
ctx.stroke();
});
// Draw Nodes (Circles and Labels)
for (let i = 0; i < nodes.length; i++) {
const n = nodes[i];
// Node circle
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.arc(n.x, n.y, 6, 0, Math.PI * 2);
ctx.fill();
// Label
ctx.fillStyle = '#333';
ctx.font = '12px monospace';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(i, n.x, n.y);
}
}
function updateSimulation() {
const energy = calculateForces();
draw();
infoDiv.innerHTML = `Nodes: ${nodes.length} | Energy: ${energy.toFixed(2)}`;
}
// --- Animation Loop and State Management ---
let lastEnergy = 0;
const STABILITY_THRESHOLD = 1.5; // If energy change is below this, consider it settled.
function animate() {
if (!simulationRunning) return;
updateSimulation();
// Check for stability (energy dampening)
let energyChange = Math.abs(Math.sqrt(lastEnergy * lastEnergy + 1)); // Simple metric proxy for change
// Since calculating the exact potential energy is complex, we use a simple decay check:
// If the speed of movement/force application significantly drops over time, it has settled.
if (energy < STABILITY_THRESHOLD && nodes.every(n => Math.abs(n.vx) < 0.1 && Math.abs(n.vy) < 0.1)) {
console.log("Simulation settled.");
simulationRunning = false;
setTimeout(resetGraph, 2000); // Wait 2 seconds before restarting
}
lastEnergy = energy;
requestAnimationFrame(animate);
}
function resetGraph() {
initGraph(25); // Always use 25 nodes as specified
simulationRunning = true;
lastEnergy = 1000; // Initialize high energy to start the movement
// Start the loop if it wasn't running
if (!animationLoopId) {
animate();
}
}
let animationLoopId = requestAnimationFrame(animate);
// Initial setup call
resetGraph();
</script></body></html>
```
No answer reached us (TIMEOUT) — 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.
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.
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
▶ Playstarts, but the canvas stays empty Show code ```html
<!DOCTYPE html>
<html>
<head><title>Force Graph Simulation</title><style>body{margin:0;overflow:hidden}canvas{display:block}</style></head><body><canvas id="graphCanvas" width="800" height="600"></canvas><script>
const canvas = document.getElementById('graphCanvas');
const ctx = canvas.getContext('2d');
let nodes = [];
let edges = [];
let isSimulating = false;
let lastEnergy = 0;
let simulationInterval = 1; // Lower means faster updates
let animationFrameId = null;
// --- Physics Constants ---
const K_REPEL = 3000; // Repulsion constant (higher = stronger push)
const K_ATTRACT = 0.05; // Attraction constant (spring stiffness)
const DAMPING = 0.98; // Energy decay per step
const MAX_STEPS = 1000; // Max steps before considering the graph settled
function initializeNodes(count, width, height) {
nodes = [];
for (let i = 0; i < count; i++) {
nodes.push({ x: Math.random() * width, y: Math.random() * height, vx: 0, vy: 0, index: i });
}
}
function initializeEdges(nodeCount) {
edges = [];
for (let i = 0; i < nodeCount; i++) {
for (let j = i + 1; j < nodeCount; j++) {
// Connect every pair (complete graph)
edges.push({ u: i, v: j });
}
}
}
function calculateForces() {
let totalEnergy = 0;
const N = nodes.length;
// Reset velocities
for (let node of nodes) {
node.vx *= DAMPING;
node.vy *= DAMPING;
}
// Apply forces for all pairs
for (let i = 0; i < N; i++) {
const n1 = nodes[i];
// Repulsion force (all other nodes)
for (let j = 0; j < N; j++) {
if (i === j) continue;
const n2 = nodes[j];
let dx = n2.x - n1.x;
let dy = n2.y - n1.y;
let distSq = dx * dx + dy * dy;
let dist = Math.sqrt(distSq);
if (dist < 0.1) continue;
// Repulsion force: proportional to 1/d^2
let fx_repel = K_REPEL / distSq / N;
let fy_repel = K_REPEL / distSq / N;
n1.vx -= (fx_repel * dx) / dist;
n1.vy -= (fy_repel * dy) / dist;
}
}
// Apply spring force (edges)
for (const edge of edges) {
const n1 = nodes[edge.u];
const n2 = nodes[edge.v];
let dx = n2.x - n1.x;
let dy = n2.y - n1.y;
let dist = Math.sqrt(dx * dx + dy * dy);
// Ideal length (L=1 for simplicity, giving stiffness)
let displacement = 1 - dist;
// Spring force magnitude: -k_s * x (Hooke's Law simplified)
let fx_spring = K_ATTRACT * displacement * dx / dist;
let fy_spring = K_ATTRACT * displacement * dy / dist;
// Apply forces equally to both nodes (A pulls B, B pulls A)
n1.vx += fx_spring;
n1.vy += fy_spring;
n2.vx -= fx_spring;
n2.vy -= fy_spring;
}
// Update positions using accumulated velocities
const W = canvas.width;
const H = canvas.height;
for (let node of nodes) {
node.x += node.vx;
node.y += node.vy;
// Simple boundary containment
if (node.x < 0 || node.x > W) node.vx -= Math.sign(node.x - W/2);
if (node.y < 0 || node.y > H) node.vy -= Math.sign(node.y - H/2);
}
// Calculate total energy change (simplified potential energy sum)
let currentEnergy = 0;
for (const edge of edges) {
const n1 = nodes[edge.u];
const n2 = nodes[edge.v];
const dx = n2.x - n1.x;
const dy = n2.y - n1.y;
let dist = Math.sqrt(dx * dx + dy * dy);
// Potential Energy: 0.5 * k * x^2 (Spring) + K_REPEL/d (Repulsion approximation)
currentEnergy += 0.5 * K_ATTRACT * (1 - dist)**2;
}
return currentEnergy;
}
function drawGraph() {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw Edges
ctx.strokeStyle = '#333';
ctx.lineWidth = 1;
for (const edge of edges) {
const n1 = nodes[edge.u];
const n2 = nodes[edge.v];
ctx.beginPath();
ctx.moveTo(n1.x, n1.y);
ctx.lineTo(n2.x, n2.y);
ctx.stroke();
}
// Draw Nodes and Labels
for (let i = 0; i < nodes.length; i++) {
const node = nodes[i];
// Node circle
ctx.beginPath();
ctx.arc(node.x, node.y, 5, 0, Math.PI * 2);
ctx.fillStyle = '#1E90FF';
ctx.fill();
// Label
ctx.font = '10px Arial';
ctx.fillText(i, node.x + 8, node.y - 5);
}
}
function updateSimulation() {
if (!isSimulating) return;
calculateForces();
drawGraph();
// Convergence Check: If energy change is minimal, we consider it settled.
const currentEnergy = calculatePotentialEnergy();
if (Math.abs(currentEnergy - lastEnergy) < 0.1 && simulationInterval > 1) {
console.log("Converged.");
resetGraph();
}
lastEnergy = currentEnergy;
animationFrameId = requestAnimationFrame(updateSimulation);
}
function calculatePotentialEnergy() {
let energy = 0;
for (const edge of edges) {
const n1 = nodes[edge.u];
const n2 = nodes[edge.v];
let dx = n2.x - n1.x;
let dy = n2.y - n1.y;
let dist = Math.sqrt(dx * dx + dy * dy);
// Spring Potential Energy: 0.5 * k * x^2
energy += 0.5 * K_ATTRACT * (1 - dist)**2;
}
return energy;
}
function displayStats(energy) {
const count = nodes.length;
let statsHtml = `Nodes: ${count} | Energy: ${energy.toFixed(2)}`;
document.getElementById('graphCanvas').insertAdjacentHTML('afterend', `<div style="position:absolute; top:10px; left:10px; color:#333; font-family: monospace;">${statsHtml}</div>`);
}
function drawStats() {
const energy = calculatePotentialEnergy();
// Update or create the stats display element
let statDiv = document.querySelector('div[style*="top:10px"]');
if (!statDiv) {
statDiv = document.createElement('div');
statDiv.setAttribute('style', 'position:absolute; top:10px; left:10px; color:#333; font-family: monospace;');
document.getElementById('graphCanvas').insertAdjacentElement('afterend', statDiv);
}
statDiv.innerHTML = `Nodes: ${nodes.length} | Energy: ${energy.toFixed(2)}`;
}
function resetGraph() {
// Reset simulation state
cancelAnimationFrame(animationFrameId);
isSimulating = false;
// Generate new random graph structure
const newNodeCount = Math.min(30, 10 + Math.floor(Math.random() * 25));
initializeNodes(newNodeCount, canvas.width, canvas.height);
initializeEdges(newNodeCount);
nodes.forEach(n => { n.vx = 0; n.vy = 0; });
// Restart simulation
isSimulating = true;
lastEnergy = 0;
animationFrameId = requestAnimationFrame(updateSimulation);
}
// --- Initialization ---
const WIDTH = 800;
const HEIGHT = 600;
canvas.width = WIDTH;
canvas.height = HEIGHT;
function start() {
resetGraph();
}
start();
</script></body></html>
```
Results at a glance — every model in this round with score, response time and status.