"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var RULE_DIRECTION;
(function (RULE_DIRECTION) {
    RULE_DIRECTION["UP"] = "UP";
    RULE_DIRECTION["DOWN"] = "DOWN";
    RULE_DIRECTION["LEFT"] = "LEFT";
    RULE_DIRECTION["RIGHT"] = "RIGHT";
    RULE_DIRECTION["ACTION"] = "ACTION";
    RULE_DIRECTION["STATIONARY"] = "STATIONARY";
    RULE_DIRECTION["RANDOMDIR"] = "RANDOMDIR";
})(RULE_DIRECTION = exports.RULE_DIRECTION || (exports.RULE_DIRECTION = {}));
// From https://stackoverflow.com/questions/10865025/merge-flatten-an-array-of-arrays-in-javascript/39000004#39000004
function _flatten(arrays) {
    return [].concat.apply([], arrays);
}
exports._flatten = _flatten;
// export function _zip<T1, T2>(array1: T1[], array2: T2[]) {
//     if (array1.length < array2.length) {
//         throw new Error(`BUG: Zip array length mismatch ${array1.length} != ${array2.length}`)
//     }
//     return array1.map((v1, index) => {
//         return [v1, array2[index]]
//     })
// }
// export function _extend(dest: any, ...rest: any[]) {
//     for (const obj of rest) {
//         for (const key of Object.keys(obj)) {
//             dest[key] = obj[key]
//         }
//     }
//     return dest
// }
function _debounce(callback) {
    let timeout; // NodeJS.Timer
    return () => {
        if (timeout) {
            clearTimeout(timeout);
        }
        timeout = setTimeout(() => {
            callback();
        }, 10);
    };
}
exports._debounce = _debounce;
function opposite(dir) {
    switch (dir) {
        case RULE_DIRECTION.UP:
            return RULE_DIRECTION.DOWN;
        case RULE_DIRECTION.DOWN:
            return RULE_DIRECTION.UP;
        case RULE_DIRECTION.LEFT:
            return RULE_DIRECTION.RIGHT;
        case RULE_DIRECTION.RIGHT:
            return RULE_DIRECTION.LEFT;
        default:
            throw new Error(`BUG: Invalid direction: "${dir}"`);
    }
}
exports.opposite = opposite;
function setEquals(set1, set2) {
    if (set1.size !== set2.size)
        return false;
    for (const elem of set2) {
        if (!set1.has(elem))
            return false;
    }
    return true;
}
exports.setEquals = setEquals;
function setAddAll(setA, iterable) {
    const newSet = new Set(setA);
    for (const elem of iterable) {
        newSet.add(elem);
    }
    return newSet;
}
exports.setAddAll = setAddAll;
function setIntersection(setA, setB) {
    const intersection = new Set();
    for (const elem of setB) {
        if (setA.has(elem)) {
            intersection.add(elem);
        }
    }
    return intersection;
}
exports.setIntersection = setIntersection;
function setDifference(setA, setB) {
    const difference = new Set(setA);
    for (const elem of setB) {
        difference.delete(elem);
    }
    return difference;
}
exports.setDifference = setDifference;
// From https://stackoverflow.com/a/19303725
let seed = 1;
let randomValuesForTesting = null;
function nextRandom(maxNonInclusive) {
    if (randomValuesForTesting) {
        if (randomValuesForTesting.length <= seed - 1) {
            throw new Error(`BUG: the list of random values for testing was too short.
            See calls to setRandomValuesForTesting([...]).
            The list was [${randomValuesForTesting}]. Index being requested is ${seed - 1}`);
        }
        const ret = randomValuesForTesting[seed - 1];
        seed++;
        // console.log(`Sending "random" value of "${ret}"`);
        return ret;
    }
    const x = Math.sin(seed++) * 10000;
    return Math.round((x - Math.floor(x)) * (maxNonInclusive - 1));
    // return Math.round(Math.random() * (maxNonInclusive - 1))
}
exports.nextRandom = nextRandom;
function resetRandomSeed() {
    seed = 1;
}
exports.resetRandomSeed = resetRandomSeed;
function setRandomValuesForTesting(values) {
    randomValuesForTesting = values;
    resetRandomSeed();
}
exports.setRandomValuesForTesting = setRandomValuesForTesting;
function clearRandomValuesForTesting() {
    randomValuesForTesting = null;
    resetRandomSeed();
}
exports.clearRandomValuesForTesting = clearRandomValuesForTesting;
function getRandomSeed() {
    return seed;
}
exports.getRandomSeed = getRandomSeed;
/**
 * A `DEBUGGER` flag in the game source that causes the evaluation to pause.
 * It works like the
 * [debugger](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger)
 * keyword in JavaScript.
 *
 * **Note:** the game needs to run in debug mode (`node --inspect-brk path/to/puzzlescript.js` or `npm run play-debug`)
 * for this flag to have any effect.
 *
 * This string can be added to:
 *
 * - A Rule. Example: `DEBUGGER [ > player | cat ] -> [ > player | > cat ]`
 * - A bracket when the condition is updated: `[ > player | cat ] DEBUGGER -> [ > player | > cat ]`
 * - A bracket when it is evaluated: `[ > player | cat ] -> [ > player | > cat ] DEBUGGER`
 * - A neighbor when the condition is updated: `[ > player DEBUGGER | cat ] -> [ > player | > cat ]`
 * - A neighbor when it is evaluated: `[ > player | cat ] -> [ > player | > cat DEBUGGER ]`
 * - A tile when the condition is updated: `[ > player | DEBUGGER cat ] -> [ > player | > cat ]`
 * - A tile when it is matched: `[ > player | cat ] -> [ > player | DEBUGGER > cat ]`
 */
var DEBUG_FLAG;
(function (DEBUG_FLAG) {
    DEBUG_FLAG["BREAKPOINT"] = "DEBUGGER";
    /**
     * Pause when a Cell causes an entry to be removed from the set of matches for this rule/bracket/neighbor/tile
     */
    DEBUG_FLAG["BREAKPOINT_REMOVE"] = "DEBUGGER_REMOVE";
})(DEBUG_FLAG = exports.DEBUG_FLAG || (exports.DEBUG_FLAG = {}));
//# sourceMappingURL=util.js.map