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 };
}