OverviewCode › R66
Code · blind round

R66 · AVL tree rebalancing with rotations

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.

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 inserts 20 random keys one at a time into an AVL tree and draws the tree on a <canvas> after every insertion. Label each node with its key and balance factor. When a subtree becomes unbalanced, name the rotation being applied (LL, RR, LR or RL) as a visible label and animate the rotation instead of jumping to the result. Show the tree height and the number of rotations performed. 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 Agemma4:26bDNF
No usable answer reached the harness (TIMEOUT). Counted as a did-not-finish.
MODEL Bqwen3.5:9bBLANKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Animated AVL Tree</title>
    <style>
        body { font-family: sans-serif; display: flex; flex-direction: column; align-items: center; background-color: #f4f4f9; }
        #canvas { border: 1px solid #ccc; margin-top: 20px; background-color: white; }
        #info { margin-top: 10px; padding: 10px; border: 1px solid #ddd; width: 80%; max-width: 600px; background: #eef; }
    </style>
</head>
<body>

<h1>AVL Tree Insertion Simulation</h1>
<canvas id="canvas" width="900" height="500"></canvas>
<div id="info">Height: N/A | Rotations: 0</div>

<script>
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    const infoDiv = document.getElementById('info');
    let keysToInsert = [];
    let rotationCount = 0;
    let isAnimating = false;

    class Node {
        constructor(key) {
            this.key = key;
            this.left = null;
            this.right = null;
            this.parent = null;
            this.height = 1;
        }
    }

    class AVLTree {
        constructor() {
            this.root = null;
            this.rotationLabel = { active: false, type: '', duration: 0 };
        }

        getHeight(node) { return node ? node.height : 0; }
        getBalanceFactor(node) { return this.getHeight(node.left) - this.getHeight(node.right); }
        updateHeight(node) { node.height = Math.max(this.getHeight(node.left), this.getHeight(node.right)) + 1; }

        insertAndBalance(root, key, parentNode) {
            if (!root) return new Node(key);
            let result;

            if (key < root.key) {
                const leftChild = root.left ? this.insertAndBalance(root.left, key, root) : null;
                result = { node: Object.assign(root, { left: leftChild }), done: true };
            } else if (key > root.key) {
                const rightChild = root.right ? this.insertAndBalance(root.right, key, root) : null;
                result = { node: Object.assign(root, { right: rightChild }), done: true };
            } else {
                return root; // Duplicate keys not allowed
            }

            let node = result.node;
            if (node && !parentNode) node.parent = null;
            else if (parentNode) node.parent = parentNode;
            
            this.updateHeight(node);

            let balance = this.getBalanceFactor(node);
            
            // Check for unbalance and perform rotations
            if (Math.abs(balance) > 1) {
                const p = node.left ? node.left : node.right; // The child causing imbalance
                if (balance < -1 && p.key > node.key) { /* Right heavy, right insert */ }

                // Simplified logic for rotation detection/execution: assumes the function call stack handles parent linking correctly during recursion. 
                // Due to line constraints and complexity of full pointer management in a recursive simulator, we must rely on simplified restructuring that updates the root property directly.
            }
            return node;
        }

        insert(key) {
            if (!this.root) { this.root = new Node(key); return; }
            let newNode = new Node(key);
            const oldRoot = this.root;

            // --- Standard BST Insertion (Simplified for Line Limit) ---
            let current = this.root;
            let parent = null;
            while (current) {
                parent = current;
                if (key < current.key) {
                    current = current.left;
                } else if (key > current.key) {
                    current = current.right;
                } else {
                    return false; // Already exists
                }
            }

            newNode.parent = parent;
            if (key < parent.key) parent.left = newNode;
            else parent.right = newNode;

            // --- Rebalancing Loop (Crucial and complex, heavily simplified for demo viability within line limit) ---
            let current_node = newNode;
            while (current_node && Math.abs(this.getBalanceFactor(current_node)) > 1) {
                let node = current_node;
                let parent = node.parent;

                if (!parent || !parentNode) break; // Safety break if we hit the root/edge case too fast

                // Placeholder for actual rotation logic (LL, RR, LR, RL)
                // Due to line limit, full pointer redirection is impossible. We assume a simplified restructuring happens and only update metrics.
                if (Math.abs(this.getBalanceFactor(node)) > 1) {
                    rotationCount++;
                    // In a real simulation, the tree structure needs deep manipulation here.
                }

                current_node = parent; // Move up to check ancestors
            }
        }
    }

    let avlTree = new AVLTree();
    const ANIMATION_SPEED = 0.02;
    let insertionIndex = 0;

    function generateKeys() {
        let keys = [];
        let currentKey = 1;
        while (keys.length < 20) {
            if (Math.random() > 0.5) {
                currentKey += Math.floor(Math.random() * 90); // Generate random jump between 1 and 100 approx
            } else {
                currentKey += 1;
            }
            keys.push(currentKey % 200 + 1); // Keep keys manageable
        }
        return keys;
    }

    function initialize() {
        keysToInsert = generateKeys();
        avlTree = new AVLTree();
        rotationCount = 0;
        insertionIndex = 0;
        infoDiv.innerHTML = `Height: N/A | Rotations: ${rotationCount}`;
        drawTree(true); // Initial empty draw
    }

    function drawTree(isInitial = false) {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (!avlTree.root) return;

        const LAYOUT_CONFIG = { x: 450, y: 100 };
        
        function drawNode(node, x, y, isRoot=false) {
            const nodeWidth = 80;
            const radius = 20;
            const labelY = y + 10;

            // Draw connections (Parent to Child)
            if (!isRoot && node.parent) {
                let px = getNodePosition(node.parent).x;
                let py = getNodePosition(node.parent).y;
                ctx.beginPath();
                ctx.moveTo(px, py + radius);
                ctx.lineTo(x, y - 20);
                ctx.strokeStyle = '#333';
                ctx.lineWidth = 1.5;
                ctx.stroke();
            }

            // Draw Node Box
            ctx.fillStyle = '#d9edf7';
            ctx.fillRect(x - nodeWidth / 2, y - radius, nodeWidth, radius * 2);
            ctx.strokeStyle = '#31b7ce';
            ctx.strokeRect(x - nodeWidth / 2, y - radius, nodeWidth, radius * 2);

            // Draw Key and BF
            ctx.fillStyle = 'black';
            ctx.font = 'bold 14px Arial';
            ctx.fillText(`${node.key}`, x - 30, y + 5);
            ctx.font = 'bold 12px Arial';
            let bfText = `${Math.round(avlTree.getBalanceFactor(node))}`;
            ctx.fillStyle = '#a94444';
            ctx.fillText(`BF: ${bfText}`, x + 10, y + 5);

            // Draw Rotation Label (If applicable)
            if (avlTree.rotationLabel.active && node.key === avlTree.rotationLabel.typeKey) {
                ctx.fillStyle = '#f0ad4e';
                ctx.fillRect(x - 60, y - 35, 120, 20);
                ctx.fillStyle = 'white';
                ctx.textAlign = 'center';
                ctx.fillText(`ROT: ${avlTree.rotationLabel.type}`, x, y - 24);
            }

            // Positioning children recursively
            let childY = y + radius * 1.5;
            const spacing = nodeWidth * 1.8;
            if (node.left) drawNode(node.left, x - spacing / 2, childY, false);
            if (node.right) drawNode(node.right, x + spacing / 2, childY, false);
        }

        function getNodePosition(node) {
            // Simple hack: Store positions on the node temporarily for drawing connections
            if (!node.__pos) {
                node.__pos = { x: canvas.width / 2, y: 0 };
            }
            return node.__pos;
        }

        // Reset and calculate positions before drawing (BFS approach is best for layout)
        let queue = [{ node: avlTree.root, depth: 0, xOffset: 0 }];
        let nodes = [];

        while(queue.length > 0) {
            let item = queue.shift();
            item.node.__pos = { x: 0, y: 0 }; // Reset position helper
            nodes.push(item);
            if (item.node.left) queue.push({ node: item.node.left, depth: item.depth + 1, xOffset: item.xOffset - 1 });
            if (item.node.right) queue.push({ node: item.node.right, depth: item.depth + 1, xOffset: item.xOffset + 1 });
        }

        // Simple horizontal layout assignment (Approximate positioning)
        let maxDepth = nodes.reduce((max, n) => Math.max(max, n.depth), 0);
        const effectiveWidth = canvas.width - 100;
        const nodeSpacing = effectiveWidth / Math.pow(2, maxDepth);

        nodes.forEach((item, index) => {
            let depth = item.depth;
            // Calculate X based on simple binary tree indexing approximation
            let xOffsetIndex = (item.node.left ? 1 : 0) + (item.node.right ? Math.pow(2, maxDepth - depth) : 0);
            let xPos = canvas.width * (xOffsetIndex / Math.pow(2, maxDepth));

            // Keep Y spacing proportional to depth
            let yPos = 50 + Math.pow(2, maxDepth - depth) * 15;

            item.node.__pos = { x: xPos, y: yPos };
        });


        // Redraw using the calculated positions
        ctx.save();
        nodes.forEach(item => drawNode(item.node, item.node.__pos.x, item.node.__pos.y));
        ctx.restore();

        infoDiv.innerHTML = `Height: ${Math.max(...nodes.map(n => n.depth)) + 1} | Rotations: ${rotationCount}`;
    }

    async function animateInsertion() {
        if (insertionIndex >= keysToInsert.length) {
            isAnimating = false;
            alert("Finished all insertions!");
            return;
        }
MODEL Cllama3.1:8bDNF
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 Eqwen3:14bBLANKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html>
<head><title>Animated AVL Tree</title></head>
<body id="body">
<canvas id="avlCanvas" style="border: 1px solid #ccc;"></canvas>
<div id="info">Height: 0 | Rotations: 0</div>
<script>
let canvas, ctx, infoDiv;
const CANVAS_W = 800;
const CANVAS_H = 500;

class Node {
    constructor(key) {
        this.key = key;
        this.height = 1;
        this.left = null;
        this.right = null;
        this.bf = 0;
        this.x = 0;
        this.y = 0;
    }
}

let currentRoot = null;
let rotationCount = 0;
let animationActive = false;
const MAX_KEYS = 20;
let keysToInsert = [];

function setup() {
    canvas = document.getElementById('avlCanvas');
    ctx = canvas.getContext('2d');
    infoDiv = document.getElementById('info');
    canvas.width = CANVAS_W;
    canvas.height = CANVAS_H;
}

// --- AVL Helper Functions ---

function height(node) { return node ? node.height : 0; }
function balanceFactor(node) { return node ? (height(node.left) - height(node.right)) : 0; }

function updateNodeMetrics(node, parent = null) {
    if (!node) return;
    node.bf = balanceFactor(node);
    node.height = Math.max(height(node.left), height(node.right)) + 1;
}

// --- AVL Rotations (Structural Only for Animation Context) ---

function rotateRight(y, x) {
    const b = y.left;
    y.left = b.right;
    b.right = y;
    updateNodeMetrics(y);
    updateNodeMetrics(b);
    return b;
}

function rotateLeft(x, y) {
    const b = x.right;
    x.right = b.left;
    b.left = x;
    updateNodeMetrics(x);
    updateNodeMetrics(b);
    return b;
}

// --- AVL Insertion (Recursive and State-Tracking) ---

function insertKey(root, key) {
    if (!root) return new Node(key);
    
    let oldRoot = root;
    let parentNode = null;

    if (key < root.key) {
        parentNode = root;
        root.left = insertKey(root.left, key);
    } else if (key > root.key) {
        parentNode = root;
        root.right = insertKey(root.right, key);
    } else {
        return root; // Duplicate keys ignored
    }

    updateNodeMetrics(root, parentNode);

    let balance = balanceFactor(root);

    // Check for imbalance and perform rotation
    if (balance > 1) { // Left Heavy
        const leftBF = balanceFactor(root.left);
        if (leftBF >= 0) { // LL Case
            return rotateRight(root, root.left);
        } else { // LR Case
            root.left = rotateLeft(root.left, root.left.left);
            return rotateRight(root, root.left);
        }
    }
    if (balance < -1) { // Right Heavy
        const rightBF = balanceFactor(root.right);
        if (rightBF <= 0) { // RR Case
            return rotateLeft(root, root.right);
        } else { // RL Case
            root.right = rotateRight(root.right, root.right.right);
            return rotateLeft(root, root.right);
        }
    }

    return root;
}

// --- Visualization and Animation ---

function calculatePositions(node, xStart, y) {
    if (!node) return 0;
    let currentX = xStart;
    
    calculatePositions(node.left, xStart - 150, y + 40);
    node.x = xStart;
    node.y = y;
    calculatePositions(node.right, xStart + 150, y + 40);

    return Math.max(0, Math.min(CANVAS_W - 150, currentX)); // Placeholder return
}

function drawNode(node) {
    if (!node) return;
    ctx.beginPath();
    ctx.arc(node.x, node.y, 20, 0, Math.PI * 2);
    ctx.fillStyle = '#4CAF50';
    ctx.fill();
    ctx.strokeStyle = '#388E3C';
    ctx.lineWidth = 2;
    ctx.stroke();

    // Draw key and BF label
    ctx.font = '14px Arial';
    ctx.fillStyle = 'black';
    ctx.fillText(node.key, node.x - 30, node.y + 5);
    ctx.fillText(`BF: ${node.bf}`, node.x + 20, node.y + 5);
}

function drawTreeConnections(root) {
    if (!root) return;
    const lineThickness = 2;
    
    let tempArray = [];
    function traverse(node) {
        if (!node) return;
        tempArray.push(node);
        traverse(node.left);
        traverse(node.right);
    }
    tempArray = [];
    traverse(root);

    for(let i=0; i<tempArray.length - 1; i++){
        const n1 = tempArray[i];
        const n2 = tempArray[i+1];
        ctx.beginPath();
        ctx.moveTo(n1.x, n1.y + 20);
        ctx.lineTo(n2.x, n2.y - 20); // Simple vertical connection approximation
        ctx.strokeStyle = '#333';
        ctx.lineWidth = lineThickness;
        ctx.stroke();
    }

    // Draw nodes
    tempArray.forEach(drawNode);
}

function drawTree() {
    if (!currentRoot) return;
    ctx.clearRect(0, 0, CANVAS_W, CANVAS_H);
    calculatePositions(currentRoot, CANVAS_W / 2, 30);
    drawTreeConnections(currentRoot);
}


// --- Animation Logic ---

let animationSteps = [];
let currentStepIndex = 0;

function animateRotation(oldRoot, newRoot, rotationName) {
    animationActive = true;
    const steps = 50;
    const startNodes = []; // Nodes before rotation
    const endNodes = [];   // Nodes after rotation

    // Simplified: Just store the final state and flash/re-draw rapidly to simulate transition.
    // Full physics simulation is too complex for line limit. We fake it by marking nodes.
    animationSteps = [{ root: oldRoot, newRoot: newRoot, name: rotationName }]; 
    currentStepIndex = 0;

    const animate = () => {
        if (!animationSteps[currentStepIndex]) {
            // Animation finished
            animationActive = false;
            drawTree(); // Final draw
            updateInfo();
            return;
        }
        
        const step = animationSteps[currentStepIndex];
        // For simplicity in the time constraint, we just redraw the final state immediately after "animating" a few frames.
        setTimeout(() => { 
             drawTreeConnections(step.newRoot);
        }, currentStepIndex * 10);

        currentStepIndex++;
        requestAnimationFrame(animate);
    };
    requestAnimationFrame(animate);
}


// --- Main Loop & Control ---

function updateInfo() {
    const heightVal = currentRoot ? currentRoot.height : 0;
    infoDiv.innerHTML = `Height: ${heightVal} | Rotations: ${rotationCount}`;
}

async function runNextInsertion() {
    if (keysToInsert.length === 0) return;

    const key = keysToInsert.shift();
    
    // Store old state for potential animation context
    let oldRoot = currentRoot; 
    
    // Perform insertion and structural update
    currentRoot = insertKey(currentRoot, key);

    if (oldRoot !== currentRoot) {
        // A rotation occurred. We need to detect WHICH one happened and animate it.
        // Since `insertKey` handles the math internally, we just trigger a generic animation flag 
        // and update the count based on the assumption that *some* balancing occurred.
        const lastKeys = keysToInsert.length; // Crude check for remaining steps
        if (lastKeys > 0 && oldRoot !== currentRoot) {
             rotationCount++;
             animateRotation(oldRoot, currentRoot, "N/A"); // Animation placeholder
        }
    }

    // Wait for animation to finish before proceeding
    await new Promise(resolve => {
        const checkInterval = setInterval(() => {
            if (!animationActive)
MODEL Fdeepseek-r1:14bBLANKFORMAT
Show code
```html
<!DOCTYPE html>
<html><title>Random AVL Tree</title>
<canvas id=c width=800 height=600></canvas>
<script>
const c=document.getElementById('c'), ctx=c.getContext('2d');
let tree={};
let rotations=0, height=0;
class Node{
  constructor(v){
    this.v=v,this.left=this.right=null,this.bf=1,this.parent=null;
  }
}
function drawNode(x,y,r,v){
  ctx.beginPath();
  ctx.arc(x,y,5,0,2*Math.PI);ctx.fillStyle='white';ctx.fill();
  ctx.fillStyle='black';
  ctx.fillText(v, x-3,y+3);
  ctx.strokeStyle='black';ctx.stroke();
  if(r)ctx.fillText(r,x-3,y+18);
}
function drawTree(node,x,y,dx){
  if(!node)return;
  drawNode(x,y,dx,node.v);
  const l=node.left,r=node.right;
  let ly= y+20, lx=x-dx*4,lly=y+45,llx=l ? (l.x?l.x:x - dx *8) : x - dx*4;
  drawTree(l, lx,ly,dx/2);
  if(r){
    const ry=y+20, rx=x+dx*4;
    drawTree(r, rx,ry,dx/2);
    const mid=(x+rx)/2;drawNode(mid,y+30,dx,r.v);drawLines(x,y,mid,ry);
  }
  if(l)drawLines(x,y,lx,ly);
}
function drawLines(x1,y1,x2,y2){
  ctx.beginPath();
  ctx.moveTo(x1,y1);ctx.lineTo(x2,y2);ctx.stroke();
}
function rotateLL(root){
  const p=root.left,u=p.right;
  p.right=root;p.left=p.left;root.parent=p;
  root.left=u;if(u)u.parent=root;
  if(p.parent)p.parent.left=p;p.bf=0;root.bf=-1;
}
function rotateRR(root){
  const p=root.right,u=p.left;
  p.left=root;p.right=p.right;root.parent=p;
  root.right=u;if(u)u.parent=root;
  if(p.parent)p.parent.right=p;p.bf=0;root.bf=1;
}
function rotateLR(root){
  rotateLL(root.right);rotateRR(root);
}
function rotateRL(root){
  rotateRR(root.left);rotateLL(root);
}
function insert(v,p){
  if(!p)return new Node(v);
  const cmp=v-p.v;if(cmp<0) {
    p.left=insert(v,p.left);if(p.left)p.parent=p;
    return balance(p);
  }
  p.right=insert(v,p.right);if(p.right)p.parent=p;
  return balance(p);
}
function balance(node){
  if(!node)return node;
  let b=node.bf;let left=node.left?node.left.bf||0: -1;
  let right=node.right?node.right.bf||0: -1;
  if(left-right>1){
    if(left<right)rotateLR(node);
    else rotateLL(node);return rotateLL(node);
  }
  if(right-left>1){
    if(right>left)rotateRR(node);
    else rotateRL(node);return rotateRL(node);
  }
  node.bf=0;return node;
}
function randomInsert(){
  const keys=[];let prev=null,rotCount=0,h=0;
  for(let i=0;i<20;++i){
    while(prev===null||keys.includes(Math.random()*100|0)) ;
    prev=null;keys.push(...keys.splice(Math.random()*keys.length,1));
  }
}
</script>
</html>
```
MODEL Gqwen3-coder:30bBLANKLIMFORMAT
Show code
```html
<!DOCTYPE html>
<html><head><title>AVL Tree Animator</title></head><body>
<canvas id="treeCanvas" style="border:1px solid black;"></canvas>
<div>Height: <span id="heightDisplay">0</span> | Rotations: <span id="rotationsDisplay">0</span></div>

<script>
const canvas = document.getElementById('treeCanvas');
const ctx = canvas.getContext('2d');
canvas.width = 900;
canvas.height = 500;

let AVLTree = null;
let keysToInsert = [];
let currentKeyIndex = 0;
let animationRunning = false;

class AVLNode {
    constructor(key) {
        this.key = key;
        this.left = null;
        this.right = null;
        this.height = 1;
        this.bf = 0;
    }
}

function height(node) { return node ? node.height : 0; }
function balanceFactor(node) { return (height(node.left) - height(node.right)); }
function updateNode(node) { 
    if (!node) return;
    node.height = Math.max(height(node.left), height(node.right)) + 1;
    node.bf = balanceFactor(node);
}

// --- ROTATION LOGIC ---

function rotateRight(y, x, rotationName) {
    let T2 = x.right;
    x.right = y.left;
    y.left = x;

    updateNode(T2); // Update right subtree first
    updateNode(x);
    updateNode(y);

    return y;
}

function rotateLeft(x, y, rotationName) {
    let T2 = x.left;
    x.left = y.right;
    y.right = x;

    updateNode(T2); // Update left subtree first
    updateNode(x);
    updateNode(y);

    return x;
}


// --- INSERTION & BALANCING (The state machine) ---

function insertRecursive(node, key) {
    if (!node) return new AVLNode(key);

    if (key < node.key) {
        node.left = insertRecursive(node.left, key);
    } else if (key > node.key) {
        node.right = insertRecursive(node.right, key);
    } else {
        return node; // Duplicate keys not allowed
    }

    updateNode(node);

    let balance = node.bf;
    if (Math.abs(balance) > 1) {
        // Imbalance detected: Handle rotations based on the path taken
        if (balance < -1 && key > node.right.key) { // RL case structure
            return rotateLeft(node, new AVLNode(0), "RL");
        } else if (balance > 1 && key < node.left.key) { // LL case structure
            return rotateRight(node, new AVLNode(0), "LL");
        } else if (balance < -1 && key < node.right.key) { // LR case structure
             let temp = rotateLeft(node.right, new AVLNode(0), null);
             node.right = temp;
             return rotateRight(node, new AVLNode(0), "LR");
        } else if (balance > 1 && key > node.left.key) { // RR case structure
            let temp = rotateRight(node.left, new AVLNode(0), null);
            node.left = temp;
            return rotateLeft(node, new AVLNode(0), "RR");
        }
    }

    return node;
}

// --- ANIMATION & DRAWING LOGIC ---

const NODE_RADIUS = 25;
let rotationAnimationStep = {}; // Stores state for current animation

function setRotationState(root, parentKey, childKey, type) {
    rotationAnimationStep = { root: root, parentKey: parentKey, childKey: childKey, type: type, startNode: null };
}

// This drawing function handles the rendering for a given state (including animation factor 't')
function drawTree(node, x_offset, y, t) {
    if (!node) return;

    const currentX = x_offset + Math.pow(2, y - 1) * 80; // Pseudo-positioning for visualization
    
    // Calculate actual leaf/branch positions (simplified horizontal layout)
    let base_x = canvas.width / 2;
    let node_w = 40;
    const x_pos = base_x + Math.pow(2, y - 1) * 80;

    // ----- Animation Offset Calculation -----
    let currentXOffset = x_pos;
    let rotationTransform = { scale: 1, angle: 0 };
    if (rotationAnimationStep && Math.abs(t - 0.5) < 0.1) {
        const s = t * Math.PI;
        let center = {x: x_pos, y: canvas.height / 2};
        // In a real implementation, we would calculate the actual rotation matrix here based on step 't'
    }

    ctx.save();
    ctx.translate(currentXOffset, y);

    // Draw Node Circle
    ctx.beginPath();
    ctx.arc(0, 0, NODE_RADIUS, 0, Math.PI * 2);
    ctx.fillStyle = '#d9eaf7';
    ctx.stroke();
    ctx.fill();

    // Label Key and BF
    ctx.font = "14px Arial";
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";
    ctx.fillStyle = "#333";
    ctx.fillText(`${node.key} (BF: ${node.bf})`, 0, 0);

    // Draw Connections
    if (node.left) {
        const leftXOffset = x_offset - 1;
        drawConnection(currentXOffset, y, node.left, leftXOffset, y + 70, t);
        drawTree(node.left, x_offset - 1, y + 70, t);
    }

    if (node.right) {
        const rightXOffset = x_offset + 1;
        drawConnection(currentXOffset, y, node.right, x_offset + 1, y + 70, t);
        drawTree(node.right, x_offset + 1, y + 70, t);
    }

    ctx.restore();
}

// Simplified drawing function for connections (ignores complex animation geometry)
function drawConnection(startPos, startY, targetNode, endXOffset, endY, t) {
    const dx = Math.abs(startPos - (endXOffset + 40));
    const dy = Math.abs(startY - endY);

    ctx.beginPath();
    ctx.moveTo(startPos, startY);
    // For animation, we would draw an arc or straight line segment that morphs based on 't'
    ctx.lineTo(endXOffset + 40, endY); 
    ctx.strokeStyle = '#555';
    ctx.lineWidth = 2;
    ctx.stroke();
}


// --- MAIN ANIMATION LOOP ---

function animateInsertionStep(root, currentKey) {
    if (animationRunning) return;
    animationRunning = true;
    let rotationName = null;

    const initialRoot = JSON.parse(JSON.stringify(root)); // Deep copy for reference
    
    // Step 1: Re-run the insertion path to detect imbalance and identify rotations
    let tempRoot = root;
    let steps = []; // To store history of changes/rotations

    function traceInsert(node, key) {
        if (!node) return null;

        if (key < node.key) {
            const newLeft = traceInsert(node.left, key);
            node.left = newLeft;
        } else if (key > node.key) {
            const newRight = traceInsert(node.right, key);
            node.right = newRight;
        }

        updateNode(node);
        let balance = Math.abs(node.bf);

        if (balance > 1 && !steps[steps.length - 1] || steps[steps.length - 1].rotation === null) {
            // This is where the rotation logic would ideally be triggered and captured for animation
            // Due to complexity limitations, we simulate the state change immediately after calculating the result
        }
        return node;
    }

    let previousRoot = JSON.parse(JSON.stringify(root)); // State before insertion
    let newRoot = insertRecursive(tempRoot, currentKey);
    
    // --- VISUALIZATION OF ROTATION (Simplified) ---
    if (rotationAnimationStep.type) {
        console.log(`Animating ${rotationAnimationStep.type}`);
        const startTime = performance.now();

        function animate(timestamp) {
            const elapsed = timestamp - startTime;
            let t = Math.min(1, elapsed / 500); // Animation duration: 500ms
            
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            // Draw the tree at the animated state (
MODEL Hqwen3:8bDNF
No usable answer reached the harness (ERR). Counted as a did-not-finish.
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 gemma4:26b DNF
MODEL B qwen3.5:9b 75.2 sOK
MODEL C llama3.1:8b DNF
MODEL D mistral-small:24b DNF
MODEL E qwen3:14b 49.8 sOK
MODEL F deepseek-r1:14b 20.2 sOK
MODEL G qwen3-coder:30b 39.2 sOK
MODEL H qwen3:8b DNF

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
Show code
<!doctype html>
<html lang="en"><head><meta charset="utf-8"><title>AVL Tree — Animated Insertions &amp; Rotations</title>
<style>html,body{margin:0;height:100%;background:#0b0f16;display:flex;align-items:center;justify-content:center}
canvas{background:#0d1117;border:1px solid #1e2836;border-radius:10px;max-width:100%}</style></head><body>
<canvas id="c" width="980" height="560"></canvas>
<script>
const c=document.getElementById('c'),g=c.getContext('2d'),W=980,H=560;
const PX=(x,n)=>W/2+(x-(n-1)/2)*44,PY=d=>140+d*64,L=(a,b,s)=>a+(b-a)*s;
let root=null,rots=0,keys=[],ki=0,q=[],prev=null,cur=null,t0=0,dur=400;
const h=n=>n?n.h:0,bf=n=>n?h(n.l)-h(n.r):0,up=n=>{n.h=1+Math.max(h(n.l),h(n.r))};
function rep(o,w){const p=o.p;w.p=p;if(!p)root=w;else if(p.l===o)p.l=w;else p.r=w}
function rotR(n){const a=n.l;n.l=a.r;if(a.r)a.r.p=n;rep(n,a);a.r=n;n.p=a;up(n);up(a)}
function rotL(n){const a=n.r;n.r=a.l;if(a.l)a.l.p=n;rep(n,a);a.l=n;n.p=a;up(n);up(a)}
function snap(msg,rot,pivot){let i=0,a=[],e=[];
  (function w(n,d){if(!n)return;w(n.l,d+1);n._x=i++;n._d=d;w(n.r,d+1)})(root,0);
  (function v(n){if(!n)return;a.push({n:n,k:n.k,b:bf(n),x:n._x,y:n._d});
    if(n.l){e.push([n,n.l]);v(n.l)}if(n.r){e.push([n,n.r]);v(n.r)}})(root);
  q.push({msg:msg,rot:rot||"",pivot:pivot||null,nodes:a,edges:e,th:h(root),rots:rots});}
function insert(k){const nd={k:k,l:null,r:null,p:null,h:1};
  if(!root)root=nd;else{let n=root;for(;;){if(k<n.k){if(!n.l){n.l=nd;nd.p=n;break}n=n.l}
    else{if(!n.r){n.r=nd;nd.p=n;break}n=n.r}}}
  snap("Inserted key "+k,"",nd);
  let n=nd.p;
  while(n){up(n);const b=bf(n),par=n.p,kk=n.k;
    if(b>1){const d=bf(n.l)<0;
      if(d){rots++;rotL(n.l);snap("LR: step 1 — left rotation on left child of "+kk,"LR",n)}
      rots++;rotR(n);snap((d?"LR: step 2 — right rotation on ":"LL: right rotation on ")+kk,d?"LR":"LL",n);}
    else if(b<-1){const d=bf(n.r)>0;
      if(d){rots++;rotR(n.r);snap("RL: step 1 — right rotation on right child of "+kk,"RL",n)}
      rots++;rotL(n);snap((d?"RL: step 2 — left rotation on ":"RR: left rotation on ")+kk,d?"RL":"RR",n);}
    n=par;}}
function reset(){root=null;rots=0;ki=0;q=[];const s=new Set();
  while(s.size<20)s.add(1+Math.floor(Math.random()*99));
  keys=[...s];cur={msg:"New random AVL tree",rot:"",pivot:null,nodes:[],edges:[],th:0,rots:0};
  prev=cur;t0=performance.now();dur=500;}
function step(){if(!q.length&&ki<keys.length)insert(keys[ki++]);
  if(q.length){prev=cur;cur=q.shift();t0=performance.now();dur=cur.rot?900:480;}}
function ease(e){return e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2}
function bcol(b){return Math.abs(b)>1?"#ff5f6d":Math.abs(b)===1?"#f4c15d":"#5ad6a0"}
function draw(s,now){
  g.clearRect(0,0,W,H);g.fillStyle="#0d1117";g.fillRect(0,0,W,H);
  const pn=prev.nodes.length,cn=cur.nodes.length,pm=new Map(),pos=new Map();
  prev.nodes.forEach(o=>pm.set(o.n,o));
  cur.nodes.forEach(o=>{const p=pm.get(o.n),tx=PX(o.x,cn),ty=PY(o.y);
    if(p)pos.set(o.n,{x:L(PX(p.x,pn),tx,s),y:L(PY(p.y),ty,s),a:1});
    else pos.set(o.n,{x:tx,y:ty,a:s});});
  g.lineWidth=2;g.strokeStyle="#33465e";
  cur.edges.forEach(p=>{const A=pos.get(p[0]),B=pos.get(p[1]);g.globalAlpha=Math.min(A.a,B.a);
    g.beginPath();g.moveTo(A.x,A.y);g.lineTo(B.x,B.y);g.stroke();});
  g.globalAlpha=1;
  cur.nodes.forEach(o=>{const p=pos.get(o.n);g.globalAlpha=.25+.75*p.a;
    g.beginPath();g.arc(p.x,p.y,18,0,7);g.fillStyle="#16202e";g.fill();
    g.lineWidth=2.5;g.strokeStyle=bcol(o.b);g.stroke();
    if(cur.pivot===o.n){g.beginPath();g.arc(p.x,p.y,18+4+2*Math.sin(now/110),0,7);
      g.lineWidth=2;g.strokeStyle=cur.rot?"#ffd166":"#6ea8ff";g.stroke();}
    g.fillStyle="#e8eef7";g.font="bold 15px system-ui,sans-serif";g.textAlign="center";
    g.textBaseline="middle";g.fillText(o.k,p.x,p.y);
    g.font="bold 11px system-ui,sans-serif";g.fillStyle=bcol(o.b);g.textAlign="left";
    g.fillText((o.b>0?"+":"")+o.b,p.x+19,p.y-15);g.globalAlpha=1;});
  g.textAlign="left";g.textBaseline="alphabetic";
  g.fillStyle="#e8eef7";g.font="bold 19px system-ui,sans-serif";
  g.fillText("AVL Tree — self-balancing insertion",24,36);
  g.font="13px system-ui,sans-serif";g.fillStyle="#8fa3bb";
  g.fillText("node = key,  small colored value = balance factor (height(left) − height(right))",24,58);
  g.font="bold 15px system-ui,sans-serif";g.fillStyle="#6ea8ff";
  g.fillText("Height: "+cur.th,24,88);
  g.fillStyle="#ffd166";g.fillText("Rotations: "+cur.rots,140,88);
  g.fillStyle="#5ad6a0";g.fillText("Inserted: "+cur.nodes.length+" / 20",286,88);
  g.textAlign="right";g.font="13px system-ui,sans-serif";g.fillStyle="#9db1c9";
  g.fillText(cur.msg,W-24,88);
  if(cur.rot){const a=.35+.65*Math.abs(Math.sin(now/220));g.globalAlpha=a;
    g.textAlign="center";g.font="bold 40px system-ui,sans-serif";g.fillStyle="#ffd166";
    g.fillText(cur.rot+" ROTATION",W/2,H-34);g.globalAlpha=1;}
  else if(!q.length&&ki>=keys.length){g.textAlign="center";g.font="bold 17px system-ui,sans-serif";
    g.fillStyle="#5ad6a0";g.fillText("balanced — restarting with a fresh random tree…",W/2,H-34);}}
function frame(now){const e=Math.min(1,(now-t0)/dur);draw(ease(e),now);
  if(e>=1){if(!q.length&&ki>=keys.length){if(now-t0>dur+2200)reset();}else step();}
  requestAnimationFrame(frame);}
reset();requestAnimationFrame(frame);
</script></body></html>