/** * @author gchq77703 [gchq77703@gchq.gov.uk] * @copyright Crown Copyright 2019 * @license Apache-2.0 */ import Operation from "../Operation.mjs"; import OperationError from "../errors/OperationError.mjs"; /** * Generate De Bruijn Sequence operation */ class GenerateDeBruijnSequence extends Operation { /** * GenerateDeBruijnSequence constructor */ constructor() { super(); this.name = "Generate De Bruijn Sequence"; this.module = "Default"; this.description = "Generates rolling keycode combinations given a certain alphabet size and key length."; this.infoURL = "https://wikipedia.org/wiki/De_Bruijn_sequence"; this.inputType = "string"; this.outputType = "string"; this.args = [ { name: "Alphabet size (k)", type: "number", value: 2 }, { name: "Key length (n)", type: "number", value: 3 } ]; } /** * @param {string} input * @param {Object[]} args * @returns {string} */ run(input, args) { const [k, n] = args; if (k < 2 || k > 9) { throw new OperationError("Invalid alphabet size, required to be between 2 and 9 (inclusive)."); } if (n < 2) { throw new OperationError("Invalid key length, required to be at least 2."); } if (Math.pow(k, n) > 50000) { throw new OperationError("Too many permutations, please reduce k^n to under 50,000."); } const a = new Array(k * n).fill(0); const sequence = []; (function db(t = 1, p = 1) { if (t > n) { if (n % p !== 0) return; for (let j = 1; j <= p; j++) { sequence.push(a[j]); } return; } a[t] = a[t - p]; db(t + 1, p); for (let j = a[t - p] + 1; j < k; j++) { a[t] = j; db(t + 1, t); } })(); return sequence.join(""); } } export default GenerateDeBruijnSequence;