Refactor: Replace all 'var' with 'let' (JS keyword only)
This commit is contained in:
parent
113b8ff758
commit
8d16936f5d
1 changed files with 169 additions and 169 deletions
|
|
@ -197,7 +197,7 @@
|
|||
<div class="flex-1"></div>
|
||||
<div class="text-center">
|
||||
<h1 class="title-text font-bold tracking-tight" style="color: var(--c-text); text-shadow: 0 0 40px rgba(74,124,255,0.3);">
|
||||
Sortier-Algorithmen <span style="font-size: 0.45em; font-weight: 400; opacity: 0.5; vertical-align: middle;">v0.2.6</span>
|
||||
Sortier-Algorithmen <span style="font-size: 0.45em; font-weight: 400; opacity: 0.5; vertical-align: middle;">v0.2.7</span>
|
||||
</h1>
|
||||
<p class="text-muted text-sm mt-0.5">Interaktive Visualisierung mit schrittweiser Animation</p>
|
||||
</div>
|
||||
|
|
@ -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 };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue