Merge Sort: Continuation passing style

by Devin Samarin

HTML

<div class="questionbox">
  <div class="question">
    What do you like better? <span id="progress">1/1</span>
  </div>
  <div class="answers">
    <a href="#" id="a1">Apple</a>
    <a href="#" id="a2">Mango</a>
  </div>
</div>

<div class="output"><ol id="list"></ol></div>

CSS

body { 
  font: 16pt sans-serif;
  }

.questionbox {
  background: white;
  padding: 1em;
}

.question {
  border: 1px solid grey;
  padding: 1em;
 }
 
 .answers {
   display: flex;
 }
 .answers a {
   display: block;
   flex-grow: 1;
   text-align: center;
   color: black;
   text-decoration: none;
   padding: 1em;
   background: black;
   color: white;
 }
 .answers a:hover {
   background: grey;
 }

JavaScript

var array = [
'Bison',
'Dolphin',
'Eagle',
'Pony',
'Ape',
'Lobster',
'Monkey',
'Cow',
'Deer',
'Duck',
'Rabbit',
'Spider',
'Wolf',
'Turkey',
'Lion',
'Pig',
'Snake',
'Shark',
'Bird',
'Bear',
'Fish',
'Chicken',
'Horse',
'Cat',
'Dog'
];

function NumberOfComparisons(n) {
	const ceil = Math.ceil(Math.log(n) / Math.log(2));
	return n * ceil - Math.pow(2, ceil) + 1;
}

function MergeSort(array, compare, callback) {
	if (array.length < 2) {
		callback(array);
	} else {
		var middle = Math.floor(array.length / 2);
		MergeSort(array.slice(0, middle), compare, function(left) {
    	MergeSort(array.slice(middle, array.length), compare, function(right) {
				Merge(left, right, compare, callback);
      });
  	});
  }
}
 
function Merge(left, right, compare, callback) {
	var result = [];

	(function next() {
		if (left.length && right.length) {
  		compare(left[0], right[0], function(leftfirst) {
  	  	if (leftfirst) {
  	  		result.push(left.shift());
  	    } else {
  	    	result.push(right.shift());
  	    }
        next();
  	  });
		} else {
			while (left.length)
				result.push(left.shift());
			while (right.length)
				result.push(right.shift());
			callback(result);
    }
  }());
}

let ComparisonsMade = 0;

MergeSort(array, function(left, right, callback) {
	const a1 = document.getElementById('a1');
  const a2 = document.getElementById('a2');
  const answersbox = a1.parentNode;
  const progress = document.getElementById('progress');
  
  a1.textContent = left;
  a2.textContent = right;
  progress.textContent = (ComparisonsMade++) + '/' + NumberOfComparisons(array.length);
  
  answersbox.addEventListener('click', function click(event) {
  	const target = event.target;
    if (target === a1 || target === a2) {
    	answersbox.removeEventListener('click', click);
    	callback(target === a1);
    } else {
    	console.log("Error")
    }
  });
  
}, function(list) {
	const ol = document.getElementById('list');
  const progress = document.getElementById('progress');
  
...