Added Colossus operation
This commit is contained in:
parent
610d46a1a4
commit
dfc8f517f2
426
src/core/lib/Colossus.mjs
Normal file
426
src/core/lib/Colossus.mjs
Normal file
@ -0,0 +1,426 @@
|
|||||||
|
/**
|
||||||
|
* Colossus - an emulation of the world's first electronic computer
|
||||||
|
*
|
||||||
|
* @author VirtualColossus
|
||||||
|
* @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";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colossus simulator class.
|
||||||
|
*/
|
||||||
|
export class ColossusComputer {
|
||||||
|
/**
|
||||||
|
* Construct a Colossus.
|
||||||
|
*
|
||||||
|
* @param {string} ciphertext
|
||||||
|
* @param {string} pattern - named pattern of Chi, Mu and Psi wheels
|
||||||
|
* @param {Object} qbusin - which data inputs are being sent to q bus - each can be null, plain or delta
|
||||||
|
* @param {Object[]} qbusswitches - Q bus calculation switches, multiple rows
|
||||||
|
* @param {Object} control - control switches which specify stepping modes
|
||||||
|
* @param {Object} starts - rotor start positions
|
||||||
|
*/
|
||||||
|
constructor(ciphertext, pattern, qbusin, qbusswitches, control, starts, settotal, limit) {
|
||||||
|
|
||||||
|
this.ITAlookup = ITA2_TABLE;
|
||||||
|
this.REVERSE_ITAlookup = {};
|
||||||
|
for (const letter in this.ITAlookup) {
|
||||||
|
const code = this.ITAlookup[letter];
|
||||||
|
this.REVERSE_ITAlookup[code] = letter;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initThyratrons(pattern);
|
||||||
|
|
||||||
|
this.ciphertext = ciphertext;
|
||||||
|
this.qbusin = qbusin;
|
||||||
|
this.qbusswitches = qbusswitches;
|
||||||
|
this.control = control;
|
||||||
|
this.starts = starts;
|
||||||
|
this.settotal = settotal;
|
||||||
|
this.limitations = limit;
|
||||||
|
|
||||||
|
|
||||||
|
this.allCounters = [0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
this.Zbits = [0, 0, 0, 0, 0]; // Z input is the cipher tape
|
||||||
|
this.ZbitsOneBack = [0, 0, 0, 0, 0]; // for delta
|
||||||
|
this.Qbits = [0, 0, 0, 0, 0]; // input generated for placing onto the Q-bus (the logic processor)
|
||||||
|
|
||||||
|
this.Xbits = [0, 0, 0, 0, 0]; // X is the Chi wheel bits
|
||||||
|
this.Xptr = [0, 0, 0, 0, 0]; // pointers to the current X bits (Chi wheels)
|
||||||
|
this.XbitsOneBack = [0, 0, 0, 0, 0]; // the X bits one back (for delta)
|
||||||
|
|
||||||
|
this.Sbits = [0, 0, 0, 0, 0]; // S is the Psi wheel bits
|
||||||
|
this.Sptr = [0, 0, 0, 0, 0]; // pointers to the current S bits (Psi wheels)
|
||||||
|
this.SbitsOneBack = [0, 0, 0, 0, 0]; // the S bits one back (for delta)
|
||||||
|
|
||||||
|
this.Mptr = [0, 0];
|
||||||
|
|
||||||
|
this.rotorPtrs = {};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin a run
|
||||||
|
* @returns {object} -
|
||||||
|
*/
|
||||||
|
run() {
|
||||||
|
|
||||||
|
let 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;
|
||||||
|
let runcount = 1;
|
||||||
|
|
||||||
|
const fast = this.control.fast;
|
||||||
|
const slow = this.control.slow;
|
||||||
|
|
||||||
|
// Print Headers
|
||||||
|
result.printout += fast + " " + slow + "\n";
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
this.allCounters = [0, 0, 0, 0, 0];
|
||||||
|
this.ZbitsOneBack = [0, 0, 0, 0, 0];
|
||||||
|
this.XbitsOneBack = [0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
// Run full tape loop and process counters
|
||||||
|
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);
|
||||||
|
result.printout += fastRef + " " + slowRef + " : ";
|
||||||
|
for (let c=0;c<5;c++) {
|
||||||
|
if (this.allCounters[c] > this.settotal) {
|
||||||
|
result.printout += String.fromCharCode(c+97) + this.allCounters[c]+" ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.printout += "\n";
|
||||||
|
|
||||||
|
// Step fast rotor if required
|
||||||
|
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]) {
|
||||||
|
this.rotorPtrs[slow]++;
|
||||||
|
if (this.rotorPtrs[slow] > ROTOR_SIZES[slow]) this.rotorPtrs[slow] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
runcount++;
|
||||||
|
|
||||||
|
} while (JSON.stringify(this.rotorPtrs) !== JSON.stringify(this.starts));
|
||||||
|
|
||||||
|
result.counters = this.allCounters;
|
||||||
|
result.runcount = runcount;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run tape loop
|
||||||
|
*/
|
||||||
|
runTape() {
|
||||||
|
|
||||||
|
let charZin = "";
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Firstly, we check what inputs are specified on the Q-bus input switches
|
||||||
|
this.getQbusInputs(charZin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pattern conditions on individual impulses. Matching patterns of bits on the Q bus.
|
||||||
|
* This is the top section on Colussus K rack - the Q bus programming switches
|
||||||
|
*/
|
||||||
|
this.runQbusProcessingConditional();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Addition of impulses.
|
||||||
|
* This is the bottom section of Colossus K rack.
|
||||||
|
*/
|
||||||
|
this.runQbusProcessingAddition();
|
||||||
|
|
||||||
|
// Step rotors
|
||||||
|
this.stepThyratrons();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Step thyratron rings to simulate movement of Lorenz rotors
|
||||||
|
* Chi rotors all step one per character
|
||||||
|
* Motor M61 rotor steps one per character, M37 steps dependant on M61 setting
|
||||||
|
* Psi rotors only step dependant on M37 setting + limitation
|
||||||
|
*/
|
||||||
|
stepThyratrons() {
|
||||||
|
let X2bPtr = this.Xptr[1]-1;
|
||||||
|
if (X2bPtr==0) X2bPtr = ROTOR_SIZES.X2;
|
||||||
|
let S1bPtr = this.Sptr[0]-1;
|
||||||
|
if (S1bPtr==0) S1bPtr = ROTOR_SIZES.S1;
|
||||||
|
|
||||||
|
const x2sw = this.limitations.X2;
|
||||||
|
const s1sw = this.limitations.S1;
|
||||||
|
|
||||||
|
// Limitation calculations
|
||||||
|
var 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]);
|
||||||
|
const basicmotor = this.rings.M[2][this.Mptr[0]-1];
|
||||||
|
let totalmotor = basicmotor;
|
||||||
|
|
||||||
|
if (x2sw || s1sw) {
|
||||||
|
if (basicmotor===0 && lim===1) {
|
||||||
|
totalmotor = 0;
|
||||||
|
} else {
|
||||||
|
totalmotor = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//console.log('BM='+basicmotor+', TM='+totalmotor);
|
||||||
|
|
||||||
|
// Step Chi rotors
|
||||||
|
for (let r=0; r<5; r++) {
|
||||||
|
this.Xptr[r]++;
|
||||||
|
if (this.Xptr[r] > ROTOR_SIZES["X"+(r+1)]) this.Xptr[r] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totalmotor) {
|
||||||
|
//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.Mptr[0] > ROTOR_SIZES.M37) this.Mptr[0]=1;
|
||||||
|
|
||||||
|
// Always move M61 rotor
|
||||||
|
this.Mptr[1]++;
|
||||||
|
if (this.Mptr[1] > ROTOR_SIZES.M61) this.Mptr[1]=1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Q bus inputs
|
||||||
|
*/
|
||||||
|
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') {
|
||||||
|
// direct Z
|
||||||
|
this.Qbits = this.Zbits;
|
||||||
|
//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++) {
|
||||||
|
this.Qbits[b] = this.Zbits[b] ^ this.ZbitsOneBack[b];
|
||||||
|
}
|
||||||
|
|
||||||
|
//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("")]+']');
|
||||||
|
|
||||||
|
// Xbits - the current Chi wheel bits
|
||||||
|
//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 == "Χ") {
|
||||||
|
// 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 == "ΔΧ") {
|
||||||
|
// delta X
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.XbitsOneBack = this.Xbits.slice();
|
||||||
|
//console.log('setting XbitsOneBack to '+this.Xbits);
|
||||||
|
|
||||||
|
//console.log('Zin+Xin::Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']');
|
||||||
|
|
||||||
|
// Sbits - the current Psi wheel bits
|
||||||
|
//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 == "Ψ") {
|
||||||
|
// 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 == "ΔΨ") {
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.SbitsOneBack = this.Sbits.slice();
|
||||||
|
|
||||||
|
//console.log('Q bus now '+this.Qbits+'['+this.REVERSE_ITAlookup[this.Qbits.join("")]+']');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditional impulse Q bus section
|
||||||
|
*/
|
||||||
|
runQbusProcessingConditional() {
|
||||||
|
let 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];
|
||||||
|
if (row.Counter !== "") {
|
||||||
|
let result = true;
|
||||||
|
let 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;
|
||||||
|
}
|
||||||
|
// Check for NOT switch
|
||||||
|
if (row.Negate) result = !result;
|
||||||
|
|
||||||
|
// AND each row to get final result
|
||||||
|
if (cnt[cPnt] == -1) {
|
||||||
|
cnt[cPnt] = result;
|
||||||
|
} else if (result==0) {
|
||||||
|
cnt[cPnt] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negate the whole column, this allows A OR B by doing NOT(NOT A AND NOT B)
|
||||||
|
for (let c=0;c<5;c++) {
|
||||||
|
if (this.qbusswitches.condNegateAll) cnt[c] = !cnt[c];
|
||||||
|
|
||||||
|
if (cnt[c]==1) this.allCounters[c]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Addition of impulses Q bus section
|
||||||
|
*/
|
||||||
|
runQbusProcessingAddition() {
|
||||||
|
let row = this.qbusswitches.addition[0];
|
||||||
|
const Qswitch = row.Qswitches.slice();
|
||||||
|
if (row.C1) {
|
||||||
|
let addition = 0;
|
||||||
|
for (let s=0;s<5;s++) {
|
||||||
|
// XOR addition
|
||||||
|
if (Qswitch[s]) {
|
||||||
|
addition = addition ^ this.Qbits[s];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const equals = (row.Equals==""?-1:(row.Equals=="."?0:1));
|
||||||
|
if (addition == equals) {
|
||||||
|
this.allCounters[0]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//console.log("counter1="+this.allCounters[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise thyratron rings
|
||||||
|
* These hold the pattern of 1s & 0s for each rotor on banks of thyraton GT1C valves which act as a one-bit store.
|
||||||
|
*/
|
||||||
|
initThyratrons(pattern) {
|
||||||
|
this.rings = {
|
||||||
|
X: {
|
||||||
|
1: INIT_PATTERNS[pattern].X[1].slice().reverse(),
|
||||||
|
2: INIT_PATTERNS[pattern].X[2].slice().reverse(),
|
||||||
|
3: INIT_PATTERNS[pattern].X[3].slice().reverse(),
|
||||||
|
4: INIT_PATTERNS[pattern].X[4].slice().reverse(),
|
||||||
|
5: INIT_PATTERNS[pattern].X[5].slice().reverse()
|
||||||
|
},
|
||||||
|
M: {
|
||||||
|
1: INIT_PATTERNS[pattern].M[1].slice().reverse(),
|
||||||
|
2: INIT_PATTERNS[pattern].M[2].slice().reverse(),
|
||||||
|
},
|
||||||
|
S: {
|
||||||
|
1: INIT_PATTERNS[pattern].S[1].slice().reverse(),
|
||||||
|
2: INIT_PATTERNS[pattern].S[2].slice().reverse(),
|
||||||
|
3: INIT_PATTERNS[pattern].S[3].slice().reverse(),
|
||||||
|
4: INIT_PATTERNS[pattern].S[4].slice().reverse(),
|
||||||
|
5: INIT_PATTERNS[pattern].S[5].slice().reverse()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Left Pad number
|
||||||
|
*/
|
||||||
|
leftPad(number, targetLength) {
|
||||||
|
let output = number + "";
|
||||||
|
while (output.length < targetLength) {
|
||||||
|
output = "0" + output;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read argument bus switches X & . and convert to 1 & 0
|
||||||
|
*/
|
||||||
|
readBusSwitches(row) {
|
||||||
|
let 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;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
155
src/core/lib/Lorenz.mjs
Normal file
155
src/core/lib/Lorenz.mjs
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/**
|
||||||
|
* Resources required by the Lorenz SZ40/42 and Colossus
|
||||||
|
*
|
||||||
|
* @author VirtualColossus
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
|
export const SWITCHES = [
|
||||||
|
{name: "Up (.)", value: "."},
|
||||||
|
{name: "Centre", value: ""},
|
||||||
|
{name: "Down (x)", value: "x"}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const ITA2_TABLE = {
|
||||||
|
"A": "11000",
|
||||||
|
"B": "10011",
|
||||||
|
"C": "01110",
|
||||||
|
"D": "10010",
|
||||||
|
"E": "10000",
|
||||||
|
"F": "10110",
|
||||||
|
"G": "01011",
|
||||||
|
"H": "00101",
|
||||||
|
"I": "01100",
|
||||||
|
"J": "11010",
|
||||||
|
"K": "11110",
|
||||||
|
"L": "01001",
|
||||||
|
"M": "00111",
|
||||||
|
"N": "00110",
|
||||||
|
"O": "00011",
|
||||||
|
"P": "01101",
|
||||||
|
"Q": "11101",
|
||||||
|
"R": "01010",
|
||||||
|
"S": "10100",
|
||||||
|
"T": "00001",
|
||||||
|
"U": "11100",
|
||||||
|
"V": "01111",
|
||||||
|
"W": "11001",
|
||||||
|
"X": "10111",
|
||||||
|
"Y": "10101",
|
||||||
|
"Z": "10001",
|
||||||
|
"3": "00010",
|
||||||
|
"4": "01000",
|
||||||
|
"9": "00100",
|
||||||
|
"/": "00000",
|
||||||
|
" ": "00100",
|
||||||
|
".": "00100",
|
||||||
|
"8": "11111",
|
||||||
|
"5": "11011",
|
||||||
|
"-": "11111",
|
||||||
|
"+": "11011"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ROTOR_SIZES = {
|
||||||
|
S1: 43,
|
||||||
|
S2: 47,
|
||||||
|
S3: 51,
|
||||||
|
S4: 53,
|
||||||
|
S5: 59,
|
||||||
|
M37: 37,
|
||||||
|
M61: 61,
|
||||||
|
X1: 41,
|
||||||
|
X2: 31,
|
||||||
|
X3: 29,
|
||||||
|
X4: 26,
|
||||||
|
X5: 23
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial rotor patterns
|
||||||
|
*/
|
||||||
|
export const INIT_PATTERNS = {
|
||||||
|
"No Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"KH Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
|
||||||
|
2: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0],
|
||||||
|
3: [0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0],
|
||||||
|
4: [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||||
|
5: [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1],
|
||||||
|
2: [0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
|
||||||
|
3: [0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
|
||||||
|
4: [0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
|
||||||
|
5: [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||||
|
2: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ZMUG Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
|
||||||
|
2: [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0],
|
||||||
|
3: [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0],
|
||||||
|
4: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1],
|
||||||
|
5: [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1],
|
||||||
|
3: [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1],
|
||||||
|
4: [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1],
|
||||||
|
5: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
|
||||||
|
2: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"BREAM Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||||
|
2: [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
|
||||||
|
3: [1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0],
|
||||||
|
4: [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0],
|
||||||
|
5: [0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
|
||||||
|
2: [1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
|
||||||
|
3: [1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||||
|
4: [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1],
|
||||||
|
5: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1],
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
517
src/core/operations/Colossus.mjs
Normal file
517
src/core/operations/Colossus.mjs
Normal file
@ -0,0 +1,517 @@
|
|||||||
|
/**
|
||||||
|
* Emulation of Colossus.
|
||||||
|
*
|
||||||
|
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { ColossusComputer } from "../lib/Colossus.mjs";
|
||||||
|
import { SWITCHES } from "../lib/Lorenz.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colossus operation
|
||||||
|
*/
|
||||||
|
class Colossus extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lorenz constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.name = "Colossus";
|
||||||
|
this.module = "Bletchley";
|
||||||
|
this.description = "Colossus ... ";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Colossus_computer";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "JSON";
|
||||||
|
this.presentType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Input",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Pattern",
|
||||||
|
type: "option",
|
||||||
|
value: ["KH Pattern", "ZMUG Pattern", "BREAM Pattern"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "QBusZ",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "Z", "ΔZ"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "QBusΧ",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "Χ", "ΔΧ"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "QBusΨ",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "Ψ", "ΔΨ"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Limitation",
|
||||||
|
type: "option",
|
||||||
|
value: ["None", "Χ2", "Χ2 + P5", "X2 + Ψ1", "X2 + Ψ1 + P5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "K Rack Option",
|
||||||
|
type: "argSelector",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
name: "Select Program",
|
||||||
|
on: [7],
|
||||||
|
off: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Top Section - Conditional",
|
||||||
|
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
||||||
|
off: [7, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bottom Section - Addition",
|
||||||
|
on: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||||
|
off: [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Advanced",
|
||||||
|
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||||
|
off: [7]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Program to run",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "1+2=. (1+2 Break In, Find X1,X2)", "4=3=/1=2 (Given X1,X2 find X4,X5)", "/,5,U (Count chars to find X3)"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "K Rack: Conditional",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q1",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q2",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q3",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q4",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q5",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Negate",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Counter",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "1", "2", "3", "4", "5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q1",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q2",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q3",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q4",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q5",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Negate",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Counter",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "1", "2", "3", "4", "5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q1",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q2",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q3",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q4",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q5",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Negate",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Counter",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "1", "2", "3", "4", "5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Negate All",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "K Rack: Addition",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q1",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q2",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q3",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q4",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q5",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Equals",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Counter1",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add Negate All",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Total Motor",
|
||||||
|
type: "boolean"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Master Control Panel",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Set Total",
|
||||||
|
type: "number",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fast Step",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Slow Step",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start X1",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start X2",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start X3",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start X4",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start X5",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start M61",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start M37",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start S1",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start S2",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start S3",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start S4",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start S5",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
|
||||||
|
const pattern = args[1];
|
||||||
|
const qbusin = {
|
||||||
|
"Z": args[2],
|
||||||
|
"Chi": args[3],
|
||||||
|
"Psi": args[4],
|
||||||
|
};
|
||||||
|
|
||||||
|
const limitation = args[5];
|
||||||
|
let 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;
|
||||||
|
const limit = {
|
||||||
|
X2: lm[0], S1: lm[1], P5: lm[2]
|
||||||
|
};
|
||||||
|
|
||||||
|
const KRackOpt = args[6];
|
||||||
|
const setProgram = args[7];
|
||||||
|
|
||||||
|
if (KRackOpt === "Select Program" && setProgram !== "") {
|
||||||
|
args = this.selectProgram(setProgram, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Q1,Q2,Q3,Q4,Q5,negate,counter1
|
||||||
|
const qbusswitches = {
|
||||||
|
condition: [
|
||||||
|
{Qswitches: [args[9], args[10], args[11], args[12], args[13]], Negate: args[14], Counter: args[15]},
|
||||||
|
{Qswitches: [args[16], args[17], args[18], args[19], args[20]], Negate: args[21], Counter: args[22]},
|
||||||
|
{Qswitches: [args[23], args[24], args[25], args[26], args[27]], Negate: args[28], Counter: args[29]}
|
||||||
|
],
|
||||||
|
condNegateAll: args[30],
|
||||||
|
addition: [
|
||||||
|
{Qswitches: [args[32], args[33], args[34], args[35], args[36]], Equals: args[37], C1: args[38]}
|
||||||
|
],
|
||||||
|
addNegateAll: args[39],
|
||||||
|
totalMotor: args[40]
|
||||||
|
};
|
||||||
|
|
||||||
|
const settotal = args[42];
|
||||||
|
|
||||||
|
// null|fast|slow for each of S1-5,M1-2,X1-5
|
||||||
|
const control = {
|
||||||
|
fast: args[43],
|
||||||
|
slow: args[44]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start positions
|
||||||
|
const starts = {
|
||||||
|
X1: args[45], X2: args[46], X3: args[47], X4: args[48], X5: args[49],
|
||||||
|
M61: args[50], M37: args[51],
|
||||||
|
S1: args[52], S2: args[53], S3: args[54], S4: args[55], S5: args[56]
|
||||||
|
};
|
||||||
|
|
||||||
|
const colossus = new ColossusComputer(input, pattern, qbusin, qbusswitches, control, starts, settotal, limit);
|
||||||
|
const result = colossus.run();
|
||||||
|
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select Program
|
||||||
|
*/
|
||||||
|
selectProgram(progname, args) {
|
||||||
|
|
||||||
|
// Bill Tutte's 1+2 Break In
|
||||||
|
if(progname == "1+2=. (1+2 Break In, Find X1,X2)") {
|
||||||
|
// Clear any other counters
|
||||||
|
args[15] = ""; // Conditional R1
|
||||||
|
args[22] = ""; // Conditional R2
|
||||||
|
args[29] = ""; // Conditional R3
|
||||||
|
// Set Add Q1+Q2=. into Counter 1
|
||||||
|
args[32] = true;
|
||||||
|
args[33] = true;
|
||||||
|
args[34] = false;
|
||||||
|
args[35] = false;
|
||||||
|
args[36] = false;
|
||||||
|
args[37] = ".";
|
||||||
|
args[38] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4=3=/1=2 : Find X4 & X5 where X1 & X2 are known
|
||||||
|
if(progname == "4=3=/1=2 (Given X1,X2 find X4,X5)") {
|
||||||
|
// Set Conditional R1 : Match NOT ..?.. into counter 1
|
||||||
|
args[9] = ".";
|
||||||
|
args[10] = ".";
|
||||||
|
args[11] = "";
|
||||||
|
args[12] = ".";
|
||||||
|
args[13] = ".";
|
||||||
|
args[14] = true;
|
||||||
|
args[15] = "1";
|
||||||
|
// Set Conditional R2 : AND Match NOT xx?xx into counter 1
|
||||||
|
args[16] = "x";
|
||||||
|
args[17] = "x";
|
||||||
|
args[18] = "";
|
||||||
|
args[19] = "x";
|
||||||
|
args[20] = "x";
|
||||||
|
args[21] = true;
|
||||||
|
args[22] = "1";
|
||||||
|
// clear Conditional R3
|
||||||
|
args[29] = "";
|
||||||
|
// Negate result, giving NOT(NOT Q1 AND NOT Q2) which is equivalent to Q1 OR Q2
|
||||||
|
args[30] = true;
|
||||||
|
// Clear Addition row counter
|
||||||
|
args[38] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /,5,U : Count number of matches of /, 5 & U 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] = ".";
|
||||||
|
args[11] = ".";
|
||||||
|
args[12] = ".";
|
||||||
|
args[13] = ".";
|
||||||
|
args[14] = false;
|
||||||
|
args[15] = "1";
|
||||||
|
// Set Conditional R2 : Match 5 char, ITA2 = xx.xx into counter 2
|
||||||
|
args[16] = "x";
|
||||||
|
args[17] = "x";
|
||||||
|
args[18] = ".";
|
||||||
|
args[19] = "x";
|
||||||
|
args[20] = "x";
|
||||||
|
args[21] = false;
|
||||||
|
args[22] = "2";
|
||||||
|
// Set Conditional R3 : Match U char, ITA2 = xxx.. into counter 3
|
||||||
|
args[23] = "x";
|
||||||
|
args[24] = "x";
|
||||||
|
args[25] = "x";
|
||||||
|
args[26] = ".";
|
||||||
|
args[27] = ".";
|
||||||
|
args[28] = false;
|
||||||
|
args[29] = "3";
|
||||||
|
// Clear Negate result
|
||||||
|
args[30] = false;
|
||||||
|
// Clear Addition row counter
|
||||||
|
args[38] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays Colossus results in an HTML table
|
||||||
|
*
|
||||||
|
* @param {Object} output
|
||||||
|
* @param {Object[]} output.counters
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
present(output) {
|
||||||
|
console.log("output="+ typeof(output));
|
||||||
|
console.log("counters="+ typeof(output.counters));
|
||||||
|
|
||||||
|
let html = "Colossus Printer\n\n";
|
||||||
|
html += output.printout + "\n\n";
|
||||||
|
html += "Colossus Counters\n\n";
|
||||||
|
html += "<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>C1</th> <th>C2</th> <th>C3</th> <th>C4</th> <th>C5</th></tr>\n";
|
||||||
|
html += "<tr>";
|
||||||
|
for (const ct of output.counters) {
|
||||||
|
html += `<td>${ct}</td>\n`;
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
html += "</table>";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Colossus;
|
Loading…
Reference in New Issue
Block a user