OverviewCode › R21
Code

R21 · Sorting race bubble/insertion/selection

Archive round — this round predates the blind-first layout, so answers appear with model names attached. Newer rounds keep the models anonymous until you reveal them.
scored 11/13 models answered
Show task
Create ONE self-contained HTML file (STRICT LIMIT: max 120 lines total) that visually races exactly 3 sorting algorithms — bubble sort, insertion sort, selection sort — on the SAME shuffled array of 40 values. Three labeled panels on one <canvas> (or three small canvases), bars animated step by step, each panel shows "DONE" when its algorithm finishes. No external libraries, no comments needed. Output ONLY the HTML file content, nothing else.

Answers

Local (Brain cluster)
gemma4:26b DNF / pending DNF (infra)
DNF — infrastructure: 9/10 rounds ended in provider errors; its only completed round, R28, scored 8.5
qwen3-coder:30b29.0 sERRSTATLIM★ 1.5/10
Show code
```html
<!DOCTYPE html>
<html>
<head>
<title>Sorting Race</title>
<style>
body {display: flex; justify-content: center; background-color: #1e1e2f; font-family: sans-serif;}
#container {display: flex; gap: 20px; padding: 20px;}
.panel {flex: 1; border: 2px solid #4a386d; background-color: #25253e; }
h2 {color: #eeeeef; text-align: center; margin-top: 0;}
</style>
</head>
<body>

<div id="container">
    <div class="panel"><canvas id="bubbleCanvas" width="280" height="300"></canvas><h2>Bubble Sort</h2></div>
    <div class="panel"><canvas id="insertionCanvas" width="280" height="300"></canvas><h2>Insertion Sort</h2></div>
    <div class="panel"><canvas id="selectionCanvas" width="280" height="300"></canvas><h2>Selection Sort</h2></div>
</div>

<script>
const SIZE = 40;
let arrOriginal = [];

function shuffle(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
    }
    return arr;
}

// Generate shared array and initialize canvases
let arrGlobal = [];
document.addEventListener('DOMContentLoaded', () => {
    arrGlobal = shuffle(Array.from({length: SIZE}, i => Math.floor(Math.random() * 100) + 1));
    const cB = document.getElementById('bubbleCanvas');
    const cI = document.getElementById('insertionCanvas');
    const cS = document.getElementById('selectionCanvas');

    let colorArray = (arr, i, j){return Math.abs(arr[i] - arr[j]) < 5 ? '#ffeb3b' : (i === j ? '#4CAF50':'#25253e');};
    const draw = (canvasId, arrayState, highlightIndices) => {
        const canvas = document.getElementById(canvasId);
        const ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        if (!arrayState || !arrayState.length) return;

        const barWidth = canvas.width / SIZE; 

        for (let i = 0; i < SIZE; i++) {
            let x = i * barWidth;
            let y = canvas.height - (arrayState[i] / 100) * canvas.height;
            let height = arrayState[i] / 100 * canvas.height;

            if (highlightIndices && highlightIndices.has(i)) {
                ctx.fillStyle = '#ff9800';
            } else if (Array.isArray(highlightIndices) && highlightIndices.includes(i)) {
                 ctx.fillStyle = '#f44336';
            } else {
                ctx.fillStyle = '#757575';
            }
            ctx.fillRect(x, y, barWidth - 1, height);
        }
    };

    const animateStep = (callback, id, initialArray) => {
        let currentState = [...initialArray];
        let stepIndex = 0;
        function loop() {
            if (stepIndex < callback.length) {
                ({[id]: step} = callback.shift());
                currentState = [...step].map((v, i) => v); // Use the provided state map when available
                draw(id === 'bubbleCanvas' ? 'bubbleCanvas' : id === 'insertionCanvas' ? 'insertionCanvas' : 'selectionCanvas', currentState, (i, j) => {
                    if (typeof callback.length > 0 && Array.isArray(callback[stepIndex]) && typeof callback[stepIndex][i] !== 'undefined') return i;
                    return null; // Complex highlighting logic omitted for brevity/line count
                });
                setTimeout(loop, 15);
            } else {
                draw(id === 'bubbleCanvas' ? 'bubbleCanvas' : id === 'insertionCanvas' ? 'insertionCanvas' : 'selectionCanvas', currentState);
                document.querySelector(`#container .panel:nth-child(${[[['bubbleCanvas',1], ['insertionCanvas',2], ['selectionCanvas',3]][id]]}) h2`).innerHTML = "DONE";
            }
        }
        setTimeout(loop, 15);
    };

    // --- Algorithms (Generator/Step Function Approach) ---

    // Bubble Sort Implementation
    function* bubbleSort(arr) {
        let a = [...arr];
        for (let i = 0; i < a.length - 1; i++) {
            let swapped = false;
            for (let j = 0; j < a.length - 1 - i; j++) {
                const stepState = [...a];
                stepState[j] = Math.min(a[j], a[j+1]);
                stepState[j+1] = Math.max(a[j], a[j+1]);
                yield({ state: stepState, indices: [j, j + 1] });
                if (a[j] > a[j+1]) {
                    [a[j], a[j+1]] = [a[j+1], a[j]];
                    swapped = true;
                }
            }
            if (!swapped) break;
        }
    }

    // Insertion Sort Implementation
    function* insertionSort(arr) {
        let a = [...arr];
        for (let i = 1; i < a.length; i++) {
            let key = a[i];
            let j = i - 1;
            while (j >= 0 && a[j] > key) {
                yield({ state: [...a], indices: [j, i] }); // Highlight compare/shift
                a[j + 1] = a[j];
                [a[j], a[j+1]] = [null, a[j]]; // Simulate shift visually (simple placeholder)
                if (typeof a[j] === 'object') {
                     let temp = a[j];
                     a[j] = a[j + 1];
                     a[j + 1] = temp;
                } else {
                    a[j+1] = a[j];
                    a[j] = null; // Placeholder for the shifted element in this simplified model
                }

                j--;
            }
            yield({ state: [...a], indices: [j + 1, i] }); // Final place step
        }
    }

    // Selection Sort Implementation
    function* selectionSort(arr) {
        let a = [...arr];
        for (let i = 0; i < a.length - 1; i++) {
            let min_idx = i;
            for (let j = i + 1; j < a.length; j++) {
                yield({ state: [...a], indices: [i, j] }); // Highlight current comparison pair
                if (a[j] < a[min_idx]) {
                    min_idx = j;
                }
            }
            if (min_idx !== i) {
                [a[i], a[min_idx]] = [a[min_idx], a[i]];
                yield({ state: [...a], indices: [i, min_idx] }); // Highlight swap
            }
        }
    }

    // Run Animations (Converting generators to array of steps)
    const bubbleSteps = Array.from(bubbleSort(arrGlobal));
    const insertionSteps = Array.from(insertionSort(arrGlobal));
    const selectionSteps = Array.from(selectionSort(arrGlobal));


    animateStep(bubbleSteps, 'bubbleCanvas', arrGlobal);
    setTimeout(() => animateStep(insertionSteps, 'insertionCanvas', arrGlobal), 100);
    setTimeout(() => animateStep(selectionSteps, 'selectionCanvas', arrGlobal), 200);

});
</script>
</body>
</html>
```
qwen3.5:9b35.0 sOKLIM★ 7.5/10
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Live Sort Race</title>
    <style>
        body { font-family: sans-serif; display: flex; justify-content: space-around; margin: 20px; background-color: #f4f4f9;}
        .panel { border: 1px solid #ccc; padding: 10px; text-align: center; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
        canvas { background-color: #fff; display: block; margin: 10px auto; }
    </style>
</head>
<body>
    <div class="panel"><h3 id="title_bubble">Bubble Sort</h3><canvas id="canvas_bria" width="450" height="200"></canvas><p id="status_bubble">Awaiting start...</p></div>
    <div class="panel"><h3 id="title_insert">Insertion Sort</h3><canvas id="canvas_insr" width="450" height="200"></canvas><p id="status_insert">Awaiting start...</p></div>
    <div class="panel"><h3 id="title_select">Selection Sort</h3><canvas id="canvas_selec" width="450" height="200"></canvas><p id="status_select">Awaiting start...</p></div>

    <script>
        const N = 40;
        let A = Array(N).fill(0).map(() => Math.floor(Math.random() * 90) + 10);
        const canvases = { bria: document.getElementById('canvas_bria').getContext('2d'), insr: document.getElementById('canvas_insr').getContext('2d'), selec: document.getElementById('canvas_selec').getContext('2d') };
        let running = true;

        function draw(ctx, array, start = null, end = null, highlight1 = null, highlight2 = null) {
            const w = ctx.canvas.width;
            const h = ctx.canvas.height;
            const barWidth = (w / N) * 0.7;
            let x = 0;
            ctx.clearRect(0, 0, w, h);

            for (let i = 0; i < N; i++) {
                let height = array[i] * (h / 100);
                let color = '#4a90e2';
                if (i === start || i === end) {
                    color = 'rgb(255, 153, 0)'; // Highlighted/Compared element
                } else if ((start !== null && i >= start && i <= end)) {
                    color = '#ff7f2e'; // Range highlight
                }
                ctx.fillStyle = color;
                ctx.fillRect(x, h - height, barWidth * 0.8, height);
                x += Math.floor(barWidth * 0.8 + (w / N * 0.1));
            }
        }

        function sortAlg(arrCopy, type) {
            let state = [];
            const auxArr = [...arrCopy];
            let i = 0;
            let j = 0;
            let k = 0;

            if (type === 'B') {
                // Bubble Sort
                for (i = 0; i < N - 1; i++) {
                    for (j = 0; j < N - 1 - i; j++) {
                        state.push({ arr: [...auxArr], h1: j, h2: j + 1 });
                        if (auxArr[j] > auxArr[j + 1]) {
                            [auxArr[j], auxArr[j + 1]] = [auxArr[j + 1], auxArr[j]];
                            state.push({ arr: [...auxArr], h: j }); // Swapped state
                        }
                    }
                }
            } else if (type === 'I') {
                // Insertion Sort
                for (i = 1; i < N; i++) {
                    let current = auxArr[i];
                    for (j = i - 1; j >= 0 && auxArr[j] > current; j--) {
                        state.push({ arr: [...auxArr], h1: j + 1, h2: j }); // Comparison before shift
                         [auxArr[j+1], auxArr[j]] = [auxArr[j], auxArr[j+1]];
                    }
                }
            } else if (type === 'S') {
                // Selection Sort
                 for (i = 0; i < N - 1; i++) {
                    let minIdx = i;
                    for (j = i + 1; j < N; j++) {
                        state.push({ arr: [...auxArr], h2: j, h1: minIdx }); // Comparison step
                        if (auxArr[j] < auxArr[minIdx]) {
                            minIdx = j;
                        }
                    }
                    if (minIdx !== i) {
                         state.push({ arr: [...auxArr], s: i, t: minIdx }); // Swap state for final placement
                        [auxArr[i], auxArr[minIdx]] = [auxArr[minIdx], auxArr[i]];
                    }
                }
            }

            return state;
        }

        const stepsBria = sortAlg(A, 'B');
        const stepsInsr = sortAlg(A, 'I');
        const stepsSelecA = sortAlg(A, 'S');


        let stepIndexBria = -1, stepIndexInsr = -1, stepIndexSeleca = -1;

        function animateStep() {
            if (!running) return;

            // Bubble Sort Step
            if (stepIndexBria < stepsBria.length - 1) {
                const state = stepsBria[++stepIndexBria];
                draw(canvases.bria, state.arr, state.h1, state.h2);
                document.getElementById('status_bubble').innerText = `Running...`;
            } else if (!isFinishedBubble()) {
                 // Ensure final sorted draw happens even if logic missed the exact last step drawing
                draw(canvases.bria, stepsBria[stepsBria.length - 1].arr);
                document.getElementById('status_bubble').innerText = `DONE!`;
            }

            // Insertion Sort Step
            if (stepIndexInsr < stepsInsr.length - 1) {
                const state = stepsInsr[++stepIndexInsr];
                let start, end;
                if(state.h1 !== undefined && state.h2 !== undefined) { // General compare step
                    start = Math.max(state.h1, state.h2);
                    end = Math.min(state.h1, state.h2); 
                } else if (state.s !== undefined) { // Swap step
                    start = state.s; end = state.t;
                } else { // Default/initial draw
                    start = Math.floor(N * (stepIndexInsr / stepsInsr.length));
                    end = start + 1;
                }
                draw(canvases.insr, state.arr, start === undefined ? null : start, end === undefined ? null : end);
                 document.getElementById('status_insert').innerText = `Running...`;

            } else if (!isFinishedInsertion()) {
                draw(canvases.insr, stepsInsr[stepsInsr.length - 1].arr);
                document.getElementById('status_insert').innerText = `DONE!`;
            }
            
            // Selection Sort Step (Needs special handling due to variable step data)
            if (stepIndexSeleca < stepsSelecA.length - 1) {
                 const state = stepsSelecA[++stepIndexSeleca];
                let start, end;
                 if(state.h1 !== undefined && state.h2 !== undefined) { // Comparison highlight
                    start = Math.min(state.h1, state.h2);
                    end = Math.max(state.h1, state.h2);
                } else if (state.s !== undefined && state.t !== undefined) { // Final Swap
                    start = state.s; end = state.t; 
                } else { 
                    // Use comparison pointers for draw
                    start = Math.min(stepsSelecA[stepIndexSeleca].h1, stepsSelecA[stepIndexSeleca].h2);
                    end = Math.max(stepsSelecA[stepIndexSeleca].h1, stepsSelecA[stepIndexSeleca].h2);
                }

                draw(canvases.selec, state.arr, start, end);
                document.getElementById('status_select').innerText = `Running...`;
            } else if (!isFinishedSelection()) {
                 draw(canvases.selec, stepsSelecA[stepsSelecA.length - 1].arr);
                document.getElementById('status_select').innerText = `DONE!`;
            }


            if (stepIndexBria >= stepsBria.length && stepIndexInsr >= stepsInsr.length && stepIndexSeleca >= stepsSelecA.length) {
                 running = false;
            }

            setTimeout(animateStep, 15); // Animation speed control
        }
        
        function isFinishedBubble() { return stepsBria[stepsBria.length - 1] && Object.keys(stepsBria.length).includes("!"); }
        function isFinishedInsertion() { return stepsInsr[stepsInsr.length - 1] && Object.keys(stepsInsr.length).includes("!"); }
        function isFinishedSelection() { return stepsSelecA[stepsSelecA.length - 1] && Object.keys(stepsSelecA.length).includes("!"); }


        setTimeout(animateStep, 50); // Kick off the race
    </script>
</body>
</html>
```
qwen3:14b36.2 sERRSTATLIM★ 1.5/10
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sort Racer</title>
    <style>
        body { font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f0f0f0; }
        #container { display: flex; gap: 20px; max-width: 90vw; }
        canvas { border: 1px solid #ccc; background: white; }
        h3 { margin-bottom: 5px; text-align: center; font-size: 1.1em; }
    </style>
</head>
<body>

<div id="container">
    <div><h3>Bubble Sort</h3><canvas id="bubbleCanvas" width="600" height="200"></canvas></div>
    <div><h3>Insertion Sort</h3><canvas id="insertionCanvas" width="600" height="200"></canvas></div>
    <div><h3>Selection Sort</h3><canvas id="selectionCanvas" width="600" height="200"></canvas></div>
</div>

<script>
const N = 40;
const CANVAS_W = 600;
const CANVAS_H = 200;
let shuffleArray = (arr) => { for (let i = arr.length - 1; i > 0; i--) { let j = Math.floor(Math.random() * (i + 1)); [arr[i], arr[j]] = [arr[j], arr[i]]; } return arr };
let initialArray = Array.from({ length: N }, (_, i) => Math.floor(Math.random() * 90) + 1);

let state = {
    bubble: { arr: [...initialArray], done: false, steps: 0, maxPass: 0, pointers: [0, 0] },
    insertion: { arr: [...initialArray], done: false, diff: 0, steps: 0, maxPass: 0, pointers: [1, 1] },
    selection: { arr: [...initialArray], done: false, swapIndex: -1, steps: 0 }
};

/** Draws the current state of the array on the specified canvas. */
function draw(id) {
    const ctx = document.getElementById(`${id}Canvas`).getContext('2d');
    ctx.clearRect(0, 0, CANVAS_W, CANVAS_H);
    if (state[id].done) {
        ctx.fillStyle = '#66bb6a';
        ctx.fillRect(0, 0, CANVAS_W, CANVAS_H);
        return;
    }

    const arr = state[id].arr;
    const barWidth = CANVAS_W / N > 5 ? Math.max(1, Math.floor((CANVAS_W - barWidth) / N)) : 1;
    let xOffset = 0;

    for (let i = 0; i < N; i++) {
        const heightRatio = arr[i] / 95;
        const barHeight = Math.floor(CANVAS_H * heightRatio);
        const highlightStep = state[id].steps + (2 * i % 3);

        ctx.fillStyle = '#3f51b5';
        if ((id === 'bubble' && Math.abs((state.bubble.pointers[0] - i) < 2 || state.bubble.pointers[1] - i < 2)) ||
            (id === 'insertion' && Math.abs((state.insertion.pointers[0] - i) < 3 || state.insertion.pointers[1] - i < 3)) ||
            (id === 'selection' && (i === state.selection.swapIndex || i === state.selection.swapIndex + 1))) {
            ctx.fillStyle = '#ff9800'; // Highlight color
        } else if (heightRatio > 0) {
             ctx.fillStyle = '#3f51b5';
        }

        ctx.fillRect(xOffset, CANVAS_H - barHeight, barWidth, barHeight);
        xOffset += barWidth + Math.floor((CANVAS_W / N) * 0.1);
    }
}


/** Simulates/updates Bubble Sort one step */
function bubbleStep() {
    const s = state.bubble;
    if (s.done || s.steps >= N * N / 2) return false;

    let tempArr = [...state.bubble.arr];
    let passes = Math.floor(s.steps / N);
    let comparisons = s.steps % N;
    
    s.steps++;
    
    if (passes + 1 > N - 1) {
        s.done = true;
        return false;
    }

    for (let i = Math.min(N - 1, passes), j = Math.max(0, comparisons); j < Math.min(N - 1, passes + 1); j++) {
         if (tempArr[j] > tempArr[j+1]) {
            [tempArr[j], tempArr[j+1]] = [tempArr[j+1], tempArr[j]];
        }
    }

    state.bubble.arr = [...state.bubble.arr];
    for(let i=0; i<N; i++) state.bubble.arr[i] = tempArr[i];
    return true;
}

/** Simulates/updates Insertion Sort one step */
function insertionStep() {
    const s = state.insertion;
     if (s.done || s.steps > N * 2) return false;

    let arr = [...state.insertion.arr];
    let i = Math.floor(Math.min(N - 1, s.steps % N)) + 1; // Current element index
    let j = Math.max(0, s.steps % (i)); // Comparison start point

    s.steps++;

    if (i >= N) {
        s.done = true;
        return false;
    }

    let key = arr[i];
    for (j++) {
        if (arr[j] > key && j > 0) {
            arr[j] = arr[j - 1];
        } else if (arr[j] <= key) {
             break;
        }
    }
    arr[j] = key;
    state.insertion.arr = [...arr];
    return true;
}

/** Simulates/updates Selection Sort one step */
function selectionStep() {
    const s = state.selection;
    if (s.done) return false;

    let arr = [...state.selection.arr];
    const nPasses = Math.floor(s.steps / 3);
    const currentPass = nPasses % N;

    s.steps++;

    if (currentPass >= N - 1 && s.steps > 1) {
        s.done = true;
        return false;
    }

    let minIdx = currentPass;
    for (let j = currentPass + 1; j < N; j++) {
        if (arr[j] < arr[minIdx]) {
            minIdx = j;
        }
    }
    if (s.steps % 3 === 0 || s.steps % 3 === 2) {
         if (minIdx !== currentPass) {
            [arr[currentPass], arr[minIdx]] = [arr[minIdx], arr[currentPass]];
        }
    }

     state.selection.arr = [...arr];
     return true; // Always returns possible since we are always within bounds of N passes
}


function animate() {
    let allDone = state.bubble.done && state.insertion.done && state.selection.done;

    if (allDone) {
        setTimeout(() => draw('final'), 100); // Ensure final draw happens
        return;
    }
    
    // Advance one step for each algorithm independently
    let bubbleActive = bubbleStep();
    let insertionActive = insertionStep();
    let selectionActive = selectionStep();

    // Redraw all three canvases every tick
    draw('bubble');
    draw('insertion');
    draw('selection');

    requestAnimationFrame(animate);
}

animate();
</script>

</body>
</html>
```
qwen3:8b DNF / pending DNF (infra)
DNF — infrastructure: 10/10 requests returned status 500
llama3.125.5 sERRSTATLIM★ 1.5/10
Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sorting Algorithms</title>
<style>
    canvas {
        border: 1px solid black;
        width: 300px;
        height: 200px;
        display: inline-block;
    }
    label {
        font-size: 24pt;
    }
    span {
        padding-left: 5px;
    }
</style>
</head>
<body>
<canvas id="bCanvas" width="100"></canvas>
<label for="bubbleSort">Bubble Sort:</label> <span id="bsStatus"></span><br>
<canvas id="iCanvas" width="100"></canvas>
<label for="insertionSort">Insertion Sort:</label> <span id="isStatus"></span><br>
<canvas id="sCanvas" width="100"></canvas>
<label for="selectionSort">Selection Sort:</label> <span id="ssStatus"></span>

<script>
    let bubblesortCanvas = document.getElementById("bCanvas");
    let insertionSortCanvas = document.getElementById("iCanvas");
    let selectionSortCanvas = document.getElementById("sCanvas");

function shuffle(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
    }
}

shuffle([3,7,9,2,4,6]);
console.log(shuffle([3,7,9,2,4,6]));

function bubbleSort(arr) {
    let len = arr.length;
    for (let i = 0; i < len - 1; ++i) {
        let swapped = false;
        for(let j=0;j<len-i-1;j++) {

            if(arr[j] > arr[j+1]) {
                [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
                swapped = true;

                let ctx = bubblesortCanvas.getContext("2d");
                ctx.fillStyle = "blue";
                for (let k=0;k<arr.length;k++)
                    ctx.fillRect(k*10, 200-arr[k]*2, 5, -arr[k]*2);

        if (swapped) {
            document.getElementById('bsStatus').innerText="Swap: " + i+j;
        } else break;

const wait= () => { return new Promise(resolve=> setTimeout(() => {resolve()},100))};

const render = async() => {

let swapped=false
let len=bubbleSortCanvas.width/10//arr.length

for (j=0;j<len-1; j++) {
      let ctx=bubblesortCanvas.getContext("2d");
              ctx.fillStyle="blue";
              for (k=0;k<arr.length;k++)
                ctx.fillRect(k*10,200-arr[k]*2,5,-arr[k]*2);

if(swapped){
    document.getElementById('bsStatus').innerText="Done"
}else{
      if(arr[j]>arr[j+1]){
        [arr[j], arr[j+1]] =[arr[j+1], arr[j]];
        swapped=true;

ctx.fillStyle = "orange";
ctx.fillRect(j*10, 200-arr[j]*2, 5,-arr[j]*2);

wait().then(render);
}}}
    }
}

async function renderBubbleSort() {
 document.getElementById('bsStatus').innerText="Sort in progress...";
 const ctx=bubblesortCanvas.getContext("2d");
        ctx.fillStyle="blue";
        for (let k=0;k<array.length;k++)
            ctx.fillRect(k*10,200-array[k]*2,5,-array[k]*2);
for(let i=0;i<array.length-1;++i) {
 let swapped = false;
 for(let j=0;j<parseInt(bubblesortCanvas.width/10)-1;j++) {

let swapCount=bubbleSortArray[i+j]

if(array[j]>array[j+1]){
 array[j], array[j+1]= [array[j + 1], array[j]];
document.getElementById('bsStatus').innerText="Swap: "+(i+j)

ctx.fillStyle = "orange";
ctx.fillRect(swapCount * 10, 200-array[swapCount]*2, 5,-array[swapCount]*2);
ctx.clearRect(j*10+5,0,j*10+20,200);
}
await wait();}
if(!swapped) break;
document.getElementById('bsStatus').innerText="Done";
bubblesortCanvas.width=bubbleSortCanvas.width;

}

async function renderBubbleSort() {
    document.getElementById('bsStatus').innerText="Sort in progress...";
    const ctx=bubblesortCanvas.getContext("2d");
            ctx.fillStyle="blue";
            for (let k=0;k<array.length;k++)
                ctx.fillRect(k*10,200-array[k]*2,5,-array[k]*2);
    for(let i=0;i<array.length-1;++i) {
        let swapped = false;
        for(let j=0;j<parseInt(bubblesortCanvas.width/10)-1;j++) {

            let swapCount=bubbleSortArray[i+j]

            if(array[j]>array[j+1]){
                array[j], array[j+1]= [array[j + 1], array[j]];
                document.getElementById('bsStatus').innerText="Swap: "+(i+j)

                ctx.fillStyle = "orange";
                ctx.fillRect(swapCount * 10, 200-array[swapCount]*2, 5,-array[swapCount]*2);
                ctx.clearRect(j*10+5,0,j*10+20,200);
            }
            await wait()
        }
        if(!swapped) break;
        document.getElementById('bsStatus').innerText="Done";
        bubblesortCanvas.width=bubbleSortCanvas.width;

    }

async function renderBubbleSort() {
    document.getElementById('bsStatus').innerText="Sort in progress...";
const ctx=bubblesortCanvas.getContext("2d");
ctx.fillStyle="blue";
for (let k=0;k<array.length;k++)
  ctx.fillRect(k*10,200-array[k]*2,5,-array[k]*2);
for(let i=0;i<array.length-1;++i) {
 let swapped = false;
 for(let j=0;j<parseInt(bubblesortCanvas.width/10)-1;j++) {

let swapCount=bubbleSortArray[i+j]

if(array[j]>array[j+1]){
   array[j], array[j+1]= [array[j + 1], array[j]];
document.getElementById('bsStatus').innerText="Swap: "+(i+j)

ctx.fillStyle = "orange";
ctx.fillRect(swapCount * 10, 200-array[swapCount]*2, 5,-array[swapCount]*2);
                ctx.clearRect(j*10+5,0,j*10+20,200);
 }
}
if(!swapped) break;
document.getElementById('bsStatus').innerText="Done";
bubblesortCanvas.width=bubbleSortCanvas.width;

}

const wait= async() => {await  new Promise(resolve=>setTimeout(() => {
   resolve()
},100))};

function startBubbleSort() {
    array=[3,7,9,2,4,6];
    console.log([3,7,9,2,4,6]);

render =async () =>{
 let swapped=false
                let len=bubbleSortCanvas.width/10//arr.length

 for (j=0;j<len-1; j++) {
  let ctx=bubblesortCanvas.getContext("2d");
                  ctx.fillStyle="blue";
                  for (k=0;k<array.length;k++)
                    ctx.fillRect(k*10,200-array[k]*2,5,-array[k]*2);

 if(swapped){
    document.getElementById('bsStatus').innerText="Done"
 }else{
      if(array[j]>array[j+1]){
        [array[j], array[j+1]] =[array[j+1], array[j]];
        swapped=true;

ctx.fillStyle = "orange";
 ctx.fillRect(j*10, 200-array[j]*2, 5,-array[j]*2);
ctx.clearRect(swapCount*j/j*j+j,j*k,j*k-j);
}
await wait().then(render);
}}}
document.getElementById('bsStatus').innerText="Sort in progress..";

}

async function insertionSort(arr) {
let len = arr.length;
for (let i = 1; i < len; ++i) {
 let swapped=false
 for(let j=i;j>0;j--) {

   if(arr[j]<arr[j-1]){
     [arr[j], arr[j-1]] =[ arr[j - 1], arr[j]];
      document.getElementById('isStatus').innerText='Swap:'+(j)


let ctx = insertionSortCanvas.getContext("2d");
ctx.fillStyle="blue";
for (k=0;k<arr.length;k++)
  ctx.fillRect(k*10,200-arr[k]*2,5,-arr[k]*2);
  await wait();
   }

if(swapped)break
  document.getElementById('isStatus').innerText='Done!'
await insertionSort(arr)}
}

let ctx=isCanvas.getContext("2d")
  for (k=0;k<array.length;k++)
    ctx.fillRect(k*10,200-array[k]*2,5,-array[k]*2)


}

async function selectionSort(arr) {
let len = arr.length;
for (let i = 0; i < len - 1; ++i) {

 let minPos=i
 for(let j=i+1;j<len;j++) {

   if(arr[j] < arr[minPos]) {
     [arr[i],arr[minPos]] =[ arr[minPos], array[i]];
      document.getElementById('ssStatus').innerText = 'Swap: '+j

let ctx= selectionSortCanvas.getContext("2d");
ctx.fillStyle="blue";
  for (k=0;k<arr.length;k++)
    ctx.fillRect(k*10,200-arr[k]*2,5,-arr[k]*2);
}
const wait1 = () => { return new Promise(resolve=> setTimeout(() => {
resolve()} ,
100))}
await wait1();
if(minPos!=i) break;

document.getElementById('ssStatus').innerText="Done"

ctx.fillStyle = "orange";
 ctx.fillRect((i+1)*10,200-array[i+1]*2,5,-array[i+1]*2);
}

}
}

async function renderSelectionSort() {
    document.getElementById('ssStatus').innerText="Sort in progress..";
 const ctx = selectionSortCanvas.getContext("2d");
   let arr=shuffle([3,2,4,7,9,6]);
          for (let k=0;k<arr.length;k++)
        ctx.fillRect(k*10,200-arr[k]*2,5,-arr[k]*2);

          await selectionSort(arr);
document.getElementById('ssStatus').innerText="Done"
}
</script>
</body>
</html>
```
deepseek-r135.2 sERRBLANK★ 1/10
Show code
```html
<!DOCTYPE html>
<html><head><style>.c{position:absolute}#a{left:0;width:33%;}#b{left:34%;width:32%;}#c{left:67%;width:31%;}.t{l:5px;top:5px;}</style></head>
<body style="margin:0"><canvas id=c size=800 height=400 width=800""></canvas>
<script>let c=document.getElementById('c'),ctx=c.getContext('2d');let w=c.width/3,h=w-6,HW=Math.min(window.innerHeight,100*h)/window.devicePixelRatio;let maxVal=Math.floor(40*1.5+1),arr=[...Array(40)].map(_=>Math.random()*maxVal|0);let scales=[[0,0], [20,80],[92,36]];let swaps=[[],[],[]];let i=0;const start = (a,r,g) => {scales[i]= [Math.max(...arr),H=a.length?H=arr.slice().sort((x,y)=>x-y)[arr.length/2|0]:1];for(let j in a)scales[j].push(a[j]);i++;},anim=[];function bS(i,u){let s=i;while(i<u-1)if(arr[i]>arr[i+1]) [arr[i],arr[i+1]] = [arr[i+1],arr[i]],s=i--.else i++}.function insert(x){x=0;while(x < arr.length - 1 && arr[x] > arr[x + 1]){[arr[x], arr[x + 1]] = [arr[x +1 ,arr[x]]; x--;}}.function sS(l,r){l< r&&(let min=l,i=l;while++i<r)if(arr[i]<arr[min])min=i;if(min != l)[arr[l],arr[min]]=[arr[min], arr[l]]};</script>
<script>let H=arr.length/2|0,c.getContext('2d');c.width=w*3;w=800/(900); let done=false,anim=[];for(let i in [0,1,2]) anim[i]=new Promise((r,e)=>{let a=[...arr];let sort;switch(Number(i)+1){case 1:sort=(...args)=>bS(...args);break; case 2:sort=insert;case3:sort=sS} let panel=i* w;ctx.fillStyle='white'; start(anim[i],0,i*64+192);}).then(r => {ctx.fillStyle='#0f0';ctx.fillRect(panel,lw, H+lw);ctx.fillStyle='black';ctx.font='9px arial';for(let j=0;j<arr.length;j++)start(ctx.fillStyle='black',1, ...)  but in the given HTML file, which needs to stay under 120 lines. Hmm, maybe the problem is that when trying to write the three sorting functions, it's a bit more involved, and wrapping them into an async animation loop might require more code than allowed.

Wait, perhaps I can find a way to structure the animations more concisely by reusing some code or reducing variable declarations.
Alternatively, perhaps using the requestAnimationFrame approach for each sort without Promises would reduce complexity. But then synchronicity could be tricky since all three sorts need to run independently.

Another thought: Since the user is allowing self-contained and no comments, but they're okay with the max 120 lines, maybe I can find a way to implement the animations in a compact way.

But for the sake of time, perhaps the initial code I wrote was over 120 lines, so to make it fit, I'll have to simplify some parts.

Let me recount:

- The HTML part is short (~09 lines).
- The script section has functions and setup. Perhaps combining animation logic into a common loop will help reduce redundancy.

I think that's the key: instead of having separate animation loops for each algorithm, find a way to manage all three within a single animation loop but track their states separately.

This would involve:

- A canvas divided into panels.
- Three arrays or objects tracking each sort's progress.
- In each animation frame, update and draw each panel based on its respective state.

But writing this concisely in 120 lines while maintaining clarity is challenging. I might have to merge some functions or reduce variable names.

Okay, putting it all together, perhaps something like this:

<!DOCTYPE html>
<html><head>
<style>
canvas {position:absolute}
#panels {left:0;width:33%}
...
</style>
</head>
<body><canvas id='c' width='800' height='400'></canvas>
<script>
const c=document.getElementById('c'),ctx=c.getContext('2d');
let w=800/3,h=400,maxVal=1e2;let arr=[...Array(40)].map(_=>Math.random()*maxVal|0);
let scales=[[]., ...], anim=[];for(let i=0;i<3;i++) anim[i]=[];
</script>
</body></html>

Wait—this is an attempt to structure the code in one script section, but I'm still over line limits. It might be tricky, but perhaps combining everything into a single, compact function would work.

Ultimately, it seems that creating a self-contained HTML file with all required logic within 120 lines while providing a clear visualization of three sorting algorithms is challenging but manageable by carefully compressing the code and reusing as much logic as possible.
</think>

```html
<!DOCTYPE html>
<html><head></head><body style="margin:0"><canvas id=c width=800 height=400"></canvas>
<script>let c=document.getElementById('c'),ctx=c.getContext('2d');const W=c.width/3,H=40;let arr=[...Array(40)].map(_=>Math.random()*1e2|0);let scales=[[].,[].,[]];let swaps=[[]];function bS(a,s,r) {for(let i=r; i<s-1; i++) if(arr[i]>arr[i+1]) [arr[i],arr[i+1]]=[arr[i+1],arr[i]], s=i,i--; else i++} function insert(a) {let x=0;while(x<a.length-1&&(a[x]>a[x+1]))[a[x],a[x+1]]=[a[x+1],a[x]],x->-1}function sS(l,r,a){l<r&&(let m=l,i=l; while(i<r)if(a[i]<a[m])m=i,i++; if(m!=l)[a[l],a[m]]=[a[m],a[l]]);return ...}.<script>
</body>
```
mistral-small91.3 sSTAT★ 3.5/10

📝 bars frozen, no labels/DONE, third panel cut off (3.5)

Show code
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sorting Algorithms Visualization</title>
    <style>
        canvas {
            border: 1px solid black;
        }
        .container {
            display: flex;
            justify-content: space-around;
        }
    </style>
</head>
<body>
<div class="container">
<canvas id="bubble" width="400" height="350"></canvas>
<canvas id="insertion" width="400" height="350"></canvas>
<canvas id="selection" width="400" height="350"></canvas>
</div>

<script>
const ctx = [document.getElementById('bubble').getContext('2d'),
             document.getElementById('insertion').getContext('2d'),
             document.getElementById('selection').getContext('2d')];

function drawArray(ctx, arr) {
    ctx.clearRect(0, 0, 400, 350);
    const barWidth = 10;
    for (let i = 0; i < arr.length; i++) {
        let height = arr[i] * 8.75;
        ctx.fillStyle = 'blue';
        ctx.fillRect(i * barWidth + 2, 350 - height, barWidth - 1, height);
    }
}

function bubbleSort(arr) {
    const n = arr.length;
    for (let i = 0; i < n-1; i++) {
        for (let j = 0; j < n-i-1; j++) {
            drawArray(ctx[1], arr.slice());
            let sleep = Date.now();
            while (Date.now() - sleep < 5) { }
            if (arr[j] > arr[j+1]) {
                [arr[j], arr[j+1]] = [arr[j+1], arr[j]];
                drawArray(ctx[0], arr);
            }

        }
    }
    ctx[2].font = "30px Arial";
    ctx[2].fillText('DONE', 150, 340);

}

function insertionSort(arr) {
    for (let i = 1; i < arr.length; i++) {
        const key = arr[i];
        let j = i - 1;
        while (j >= 0 && arr[j] > key) {
            drawArray(ctx[2], arr.slice());
            let sleep = Date.now();
            while (Date.now() - sleep < 5) { }
            arr[j + 1] = arr[j];
            j--;
            drawArray(ctx[1], arr);
        }
        arr[j + 1] = key;
    }
    ctx[2].font = "30px Arial";
    ctx[2].fillText('DONE', 150, 340);

}

function selectionSort(arr) {
    const n = arr.length;
    for (let i = 0; i < n-1; i++) {
        let minIdx = i;
        for (let j = i+1; j < n; j++) {
            if (arr[j] < arr[minIdx]) {
                minIdx = j;
            }
        }
        [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]];
        drawArray(ctx[2], arr.slice());

    }

    ctx[0].font = "30px Arial";
    ctx[0].fillText('DONE', 150, 340);
}

function generateRandomArray() {
    return Array.from({ length: 40 }, () => Math.floor(Math.random() * 26) + 5);
}

const arr = generateRandomArray();
setTimeout(()=>{bubbleSort(arr.slice());},5);
insertionSort((arr.slice()));
selectionSort((arr.slice()))
</script>
</body>
</html>

```
Cloud
GPT-5.5 (codex)20.6 sOK★ 8.5/10
Show code
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Sort Race</title>
<style>
html,body{margin:0;height:100%;background:#111;color:#eee;font-family:system-ui}
body{display:grid;place-items:center}
canvas{width:min(1100px,96vw);height:min(720px,92vh);background:#181818;border:1px solid #333}
</style>
</head>
<body>
<canvas id="c" width="1100" height="720"></canvas>
<script>
const c=document.getElementById("c"),x=c.getContext("2d"),N=40;
let base=Array.from({length:N},(_,i)=>i+1);
for(let i=N-1;i>0;i--){let j=Math.random()*(i+1)|0;[base[i],base[j]]=[base[j],base[i]]}
function bubble(a){let i=0,j=0;return()=>{if(i>=N-1)return 1;if(j<N-i-1){if(a[j]>a[j+1])[a[j],a[j+1]]=[a[j+1],a[j]];j++}else{j=0;i++}return i>=N-1}}
function insertion(a){let i=1,j=1,key=a[1],hold=0;return()=>{if(i>=N)return 1;if(!hold){key=a[i];j=i-1;hold=1}if(j>=0&&a[j]>key){a[j+1]=a[j];j--}else{a[j+1]=key;i++;hold=0}return i>=N}}
function selection(a){let i=0,j=1,m=0;return()=>{if(i>=N-1)return 1;if(j<N){if(a[j]<a[m])m=j;j++}else{[a[i],a[m]]=[a[m],a[i]];i++;m=i;j=i+1}return i>=N-1}}
let sims=[
{name:"BUBBLE SORT",a:base.slice(),step:null,done:0,color:"#49a6ff"},
{name:"INSERTION SORT",a:base.slice(),step:null,done:0,color:"#62d26f"},
{name:"SELECTION SORT",a:base.slice(),step:null,done:0,color:"#ffbd45"}
];
sims[0].step=bubble(sims[0].a);sims[1].step=insertion(sims[1].a);sims[2].step=selection(sims[2].a);
function draw(){
x.clearRect(0,0,c.width,c.height);
sims.forEach((s,p)=>{
let y=p*240,w=c.width,h=240,pad=28,bw=(w-pad*2)/N;
x.fillStyle="#202020";x.fillRect(0,y,w,h-1);
x.fillStyle="#eee";x.font="22px system-ui";x.fillText(s.name,24,y+34);
if(s.done){x.fillStyle="#fff";x.font="30px system-ui";x.fillText("DONE",w-120,y+38)}
for(let i=0;i<N;i++){
let bh=s.a[i]/N*(h-72),bx=pad+i*bw,by=y+h-22-bh;
x.fillStyle=s.color;x.fillRect(bx,by,Math.max(2,bw-2),bh);
}
});
}
function tick(){
for(let k=0;k<3;k++)if(!sims[k].done)for(let n=0;n<2;n++)sims[k].done=sims[k].step();
draw();
if(sims.some(s=>!s.done))requestAnimationFrame(tick);
}
draw();setTimeout(tick,400);
</script>
</body>
</html>
Claude HaikuOK★ 8.5/10
Show code
<!DOCTYPE html>
<html>
<head>
<title>Sorting Race</title>
<style>
body { display: flex; gap: 20px; padding: 20px; background: #222; margin: 0; }
canvas { border: 1px solid #666; background: #111; }
.panel { text-align: center; }
.label { color: #fff; margin-bottom: 10px; font-weight: bold; }
.status { color: #fff; height: 20px; margin-top: 5px; }
.done { color: #0f0; }
</style>
</head>
<body>
<div class="panel"><div class="label">Bubble Sort</div><canvas id="c1" width="250" height="300"></canvas><div id="s1" class="status"></div></div>
<div class="panel"><div class="label">Insertion Sort</div><canvas id="c2" width="250" height="300"></canvas><div id="s2" class="status"></div></div>
<div class="panel"><div class="label">Selection Sort</div><canvas id="c3" width="250" height="300"></canvas><div id="s3" class="status"></div></div>
<script>
const data = Array.from({length: 40}, (_, i) => i + 1).sort(() => Math.random() - 0.5);
function draw(canvas, arr, h) {
  const ctx = canvas.getContext('2d');
  ctx.fillStyle = '#111';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  const w = canvas.width / arr.length;
  const mh = Math.max(...arr);
  for (let i = 0; i < arr.length; i++) {
    ctx.fillStyle = h.includes(i) ? '#f00' : '#0f0';
    const barH = (arr[i] / mh) * (canvas.height - 20);
    ctx.fillRect(i * w, canvas.height - barH, w - 1, barH);
  }
}
function* bubbleSort(arr) {
  const a = [...arr];
  for (let i = 0; i < a.length; i++) {
    for (let j = 0; j < a.length - i - 1; j++) {
      if (a[j] > a[j + 1]) [a[j], a[j + 1]] = [a[j + 1], a[j]];
      yield [a, [j, j + 1]];
    }
  }
  yield [a, []];
}
function* insertionSort(arr) {
  const a = [...arr];
  for (let i = 1; i < a.length; i++) {
    let k = i;
    while (k > 0 && a[k - 1] > a[k]) {
      [a[k - 1], a[k]] = [a[k], a[k - 1]];
      k--;
      yield [a, [k, i]];
    }
  }
  yield [a, []];
}
function* selectionSort(arr) {
  const a = [...arr];
  for (let i = 0; i < a.length; i++) {
    let m = i;
    for (let j = i + 1; j < a.length; j++) {
      if (a[j] < a[m]) m = j;
      yield [a, [i, m]];
    }
    [a[i], a[m]] = [a[m], a[i]];
  }
  yield [a, []];
}
const gen = [bubbleSort(data), insertionSort(data), selectionSort(data)];
const done = [false, false, false];
const canv = [document.getElementById('c1'), document.getElementById('c2'), document.getElementById('c3')];
const status = [document.getElementById('s1'), document.getElementById('s2'), document.getElementById('s3')];
const arrays = [data.slice(), data.slice(), data.slice()];
function frame() {
  for (let i = 0; i < 3; i++) {
    if (!done[i]) {
      const r = gen[i].next();
      if (!r.done) {
        arrays[i] = r.value[0];
        draw(canv[i], arrays[i], r.value[1]);
      } else {
        done[i] = true;
        draw(canv[i], arrays[i], []);
        status[i].textContent = 'DONE';
        status[i].classList.add('done');
      }
    }
  }
  if (!done.every(x => x)) requestAnimationFrame(frame);
}
frame();
</script>
</body>
</html>
Claude SonnetOK★ 8.5/10
Show code
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Sorting Algorithm Race</title>
<style>
  body{background:#111;color:#eee;font-family:sans-serif;text-align:center;margin:0;padding:20px}
  h1{margin:0 0 20px}
  .wrap{display:flex;justify-content:center;gap:20px;flex-wrap:wrap}
  .panel{background:#1b1b1b;border-radius:8px;padding:10px}
  h3{margin:0 0 8px;font-weight:normal;color:#8ab4ff}
  canvas{background:#000;border-radius:4px;display:block}
</style>
</head>
<body>
<h1>Sorting Algorithm Race — Bubble vs Insertion vs Selection</h1>
<div class="wrap">
  <div class="panel"><h3>Bubble Sort</h3><canvas id="c0" width="280" height="220"></canvas></div>
  <div class="panel"><h3>Insertion Sort</h3><canvas id="c1" width="280" height="220"></canvas></div>
  <div class="panel"><h3>Selection Sort</h3><canvas id="c2" width="280" height="220"></canvas></div>
</div>
<script>
const N = 40;

function shuffled() {
  let a = Array.from({length: N}, (_, i) => i + 1);
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

const base = shuffled();
const arrs = [base.slice(), base.slice(), base.slice()];
const highlights = [[], [], []];
const done = [false, false, false];

const canvases = [0, 1, 2].map(i => document.getElementById('c' + i));
const ctxs = canvases.map(c => c.getContext('2d'));

function* bubbleSort(a, hi) {
  for (let i = 0; i < a.length - 1; i++) {
    for (let j = 0; j < a.length - 1 - i; j++) {
      hi[0] = j; hi[1] = j + 1;
      yield;
      if (a[j] > a[j + 1]) { [a[j], a[j + 1]] = [a[j + 1], a[j]]; yield; }
    }
  }
}

function* insertionSort(a, hi) {
  for (let i = 1; i < a.length; i++) {
    let key = a[i], j = i - 1;
    hi[0] = i; hi[1] = -1;
    yield;
    while (j >= 0 && a[j] > key) {
      a[j + 1] = a[j]; hi[1] = j; j--;
      yield;
    }
    a[j + 1] = key;
    yield;
  }
}

function* selectionSort(a, hi) {
  for (let i = 0; i < a.length - 1; i++) {
    let min = i;
    for (let j = i + 1; j < a.length; j++) {
      hi[0] = j; hi[1] = min;
      yield;
      if (a[j] < a[min]) min = j;
    }
    [a[i], a[min]] = [a[min], a[i]];
    yield;
  }
}

const gens = [
  bubbleSort(arrs[0], highlights[0]),
  insertionSort(arrs[1], highlights[1]),
  selectionSort(arrs[2], highlights[2])
];

function draw(i) {
  const ctx = ctxs[i], w = canvases[i].width, h = canvases[i].height, a = arrs[i];
  ctx.clearRect(0, 0, w, h);
  const bw = w / a.length;
  for (let k = 0; k < a.length; k++) {
    const barH = (a[k] / N) * (h - 10);
    ctx.fillStyle = highlights[i].includes(k) ? '#ff5555' : '#4da3ff';
    ctx.fillRect(k * bw, h - barH, bw - 1, barH);
  }
  if (done[i]) {
    ctx.fillStyle = 'rgba(0,0,0,0.65)';
    ctx.fillRect(0, 0, w, h);
    ctx.fillStyle = '#3dff6e';
    ctx.font = 'bold 30px sans-serif';
    ctx.textAlign = 'center';
    ctx.fillText('DONE', w / 2, h / 2 + 10);
  }
}

function step() {
  let allDone = true;
  for (let i = 0; i < 3; i++) {
    if (!done[i]) {
      const r = gens[i].next();
      if (r.done) { done[i] = true; highlights[i] = []; }
    }
    draw(i);
    if (!done[i]) allDone = false;
  }
  if (!allDone) requestAnimationFrame(step);
}

requestAnimationFrame(step);
</script>
</body>
</html>
Claude OpusOK★ 8.5/10
Show code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Sorting Race</title>
<style>
body{background:#0f172a;color:#e2e8f0;font-family:system-ui,sans-serif;margin:0;padding:20px;text-align:center}
h1{font-size:20px;margin:0 0 16px}
.race{display:flex;gap:16px;justify-content:center;flex-wrap:wrap}
.panel{background:#1e293b;border-radius:10px;padding:12px;width:260px}
.panel h2{font-size:14px;margin:0 0 8px}
canvas{background:#0f172a;border-radius:6px;width:100%;height:150px}
.done{color:#34d399;font-weight:bold;height:18px;font-size:13px}
</style>
</head>
<body>
<h1>Sorting Race \u2014 40 values</h1>
<div class="race">
<div class="panel"><h2>Bubble Sort</h2><canvas id="c0" width="240" height="150"></canvas><div class="done" id="d0"></div></div>
<div class="panel"><h2>Insertion Sort</h2><canvas id="c1" width="240" height="150"></canvas><div class="done" id="d1"></div></div>
<div class="panel"><h2>Selection Sort</h2><canvas id="c2" width="240" height="150"></canvas><div class="done" id="d2"></div></div>
</div>
<script>
const N=40, base=[];
for(let i=0;i<N;i++)base.push(Math.random());
function clone(a){return a.slice()}
function draw(id,arr,active){
  const cv=document.getElementById(id),g=cv.getContext('2d'),w=cv.width/N;
  g.clearRect(0,0,cv.width,cv.height);
  for(let i=0;i<N;i++){
    g.fillStyle=active&&active.includes(i)?'#f59e0b':'#38bdf8';
    const h=arr[i]*cv.height;
    g.fillRect(i*w,cv.height-h,w-1,h);
  }
}
function* bubble(a){
  for(let i=0;i<a.length;i++)for(let j=0;j<a.length-1-i;j++){
    if(a[j]>a[j+1]){[a[j],a[j+1]]=[a[j+1],a[j]];}
    yield[j,j+1];
  }
}
function* insertion(a){
  for(let i=1;i<a.length;i++){let k=a[i],j=i-1;
    while(j>=0&&a[j]>k){a[j+1]=a[j];j--;yield[j+1,i];}
    a[j+1]=k;yield[j+1,i];
  }
}
function* selection(a){
  for(let i=0;i<a.length;i++){let m=i;
    for(let j=i+1;j<a.length;j++){if(a[j]<a[m])m=j;yield[i,j,m];}
    [a[i],a[m]]=[a[m],a[i]];yield[i,m];
  }
}
const runners=[
  {c:'c0',d:'d0',a:clone(base),g:null,f:bubble},
  {c:'c1',d:'d1',a:clone(base),g:null,f:insertion},
  {c:'c2',d:'d2',a:clone(base),g:null,f:selection}
];
runners.forEach(r=>r.g=r.f(r.a));
function tick(){
  let running=false;
  for(const r of runners){
    if(r.done){continue;}
    const step=r.g.next();
    if(step.done){r.done=true;draw(r.c,r.a,[]);document.getElementById(r.d).textContent='DONE';}
    else{running=true;draw(r.c,r.a,step.value);}
  }
  if(running)requestAnimationFrame(tick);
}
runners.forEach(r=>draw(r.c,r.a,[]));
requestAnimationFrame(tick);
</script>
</body>
</html>
Claude FableOK★ 8.5/10
Show code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sorting Race</title>
<style>
body{background:#0b1220;color:#e6e9f0;font-family:system-ui;text-align:center}
.row{display:flex;gap:12px;justify-content:center;margin-top:20px}
.panel{background:#121a30;border:1px solid #26304d;border-radius:8px;padding:10px}
h3{margin:4px 0 8px;font-size:14px}
.done{color:#34d399;font-weight:bold;height:18px;font-size:13px}
</style>
</head>
<body>
<h1>Sorting Race: Bubble vs Insertion vs Selection</h1>
<div class="row">
<div class="panel"><h3>Bubble</h3><canvas id="c0" width="240" height="160"></canvas><div class="done" id="d0"></div></div>
<div class="panel"><h3>Insertion</h3><canvas id="c1" width="240" height="160"></canvas><div class="done" id="d1"></div></div>
<div class="panel"><h3>Selection</h3><canvas id="c2" width="240" height="160"></canvas><div class="done" id="d2"></div></div>
</div>
<script>
const N=40, base=Array.from({length:N},()=>Math.random()*150+5);
function* bubble(a){for(let i=0;i<N;i++)for(let j=0;j<N-1-i;j++){if(a[j]>a[j+1]){[a[j],a[j+1]]=[a[j+1],a[j]];}yield;}}
function* insertion(a){for(let i=1;i<N;i++){let k=a[i],j=i-1;while(j>=0&&a[j]>k){a[j+1]=a[j];j--;yield;}a[j+1]=k;yield;}}
function* selection(a){for(let i=0;i<N;i++){let m=i;for(let j=i+1;j<N;j++){if(a[j]<a[m])m=j;yield;}[a[i],a[m]]=[a[m],a[i]];yield;}}
const runs=[bubble,insertion,selection].map((g,i)=>({
  arr:base.slice(), gen:null, ctx:document.getElementById('c'+i).getContext('2d'),
  done:false, el:document.getElementById('d'+i), make:g
}));
runs.forEach(r=>r.gen=r.make(r.arr));
function draw(r){
  r.ctx.clearRect(0,0,240,160);
  r.ctx.fillStyle=r.done?'#34d399':'#7aa2ff';
  const w=240/N;
  r.arr.forEach((v,i)=>r.ctx.fillRect(i*w,160-v,w-1,v));
}
function tick(){
  let running=false;
  runs.forEach(r=>{
    if(!r.done){
      if(r.gen.next().done){r.done=true;r.el.textContent='DONE';}
      running=true;
    }
    draw(r);
  });
  if(running)requestAnimationFrame(tick);
}
tick();
</script>
</body>
</html>