@ondoher/enigma 0.1.7 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +454 -93
- package/bin/enigma.js +0 -0
- package/jsconfig.json +3 -0
- package/lib/enigma/Encoder.js +12 -13
- package/lib/enigma/Enigma.js +68 -50
- package/lib/enigma/EnigmaTypes.d.ts +101 -0
- package/lib/enigma/EntryDisc.js +13 -5
- package/lib/enigma/Inventory.js +26 -6
- package/lib/enigma/PlugBoard.js +20 -17
- package/lib/enigma/Reflector.js +4 -11
- package/lib/enigma/Rotor.js +5 -35
- package/lib/enigma/standardInventory.js +2 -2
- package/lib/enigma/tests/EnigmaSpec.js +0 -5
- package/lib/enigma/tests/PlugBoardSpec.js +15 -14
- package/lib/enigma/tests/RotorSpec.js +1 -1
- package/lib/generator/CodeBook.js +180 -0
- package/lib/generator/Generator.js +94 -386
- package/lib/generator/GeneratorTypes.d.ts +100 -0
- package/lib/generator/index.js +2 -0
- package/lib/utils/Random.js +236 -0
- package/package.json +10 -3
package/bin/enigma.js
ADDED
|
File without changes
|
package/jsconfig.json
ADDED
package/lib/enigma/Encoder.js
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
import { STANDARD_ALPHABET } from "./consts.js";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* This is the listener for Enigma and component events
|
|
5
|
-
* @callback Listener
|
|
6
|
-
* @param {String} event a string that identifies the event being fired
|
|
7
|
-
* @param {String} name the name of the component firing the event
|
|
8
|
-
* @param {String} message a human readable description of the evebnt details
|
|
9
|
-
* @param {Object} into event specific data for the event
|
|
10
|
-
*/
|
|
11
3
|
|
|
12
4
|
/**
|
|
13
5
|
* This is the base class for an encoder. The default implementation of the
|
|
14
6
|
* encode method is to return the input as the output
|
|
15
7
|
*/
|
|
16
8
|
export default class Encoder {
|
|
17
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Constructor for the base encoder
|
|
11
|
+
*
|
|
12
|
+
* @param {string} name
|
|
13
|
+
* @param {EncoderSetup} settings
|
|
14
|
+
*/
|
|
15
|
+
constructor(name, settings) {
|
|
16
|
+
let {cb, alphabet = STANDARD_ALPHABET} = settings;
|
|
18
17
|
this.name = name;
|
|
19
18
|
this.alphabet = alphabet;
|
|
20
19
|
this.contactCount = alphabet.length;
|
|
@@ -48,7 +47,7 @@ export default class Encoder {
|
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
/**
|
|
51
|
-
* given an existing connection map from
|
|
50
|
+
* given an existing connection map from input to out put, create a new map
|
|
52
51
|
* that has the connections going in the other direction, output to input.
|
|
53
52
|
*
|
|
54
53
|
* @param {Array.<Number>} map connection map
|
|
@@ -69,13 +68,13 @@ export default class Encoder {
|
|
|
69
68
|
* the given direction The default encode method just passes the input value
|
|
70
69
|
* through
|
|
71
70
|
*
|
|
72
|
-
* @param {
|
|
71
|
+
* @param {Direction} _direction either right for moving towards the reflector
|
|
73
72
|
* or left if moving back
|
|
74
73
|
* @param {Number} input the specific connection receiving an input
|
|
75
74
|
*
|
|
76
75
|
* @returns {Number} The translated output connector number
|
|
77
76
|
*/
|
|
78
|
-
encode(
|
|
77
|
+
encode(_direction, input) {
|
|
79
78
|
return input;
|
|
80
79
|
}
|
|
81
80
|
|
|
@@ -93,7 +92,7 @@ export default class Encoder {
|
|
|
93
92
|
* Call this method to call the event listener
|
|
94
93
|
*
|
|
95
94
|
* @param {String} name the name of the event
|
|
96
|
-
* @param {
|
|
95
|
+
* @param {unknown[]} rest the parameters to pass to the callback
|
|
97
96
|
*/
|
|
98
97
|
fire(name, ...rest) {
|
|
99
98
|
if (this.cb) this.cb(name, ...rest);
|
package/lib/enigma/Enigma.js
CHANGED
|
@@ -4,40 +4,44 @@ import Rotor from "./Rotor.js";
|
|
|
4
4
|
import Reflector from "./Reflector.js";
|
|
5
5
|
import inventory from './Inventory.js'
|
|
6
6
|
import { STANDARD_ALPHABET } from "./consts.js";
|
|
7
|
+
import Encoder from "./Encoder.js";
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Construct this class to get a new instance of the Enigma. Many of the
|
|
10
11
|
* parameters to the constructor and the config method reference the names of
|
|
11
|
-
* standard Enigma parts. These are
|
|
12
|
+
* standard Enigma parts. These are retrieved from the Inventory instance
|
|
12
13
|
*/
|
|
13
14
|
export default class Enigma {
|
|
14
15
|
/**
|
|
15
16
|
* The constructor for the Enigma. This represents the unconfigurable
|
|
16
17
|
* settings of the device.
|
|
17
18
|
*
|
|
18
|
-
* @param {
|
|
19
|
-
* @property {String} [entryDisc] the name of entry disc in the inventory
|
|
20
|
-
* this defaults 'default'
|
|
21
|
-
* @param {String} reflector specifies one of possible reflectors, the
|
|
22
|
-
* predefined reflectors are A, B, C, Thin-B and Thin-C
|
|
23
|
-
* @param {String} [alphabet] the alphabet used by the system, usually just
|
|
24
|
-
* the uppercase latin letters
|
|
19
|
+
* @param {EnigmaSetup} settings
|
|
25
20
|
*/
|
|
26
21
|
constructor(settings) {
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
let {entryDisc = 'default', reflector, alphabet = STANDARD_ALPHABET, model = "Enigma"} = settings;
|
|
23
|
+
let entryDiscSettings = inventory.getEntryDisc(entryDisc)
|
|
29
24
|
|
|
30
|
-
|
|
25
|
+
let reflectorSettings = inventory.getReflector(reflector)
|
|
31
26
|
this.alphabet = alphabet;
|
|
32
27
|
this.plugboard = new PlugBoard('plugboard', {});
|
|
33
28
|
this.entryDisc = new EntryDisc('entry-disc', entryDiscSettings);
|
|
34
29
|
this.reflector = new Reflector('reflector', reflectorSettings)
|
|
35
30
|
this.length = alphabet.length;
|
|
31
|
+
/** @type {Rotor[]} */
|
|
32
|
+
this._rotors = [];
|
|
33
|
+
/** @type {{[rotor: number]: boolean}} */
|
|
34
|
+
this.pending = [];
|
|
35
|
+
this.name = model;
|
|
36
|
+
/** @type {Encoder[]} */
|
|
37
|
+
this.encoders = [];
|
|
38
|
+
/**@type {SimplifiedConfiguration & {reflector: string}} */
|
|
39
|
+
this._configuration = {reflector}
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
/**
|
|
39
43
|
* Call this method to normalize a connector number to be within the
|
|
40
|
-
* the length of the
|
|
44
|
+
* the length of the current alphabet
|
|
41
45
|
*
|
|
42
46
|
* @param {Number} connector the number to be normalized
|
|
43
47
|
*
|
|
@@ -50,43 +54,47 @@ export default class Enigma {
|
|
|
50
54
|
return connector;
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
/**
|
|
58
|
+
* the configured rotors
|
|
59
|
+
*
|
|
60
|
+
* @return {Rotor[]}
|
|
61
|
+
*/
|
|
62
|
+
get rotors() {
|
|
63
|
+
return this._rotors;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @returns {SimplifiedConfiguration & {reflector: string}}
|
|
68
|
+
*/
|
|
69
|
+
get configuration() {
|
|
70
|
+
return this._configuration;
|
|
71
|
+
}
|
|
72
|
+
|
|
53
73
|
/**
|
|
54
74
|
* Configure the Enigma for encoding.
|
|
55
75
|
*
|
|
56
|
-
* @param {
|
|
57
|
-
* represent the aspects of the Enigma that can can change for daily
|
|
76
|
+
* @param {EnigmaConfiguration} settings - the configuration of the Enigma.
|
|
77
|
+
* These settings represent the aspects of the Enigma that can can change for daily
|
|
58
78
|
* configuration.
|
|
59
|
-
* @property {Array.<String>|String} [plugs] array of strings with each
|
|
60
|
-
* element being a pair of letters from the alphabet that are being swapped
|
|
61
|
-
* on the plug board
|
|
62
|
-
* @property {Array.<String>} rotors the array of installed rotors. The
|
|
63
|
-
* order here is signicant and is given in the left to right direction.
|
|
64
|
-
* This means that last name in this list is the first rotor used in the
|
|
65
|
-
* forward direction and last used in the backward direction. Each element
|
|
66
|
-
* is the name of the rotor to use in the corresponding position. Stepping
|
|
67
|
-
* stops at the first fixed rotor
|
|
68
|
-
* @property {String|Array<Number>} [ringSettings] each letter in this
|
|
69
|
-
* string represents the offset of the key settings from the rotor start
|
|
70
|
-
* position. If it is an array, then each value is the one based key
|
|
71
|
-
* setting for the related rotor,
|
|
72
79
|
*/
|
|
73
80
|
configure(settings) {
|
|
74
|
-
|
|
81
|
+
let { rotors, ringSettings = [], plugs = [] } = settings;
|
|
75
82
|
|
|
76
83
|
// make copies of these configurations so that we don't change the
|
|
77
84
|
// values from the caller, which in JavaScript are passed by reference.
|
|
78
|
-
|
|
79
|
-
ringSettings =
|
|
85
|
+
let useRotors = structuredClone(rotors);
|
|
86
|
+
ringSettings = structuredClone(ringSettings);
|
|
80
87
|
|
|
81
88
|
// the rotors are given in the left to right direction, but are actually
|
|
82
89
|
// used in the right to left direction. So, here we reverse them
|
|
83
|
-
|
|
90
|
+
useRotors = useRotors.reverse();
|
|
84
91
|
|
|
85
|
-
this.plugboard.configure(
|
|
92
|
+
this.plugboard.configure(plugs)
|
|
86
93
|
|
|
87
|
-
|
|
94
|
+
/** @type {number[]} */
|
|
95
|
+
let ringOffsets = []
|
|
88
96
|
|
|
89
|
-
// because the rotors are
|
|
97
|
+
// because the rotors are specified in the reverse other they are used,
|
|
90
98
|
// we have to do the same for the ringSettings.
|
|
91
99
|
if (Array.isArray(ringSettings)) {
|
|
92
100
|
ringSettings = ringSettings.reverse();
|
|
@@ -97,19 +105,25 @@ export default class Enigma {
|
|
|
97
105
|
ringOffsets.push(this.normalize(offset - 1))
|
|
98
106
|
}, this);
|
|
99
107
|
} else {
|
|
100
|
-
|
|
108
|
+
let letters = [...ringSettings];
|
|
101
109
|
letters = letters.reverse();
|
|
102
110
|
letters.forEach(function(letter) {
|
|
103
|
-
|
|
111
|
+
let offset = this.alphabet.indexOf(letter);
|
|
104
112
|
ringOffsets.push(offset);
|
|
105
113
|
}, this)
|
|
106
114
|
}
|
|
107
115
|
|
|
108
|
-
this.
|
|
116
|
+
this._rotors = useRotors.map(function(name, idx) {
|
|
109
117
|
return new Rotor(`rotor-${name}`, {...inventory.getRotor(name), alphabet: this.alphabet, ringSetting: ringOffsets[idx], cb: this.cb});
|
|
110
118
|
}, this);
|
|
111
119
|
|
|
112
120
|
this.encoders = [this.plugboard, this.entryDisc, ...this.rotors];
|
|
121
|
+
|
|
122
|
+
this._configuration = {...this._configuration,
|
|
123
|
+
rotors,
|
|
124
|
+
ringOffsets,
|
|
125
|
+
plugs: this.plugboard.plugs
|
|
126
|
+
}
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
/**
|
|
@@ -117,7 +131,7 @@ export default class Enigma {
|
|
|
117
131
|
* stepping between all rotors
|
|
118
132
|
*/
|
|
119
133
|
step() {
|
|
120
|
-
this.
|
|
134
|
+
this._rotors.forEach(function(rotor, idx) {
|
|
121
135
|
if (rotor.isFixed()) return;
|
|
122
136
|
|
|
123
137
|
// This is the double stepping. Only do this for the middle rotor
|
|
@@ -138,21 +152,25 @@ export default class Enigma {
|
|
|
138
152
|
/**
|
|
139
153
|
* Call this method to set the starting rotation for the messages to encrypt
|
|
140
154
|
*
|
|
141
|
-
* @param {
|
|
155
|
+
* @param {number[]|string} setup - length of the string or the array
|
|
142
156
|
* should match the number of rotors and are given left to right. If start
|
|
143
157
|
* is a string then the letters of the string specify the start value seen
|
|
144
158
|
* in the window for the corresponding rotor. If it is an array then each
|
|
145
159
|
* number will be the one-based rotation.
|
|
146
160
|
*/
|
|
147
|
-
setStart(
|
|
148
|
-
|
|
149
|
-
|
|
161
|
+
setStart(setup) {
|
|
162
|
+
let start = '';
|
|
163
|
+
if (Array.isArray(setup)) {
|
|
164
|
+
let charArray = setup.map(function(number) {
|
|
150
165
|
number--;
|
|
151
166
|
return this.alphabet[number];
|
|
152
167
|
}, this);
|
|
153
168
|
|
|
154
169
|
start = charArray.join('');
|
|
170
|
+
} else {
|
|
171
|
+
start = setup;
|
|
155
172
|
}
|
|
173
|
+
|
|
156
174
|
start = [...start].reverse();
|
|
157
175
|
|
|
158
176
|
// reset the rotation pending state
|
|
@@ -168,13 +186,13 @@ export default class Enigma {
|
|
|
168
186
|
* the encoded letter
|
|
169
187
|
*
|
|
170
188
|
* @param {String} letter the key pressed
|
|
171
|
-
* @returns {String} the encoded letter
|
|
189
|
+
* @returns {String | undefined} the encoded letter
|
|
172
190
|
*/
|
|
173
191
|
keyPress(letter) {
|
|
174
192
|
letter = letter.toUpperCase();
|
|
175
193
|
if (letter.length !== 1 || this.alphabet.indexOf(letter) === -1) {
|
|
176
194
|
if (letter !== ' ')
|
|
177
|
-
console.warn(`
|
|
195
|
+
console.warn(`Unexpected character ${letter}`);
|
|
178
196
|
return;
|
|
179
197
|
}
|
|
180
198
|
|
|
@@ -182,13 +200,13 @@ export default class Enigma {
|
|
|
182
200
|
this.step();
|
|
183
201
|
|
|
184
202
|
// encode to the right
|
|
185
|
-
|
|
203
|
+
let connector = this.encoders.reduce(function(connector, encoder, idx) {
|
|
186
204
|
connector = encoder.encode('right', connector);
|
|
187
205
|
return connector;
|
|
188
206
|
}.bind(this), this.alphabet.indexOf(letter));
|
|
189
207
|
|
|
190
208
|
// reflector
|
|
191
|
-
connector = this.reflector.encode('', connector);
|
|
209
|
+
connector = this.reflector.encode('right', connector);
|
|
192
210
|
|
|
193
211
|
// encode to the left
|
|
194
212
|
connector = this.encoders.reduceRight(function(connector, encoder) {
|
|
@@ -204,15 +222,15 @@ export default class Enigma {
|
|
|
204
222
|
/**
|
|
205
223
|
* Call this shortcut method to encode a whole string
|
|
206
224
|
*
|
|
207
|
-
* @param {String} start the starting
|
|
225
|
+
* @param {String} start the starting position for the rotors
|
|
208
226
|
* @param {String} text the text to encode
|
|
209
227
|
*
|
|
210
228
|
* @returns {String} the encoded string.
|
|
211
229
|
*/
|
|
212
230
|
encode(start, text) {
|
|
213
231
|
this.setStart(start)
|
|
214
|
-
|
|
215
|
-
|
|
232
|
+
let letters = [...text];
|
|
233
|
+
let output = letters.map(function(letter) {
|
|
216
234
|
return this.keyPress(letter);
|
|
217
235
|
}, this)
|
|
218
236
|
|
|
@@ -222,7 +240,7 @@ export default class Enigma {
|
|
|
222
240
|
/**
|
|
223
241
|
* Call this method to call the event listener
|
|
224
242
|
*
|
|
225
|
-
* @param {String}
|
|
243
|
+
* @param {String} type the name of the event
|
|
226
244
|
* @param {...any} rest the parameters to pass to the callback
|
|
227
245
|
*/
|
|
228
246
|
fire(type, ...rest) {
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// type Listener = (
|
|
2
|
+
// /** name of the event being fired*/
|
|
3
|
+
// event: string,
|
|
4
|
+
|
|
5
|
+
// /** the name of th component firing the event */
|
|
6
|
+
// name: string,
|
|
7
|
+
|
|
8
|
+
// /** a human readable description of the event */
|
|
9
|
+
// message: string,
|
|
10
|
+
|
|
11
|
+
// /** event specific data */
|
|
12
|
+
// info: object
|
|
13
|
+
|
|
14
|
+
// ) => void;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
type Listener = (...params: unknown[]) => void;
|
|
19
|
+
|
|
20
|
+
interface EncoderSetup {
|
|
21
|
+
/** if specified defines an alternate alphabet for the enigma */
|
|
22
|
+
alphabet?: string;
|
|
23
|
+
|
|
24
|
+
/** if set, specifies a function to be called as the event listener */
|
|
25
|
+
cb?: Listener;
|
|
26
|
+
|
|
27
|
+
/** a string that defines the mapping between the input and output
|
|
28
|
+
* connectors. The index into the string is the input connector and the
|
|
29
|
+
* value of this string at that index is the output connector. For example,
|
|
30
|
+
* 'YRUHQSLDPXNGOKMIEBFZCWVJAT' which is the map for standard reflector B. */
|
|
31
|
+
map?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Defines how the enigma hardware is constructed. These are the settings that
|
|
36
|
+
* cannot be changed
|
|
37
|
+
*/
|
|
38
|
+
interface EnigmaSetup extends EncoderConfiguration {
|
|
39
|
+
/** which entry disc is part of the machine, defaults to "default" */
|
|
40
|
+
entryDisc?: string;
|
|
41
|
+
/** which reflector is part of the machine */
|
|
42
|
+
reflector: string;
|
|
43
|
+
/** Which alphabet is defined for the machine, defaults to A-Z */
|
|
44
|
+
alphabet?: string;
|
|
45
|
+
/** The name of the enigma model, defaults to the string "Enigma" */
|
|
46
|
+
model?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Defines the setup of the plug configuration. It is wither an array of strings
|
|
51
|
+
* or a single string. If it is a string, it must be a space separated list of
|
|
52
|
+
* letter pairs that connects one input letter to another. If it is an array
|
|
53
|
+
* then then each item is a pair of letters to specify how the plugs are connected
|
|
54
|
+
*/
|
|
55
|
+
type Plugs = string | string[];
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* The configuration of the Enigma. These settings represent the aspects of the
|
|
59
|
+
* Enigma that can can change for daily configuration.
|
|
60
|
+
*/
|
|
61
|
+
type EnigmaConfiguration = {
|
|
62
|
+
/** defines how the plugs on the plugboard are configured. Defaults to no
|
|
63
|
+
* plugs */
|
|
64
|
+
plugs?: Plugs;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Array of installed rotors. The order here is significant and is given in
|
|
68
|
+
* the left to right direction. This means that last name in this list
|
|
69
|
+
* is the first rotor used in the forward direction and last used in the
|
|
70
|
+
* backward direction. Each element is the name of the rotor to use in the
|
|
71
|
+
* corresponding position. Stepping stops at the first fixed rotor *
|
|
72
|
+
*/
|
|
73
|
+
rotors: string[];
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Specifies the setup of the ringSettings. This can specify as string of
|
|
77
|
+
* letters or an array of numbers. Each letter in the string is used for the
|
|
78
|
+
* rotor at that index. It's position in the alphabet is the offset for the
|
|
79
|
+
* ring settings. If it is an array of number, each number is the one based
|
|
80
|
+
* offset for the ring settings for the related rotor.
|
|
81
|
+
*/
|
|
82
|
+
ringSettings?: number[] | string;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Defines the setup of a Rotor. These are the unchangeable settings for the
|
|
87
|
+
* rotor
|
|
88
|
+
*/
|
|
89
|
+
interface RotorSetup extends EncoderSetup {
|
|
90
|
+
/** specifies how far forward to offset the outer ring relative to the
|
|
91
|
+
* internal wiring. */
|
|
92
|
+
ringSetting?: number;
|
|
93
|
+
/** specifies the relative* location of where on the rotor turnover will
|
|
94
|
+
* occur. The value is the what would be displayed in the window when
|
|
95
|
+
* turnover happens, expressed as a character. The standard rotors VI-VIII,
|
|
96
|
+
* available in the later model M3 had two turnover locations, M and Z.
|
|
97
|
+
* Provide an empty string when the rotor does not rotate during stepping */
|
|
98
|
+
turnovers?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
type Direction = ("right"|"left")
|
package/lib/enigma/EntryDisc.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { STANDARD_ALPHABET } from './consts.js';
|
|
1
2
|
import Encoder from './Encoder.js';
|
|
2
|
-
import { STANDARD_ALPHABET } from "./consts.js";
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
@@ -8,19 +8,27 @@ import { STANDARD_ALPHABET } from "./consts.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export default class EntryDisc extends Encoder {
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* Constructor for the entry disc.
|
|
12
12
|
*
|
|
13
|
-
* @param {String} name
|
|
14
|
-
* @param {
|
|
13
|
+
* @param {String} name the name of this entry disc
|
|
14
|
+
* @param {EncoderSetup} settings contains the alphabet being used, and the map
|
|
15
15
|
* between input and output contacts
|
|
16
16
|
*/
|
|
17
17
|
constructor(name, settings) {
|
|
18
18
|
super(name, settings);
|
|
19
|
-
var {map} = settings;
|
|
19
|
+
var {map = STANDARD_ALPHABET} = settings;
|
|
20
20
|
this.rightMap = this.makeMap(map);
|
|
21
21
|
this.leftMap = this.makeReverseMap(this.rightMap);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @param {Direction} direction either right for moving towards the reflector
|
|
27
|
+
* or left if moving back
|
|
28
|
+
* @param {Number} input the specific connection receiving an input
|
|
29
|
+
*
|
|
30
|
+
* @returns {Number} The translated output connector number
|
|
31
|
+
*/
|
|
24
32
|
encode(direction, input) {
|
|
25
33
|
var result = direction === 'right' ? this.rightMap[input]: this.leftMap[input];
|
|
26
34
|
var evName = direction === 'right' ? 'encode-right' : 'encode-left';
|
package/lib/enigma/Inventory.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* This is the class used to manage the standard
|
|
2
|
+
* This is the class used to manage the standard inventory of components. An
|
|
3
3
|
* instance of this class is exported as the default of this module
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -9,8 +9,8 @@ class Inventory {
|
|
|
9
9
|
*/
|
|
10
10
|
constructor() {
|
|
11
11
|
this.entryDiscs = {};
|
|
12
|
+
/** @type {{[name: string]: RouterInventorySpec}}*/
|
|
12
13
|
this.rotors = {};
|
|
13
|
-
this.fixedRotors = {};
|
|
14
14
|
this.reflectors = {};
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -69,7 +69,7 @@ class Inventory {
|
|
|
69
69
|
* @param {String} name the name of the rotor as it was added to the
|
|
70
70
|
* inventory.
|
|
71
71
|
*
|
|
72
|
-
* @returns {Object} the rotor
|
|
72
|
+
* @returns {Object} the rotor definition
|
|
73
73
|
* @property {String} map the connection map for the rotor
|
|
74
74
|
* @property {String} turnovers the locations where turnovers happen
|
|
75
75
|
*/
|
|
@@ -104,10 +104,30 @@ class Inventory {
|
|
|
104
104
|
/**
|
|
105
105
|
* Call this method to get the names of all the rotors in the inventory
|
|
106
106
|
*
|
|
107
|
-
* @
|
|
107
|
+
* @param {boolean} [fixed] - if specified it returns only the names of
|
|
108
|
+
* routers filtered on if they are fixed or not, otherwise it returns all
|
|
109
|
+
*
|
|
110
|
+
* @returns {string[]} the names of the rotors
|
|
108
111
|
*/
|
|
109
|
-
getRotorNames() {
|
|
110
|
-
|
|
112
|
+
getRotorNames(fixed) {
|
|
113
|
+
if (fixed === undefined) {
|
|
114
|
+
return Object.keys(this.rotors);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let entries = Object.entries(this.rotors);
|
|
118
|
+
|
|
119
|
+
entries = entries.filter(([_name, rotor]) => {
|
|
120
|
+
if (rotor.turnovers === '' && fixed) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
if (rotor.turnovers !== '' && !fixed) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return false;
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
return entries.map(([name, _router]) => name);
|
|
111
131
|
}
|
|
112
132
|
}
|
|
113
133
|
|
package/lib/enigma/PlugBoard.js
CHANGED
|
@@ -10,7 +10,7 @@ export default class PlugBoard extends Encoder {
|
|
|
10
10
|
* Constructor for the plugboard.
|
|
11
11
|
*
|
|
12
12
|
* @param {String} name the name for the plugboard, defaults to 'plugboard'
|
|
13
|
-
* @param {
|
|
13
|
+
* @param {EncoderSetup} [settings] the settings for the plugboard. Only needed if
|
|
14
14
|
* using an alternate alphabet
|
|
15
15
|
*/
|
|
16
16
|
constructor(name = 'plugboard', settings = {}) {
|
|
@@ -19,36 +19,38 @@ export default class PlugBoard extends Encoder {
|
|
|
19
19
|
var {alphabet = STANDARD_ALPHABET, map} = settings;
|
|
20
20
|
this.alphabet = alphabet;
|
|
21
21
|
this.map = map || alphabet;
|
|
22
|
+
this.rightMap = [];
|
|
23
|
+
this.leftMap = [];
|
|
24
|
+
this.plugs = '';
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
/**
|
|
25
28
|
* Call this method to configure the plug board. This will be used to
|
|
26
29
|
* provide the plug connections
|
|
27
30
|
*
|
|
28
|
-
* @param {
|
|
31
|
+
* @param {Plugs} plugs the configuration options for the plug
|
|
29
32
|
* board
|
|
30
|
-
* @property {Array.<String>|String} [plugs] either an array of strings or a
|
|
31
|
-
* single string. If it is a string, it must be a space separated list of
|
|
32
|
-
* letter pairs that connects one input letter to another. If it is an
|
|
33
|
-
* array then then each item is a pair of letters to specify how the plugs
|
|
34
|
-
* are connected
|
|
35
33
|
*/
|
|
36
|
-
configure(
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
configure(plugs = []) {
|
|
35
|
+
let map = this.map;
|
|
36
|
+
/** @type {string[]} */
|
|
39
37
|
|
|
40
|
-
if (typeof plugs === 'string')
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
if (typeof plugs === 'string') {
|
|
39
|
+
plugs = plugs.split(' ');
|
|
40
|
+
}
|
|
41
|
+
plugs.forEach((plug) => {
|
|
42
|
+
let firstIdx = this.alphabet.indexOf(plug[0]);
|
|
43
|
+
let secondIdx = this.alphabet.indexOf(plug[1]);
|
|
44
|
+
let first = map[firstIdx];
|
|
45
|
+
let second = map[secondIdx];
|
|
46
46
|
map = map.slice(0, firstIdx) + second + map.slice(firstIdx + 1);
|
|
47
47
|
map = map.slice(0, secondIdx) + first + map.slice(secondIdx + 1);
|
|
48
|
-
}
|
|
48
|
+
})
|
|
49
49
|
|
|
50
50
|
this.rightMap = this.makeMap(map);
|
|
51
51
|
this.leftMap = this.makeReverseMap(this.rightMap);
|
|
52
|
+
|
|
53
|
+
this.plugs = plugs.join(' ');
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
/**
|
|
@@ -69,6 +71,7 @@ export default class PlugBoard extends Encoder {
|
|
|
69
71
|
output: result,
|
|
70
72
|
}
|
|
71
73
|
);
|
|
74
|
+
|
|
72
75
|
return result;
|
|
73
76
|
}
|
|
74
77
|
}
|
package/lib/enigma/Reflector.js
CHANGED
|
@@ -10,18 +10,11 @@ export default class Reflector extends Encoder {
|
|
|
10
10
|
* constructor for the reflector class.
|
|
11
11
|
*
|
|
12
12
|
* @param {String} name the name of the reflector instance
|
|
13
|
-
* @param {
|
|
14
|
-
* @property {String} [alphabet] a string of letters that are an alternative
|
|
15
|
-
* to the standard A-Z. Defaults to A-Z
|
|
16
|
-
* @property {String} map a string that defines the mapping between the
|
|
17
|
-
* input and output connectors. The index into the string is the input
|
|
18
|
-
* connector and the value of this string at that index is the output
|
|
19
|
-
* connector. For example, 'YRUHQSLDPXNGOKMIEBFZCWVJAT' which is the map for
|
|
20
|
-
* standard reflector B.
|
|
13
|
+
* @param {EncoderSetup} settings The definition of the reflector
|
|
21
14
|
*/
|
|
22
15
|
constructor(name, settings) {
|
|
23
16
|
super(name, settings);
|
|
24
|
-
var {map} = settings;
|
|
17
|
+
var {map = STANDARD_ALPHABET} = settings;
|
|
25
18
|
|
|
26
19
|
this.map = this.makeMap(map);
|
|
27
20
|
}
|
|
@@ -31,13 +24,13 @@ export default class Reflector extends Encoder {
|
|
|
31
24
|
* the point where direction changes this does not have a distinction
|
|
32
25
|
* between a left and right signal path.
|
|
33
26
|
*
|
|
34
|
-
* @param {
|
|
27
|
+
* @param {Direction} _direction since this is the point where signal direction
|
|
35
28
|
* changes from right to left this parameter is not used.
|
|
36
29
|
* @param {Number} input this is the input connector
|
|
37
30
|
*
|
|
38
31
|
* @returns {Number} the mapped output connector
|
|
39
32
|
*/
|
|
40
|
-
encode(
|
|
33
|
+
encode(_direction, input) {
|
|
41
34
|
var result = this.map[input];
|
|
42
35
|
this.fire('encode', this.name,
|
|
43
36
|
`encode ${this.name} ${input} ${result}`,
|