Parcourir la source

Added argSelector ingredient type and reversed rotors in Enigma and Bombe operations.

n1474335 il y a 6 ans
Parent
commit
c005c86c27

+ 34 - 17
src/core/operations/Bombe.mjs

@@ -30,28 +30,42 @@ class Bombe extends Operation {
         this.presentType = "html";
         this.args = [
             {
-                name: "1st (right-hand) rotor",
+                name: "Model",
+                type: "argSelector",
+                value: [
+                    {
+                        name: "3-rotor",
+                        off: [1]
+                    },
+                    {
+                        name: "4-rotor",
+                        on: [1]
+                    }
+                ]
+            },
+            {
+                name: "Left-most rotor",
                 type: "editableOption",
-                value: ROTORS,
-                defaultIndex: 2
+                value: ROTORS_FOURTH,
+                defaultIndex: 0
             },
             {
-                name: "2nd (middle) rotor",
+                name: "Left-hand rotor",
                 type: "editableOption",
                 value: ROTORS,
-                defaultIndex: 1
+                defaultIndex: 0
             },
             {
-                name: "3rd (left-hand) rotor",
+                name: "Middle rotor",
                 type: "editableOption",
                 value: ROTORS,
-                defaultIndex: 0
+                defaultIndex: 1
             },
             {
-                name: "4th (left-most, only some models) rotor",
+                name: "Right-hand rotor",
                 type: "editableOption",
-                value: ROTORS_FOURTH,
-                defaultIndex: 0
+                value: ROTORS,
+                defaultIndex: 2
             },
             {
                 name: "Reflector",
@@ -93,23 +107,26 @@ class Bombe extends Operation {
      * @returns {string}
      */
     run(input, args) {
-        const reflectorstr = args[4];
-        let crib = args[5];
-        const offset = args[6];
-        const check = args[7];
+        const model = args[0];
+        const reflectorstr = args[5];
+        let crib = args[6];
+        const offset = args[7];
+        const check = args[8];
         const rotors = [];
         for (let i=0; i<4; i++) {
-            if (i === 3 && args[i] === "") {
+            if (i === 0 && model === "3-rotor") {
                 // No fourth rotor
-                break;
+                continue;
             }
-            let rstr = args[i];
+            let rstr = args[i + 1];
             // The Bombe doesn't take stepping into account so we'll just ignore it here
             if (rstr.includes("<")) {
                 rstr = rstr.split("<", 2)[0];
             }
             rotors.push(rstr);
         }
+        // Rotors are handled in reverse
+        rotors.reverse();
         if (crib.length === 0) {
             throw new OperationError("Crib cannot be empty");
         }

+ 44 - 27
src/core/operations/Enigma.mjs

@@ -28,67 +28,81 @@ class Enigma extends Operation {
         this.outputType = "string";
         this.args = [
             {
-                name: "1st (right-hand) rotor",
+                name: "Model",
+                type: "argSelector",
+                value: [
+                    {
+                        name: "3-rotor",
+                        off: [1, 2, 3]
+                    },
+                    {
+                        name: "4-rotor",
+                        on: [1, 2, 3]
+                    }
+                ]
+            },
+            {
+                name: "Left-most rotor",
                 type: "editableOption",
-                value: ROTORS,
-                // Default config is the rotors I-III *left to right*
-                defaultIndex: 2
+                value: ROTORS_FOURTH,
+                defaultIndex: 0
             },
             {
-                name: "1st rotor ring setting",
+                name: "Left-most rotor ring setting",
                 type: "option",
                 value: LETTERS
             },
             {
-                name: "1st rotor initial value",
+                name: "Left-most rotor initial value",
                 type: "option",
                 value: LETTERS
             },
             {
-                name: "2nd (middle) rotor",
+                name: "Left-hand rotor",
                 type: "editableOption",
                 value: ROTORS,
-                defaultIndex: 1
+                defaultIndex: 0
             },
             {
-                name: "2nd rotor ring setting",
+                name: "Left-hand rotor ring setting",
                 type: "option",
                 value: LETTERS
             },
             {
-                name: "2nd rotor initial value",
+                name: "Left-hand rotor initial value",
                 type: "option",
                 value: LETTERS
             },
             {
-                name: "3rd (left-hand) rotor",
+                name: "Middle rotor",
                 type: "editableOption",
                 value: ROTORS,
-                defaultIndex: 0
+                defaultIndex: 1
             },
             {
-                name: "3rd rotor ring setting",
+                name: "Middle rotor ring setting",
                 type: "option",
                 value: LETTERS
             },
             {
-                name: "3rd rotor initial value",
+                name: "Middle rotor initial value",
                 type: "option",
                 value: LETTERS
             },
             {
-                name: "4th (left-most, only some models) rotor",
+                name: "Right-hand rotor",
                 type: "editableOption",
-                value: ROTORS_FOURTH,
-                defaultIndex: 0
+                value: ROTORS,
+                // Default config is the rotors I-III *left to right*
+                defaultIndex: 2
             },
             {
-                name: "4th rotor ring setting",
+                name: "Right-hand rotor ring setting",
                 type: "option",
                 value: LETTERS
             },
             {
-                name: "4th rotor initial value",
+                name: "Right-hand rotor initial value",
                 type: "option",
                 value: LETTERS
             },
@@ -135,18 +149,21 @@ class Enigma extends Operation {
      * @returns {string}
      */
     run(input, args) {
-        const reflectorstr = args[12];
-        const plugboardstr = args[13];
-        const removeOther = args[14];
+        const model = args[0];
+        const reflectorstr = args[13];
+        const plugboardstr = args[14];
+        const removeOther = args[15];
         const rotors = [];
         for (let i=0; i<4; i++) {
-            if (i === 3 && args[i*3] === "") {
-                // No fourth rotor
-                break;
+            if (i === 0 && model === "3-rotor") {
+                // Skip the 4th rotor settings
+                continue;
             }
-            const [rotorwiring, rotorsteps] = this.parseRotorStr(args[i*3], 1);
-            rotors.push(new Rotor(rotorwiring, rotorsteps, args[i*3 + 1], args[i*3 + 2]));
+            const [rotorwiring, rotorsteps] = this.parseRotorStr(args[i*3 + 1], 1);
+            rotors.push(new Rotor(rotorwiring, rotorsteps, args[i*3 + 2], args[i*3 + 3]));
         }
+        // Rotors are handled in reverse
+        rotors.reverse();
         const reflector = new Reflector(reflectorstr);
         const plugboard = new Plugboard(plugboardstr);
         if (removeOther) {

+ 3 - 0
src/web/App.mjs

@@ -472,6 +472,7 @@ class App {
             const item = this.manager.recipe.addOperation(recipeConfig[i].op);
 
             // Populate arguments
+            log.debug(`Populating arguments for ${recipeConfig[i].op}`);
             const args = item.querySelectorAll(".arg");
             for (let j = 0; j < args.length; j++) {
                 if (recipeConfig[i].args[j] === undefined) continue;
@@ -497,6 +498,8 @@ class App {
                 item.querySelector(".breakpoint").click();
             }
 
+            this.manager.recipe.triggerArgEvents(item);
+
             this.progress = 0;
         }
 

+ 48 - 0
src/web/HTMLIngredient.mjs

@@ -240,6 +240,27 @@ class HTMLIngredient {
                     ${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
                 </div>`;
                 break;
+            case "argSelector":
+                html += `<div class="form-group inline">
+                    <label for="${this.id}" class="bmd-label-floating inline">${this.name}</label>
+                    <select
+                        class="form-control arg inline arg-selector"
+                        id="${this.id}"
+                        arg-name="${this.name}"
+                        ${this.disabled ? "disabled" : ""}>`;
+                for (i = 0; i < this.value.length; i++) {
+                    html += `<option ${this.defaultIndex === i ? "selected" : ""}
+                        turnon="${JSON.stringify(this.value[i].on || [])}"
+                        turnoff="${JSON.stringify(this.value[i].off || [])}">
+                            ${this.value[i].name}
+                        </option>`;
+                }
+                html += `</select>
+                    ${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
+                </div>`;
+
+                this.manager.addDynamicListener(".arg-selector", "change", this.argSelectorChange, this);
+                break;
             default:
                 break;
         }
@@ -321,6 +342,33 @@ class HTMLIngredient {
         this.manager.recipe.ingChange();
     }
 
+
+    /**
+     * Handler for argument selector changes.
+     * Shows or hides the relevant arguments for this operation.
+     *
+     * @param {event} e
+     */
+    argSelectorChange(e) {
+        e.preventDefault();
+        e.stopPropagation();
+
+        const option = e.target.options[e.target.selectedIndex];
+        const op = e.target.closest(".operation");
+        const args = op.querySelectorAll(".ingredients .form-group");
+        const turnon = JSON.parse(option.getAttribute("turnon"));
+        const turnoff = JSON.parse(option.getAttribute("turnoff"));
+
+        args.forEach((arg, i) => {
+            if (turnon.includes(i)) {
+                arg.classList.remove("d-none");
+            }
+            if (turnoff.includes(i)) {
+                arg.classList.add("d-none");
+            }
+        });
+    }
+
 }
 
 export default HTMLIngredient;

+ 19 - 9
src/web/RecipeWaiter.mjs

@@ -393,15 +393,6 @@ class RecipeWaiter {
         this.buildRecipeOperation(item);
         document.getElementById("rec-list").appendChild(item);
 
-        // Trigger populateOption events
-        const populateOptions = item.querySelectorAll(".populate-option");
-        const evt = new Event("change", {bubbles: true});
-        if (populateOptions.length) {
-            for (const el of populateOptions) {
-                el.dispatchEvent(evt);
-            }
-        }
-
         item.dispatchEvent(this.manager.operationadd);
         return item;
     }
@@ -439,6 +430,23 @@ class RecipeWaiter {
     }
 
 
+    /**
+     * Triggers various change events for operation arguments that have just been initialised.
+     *
+     * @param {HTMLElement} op
+     */
+    triggerArgEvents(op) {
+        // Trigger populateOption and argSelector events
+        const triggerableOptions = op.querySelectorAll(".populate-option, .arg-selector");
+        const evt = new Event("change", {bubbles: true});
+        if (triggerableOptions.length) {
+            for (const el of triggerableOptions) {
+                el.dispatchEvent(evt);
+            }
+        }
+    }
+
+
     /**
      * Handler for operationadd events.
      *
@@ -448,6 +456,8 @@ class RecipeWaiter {
      */
     opAdd(e) {
         log.debug(`'${e.target.querySelector(".op-title").textContent}' added to recipe`);
+
+        this.triggerArgEvents(e.target);
         window.dispatchEvent(this.manager.statechange);
     }
 

+ 48 - 36
tests/operations/tests/Bombe.mjs

@@ -16,10 +16,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "THISISATESTMESSAGE", 0, false
                 ]
@@ -35,10 +36,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "THISISATESTMESSAGE", 0, false
                 ]
@@ -53,10 +55,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "THISISATESTMESSAGE", 3, false
                 ]
@@ -71,10 +74,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "THISISATESTM", 0, false
                 ]
@@ -89,10 +93,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "THISISATESTM", 0, true
                 ]
@@ -108,10 +113,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "4-rotor",
                     "LEYJVCNIXWPBQMDRTAKZGFUHOS", // Beta
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AE BN CK DQ FU GY HW IJ LO MP RX SZ TV", // B thin
                     "THISISATESTMESSAGE", 0, false
                 ]
@@ -126,10 +132,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "", 0, false
                 ]
@@ -144,10 +151,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "A", 0, false
                 ]
@@ -162,10 +170,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "AAAAAAAA", 0, false
                 ]
@@ -180,10 +189,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "CCCCCCCCCCCCCCCCCCCCCC", 0, false
                 ]
@@ -198,10 +208,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "AAAAAAAAAAAAAAAAAAAAAAAAAA", 0, false
                 ]
@@ -216,10 +227,11 @@ TestRegister.addTests([
             {
                 "op": "Bombe",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "3-rotor",
                     "",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "BBBBB", -1, false
                 ]

+ 112 - 84
tests/operations/tests/Enigma.mjs

@@ -17,11 +17,12 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
+                    "3-rotor",
+                    "", "A", "A",
                     // Note: start on Z because it steps when the key is pressed
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
                     "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
-                    "", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     ""
                 ]
@@ -38,10 +39,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "W",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "F",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "N",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "N",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "F",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "W",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -59,10 +61,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "B", "Z",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "B", "Z",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -79,10 +82,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "W", "Z",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "F", "A",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "N", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "N", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "F", "A",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "W", "Z",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -99,10 +103,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -118,10 +123,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -129,10 +135,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "Z",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -149,10 +156,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "U",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "D",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "D",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "U",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -169,10 +177,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "U",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "E",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "E",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "U",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -189,10 +198,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "S",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "D",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "D",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "S",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -208,10 +218,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "H", "Z",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "H", "Z",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -227,10 +238,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "H", "F",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "C", "D",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "Q", "A",
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "Q", "A",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "C", "D",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "H", "F",
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW",
                     ""
                 ]
@@ -246,10 +258,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "D", "Q",
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "P", "F",
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "O", "E",
+                    "4-rotor",
                     "LEYJVCNIXWPBQMDRTAKZGFUHOS", "A", "X", // Beta
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "O", "E",
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "P", "F",
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "D", "Q",
                     "AE BN CK DQ FU GY HW IJ LO MP RX SZ TV", // B thin
                     ""
                 ]
@@ -265,10 +278,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "W", "U", // IV
-                    "VZBRGITYUPSDNHLXAWMJQOFECK<A", "M", "G", // V
-                    "JPGVOUMFYQBENHZRDKASXLICTW<AN", "A", "J", // VI
+                    "4-rotor",
                     "FSOKANUERHMBTIYCWLQPZXVGJD", "A", "L", // Gamma
+                    "JPGVOUMFYQBENHZRDKASXLICTW<AN", "A", "J", // VI
+                    "VZBRGITYUPSDNHLXAWMJQOFECK<A", "M", "G", // V
+                    "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "W", "U", // IV
                     "AR BD CO EJ FN GT HK IV LM PW QZ SX UY", // C thin
                     ""
                 ]
@@ -284,10 +298,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "FKQHTLXOCBJSPDZRAMEWNIUYGV<AN", "U", "Z", // VIII
-                    "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "O", "O", // IV
-                    "NZJHGRCXMYSWBOUFAIVLPEKQDT<AN", "I", "V", // VII
+                    "4-rotor",
                     "FSOKANUERHMBTIYCWLQPZXVGJD", "A", "I", // Gamma
+                    "NZJHGRCXMYSWBOUFAIVLPEKQDT<AN", "I", "V", // VII
+                    "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "O", "O", // IV
+                    "FKQHTLXOCBJSPDZRAMEWNIUYGV<AN", "U", "Z", // VIII
                     "AE BN CK DQ FU GY HW IJ LO MP RX SZ TV", // B thin
                     "WN MJ LX YB FP QD US IH CE GR"
                 ]
@@ -303,10 +318,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "FKQHTLXOCBJSPDZRAMEWNIUYGV<AN", "U", "Z", // VIII
-                    "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "O", "O", // IV
-                    "NZJHGRCXMYSWBOUFAIVLPEKQDT<AN", "I", "V", // VII
+                    "4-rotor",
                     "FSOKANUERHMBTIYCWLQPZXVGJD", "A", "I", // Gamma
+                    "NZJHGRCXMYSWBOUFAIVLPEKQDT<AN", "I", "V", // VII
+                    "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "O", "O", // IV
+                    "FKQHTLXOCBJSPDZRAMEWNIUYGV<AN", "U", "Z", // VIII
                     "AE BN CK DQ FU GY HW IJ LO MP RX SZ TV", // B thin
                     "WN MJ LX YB FP QD US IH CE GR"
                 ]
@@ -322,10 +338,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "FKQHTLXOCBJSPDZRAMEWNIUYGV<AN", "L", "Z", // VIII
-                    "JPGVOUMFYQBENHZRDKASXLICTW<AN", "E", "S", // VI
-                    "VZBRGITYUPSDNHLXAWMJQOFECK<A", "P", "D", // V
+                    "4-rotor",
                     "LEYJVCNIXWPBQMDRTAKZGFUHOS", "E", "C", // Beta
+                    "VZBRGITYUPSDNHLXAWMJQOFECK<A", "P", "D", // V
+                    "JPGVOUMFYQBENHZRDKASXLICTW<AN", "E", "S", // VI
+                    "FKQHTLXOCBJSPDZRAMEWNIUYGV<AN", "L", "Z", // VIII
                     "AR BD CO EJ FN GT HK IV LM PW QZ SX UY", // C thin
                     "AE BF CM DQ HU JN LX PR SZ VW"
                 ]
@@ -341,10 +358,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "", true
                 ]
@@ -360,10 +378,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     "", false
                 ]
@@ -378,10 +397,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQ", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQ", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     ""
                 ]
@@ -396,10 +416,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQo", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQo", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     ""
                 ]
@@ -414,10 +435,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQA", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQA", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     ""
                 ]
@@ -432,10 +454,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<RR", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<RR", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     ""
                 ]
@@ -450,10 +473,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<a", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<a", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", // B
                     ""
                 ]
@@ -470,10 +494,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
                     "AY BR CU DH EQ FS GL IP JX KN MO", // B
                     ""
                 ]
@@ -488,10 +513,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
                     "AA BR CU DH EQ FS GL IP JX KN MO TZ VV WY", // B
                     ""
                 ]
@@ -506,10 +532,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
                     "AY AR CU DH EQ FS GL IP JX KN MO TZ", // B
                     ""
                 ]
@@ -524,10 +551,11 @@ TestRegister.addTests([
             {
                 "op": "Enigma",
                 "args": [
-                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
-                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
-                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "3-rotor",
                     "", "A", "A",
+                    "EKMFLGDQVZNTOWYHXUSPAIBRCJ<R", "A", "A", // I
+                    "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "A", "A", // II
+                    "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "A", "A", // III
                     "AYBR CU DH EQ FS GL IP JX KN MO TZ", // B
                     ""
                 ]