Files
enigma-machine/src/machine.ts
2025-07-01 17:28:34 -07:00

85 lines
2.0 KiB
TypeScript

import {
buildReflectors,
buildRotors,
ReflectorValues,
RotorValues,
} from "./loadComponentData";
import { Plugboard } from "./plugboard";
import { Rotor } from "./rotors";
import { checkCharacter } from "./validation";
const rotors = buildRotors("rotors.csv");
const reflectors = buildReflectors("reflectors.csv");
export class Machine {
plugboard: Plugboard;
reflector: ReflectorValues;
rotors: Rotor[];
constructor(reflector: string, first: string, second: string, third: string) {
this.plugboard = new Plugboard();
this.reflector = getComponent(reflectors, reflector);
this.rotors = [];
this.rotors.push(getRotor(getComponent(rotors, first)));
this.rotors.push(getRotor(getComponent(rotors, second)));
this.rotors.push(getRotor(getComponent(rotors, third)));
}
rings(): string[] {
return this.rotors.map((r) => r.position());
}
stecker(one: string, two: string) {
this.plugboard.stecker(one, two);
}
input(message: string): string {
let output = "";
for (let char of message) {
checkCharacter(char, "character");
let turnover = true;
// plugboard, first pass
let scrambled = this.plugboard.in(char);
// rotors, first pass (in)
for (const rotor of this.rotors) {
if (turnover) {
turnover = rotor.rotate();
}
scrambled = rotor.in(scrambled);
}
// reflector
scrambled = this.reflector.reflector.get(scrambled)!;
// rotors, second pass (out)
for (let i = this.rotors.length - 1; i >= 0; i--) {
const rotor = this.rotors[i];
scrambled = rotor.out(scrambled);
}
// plugboard, second pass
output += this.plugboard.in(scrambled);
}
return output;
}
}
function getRotor({ name, values, turnovers }: RotorValues) {
return new Rotor(name, values, turnovers, 0);
}
function getComponent<T extends { name: string }>(
components: T[],
componentName: string,
): T {
const component = components.find(({ name }) => name === componentName);
if (!component) throw new Error(`unknown reflector: ${component}`);
return component;
}