فهرست منبع

Added argument validation

VirtualColossus 5 سال پیش
والد
کامیت
61ab9a904f
3فایلهای تغییر یافته به همراه111 افزوده شده و 89 حذف شده
  1. 69 71
      src/core/lib/Colossus.mjs
  2. 1 2
      src/core/lib/Lorenz.mjs
  3. 41 16
      src/core/operations/Colossus.mjs

+ 69 - 71
src/core/lib/Colossus.mjs

@@ -5,8 +5,6 @@
  * @copyright Crown Copyright 2019
  * @license Apache-2.0
  */
-import OperationError from "../errors/OperationError.mjs";
-import Utils from "../Utils.mjs";
 import {INIT_PATTERNS, ITA2_TABLE, ROTOR_SIZES} from "../lib/Lorenz.mjs";
 
 /**
@@ -26,10 +24,10 @@ export class ColossusComputer {
     constructor(ciphertext, pattern, qbusin, qbusswitches, control, starts, settotal, limit) {
 
         this.ITAlookup = ITA2_TABLE;
-        this.REVERSE_ITAlookup = {};
+        this.ReverseITAlookup = {};
         for (const letter in this.ITAlookup) {
             const code = this.ITAlookup[letter];
-            this.REVERSE_ITAlookup[code] = letter;
+            this.ReverseITAlookup[code] = letter;
         }
 
         this.initThyratrons(pattern);
@@ -71,13 +69,13 @@ export class ColossusComputer {
      */
     run() {
 
-        let result = {
+        const result = {
             printout: ""
         };
 
         // loop until our start positions are back to the beginning
         this.rotorPtrs = {X1: this.starts.X1, X2: this.starts.X2, X3: this.starts.X3, X4: this.starts.X4, X5: this.starts.X5, M61: this.starts.M61, M37: this.starts.M37, S1: this.starts.S1, S2: this.starts.S2, S3: this.starts.S3, S4: this.starts.S4, S5: this.starts.S5};
-        //this.rotorPtrs = this.starts;
+        // this.rotorPtrs = this.starts;
         let runcount = 1;
 
         const fast = this.control.fast;
@@ -96,11 +94,11 @@ export class ColossusComputer {
             this.runTape();
 
             // Only print result if larger than set total
-            var fastRef = "00";
-            var slowRef = "00";
-            if (fast !== "") fastRef = this.leftPad(this.rotorPtrs[fast],2);
-            if (slow !== "") slowRef = this.leftPad(this.rotorPtrs[slow],2);
-            var printline = '';
+            let fastRef = "00";
+            let slowRef = "00";
+            if (fast !== "") fastRef = this.leftPad(this.rotorPtrs[fast], 2);
+            if (slow !== "") slowRef = this.leftPad(this.rotorPtrs[slow], 2);
+            let printline = "";
             for (let c=0;c<5;c++) {
                 if (this.allCounters[c] > this.settotal) {
                     printline += String.fromCharCode(c+97) + this.allCounters[c]+" ";
@@ -110,16 +108,16 @@ export class ColossusComputer {
                 result.printout += fastRef + " " + slowRef + " : ";
                 result.printout += printline;
                 result.printout += "\n";
-            }            
+            }
 
             // Step fast rotor if required
-            if (fast != '') {
+            if (fast !== "") {
                 this.rotorPtrs[fast]++;
                 if (this.rotorPtrs[fast] > ROTOR_SIZES[fast]) this.rotorPtrs[fast] = 1;
             }
-            
+
             // Step slow rotor if fast rotor has returned to initial start position
-            if (slow != '' && this.rotorPtrs[fast] === this.starts[fast]) {
+            if (slow !== "" && this.rotorPtrs[fast] === this.starts[fast]) {
                 this.rotorPtrs[slow]++;
                 if (this.rotorPtrs[slow] > ROTOR_SIZES[slow]) this.rotorPtrs[slow] = 1;
             }
@@ -132,7 +130,7 @@ export class ColossusComputer {
         result.runcount = runcount;
 
         return result;
-    };
+    }
 
     /**
      * Run tape loop
@@ -144,13 +142,13 @@ export class ColossusComputer {
         this.Xptr = [this.rotorPtrs.X1, this.rotorPtrs.X2, this.rotorPtrs.X3, this.rotorPtrs.X4, this.rotorPtrs.X5];
         this.Mptr = [this.rotorPtrs.M37, this.rotorPtrs.M61];
         this.Sptr = [this.rotorPtrs.S1, this.rotorPtrs.S2, this.rotorPtrs.S3, this.rotorPtrs.S4, this.rotorPtrs.S5];
-        //console.log(this.Xptr);
+        // console.log(this.Xptr);
 
         // Run full loop of all character on the input tape (Z)
         for (let i=0; i<this.ciphertext.length; i++) {
             charZin = this.ciphertext.charAt(i);
 
-            //console.log('reading tape char #'+i+' : '+charZin);
+            // console.log('reading tape char #'+i+' : '+charZin);
 
             // Firstly, we check what inputs are specified on the Q-bus input switches
             this.getQbusInputs(charZin);
@@ -182,22 +180,22 @@ export class ColossusComputer {
      */
     stepThyratrons() {
         let X2bPtr = this.Xptr[1]-1;
-        if (X2bPtr==0) X2bPtr = ROTOR_SIZES.X2;
+        if (X2bPtr===0) X2bPtr = ROTOR_SIZES.X2;
         let S1bPtr = this.Sptr[0]-1;
-        if (S1bPtr==0) S1bPtr = ROTOR_SIZES.S1;
+        if (S1bPtr===0) S1bPtr = ROTOR_SIZES.S1;
 
         const x2sw = this.limitations.X2;
         const s1sw = this.limitations.S1;
 
         // Limitation calculations
-        var lim=1;
+        let lim=1;
         if (x2sw) lim = this.rings.X[2][X2bPtr-1];
         if (s1sw) {
             lim = lim ^ this.rings.S[1][S1bPtr-1];
         }
 
-        //console.log(this.Mptr);
-        //console.log(this.rings.M[2]);
+        // console.log(this.Mptr);
+        // console.log(this.rings.M[2]);
         const basicmotor = this.rings.M[2][this.Mptr[0]-1];
         this.totalmotor = basicmotor;
 
@@ -209,7 +207,7 @@ export class ColossusComputer {
             }
         }
 
-        //console.log('BM='+basicmotor+', TM='+this.totalmotor);
+        // console.log('BM='+basicmotor+', TM='+this.totalmotor);
 
         // Step Chi rotors
         for (let r=0; r<5; r++) {
@@ -218,16 +216,16 @@ export class ColossusComputer {
         }
 
         if (this.totalmotor) {
-            //console.log('step Psi');
+            // console.log('step Psi');
             // Step Psi rotors
             for (let r=0; r<5; r++) {
                 this.Sptr[r]++;
                 if (this.Sptr[r] > ROTOR_SIZES["S"+(r+1)]) this.Sptr[r] = 1;
             }
         }
-        
+
         // Move M37 rotor if M61 set
-        if (this.rings.M[1][this.Mptr[1]-1]==1) this.Mptr[0]++;
+        if (this.rings.M[1][this.Mptr[1]-1]===1) this.Mptr[0]++;
         if (this.Mptr[0] > ROTOR_SIZES.M37) this.Mptr[0]=1;
 
         // Always move M61 rotor
@@ -242,107 +240,107 @@ export class ColossusComputer {
     getQbusInputs(charZin) {
         // Zbits - the bits from the current character from the cipher tape.
         this.Zbits = this.ITAlookup[charZin].split("");
-        //console.log('Zbits = '+this.Zbits);
-        if (this.qbusin.Z == 'Z') {
+        // console.log('Zbits = '+this.Zbits);
+        if (this.qbusin.Z === "Z") {
             // direct Z
             this.Qbits = this.Zbits;
-            //console.log('direct Z: Qbits = '+this.Qbits);
-        } else if(this.qbusin.Z == 'ΔZ') {
+            // console.log('direct Z: Qbits = '+this.Qbits);
+        } else if (this.qbusin.Z === "ΔZ") {
             // delta Z, the Bitwise XOR of this character Zbits + last character Zbits
-            for(let b=0;b<5;b++) {
+            for (let b=0;b<5;b++) {
                 this.Qbits[b] = this.Zbits[b] ^ this.ZbitsOneBack[b];
             }
 
-            //console.log('delta Z: Qbits = '+this.Qbits);
+            // console.log('delta Z: Qbits = '+this.Qbits);
         }
         this.ZbitsOneBack = this.Zbits.slice(); // copy value of object, not reference
 
-        //console.log('Zin::Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']');
+        // console.log('Zin::Q bus now '+this.Qbits+'['+this.ReverseITAlookup[this.Qbits.join("")]+']');
 
         // Xbits - the current Chi wheel bits
-        //console.log(this.rings.X);
-        //console.log('Xptr = '+this.Xptr);
+        // console.log(this.rings.X);
+        // console.log('Xptr = '+this.Xptr);
 
         for (let b=0;b<5;b++) {
             this.Xbits[b] = this.rings.X[b+1][this.Xptr[b]-1];
         }
-        if (this.qbusin.Chi != "") {
-            //console.log('X Bits '+this.Xbits+'['+this.REVERSE_ITAlookup[this.Xbits.join("")]+']');
-            //console.log('X Char = ' + this.REVERSE_ITAlookup[this.Xbits.join("")]);
-            if (this.qbusin.Chi == "Χ") {
+        if (this.qbusin.Chi !== "") {
+            // console.log('X Bits '+this.Xbits+'['+this.ReverseITAlookup[this.Xbits.join("")]+']');
+            // console.log('X Char = ' + this.ReverseITAlookup[this.Xbits.join("")]);
+            if (this.qbusin.Chi === "Χ") {
                 // direct X added to Qbits
                 for (let b=0;b<5;b++) {
                     this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
                 }
-                //console.log('direct X: Qbits = '+this.Qbits);
-            } else if(this.qbusin.Chi == "ΔΧ") {
+                // console.log('direct X: Qbits = '+this.Qbits);
+            } else if (this.qbusin.Chi === "ΔΧ") {
                 // delta X
-                for(let b=0;b<5;b++) {
+                for (let b=0;b<5;b++) {
                     this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
                     this.Qbits[b] = this.Qbits[b] ^ this.XbitsOneBack[b];
                 }
-                //console.log('delta X: Xbits = '+this.Xbits+' Xbits-1 = '+this.XbitsOneBack);
-                //console.log('delta X: Qbits = '+this.Qbits);
+                // console.log('delta X: Xbits = '+this.Xbits+' Xbits-1 = '+this.XbitsOneBack);
+                // console.log('delta X: Qbits = '+this.Qbits);
             }
         }
         this.XbitsOneBack = this.Xbits.slice();
-        //console.log('setting XbitsOneBack to '+this.Xbits);
+        // console.log('setting XbitsOneBack to '+this.Xbits);
 
-        //console.log('Zin+Xin::Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']');
+        // console.log('Zin+Xin::Q bus now '+this.Qbits+'['+this.ReverseITAlookup[this.Qbits.join("")]+']');
 
         // Sbits - the current Psi wheel bits
-        //console.log(this.rings.S);
-        //console.log('Sptr = '+this.Sptr);
+        // console.log(this.rings.S);
+        // console.log('Sptr = '+this.Sptr);
         for (let b=0;b<5;b++) {
             this.Sbits[b] = this.rings.S[b+1][this.Sptr[b]-1];
         }
-        if (this.qbusin.Psi != "") {
-            //console.log('S Bits '+this.Sbits+'['+this.REVERSE_ITAlookup[this.Sbits.join("")]+']');
-            //console.log('S Char = ' + this.REVERSE_ITAlookup[this.Sbits.join("")]);
-            if(this.qbusin.Psi == "Ψ") {
+        if (this.qbusin.Psi !== "") {
+            // console.log('S Bits '+this.Sbits+'['+this.ReverseITAlookup[this.Sbits.join("")]+']');
+            // console.log('S Char = ' + this.ReverseITAlookup[this.Sbits.join("")]);
+            if (this.qbusin.Psi === "Ψ") {
                 // direct S added to Qbits
                 for (let b=0;b<5;b++) {
                     this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
                 }
-                //console.log('direct S: Qbits = '+this.Qbits);
-            } else if(this.qbusin.Psi == "ΔΨ") {
+                // console.log('direct S: Qbits = '+this.Qbits);
+            } else if (this.qbusin.Psi === "ΔΨ") {
                 // delta S
                 for (let b=0;b<5;b++) {
                     this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
                     this.Qbits[b] = this.Qbits[b] ^ this.SbitsOneBack[b];
                 }
-                //console.log('delta S: Qbits = '+this.Qbits);
+                // console.log('delta S: Qbits = '+this.Qbits);
             }
         }
         this.SbitsOneBack = this.Sbits.slice();
 
-        //console.log('Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']');
+        // console.log('Q bus now '+this.Qbits+'['+this.ReverseITAlookup[this.Qbits.join("")]+']');
     }
 
     /**
      * Conditional impulse Q bus section
      */
     runQbusProcessingConditional() {
-        let cnt = [-1, -1, -1, -1, -1];
+        const cnt = [-1, -1, -1, -1, -1];
         const numrows = this.qbusswitches.condition.length;
 
         for (let r=0;r<numrows;r++) {
-            let row = this.qbusswitches.condition[r];
+            const row = this.qbusswitches.condition[r];
             if (row.Counter !== "") {
                 let result = true;
-                let cPnt = row.Counter-1;
+                const cPnt = row.Counter-1;
                 const Qswitch = this.readBusSwitches(row.Qswitches);
                 // Match switches to bit pattern
                 for (let s=0;s<5;s++) {
-                    if (Qswitch[s] >= 0 && Qswitch[s] != this.Qbits[s]) result = false;
+                    if (Qswitch[s] >= 0 && Qswitch[s] !== this.Qbits[s]) result = false;
                 }
                 // Check for NOT switch
                 if (row.Negate) result = !result;
 
                 // AND each row to get final result
-                if (cnt[cPnt] == -1) {
+                if (cnt[cPnt] === -1) {
                     cnt[cPnt] = result;
-                } else if (result==0) {
+                } else if (result === 0) {
                     cnt[cPnt] = 0;
                 }
             }
@@ -352,10 +350,10 @@ export class ColossusComputer {
         for (let c=0;c<5;c++) {
             if (this.qbusswitches.condNegateAll) cnt[c] = !cnt[c];
 
-            if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor == 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor == 1)) {
-                if (cnt[c]==1) this.allCounters[c]++;  
+            if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor === 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor === 1)) {
+                if (cnt[c]===1) this.allCounters[c]++;
             }
-            
+
         }
 
     }
@@ -364,7 +362,7 @@ export class ColossusComputer {
      * Addition of impulses Q bus section
      */
     runQbusProcessingAddition() {
-        let row = this.qbusswitches.addition[0];
+        const row = this.qbusswitches.addition[0];
         const Qswitch = row.Qswitches.slice();
         if (row.C1) {
             let addition = 0;
@@ -374,12 +372,12 @@ export class ColossusComputer {
                     addition = addition ^ this.Qbits[s];
                 }
             }
-            const equals = (row.Equals==""?-1:(row.Equals=="."?0:1));
-            if (addition == equals) {
+            const equals = (row.Equals===""?-1:(row.Equals==="."?0:1));
+            if (addition === equals) {
                 this.allCounters[0]++;
             }
         }
-        //console.log("counter1="+this.allCounters[0]);
+        // console.log("counter1="+this.allCounters[0]);
     }
 
     /**
@@ -424,7 +422,7 @@ export class ColossusComputer {
      * Read argument bus switches X & . and convert to 1 & 0
      */
     readBusSwitches(row) {
-        let output = [-1, -1, -1, -1, -1];
+        const output = [-1, -1, -1, -1, -1];
         for (let c=0;c<5;c++) {
             if (row[c]===".") output[c] = 0;
             if (row[c]==="x") output[c] = 1;

+ 1 - 2
src/core/lib/Lorenz.mjs

@@ -5,7 +5,6 @@
  * @copyright Crown Copyright 2019
  * @license Apache-2.0
  */
-import OperationError from "../errors/OperationError.mjs";
 
 export const SWITCHES = [
     {name: "Up (.)", value: "."},
@@ -152,4 +151,4 @@ export const INIT_PATTERNS = {
             2: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1]
         }
     }
-};
+};

+ 41 - 16
src/core/operations/Colossus.mjs

@@ -278,27 +278,27 @@ class Colossus extends Operation {
                 value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
             },
             {
-                name: "Start X1",
+                name: "Start Χ1",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start X2",
+                name: "Start Χ2",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start X3",
+                name: "Start Χ3",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start X4",
+                name: "Start Χ4",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start X5",
+                name: "Start Χ5",
                 type: "number",
                 value: 1
             },
@@ -313,27 +313,27 @@ class Colossus extends Operation {
                 value: 1
             },
             {
-                name: "Start S1",
+                name: "Start Ψ1",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start S2",
+                name: "Start Ψ2",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start S3",
+                name: "Start Ψ3",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start S4",
+                name: "Start Ψ4",
                 type: "number",
                 value: 1
             },
             {
-                name: "Start S5",
+                name: "Start Ψ5",
                 type: "number",
                 value: 1
             }
@@ -355,7 +355,7 @@ class Colossus extends Operation {
         };
 
         const limitation = args[5];
-        let lm = [false,false,false];
+        const lm = [false, false, false];
         if (limitation.includes("Χ2")) lm[0] = true;
         if (limitation.includes("Ψ1")) lm[1] = true;
         if (limitation.includes("P5")) lm[2] = true;
@@ -370,6 +370,16 @@ class Colossus extends Operation {
             args = this.selectProgram(setProgram, args);
         }
 
+        const re = new RegExp("^$|^[.x]$");
+        for (let qr=0;qr<3;qr++) {
+            for (let a=0;a<5;a++) {
+                if (!re.test(args[((qr*7)+(a+9))])) throw new OperationError("Switch R"+(qr+1)+"-Q"+(a+1)+" can only be set to blank, . or x");
+            }
+        }
+
+        if (!re.test(args[37])) throw new OperationError("Switch Add-Equals can only be set to blank, . or x");
+        if (!re.test(args[40])) throw new OperationError("Switch Total Motor can only be set to blank, . or x");
+
         // Q1,Q2,Q3,Q4,Q5,negate,counter1
         const qbusswitches = {
             condition: [
@@ -385,7 +395,8 @@ class Colossus extends Operation {
             totalMotor: args[40]
         };
 
-        const settotal = args[42];
+        const settotal = parseInt(args[42], 10);
+        if (settotal < 0 || settotal > 9999) throw new OperationError("Set Total must be between 0000 and 9999");
 
         // null|fast|slow for each of S1-5,M1-2,X1-5
         const control = {
@@ -394,6 +405,20 @@ class Colossus extends Operation {
         };
 
         // Start positions
+
+        if (args[52]<1 || args[52]>43) throw new OperationError("Ψ1 start must be between 1 and 43");
+        if (args[53]<1 || args[53]>47) throw new OperationError("Ψ2 start must be between 1 and 47");
+        if (args[54]<1 || args[54]>51) throw new OperationError("Ψ3 start must be between 1 and 51");
+        if (args[55]<1 || args[55]>53) throw new OperationError("Ψ4 start must be between 1 and 53");
+        if (args[56]<1 || args[57]>59) throw new OperationError("Ψ5 start must be between 1 and 59");
+        if (args[51]<1 || args[51]>37) throw new OperationError("Μ37 start must be between 1 and 37");
+        if (args[50]<1 || args[50]>61) throw new OperationError("Μ61 start must be between 1 and 61");
+        if (args[45]<1 || args[45]>41) throw new OperationError("Χ1 start must be between 1 and 41");
+        if (args[46]<1 || args[46]>31) throw new OperationError("Χ2 start must be between 1 and 31");
+        if (args[47]<1 || args[47]>29) throw new OperationError("Χ3 start must be between 1 and 29");
+        if (args[48]<1 || args[48]>26) throw new OperationError("Χ4 start must be between 1 and 26");
+        if (args[49]<1 || args[49]>23) throw new OperationError("Χ5 start must be between 1 and 23");
+
         const starts = {
             X1: args[45], X2: args[46], X3: args[47], X4: args[48], X5: args[49],
             M61: args[50], M37: args[51],
@@ -415,7 +440,7 @@ class Colossus extends Operation {
     selectProgram(progname, args) {
 
         // Basic Letter Count
-        if (progname == "Letter Count") {
+        if (progname === "Letter Count") {
             // Set Conditional R1 : count every character into counter 1
             args[9] = "";
             args[10] = "";
@@ -434,7 +459,7 @@ class Colossus extends Operation {
         }
 
         // Bill Tutte's 1+2 Break In
-        if (progname == "1+2=. (1+2 Break In, Find X1,X2)") {
+        if (progname === "1+2=. (1+2 Break In, Find X1,X2)") {
             // Clear any other counters
             args[15] = ""; // Conditional R1
             args[22] = ""; // Conditional R2
@@ -450,7 +475,7 @@ class Colossus extends Operation {
         }
 
         // 4=3=/1=2 : Find X4 & X5 where X1 & X2 are known
-        if (progname == "4=3=/1=2 (Given X1,X2 find X4,X5)") {
+        if (progname === "4=3=/1=2 (Given X1,X2 find X4,X5)") {
             // Set Conditional R1 : Match NOT ..?.. into counter 1
             args[9] = ".";
             args[10] = ".";
@@ -476,7 +501,7 @@ class Colossus extends Operation {
         }
 
         // /,5,U : Count number of matches of /, 5 & U to find X3
-        if (progname == "/,5,U (Count chars to find X3)") {
+        if (progname === "/,5,U (Count chars to find X3)") {
             // Set Conditional R1 : Match / char, ITA2 = ..... into counter 1
             args[9] = ".";
             args[10] = ".";