Source: problems/configurationTypes/Permutation.js

/**
 * class representing permutation configuration, used for all problems with permutation configurations
 * @type {class}
 */
export class Permutation {
    /**
     * Class constructor, can create from other Permutations, random with specified size, or sorted starting with 0
     * @param {object} options contains options.fromBitArray(bool), options.size(int) and options.random(bool)
     */
    constructor(options) {
        if (!options) return;
        this._Array = [];
        if (options.fromArray) {
            this._Array = options.fromArray.map(x=>x);
        }
        else if (options.size && options.random) {
            for (var i = 0; i < options.size; i++) {
                this._Array = this.randomPermutation(options.size);
            }
        }
        else if (options.size) {
            for (var i = 0; i < options.size; i++) {
                this._Array.push(i);
            }
        }
    }

    /**
     * Returns random permutation array of specific size
     * @param  {int} size size of the permutation
     * @return {array} the generated permutation as array
     */
    randomPermutation(size) {
        // generate number sequence
        var permArray = new Array(size);
        for(var i = 0; i < size; i++){
            permArray[i] = i;
        }
        // shuffle sequence
        for (var i = size; i > 1; --i){
            var randPos = Math.floor(i * Math.random());
            var tmpStore = permArray[i-1];
            permArray[i-1] = permArray[randPos];
            permArray[randPos] = tmpStore;
        }
        return permArray;
    }
    /**
     * Return copy of the class
     * @return {class} copy of the class
     */
    copy() {
        return new Permutation({ fromArray: this._Array });
    }
    /**
     * Change the value on specific index(bit flip)
     * @param  {int} index which index to change
     * @return {class} return the class
     */
    changeOn(indexOne, indexTwo) {
        var x = this._Array[indexOne];
        this._Array[indexOne] = this._Array[indexTwo];
        this._Array[indexTwo] = x;
        return this;
    }
    /**
     * Return neighbour, either random or selected with two indexes to swap
     * @param  {int} index which index will change to get the neighbour
     * @return {class} return copy of the class with the value on index changed
     */
    getNeighbour(indexOne, indexTwo) {
        indexOne = (indexOne || indexOne === 0) ? indexOne : Math.round(Math.random() * (this._Array.length - 1));
        indexTwo = (indexTwo || indexTwo === 0) ? indexTwo : Math.round(Math.random() * (this._Array.length - 1));

        while (indexOne === indexTwo) {
            indexTwo = Math.round(Math.random() * (this._Array.length - 1));
        }
        return this.copy().changeOn(indexOne, indexTwo);
    }
    /**
     * Returns the bit array, meaning the actual array not class
     * @return {array} bitArray variable
     */
    getArray() {
        return this._Array;
    }
    /**
     * Return size of the BitArray
     * @return {int} size of the array
     */
    getSize() {
        return this._Array.length;
    }
    /**
     * Returns the type of the configuration, needed for specific method functions(like mutation for example)
     * @return {string} [description]
     */
    getType() {
        return 'permutation';
    }
    /**
     * Return the bitArray as string
     * @return {string} bitArray as string
     */
    toString() {
        var str = "";
        for (var i in this._Array) {
            str += (this._Array[i]);
        }
        return str;
    }
    /**
     * Typical equals function, compares two BitArrays
     * @param  {class} other other BitArray
     * @return {bool} equals or not
     */
    equals(other) {
        if (!other) return false; // checks for null, undefined, empty, etc.
        for (var i = 0; i < this._Array.length; i++)
            if (this._Array[i] !== other._Array[i]) return false;
        return true;
    }
}