diff --git a/js/mergesort.js b/js/mergesort.js index 0178faa..952b140 100644 --- a/js/mergesort.js +++ b/js/mergesort.js @@ -2,8 +2,86 @@ * */ var MergeSort = function(VisualizerInstance) { + //===== Inits. this.V = VisualizerInstance; this.comparisons = 0; + + //===== Action management. + // + this.initSort = function(arr, start, end) { + this.V + .instruct(this.V.unhighlight, 0) + .instruct(this.V.unfade, 0) + .instruct(this.V.fade, 0, -1, start - 1) + .instruct(this.V.fade, 0, end + 1, arr.length) + .instruct(this.V.message, 0, 1, `Comparisons: ${this.comparisons}`) + .instruct(this.V.message, 0, 2, '') + .instruct(this.V.message, 0, 3, '') + .instruct(this.V.message, 0, 4, '') + .instruct(this.V.message, 0, 5, ''); + }; + + // + this.splitSingle = function(index) { + this.V.instruct(this.V.message, 100, 2, `Single element [${index}]`); + }; + + // + this.preSort = function(start, mid, end) { + this.V + .instruct(this.V.message, 0, 2, `Sorting [${start}] - [${end}]`) + .instruct(this.V.message, 0, 3, 'Slicing and recursing:') + .instruct(this.V.message, 100, 4, `[${start}]-[${mid}] and [${mid + 1}]-[${end}]`); + }; + + // + this.preMerge = function(arr1, arr2, start, mid, end) { + var i, j, x, y, v; + var len1 = arr1.length; + var len2 = arr2.length; + + for (var i = 0; i < len1; i++) { + x = Visualizer.padding + (i + start) * (Visualizer.itemW + Visualizer.spacerW); + y = Visualizer.padding * 2 + Visualizer.itemH; + v = arr1[i].value; + this.V.instruct(this.V.item, 0, 'secondary', x, y, v, '#05350D') + } + + for (var j = 0; j < len2; j++) { + x = Visualizer.padding + (j + len1 + start) * (Visualizer.itemW + Visualizer.spacerW); + y = Visualizer.padding * 2 + Visualizer.itemH; + v = arr2[j].value; + this.V.instruct(this.V.item, 0, 'secondary', x, y, v, '#028E2D') + } + + this.V + // .instruct(this.V.fade, 0, 0, arr.length) + .instruct(this.V.message, 0, 2, ``) + .instruct(this.V.message, 0, 3, 'Merging slices:') + .instruct(this.V.message, 0, 4, `[${start}]-[${mid}] and [${mid + 1}]-[${end}]`) + .instruct(this.V.removeTertiary, 0); + }; + + // + this.postMerge = function() { + this.V.instruct(this.V.removeSecondary, 0); + }; + + // + this.midMerge = function(index, value, message) { + var x = Visualizer.padding + index * (Visualizer.itemW + Visualizer.spacerW); + var y = Visualizer.padding * 3 + Visualizer.itemH * 2 + + this.V + .instruct(this.V.item, 0, 'tertiary', x, y, value, '#8E5500') + .instruct(this.V.message, 0, 4, message) + .instruct(this.V.message, 100, 5, `Pushing ${value} to sub-result.`); + }; + + // + this.updateComparisons = function() { + this.V.instruct(this.V.message, 0, 1, `Comparisons: ${this.comparisons}`); + }; }; MergeSort.prototype = Object.create(Sorter.prototype); @@ -12,64 +90,28 @@ MergeSort.prototype = Object.create(Sorter.prototype); * */ MergeSort.prototype.sort = function(arr, start, end) { - this.V - .instruct(this.V.unhighlight, 0) - .instruct(this.V.unfade, 0) - .instruct(this.V.fade, 0, -1, start - 1) - .instruct(this.V.fade, 0, end + 1, arr.length) - .instruct(this.V.message, 0, 1, `Comparisons: ${this.comparisons}`) - .instruct(this.V.message, 0, 2, '') - .instruct(this.V.message, 0, 3, '') - .instruct(this.V.message, 0, 4, '') - .instruct(this.V.message, 0, 5, ''); + this.initSort(arr, start, end); if (arr.length === 0) { return arr; } if (start === end) { - this.V - .instruct(this.V.message, 100, 2, `Single element [${start}]`) + this.splitSingle(start); return new Array(arr[start]); } var mid = start + Math.floor((end - start) / 2); - this.V - .instruct(this.V.message, 0, 2, `Sorting [${start}] - [${end}]`) - .instruct(this.V.message, 0, 3, 'Slicing and recursing:') - .instruct(this.V.message, 100, 4, `[${start}]-[${mid}] and [${mid + 1}]-[${end}]`); - + this.preSort(start, mid, end); var arr1 = this.sort(arr, start, mid); var arr2 = this.sort(arr, mid + 1, end); - var i, j, x, y, v; - var len1 = arr1.length; - var len2 = arr2.length; - - for (var i = 0; i < len1; i++) { - x = Visualizer.padding + (i + start) * (Visualizer.itemW + Visualizer.spacerW); - y = Visualizer.padding * 2 + Visualizer.itemH; - v = arr1[i].value; - this.V.instruct(this.V.item, 0, 'secondary', x, y, v, '#05350D') - } - - for (var j = 0; j < len2; j++) { - x = Visualizer.padding + (j + len1 + start) * (Visualizer.itemW + Visualizer.spacerW); - y = Visualizer.padding * 2 + Visualizer.itemH; - v = arr2[j].value; - this.V.instruct(this.V.item, 0, 'secondary', x, y, v, '#028E2D') - } - - this.V - .instruct(this.V.fade, 0, 0, arr.length) - .instruct(this.V.message, 0, 2, ``) - .instruct(this.V.message, 0, 3, 'Merging slices:') - .instruct(this.V.message, 0, 4, `[${start}]-[${mid}] and [${mid + 1}]-[${end}]`) - + this.preMerge(arr1, arr2, start, mid, end); var result = this.merge(arr1, arr2); - this.V.instruct(this.V.removeSecondary, 0); + + this.postMerge(); return result; }; @@ -78,53 +120,32 @@ MergeSort.prototype.sort = function(arr, start, end) { */ MergeSort.prototype.merge = function(arr1, arr2) { var result = []; - var e, x, y, v; - - this.V.instruct(this.V.removeTertiary, 100); + var e; while (arr1.length > 0 || arr2.length > 0) { - x = Visualizer.padding + result.length * (Visualizer.itemW + Visualizer.spacerW); - y = Visualizer.padding * 3 + Visualizer.itemH * 2 - if (arr1.length === 0) { e = arr2.shift(); result.push(e); - - this.V - .instruct(this.V.item, 0, 'tertiary', x, y, e.value, '#8E5500') - .instruct(this.V.message, 0, 4, 'One element left to merge.') - .instruct(this.V.message, 100, 5, `Pushing ${e.value} to sub-result.`); + this.midMerge(result.length, e.value, 'One element left to merge.'); } else if (arr2.length === 0) { e = arr1.shift(); result.push(e); - - this.V - .instruct(this.V.item, 0, 'tertiary', x, y, e.value, '#8E5500') - .instruct(this.V.message, 0, 4, 'One element left to merge.') - .instruct(this.V.message, 100, 5, `Pushing ${e.value} to sub-result.`); + this.midMerge(result.length, e.value, 'One element left to merge.'); } else if (arr1[0].value <= arr2[0].value) { e = arr1.shift() result.push(e); - - this.V - .instruct(this.V.item, 0, 'tertiary', x, y, e.value, '#8E5500') - .instruct(this.V.message, 0, 4, `${e.value} <= ${arr2[0].value}`) - .instruct(this.V.message, 100, 5, `Pushing ${e.value} to sub-result.`); + this.midMerge(result.length, e.value, `${e.value} <= ${arr2[0].value}`); } else { e = arr2.shift(); result.push(e); - - this.V - .instruct(this.V.item, 0, 'tertiary', x, y, e.value, '#8E5500') - .instruct(this.V.message, 0, 4, `${arr1[0].value} > ${e.value}`) - .instruct(this.V.message, 100, 5, `Pushing ${e.value} to sub-result.`); + this.midMerge(result.length, e.value, `${arr1[0].value} > ${e.value}`); } this.comparisons++; - this.V.instruct(this.V.message, 0, 1, `Comparisons: ${this.comparisons}`); + this.updateComparisons(); } return result; diff --git a/js/visualizer-inits.js b/js/visualizer-inits.js index cc37d39..d7dce74 100644 --- a/js/visualizer-inits.js +++ b/js/visualizer-inits.js @@ -19,7 +19,7 @@ Visualizer.prototype.initItems = function(n) { this.svg.remove(); } - this.instructionIndex = 0; + this.actionIndex = 0; this.svg = d3.select(this.parent).append('svg') .attr('class', 'sorter-svg'); @@ -140,20 +140,20 @@ Visualizer.prototype.initControls = function() { this.paused = !this.paused; updatePlayPause(this.paused); - if (this.instructionIndex === this.instructions.length) { + if (this.actionIndex === this.actions.length) { this.reset(); this.paused = false; - this.followInstruction(); + this.go(); } else { - this.followInstruction(); + this.go(); } }; var forwardclick = function() { this.paused = true; - this.followInstruction(); - this.instructionIndex++; + this.go(); + this.actionIndex++; }; var restartclick = function() { diff --git a/js/visualizer.js b/js/visualizer.js index ed31f76..420aa7f 100644 --- a/js/visualizer.js +++ b/js/visualizer.js @@ -2,7 +2,7 @@ * */ function Visualizer(parent) { - this.instructions = []; + this.actions = []; this.parent = parent; this.sorter = null; this.paused = true; @@ -76,19 +76,19 @@ Visualizer.calculateX = function(index) { * */ Visualizer.prototype.instruct = function() { - this.instructions.push(arguments); + this.actions.push(arguments); return this; }; /** * Instructions contain a string with the name of a function in this object which is called to perform an action. */ -Visualizer.prototype.followInstruction = function() { - if (this.instructionIndex >= this.instructions.length) { +Visualizer.prototype.go = function() { + if (this.actionIndex >= this.actions.length) { return; } - var obj = this.instructions[this.instructionIndex]; + var obj = this.actions[this.actionIndex]; var instruction = new Array(); for (var key in obj) { @@ -115,12 +115,12 @@ Visualizer.prototype.followInstruction = function() { instruction[0].apply(this, args); if (delay === 0) { - this.instructionIndex++; - this.followInstruction(); + this.actionIndex++; + this.go(); } else if (this.paused === false) { - this.instructionIndex++; - setTimeout(this.followInstruction.bind(this), delay); + this.actionIndex++; + setTimeout(this.go.bind(this), delay); } }; @@ -128,7 +128,7 @@ Visualizer.prototype.followInstruction = function() { * */ Visualizer.prototype.reset = function() { - this.instructionIndex = 0; + this.actionIndex = 0; this.message(0, 1, ''); this.message(0, 2, '');