Eni Puzzle

Create a straight Javascript POC (ES6 + JQuery + bootstrap) that virtualizes Eni Puzzle -- See http://www.enipuzzles.com.

by brady houseknecht

HTML

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootswatch/3.3.5/paper/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script>
    document.write('<a id="githubLink" href="https://github.com/bradyhouse/house/tree/master/fiddles/jquery/fiddle-0042-EniPuzzle"' +
      '><img style="z-index: 1000; position: absolute; top: 0; right: 0; border: 0;" ' +
      'src="https://camo.githubusercontent.com/652c5b9acfaddf3a9c326fa6bde407b87f7be0f4/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6f72616e67655f6666373630302e706e67" ' +
      'alt="Fork me on GitHub"><\/a>');
  </script>
  <div class="panel panel-default">
    <div class="panel-heading">
      <h3 id="navbar">&nbsp;Eni Puzzle</h3>
    </div>
    <div id="fiddleHook" class="panel-body">
    </div>
    <div class="panel-footer">
      <div class="btn-group">
        <a class="btn btn-default" href="#" onclick="app.board.toggle(this)" title="Play">play</a>
      </div>
    </div>
  </div>

CSS

@CHARSET "UTF-8";

.enter-stage-right {
  -moz-animation-duration: 3s;
  -webkit-animation-duration: 3s;
  -moz-animation-name: slidein;
  -webkit-animation-name: slidein;
}

@-moz-keyframes slidein {
  from {
    margin-left: 100%;
  }
  to {
    margin-left: 10%;
  }
}

@-webkit-keyframes slidein {
  from {
    margin-left: 100%;
  }
  to {
    margin-left: 10%;
  }
}

.enter-stage-south {
  -moz-animation-duration: 3s;
  -webkit-animation-duration: 3s;
  -moz-animation-name: slide-up;
  -webkit-animation-name: slide-up;
}

@-moz-keyframes slide-up {
  from {
    margin-top: 100%;
  }
  to {
    margin-top: 0%;
  }
}

@-webkit-keyframes slide-up {
  from {
    margin-top: 100%;
  }
  to {
    margin-top: 0%;
  }
}

button {
  color: #000000 !important;
}

p {
  padding-top: 20px;
}

.btn{
  border-radius: 10px;
}

.btn.btn-danger {
  border-radius: 15px;
}

.btn.btn-info {
  border-radius: 15px;
}

.btn.btn-warning {
  border-radius: inherit;
  box-shadow: none;
  border: none;
  color: #ffffff;
  background-color: #ffffff;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
}


.btn-warning:active,
.btn-warning:hover,
.btn-warning:focus,
.btn-warning:before,
.btn-warning:hover {
  box-shadow: none;
  mso-border-shadow: none;
  border-radius: 0px;
  border: none;
  color: #ffffff;
  background-color: #ffffff;
}

@font-face {
  font-family: digital;
  src: url(Open24DisplaySt.ttf);
  font-weight: 400;
}

.digital {
  font-family: digital;
  font-size: 2em;
}


.col-a {
  color: yellow;
  background-color: yellow;
}

.col-b {
  color: orange;
  background-color: orange;
}

.col-c {
  color: red;
  background-color: red;
}

.col-d {
  color: darkred;
  background-color: darkred;
}

.col-e {
  color: blueviolet;
  background-color: blueviolet;
}

.col-f {
  color: blue;
  background-color: blue;
}

.col-g {
  color: turquoise;
  background-color: turquoise;
}

.col-h {
  color: green;
  background-color: green;
}

.empty {
  color: white;
 ...

JavaScript

(function(app) {
    "use strict";


    app.metadata = app.metadata || {
        gitHubUrl: 'https://github.com/bradyhouse/house/tree/master/fiddles/jquery/fiddle-0042-EniPuzzle',
        helpUrl: 'http://www.enipuzzles.com/'
    };


    class Util {
        static isEven(x) {
            return (x % 2) == 0;
        }
        static generateSequence(min, max, count) {
            let range = [],
                number = 0,
                i = 0;
            while (i < count) {
                number = Math.floor(Math.random() * (max - min + 1)) + min;
                if (range.indexOf(number) === -1) {
                    range.push(number);
                    i++;
                }
            }
            return range;
        }
        static generateSequentialSequence(min, max) {
            let sequence = [],
                i = 0,
                number = min,
                count = (max - min);
            if (count > 0) {
                while (i < (count + 1)) {
                    sequence.push(number);
                    number++;
                    i++;
                }
            }
            return sequence;
        }
        static generateGameSequence(min, max, count) {
            let sequence = Util.generateSequence(min, max, count);
            while (!Util.isValid(sequence)) {
                sequence = Util.generateSequence(min, max, count);
            }
            return sequence;
        }
        static isValid(sequence) {
            let inversionCounts = [],
                inversionSum = 0;
            sequence.forEach(function(a, x, arr) {
                let inversions = arr.filter(function(b, y) {
                    return y > x && b < a;
                });
                if (inversions.length) {
                    inversionCounts.push(inversions.length);
                } else {
                    inversionCounts.push(0);
                }
            });
            inversionCounts.forEach(function(cnt) {
        ...