From 8d16936f5d6fe38d40571bcb00c432860aa75f58 Mon Sep 17 00:00:00 2001 From: dschlueter Date: Mon, 6 Apr 2026 19:50:44 +0200 Subject: [PATCH] Refactor: Replace all 'var' with 'let' (JS keyword only) --- sorting_visualization.html | 338 ++++++++++++++++++------------------- 1 file changed, 169 insertions(+), 169 deletions(-) diff --git a/sorting_visualization.html b/sorting_visualization.html index 46e0d1f..eea5373 100644 --- a/sorting_visualization.html +++ b/sorting_visualization.html @@ -197,7 +197,7 @@

- Sortier-Algorithmen v0.2.6 + Sortier-Algorithmen v0.2.7

Interaktive Visualisierung mit schrittweiser Animation

@@ -970,7 +970,7 @@ function buildExplanation(step) { const idx = step.indices; const arr = step.array; function fmtVal(i) { - var v = arr[i]; + let v = arr[i]; return Number.isInteger(v) ? String(v) : v.toFixed(1); } switch (step.type) { @@ -1178,21 +1178,21 @@ function buildSteps(algoName) { let heapSize = n; let heapPhase = 'Heap aufbauen'; function getHeapState(highlight) { - var nodes = []; - for (var hi = 0; hi < heapSize; hi++) { - var depth = Math.floor(Math.log2(hi + 1)); + let nodes = []; + for (let hi = 0; hi < heapSize; hi++) { + let depth = Math.floor(Math.log2(hi + 1)); nodes.push({ val: arr[hi], left: 2 * hi + 1 < heapSize ? 2 * hi + 1 : -1, right: 2 * hi + 2 < heapSize ? 2 * hi + 2 : -1, idx: hi, depth: depth }); } // BFS-Positionen: In-Order ist hier nicht ideal, Level-Order-X-Positionen berechnen - var maxD = nodes.length > 0 ? nodes[nodes.length - 1].depth : 0; - var drawNodes = []; - for (var hi = 0; hi < nodes.length; hi++) { - var nd = nodes[hi], d = nd.depth; + let maxD = nodes.length > 0 ? nodes[nodes.length - 1].depth : 0; + let drawNodes = []; + let totalWidth = Math.pow(2, maxD); + for (let hi = 0; hi < nodes.length; hi++) { + let nd = nodes[hi], d = nd.depth; // Position in der Ebene - var posInLevel = hi - (Math.pow(2, d) - 1); - var levelCount = Math.min(Math.pow(2, d), heapSize - (Math.pow(2, d) - 1)); - var totalWidth = Math.pow(2, maxD); - var x = (posInLevel + 0.5) * (totalWidth / Math.pow(2, d)); + let posInLevel = hi - (Math.pow(2, d) - 1); + let levelCount = Math.min(Math.pow(2, d), heapSize - (Math.pow(2, d) - 1)); + let x = (posInLevel + 0.5) * (totalWidth / Math.pow(2, d)); drawNodes.push({ val: nd.val, left: nd.left, right: nd.right, depth: d, drawX: x, drawY: d }); } return { type: 'heap', nodes: drawNodes, totalWidth: totalWidth, maxDepth: maxD, highlight: highlight || [] }; @@ -1646,8 +1646,8 @@ function buildSteps(algoName) { assignX(drawNodes[idx].right); } assignX(0); - var maxD = 0; - for (var di = 0; di < drawNodes.length; di++) { if (drawNodes[di].depth > maxD) maxD = drawNodes[di].depth; } + let maxD = 0; + for (let di = 0; di < drawNodes.length; di++) { if (drawNodes[di].depth > maxD) maxD = drawNodes[di].depth; } return { type: 'bst', nodes: drawNodes, totalWidth: xCounter, maxDepth: maxD, highlight: highlightPath || [] }; } @@ -1754,12 +1754,12 @@ function buildSteps(algoName) { while (size < n) size <<= 1; // Padding: eindeutige Werte oberhalb des Maximums (alle > origMax → Sortierung korrekt, // aber unterschiedlich → Balken visuell unterscheidbar wenn sie in sichtbare Positionen geraten) - var origMax = 0; + let origMax = 0; for (let i = 0; i < n; i++) { if (arr[i] > origMax) origMax = arr[i]; } const bArr = arr.slice(); - var padLo = origMax * 1.05 + 1; - var padHi = origMax * 1.25 + 1; - var padCount = size - n; + let padLo = origMax * 1.05 + 1; + let padHi = origMax * 1.25 + 1; + let padCount = size - n; for (let i = n; i < size; i++) { bArr.push(padCount > 1 ? padLo + (padHi - padLo) * (i - n) / (padCount - 1) : padLo); } @@ -1768,9 +1768,9 @@ function buildSteps(algoName) { const allStages = []; function collectMergeStages(lo, cnt) { if (cnt <= 1) return; - var half = cnt >> 1; - var stage = []; - for (var i = lo; i < lo + half; i++) { + let half = cnt >> 1; + let stage = []; + for (let i = lo; i < lo + half; i++) { if (i < n && (i + half) < n) stage.push([i, i + half]); } if (stage.length > 0) allStages.push(stage); @@ -1779,7 +1779,7 @@ function buildSteps(algoName) { } function collectSortStages(lo, cnt) { if (cnt <= 1) return; - var half = cnt >> 1; + let half = cnt >> 1; collectSortStages(lo, half); collectSortStages(lo + half, half); collectMergeStages(lo, cnt); @@ -1787,12 +1787,12 @@ function buildSteps(algoName) { collectSortStages(0, size); // Stage-Index: synchron mit bitonicMerge hochgezählt - var snapStageId = 0; + let snapStageId = 0; // Snap-Wrapper: zeigt nur die ersten n Elemente + Netz-Zustand function bSnap(type, indices) { - var visIdx = indices.filter(function(idx) { return idx < n; }); - for (var k = 0; k < n; k++) arr[k] = bArr[k]; + let visIdx = indices.filter(function(idx) { return idx < n; }); + for (let k = 0; k < n; k++) arr[k] = bArr[k]; out.push({ type: type, indices: visIdx, array: arr.slice(), compares: compares, swaps: swaps, moves: moves, @@ -1806,7 +1806,7 @@ function buildSteps(algoName) { bSnap('compare', [i, j]); } if ((bArr[i] > bArr[j]) === dir) { - var tmp = bArr[i]; bArr[i] = bArr[j]; bArr[j] = tmp; + let tmp = bArr[i]; bArr[i] = bArr[j]; bArr[j] = tmp; if (i < n && j < n) { swaps++; bSnap('swap', [i, j]); @@ -1815,9 +1815,9 @@ function buildSteps(algoName) { } function bitonicMerge(lo, cnt, dir) { if (cnt <= 1) return; - var half = cnt >> 1; - var hasVisible = false; - for (var i = lo; i < lo + half; i++) { + let half = cnt >> 1; + let hasVisible = false; + for (let i = lo; i < lo + half; i++) { if (i < n && (i + half) < n) hasVisible = true; bitonicCompareSwap(i, i + half, dir); } @@ -1827,14 +1827,14 @@ function buildSteps(algoName) { } function bitonicSortRec(lo, cnt, dir) { if (cnt <= 1) return; - var half = cnt >> 1; + let half = cnt >> 1; bitonicSortRec(lo, half, true); bitonicSortRec(lo + half, half, false); bitonicMerge(lo, cnt, dir); } bitonicSortRec(0, size, true); // Ergebnis zurückkopieren (nur die ersten n Elemente, Padding verwerfen) - for (var i = 0; i < n; i++) arr[i] = bArr[i]; + for (let i = 0; i < n; i++) arr[i] = bArr[i]; break; } @@ -2061,13 +2061,13 @@ function drawBars(arr, highlights, allSorted, meta, connectedPair) { } if (meta.sortedFrom !== undefined && meta.sortedFrom < n) { ctx.fillStyle = 'rgba(60, 255, 160, 0.06)'; - var sx = PAD_L + meta.sortedFrom * slotW; + let sx = PAD_L + meta.sortedFrom * slotW; ctx.fillRect(sx, PAD_T - 2, (n - meta.sortedFrom) * slotW, areaH + 4); } // Aktiver Bereich (dünne Linie oben) if (meta.activeRange) { - var ax0 = PAD_L + meta.activeRange.lo * slotW + gapW / 2; - var ax1 = PAD_L + meta.activeRange.hi * slotW + gapW / 2 + barW; + let ax0 = PAD_L + meta.activeRange.lo * slotW + gapW / 2; + let ax1 = PAD_L + meta.activeRange.hi * slotW + gapW / 2 + barW; ctx.save(); ctx.strokeStyle = 'rgba(96, 165, 250, 0.5)'; ctx.lineWidth = 2; @@ -2084,12 +2084,12 @@ function drawBars(arr, highlights, allSorted, meta, connectedPair) { } // Partitionsbereiche (subtile Hintergrundfarben) if (meta.partitions) { - var partColors = ['rgba(96,165,250,0.05)', 'rgba(255,154,60,0.05)', 'rgba(185,74,255,0.05)']; - for (var pi = 0; pi < meta.partitions.length; pi++) { - var part = meta.partitions[pi]; + let partColors = ['rgba(96,165,250,0.05)', 'rgba(255,154,60,0.05)', 'rgba(185,74,255,0.05)']; + for (let pi = 0; pi < meta.partitions.length; pi++) { + let part = meta.partitions[pi]; ctx.fillStyle = partColors[pi % partColors.length]; - var px0 = PAD_L + part.lo * slotW; - var px1 = PAD_L + (part.hi + 1) * slotW; + let px0 = PAD_L + part.lo * slotW; + let px1 = PAD_L + (part.hi + 1) * slotW; ctx.fillRect(px0, PAD_T - 2, px1 - px0, areaH + 4); } } @@ -2097,8 +2097,8 @@ function drawBars(arr, highlights, allSorted, meta, connectedPair) { if (meta.runs) { ctx.strokeStyle = 'rgba(255, 255, 255, 0.18)'; ctx.lineWidth = 1; - for (var ri = 0; ri < meta.runs.length; ri++) { - var rx = PAD_L + meta.runs[ri] * slotW + 0.5; + for (let ri = 0; ri < meta.runs.length; ri++) { + let rx = PAD_L + meta.runs[ri] * slotW + 0.5; ctx.beginPath(); ctx.moveTo(rx, PAD_T - 2); ctx.lineTo(rx, H - PAD_B); @@ -2182,12 +2182,12 @@ function drawBars(arr, highlights, allSorted, meta, connectedPair) { if (meta.pivots) { ctx.strokeStyle = '#ffffff'; ctx.lineWidth = 2; - for (var pvi = 0; pvi < meta.pivots.length; pvi++) { - var pvIdx = meta.pivots[pvi]; + for (let pvi = 0; pvi < meta.pivots.length; pvi++) { + let pvIdx = meta.pivots[pvi]; if (pvIdx >= 0 && pvIdx < n) { - var pvBarH = Math.max(2, (arr[pvIdx] / maxVal) * areaH); - var pvX = PAD_L + pvIdx * slotW + gapW / 2; - var pvY = H - PAD_B - pvBarH; + let pvBarH = Math.max(2, (arr[pvIdx] / maxVal) * areaH); + let pvX = PAD_L + pvIdx * slotW + gapW / 2; + let pvY = H - PAD_B - pvBarH; ctx.strokeRect(pvX - 1, pvY - 1, barW + 2, pvBarH + 2); } } @@ -2251,8 +2251,8 @@ function drawBars(arr, highlights, allSorted, meta, connectedPair) { function drawMemory(state) { if (!state) return; - var dpr = window.devicePixelRatio || 1; - var W = memCanvas.width / dpr, H = memCanvas.height / dpr; + let dpr = window.devicePixelRatio || 1; + let W = memCanvas.width / dpr, H = memCanvas.height / dpr; memCtx.clearRect(0, 0, W, H); if (state.type === 'bst') drawBST(state, W, H); else if (state.type === 'heap') drawHeap(state, W, H); @@ -2264,33 +2264,33 @@ function drawMemory(state) { } function drawBST(state, W, H) { - var nodes = state.nodes, totalWidth = state.totalWidth, maxDepth = state.maxDepth, highlight = state.highlight; + let nodes = state.nodes, totalWidth = state.totalWidth, maxDepth = state.maxDepth, highlight = state.highlight; if (!nodes || nodes.length === 0) return; - var PAD = 40, aW = W - PAD * 2, aH = H - PAD * 2; - var stepX = totalWidth > 1 ? aW / (totalWidth - 1) : 0; - var stepY = maxDepth > 0 ? aH / maxDepth : 0; + let PAD = 40, aW = W - PAD * 2, aH = H - PAD * 2; + let stepX = totalWidth > 1 ? aW / (totalWidth - 1) : 0; + let stepY = maxDepth > 0 ? aH / maxDepth : 0; // Knoten-Radius skaliert mit Anzahl - var R = Math.max(6, Math.min(20, stepX * 0.4)); + let R = Math.max(6, Math.min(20, stepX * 0.4)); // Kanten zeichnen memCtx.strokeStyle = '#3a3f55'; memCtx.lineWidth = 2; - for (var i = 0; i < nodes.length; i++) { - var p = nodes[i], px = PAD + p.drawX * stepX, py = PAD + p.drawY * stepY; - var children = [p.left, p.right]; - for (var ci = 0; ci < children.length; ci++) { - var cIdx = children[ci]; + for (let i = 0; i < nodes.length; i++) { + let p = nodes[i], px = PAD + p.drawX * stepX, py = PAD + p.drawY * stepY; + let children = [p.left, p.right]; + for (let ci = 0; ci < children.length; ci++) { + let cIdx = children[ci]; if (cIdx !== -1 && nodes[cIdx]) { - var c = nodes[cIdx], cx = PAD + c.drawX * stepX, cy = PAD + c.drawY * stepY; + let c = nodes[cIdx], cx = PAD + c.drawX * stepX, cy = PAD + c.drawY * stepY; memCtx.beginPath(); memCtx.moveTo(px, py); memCtx.lineTo(cx, cy); memCtx.stroke(); } } } // Knoten zeichnen - for (var i = 0; i < nodes.length; i++) { - var n = nodes[i], x = PAD + n.drawX * stepX, y = PAD + n.drawY * stepY; - var isH = highlight.indexOf(i) !== -1; - var color = isH ? COLORS.compare : COLORS.normal; + for (let i = 0; i < nodes.length; i++) { + let n = nodes[i], x = PAD + n.drawX * stepX, y = PAD + n.drawY * stepY; + let isH = highlight.indexOf(i) !== -1; + let color = isH ? COLORS.compare : COLORS.normal; if (isH) { memCtx.save(); memCtx.shadowColor = color; memCtx.shadowBlur = 15; memCtx.fillStyle = color; memCtx.beginPath(); memCtx.arc(x, y, R, 0, Math.PI * 2); memCtx.fill(); @@ -2305,30 +2305,30 @@ function drawBST(state, W, H) { } function drawMergeArrays(state, W, H) { - var left = state.left, right = state.right, lPtr = state.lPtr, rPtr = state.rPtr; - var totalLen = left.length + right.length; + let left = state.left, right = state.right, lPtr = state.lPtr, rPtr = state.rPtr; + let totalLen = left.length + right.length; if (totalLen === 0) return; // Sicheres Maximum ohne Spread (Stack-Overflow-Schutz bei großen Arrays) - var maxV = 1; - for (var mi = 0; mi < left.length; mi++) { if (left[mi] > maxV) maxV = left[mi]; } - for (var mi = 0; mi < right.length; mi++) { if (right[mi] > maxV) maxV = right[mi]; } + let maxV = 1; + for (let mi = 0; mi < left.length; mi++) { if (left[mi] > maxV) maxV = left[mi]; } + for (let mi = 0; mi < right.length; mi++) { if (right[mi] > maxV) maxV = right[mi]; } - var PAD = 20, GAP = 20; - var isNarrow = W < 400; + let PAD = 20, GAP = 20; + let isNarrow = W < 400; if (isNarrow) { // Mobile: Arrays untereinander - var sW = (W - PAD * 2) / Math.max(left.length, right.length); - var bW = sW * 0.7, gap = sW * 0.3; - var halfH = (H - 40) / 2, aH = halfH * 0.55, baseY1 = halfH - 5, baseY2 = H - 10; + let sW = (W - PAD * 2) / Math.max(left.length, right.length); + let bW = sW * 0.7, gap = sW * 0.3; + let halfH = (H - 40) / 2, aH = halfH * 0.55, baseY1 = halfH - 5, baseY2 = H - 10; // Links memCtx.fillStyle = '#8b949e'; memCtx.font = '600 11px Inter, sans-serif'; memCtx.textAlign = 'left'; memCtx.fillText('Links (Index ' + state.l + '\u2013' + state.m + ')', PAD, 13); - for (var i = 0; i < left.length; i++) { - var x = PAD + i * sW + gap / 2, bH = Math.max(2, (left[i] / maxV) * aH), y = baseY1 - bH; - var isH = (i === lPtr), color = isH ? COLORS.compare : '#3a7cff'; + for (let i = 0; i < left.length; i++) { + let x = PAD + i * sW + gap / 2, bH = Math.max(2, (left[i] / maxV) * aH), y = baseY1 - bH; + let isH = (i === lPtr), color = isH ? COLORS.compare : '#3a7cff'; if (isH) { memCtx.save(); memCtx.shadowColor = color; memCtx.shadowBlur = 12; memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); memCtx.restore(); } memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); if (bW > 12) { memCtx.fillStyle = '#fff'; memCtx.font = '600 ' + Math.min(10, bW * 0.6) + 'px monospace'; memCtx.textAlign = 'center'; memCtx.fillText(String(left[i]), x + bW / 2, y - 4); } @@ -2337,37 +2337,37 @@ function drawMergeArrays(state, W, H) { // Rechts memCtx.fillStyle = '#8b949e'; memCtx.font = '600 11px Inter, sans-serif'; memCtx.textAlign = 'left'; memCtx.fillText('Rechts (Index ' + (state.m + 1) + '\u2013' + state.r + ')', PAD, halfH + 13); - for (var i = 0; i < right.length; i++) { - var x = PAD + i * sW + gap / 2, bH = Math.max(2, (right[i] / maxV) * aH), y = baseY2 - bH; - var isH = (i === rPtr), color = isH ? COLORS.compare : '#b94aff'; + for (let i = 0; i < right.length; i++) { + let x = PAD + i * sW + gap / 2, bH = Math.max(2, (right[i] / maxV) * aH), y = baseY2 - bH; + let isH = (i === rPtr), color = isH ? COLORS.compare : '#b94aff'; if (isH) { memCtx.save(); memCtx.shadowColor = color; memCtx.shadowBlur = 12; memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); memCtx.restore(); } memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); if (bW > 12) { memCtx.fillStyle = '#fff'; memCtx.font = '600 ' + Math.min(10, bW * 0.6) + 'px monospace'; memCtx.textAlign = 'center'; memCtx.fillText(String(right[i]), x + bW / 2, y - 4); } } } else { // Desktop: Arrays nebeneinander - var totalW = W - PAD * 2 - GAP; - var sW = totalW / totalLen, bW = sW * 0.7, gap = sW * 0.3; - var aH = H * 0.6, baseY = H - 20; + let totalW = W - PAD * 2 - GAP; + let sW = totalW / totalLen, bW = sW * 0.7, gap = sW * 0.3; + let aH = H * 0.6, baseY = H - 20; // Links memCtx.fillStyle = '#8b949e'; memCtx.font = '600 11px Inter, sans-serif'; memCtx.textAlign = 'left'; memCtx.fillText('Links (Index ' + state.l + '\u2013' + state.m + ')', PAD, 15); - for (var i = 0; i < left.length; i++) { - var x = PAD + i * sW + gap / 2, bH = Math.max(2, (left[i] / maxV) * aH), y = baseY - bH; - var isH = (i === lPtr), color = isH ? COLORS.compare : '#3a7cff'; + for (let i = 0; i < left.length; i++) { + let x = PAD + i * sW + gap / 2, bH = Math.max(2, (left[i] / maxV) * aH), y = baseY - bH; + let isH = (i === lPtr), color = isH ? COLORS.compare : '#3a7cff'; if (isH) { memCtx.save(); memCtx.shadowColor = color; memCtx.shadowBlur = 12; memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); memCtx.restore(); } memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); if (bW > 12) { memCtx.fillStyle = '#fff'; memCtx.font = '600 ' + Math.min(10, bW * 0.6) + 'px monospace'; memCtx.textAlign = 'center'; memCtx.fillText(String(left[i]), x + bW / 2, y - 4); } } // Rechts - var rightStartX = PAD + left.length * sW + GAP; + let rightStartX = PAD + left.length * sW + GAP; memCtx.fillStyle = '#8b949e'; memCtx.font = '600 11px Inter, sans-serif'; memCtx.textAlign = 'left'; memCtx.fillText('Rechts (Index ' + (state.m + 1) + '\u2013' + state.r + ')', rightStartX, 15); - for (var i = 0; i < right.length; i++) { - var x = rightStartX + i * sW + gap / 2, bH = Math.max(2, (right[i] / maxV) * aH), y = baseY - bH; - var isH = (i === rPtr), color = isH ? COLORS.compare : '#b94aff'; + for (let i = 0; i < right.length; i++) { + let x = rightStartX + i * sW + gap / 2, bH = Math.max(2, (right[i] / maxV) * aH), y = baseY - bH; + let isH = (i === rPtr), color = isH ? COLORS.compare : '#b94aff'; if (isH) { memCtx.save(); memCtx.shadowColor = color; memCtx.shadowBlur = 12; memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); memCtx.restore(); } memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); if (bW > 12) { memCtx.fillStyle = '#fff'; memCtx.font = '600 ' + Math.min(10, bW * 0.6) + 'px monospace'; memCtx.textAlign = 'center'; memCtx.fillText(String(right[i]), x + bW / 2, y - 4); } @@ -2376,31 +2376,31 @@ function drawMergeArrays(state, W, H) { } function drawHeap(state, W, H) { - var nodes = state.nodes, totalWidth = state.totalWidth, maxDepth = state.maxDepth, highlight = state.highlight; + let nodes = state.nodes, totalWidth = state.totalWidth, maxDepth = state.maxDepth, highlight = state.highlight; if (!nodes || nodes.length === 0) return; - var PAD = 30, aW = W - PAD * 2, aH = H - PAD * 2; - var stepY = maxDepth > 0 ? aH / maxDepth : 0; - var R = Math.max(6, Math.min(18, aW / (nodes.length + 1) * 0.35)); + let PAD = 30, aW = W - PAD * 2, aH = H - PAD * 2; + let stepY = maxDepth > 0 ? aH / maxDepth : 0; + let R = Math.max(6, Math.min(18, aW / (nodes.length + 1) * 0.35)); // Kanten memCtx.strokeStyle = '#3a3f55'; memCtx.lineWidth = 1.5; - for (var i = 0; i < nodes.length; i++) { - var nd = nodes[i], px = PAD + (nd.drawX / totalWidth) * aW, py = PAD + nd.drawY * stepY; - var children = [nd.left, nd.right]; - for (var ci = 0; ci < children.length; ci++) { - var cIdx = children[ci]; + for (let i = 0; i < nodes.length; i++) { + let nd = nodes[i], px = PAD + (nd.drawX / totalWidth) * aW, py = PAD + nd.drawY * stepY; + let children = [nd.left, nd.right]; + for (let ci = 0; ci < children.length; ci++) { + let cIdx = children[ci]; if (cIdx !== -1 && nodes[cIdx]) { - var c = nodes[cIdx], cx = PAD + (c.drawX / totalWidth) * aW, cy = PAD + c.drawY * stepY; + let c = nodes[cIdx], cx = PAD + (c.drawX / totalWidth) * aW, cy = PAD + c.drawY * stepY; memCtx.beginPath(); memCtx.moveTo(px, py); memCtx.lineTo(cx, cy); memCtx.stroke(); } } } // Knoten - for (var i = 0; i < nodes.length; i++) { - var n = nodes[i], x = PAD + (n.drawX / totalWidth) * aW, y = PAD + n.drawY * stepY; - var isH = highlight.indexOf(i) !== -1; - var color = isH ? COLORS.compare : COLORS.normal; + for (let i = 0; i < nodes.length; i++) { + let n = nodes[i], x = PAD + (n.drawX / totalWidth) * aW, y = PAD + n.drawY * stepY; + let isH = highlight.indexOf(i) !== -1; + let color = isH ? COLORS.compare : COLORS.normal; if (isH) { memCtx.save(); memCtx.shadowColor = color; memCtx.shadowBlur = 12; memCtx.fillStyle = color; memCtx.beginPath(); memCtx.arc(x, y, R, 0, Math.PI * 2); memCtx.fill(); @@ -2415,23 +2415,23 @@ function drawHeap(state, W, H) { } function drawCountingArray(state, W, H) { - var count = state.count, minVal = state.minVal, hl = state.highlight; - var n = count.length; + let count = state.count, minVal = state.minVal, hl = state.highlight; + let n = count.length; if (n === 0) return; - var maxC = 1; - for (var i = 0; i < n; i++) { if (count[i] > maxC) maxC = count[i]; } - var PAD = 20, aW = W - PAD * 2, aH = H * 0.55, baseY = H - 20; - var sW = aW / n, bW = Math.max(1, sW * 0.7), gap = sW * 0.15; + let maxC = 1; + for (let i = 0; i < n; i++) { if (count[i] > maxC) maxC = count[i]; } + let PAD = 20, aW = W - PAD * 2, aH = H * 0.55, baseY = H - 20; + let sW = aW / n, bW = Math.max(1, sW * 0.7), gap = sW * 0.15; memCtx.fillStyle = '#8b949e'; memCtx.font = '600 11px Inter, sans-serif'; memCtx.textAlign = 'left'; memCtx.fillText('H\u00e4ufigkeiten (Wert ' + minVal + '\u2013' + (minVal + n - 1) + ')', PAD, 14); - for (var i = 0; i < n; i++) { - var x = PAD + i * sW + gap; - var bH = count[i] > 0 ? Math.max(2, (count[i] / maxC) * aH) : 0; - var y = baseY - bH; - var isH = (i === hl); - var color = isH ? COLORS.move : '#3cffa0'; + for (let i = 0; i < n; i++) { + let x = PAD + i * sW + gap; + let bH = count[i] > 0 ? Math.max(2, (count[i] / maxC) * aH) : 0; + let y = baseY - bH; + let isH = (i === hl); + let color = isH ? COLORS.move : '#3cffa0'; if (bH > 0) { if (isH) { memCtx.save(); memCtx.shadowColor = color; memCtx.shadowBlur = 12; memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); memCtx.restore(); } memCtx.fillStyle = color; memCtx.fillRect(x, y, bW, bH); @@ -2450,29 +2450,29 @@ function drawCountingArray(state, W, H) { } function drawRadixBuckets(state, W, H) { - var buckets = state.buckets, digitPos = state.digitPos, hl = state.highlight; - var PAD = 20, GAP = 6; - var totalSlots = 10; - var slotW = (W - PAD * 2 - GAP * 9) / totalSlots; - var maxLen = 1; - for (var d = 0; d < 10; d++) { if (buckets[d].length > maxLen) maxLen = buckets[d].length; } - var baseY = H - 20; - var itemH = Math.min(16, (H - 50) / maxLen); + let buckets = state.buckets, digitPos = state.digitPos, hl = state.highlight; + let PAD = 20, GAP = 6; + let totalSlots = 10; + let slotW = (W - PAD * 2 - GAP * 9) / totalSlots; + let maxLen = 1; + for (let d = 0; d < 10; d++) { if (buckets[d].length > maxLen) maxLen = buckets[d].length; } + let baseY = H - 20; + let itemH = Math.min(16, (H - 50) / maxLen); memCtx.fillStyle = '#8b949e'; memCtx.font = '600 11px Inter, sans-serif'; memCtx.textAlign = 'left'; memCtx.fillText('Radix-Buckets (Stelle ' + digitPos + ')', PAD, 14); - for (var d = 0; d < 10; d++) { - var bx = PAD + d * (slotW + GAP); - var isH = (d === hl); + for (let d = 0; d < 10; d++) { + let bx = PAD + d * (slotW + GAP); + let isH = (d === hl); // Bucket-Label memCtx.fillStyle = isH ? COLORS.move : '#8b949e'; memCtx.font = '700 11px monospace'; memCtx.textAlign = 'center'; memCtx.fillText(String(d), bx + slotW / 2, baseY + 14); // Elemente als gestapelte Blöcke - for (var ei = 0; ei < buckets[d].length; ei++) { - var y = baseY - (ei + 1) * itemH; - var color = isH ? COLORS.move : COLORS.normal; + for (let ei = 0; ei < buckets[d].length; ei++) { + let y = baseY - (ei + 1) * itemH; + let color = isH ? COLORS.move : COLORS.normal; memCtx.fillStyle = color; memCtx.globalAlpha = 0.85; memCtx.fillRect(bx + 1, y + 1, slotW - 2, itemH - 2); memCtx.globalAlpha = 1; @@ -2486,35 +2486,35 @@ function drawRadixBuckets(state, W, H) { } function drawBuckets(state, W, H) { - var buckets = state.buckets, hl = state.highlight; - var k = buckets.length; + let buckets = state.buckets, hl = state.highlight; + let k = buckets.length; if (k === 0) return; - var PAD = 20, GAP = 4; - var slotW = (W - PAD * 2 - GAP * (k - 1)) / k; - var maxLen = 1, maxV = 1; - for (var b = 0; b < k; b++) { + let PAD = 20, GAP = 4; + let slotW = (W - PAD * 2 - GAP * (k - 1)) / k; + let maxLen = 1, maxV = 1; + for (let b = 0; b < k; b++) { if (buckets[b].length > maxLen) maxLen = buckets[b].length; - for (var j = 0; j < buckets[b].length; j++) { if (buckets[b][j] > maxV) maxV = buckets[b][j]; } + for (let j = 0; j < buckets[b].length; j++) { if (buckets[b][j] > maxV) maxV = buckets[b][j]; } } - var baseY = H - 20; - var aH = H * 0.55; + let baseY = H - 20; + let aH = H * 0.55; memCtx.fillStyle = '#8b949e'; memCtx.font = '600 11px Inter, sans-serif'; memCtx.textAlign = 'left'; memCtx.fillText('Buckets (' + k + ' St\u00fcck)', PAD, 14); - for (var b = 0; b < k; b++) { - var bx = PAD + b * (slotW + GAP); - var isH = (b === hl); + for (let b = 0; b < k; b++) { + let bx = PAD + b * (slotW + GAP); + let isH = (b === hl); // Bucket-Rahmen memCtx.strokeStyle = isH ? COLORS.move : '#3a3f55'; memCtx.lineWidth = 1; memCtx.strokeRect(bx, 24, slotW, baseY - 24); // Elemente als Balken von unten - var itemW = Math.max(1, (slotW - 4) / Math.max(1, buckets[b].length)); - for (var j = 0; j < buckets[b].length; j++) { - var bH = Math.max(2, (buckets[b][j] / maxV) * aH); - var x = bx + 2 + j * itemW; - var y = baseY - bH; - var color = isH ? COLORS.move : COLORS.normal; + let itemW = Math.max(1, (slotW - 4) / Math.max(1, buckets[b].length)); + for (let j = 0; j < buckets[b].length; j++) { + let bH = Math.max(2, (buckets[b][j] / maxV) * aH); + let x = bx + 2 + j * itemW; + let y = baseY - bH; + let color = isH ? COLORS.move : COLORS.normal; memCtx.fillStyle = color; memCtx.fillRect(x, y, Math.max(1, itemW - 1), bH); } // Bucket-Nummer @@ -2527,17 +2527,17 @@ function drawBuckets(state, W, H) { } function drawBitonicNetwork(state, W, H) { - var stages = state.stages, cur = state.currentStage, n = state.n; - var numS = stages.length; + let stages = state.stages, cur = state.currentStage, n = state.n; + let numS = stages.length; if (numS === 0 || n < 2) return; - var PAD_L = 24, PAD_R = 8, PAD_T = 10, PAD_B = 10; - var wireSpacing = (H - PAD_T - PAD_B) / Math.max(n - 1, 1); - var stageW = (W - PAD_L - PAD_R) / numS; + let PAD_L = 24, PAD_R = 8, PAD_T = 10, PAD_B = 10; + let wireSpacing = (H - PAD_T - PAD_B) / Math.max(n - 1, 1); + let stageW = (W - PAD_L - PAD_R) / numS; // Horizontale Drähte - for (var w = 0; w < n; w++) { - var wy = PAD_T + w * wireSpacing; + for (let w = 0; w < n; w++) { + let wy = PAD_T + w * wireSpacing; memCtx.strokeStyle = 'rgba(100,120,160,0.3)'; memCtx.lineWidth = 1; memCtx.beginPath(); @@ -2551,24 +2551,24 @@ function drawBitonicNetwork(state, W, H) { memCtx.font = '500 9px Inter, sans-serif'; memCtx.textAlign = 'right'; memCtx.textBaseline = 'middle'; - for (var w = 0; w < n; w++) { + for (let w = 0; w < n; w++) { memCtx.fillText(String(w), PAD_L - 4, PAD_T + w * wireSpacing); } // Komparatoren - for (var s = 0; s < numS; s++) { - var cx = PAD_L + (s + 0.5) * stageW; - var isCur = (s === cur); - var isPast = (s < cur); - var color = isCur ? COLORS.compare + for (let s = 0; s < numS; s++) { + let cx = PAD_L + (s + 0.5) * stageW; + let isCur = (s === cur); + let isPast = (s < cur); + let color = isCur ? COLORS.compare : isPast ? 'rgba(60,160,255,0.35)' : 'rgba(150,170,200,0.15)'; - var lw = isCur ? 2 : 1; - var R = isCur ? 3 : 2; + let lw = isCur ? 2 : 1; + let R = isCur ? 3 : 2; - for (var ci = 0; ci < stages[s].length; ci++) { - var a = stages[s][ci][0], b = stages[s][ci][1]; - var y1 = PAD_T + a * wireSpacing, y2 = PAD_T + b * wireSpacing; + for (let ci = 0; ci < stages[s].length; ci++) { + let a = stages[s][ci][0], b = stages[s][ci][1]; + let y1 = PAD_T + a * wireSpacing, y2 = PAD_T + b * wireSpacing; if (isCur) { memCtx.save(); memCtx.shadowColor = COLORS.compare; @@ -2635,11 +2635,11 @@ function updateMemView(memState) { // ================================================================ function renderStep(step, stepNum) { - var hi = {}; + let hi = {}; step.indices.forEach(function(i) { hi[i] = step.type; }); - var allSorted = step.type === 'done'; + let allSorted = step.type === 'done'; // Build connected pair for connection lines - var connectedPair = null; + let connectedPair = null; if (!allSorted && step.indices.length >= 2 && (step.type === 'compare' || step.type === 'swap')) { connectedPair = { indices: [step.indices[0], step.indices[1]], type: step.type }; }