131 lines
4 KiB
Rust
131 lines
4 KiB
Rust
use crate::*;
|
|
use std::fmt;
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct Rotor {
|
|
pub variant: RotorVariant,
|
|
pub mappings: Vec<Letter>,
|
|
pub position: Letter,
|
|
pub notches: Vec<Letter>,
|
|
}
|
|
|
|
impl Rotor {
|
|
pub fn variant(variant: RotorVariant) -> Self {
|
|
let (mappings, notches) = match variant {
|
|
RotorVariant::Identity => (mappings(IDENTITY), vec![Letter::Z]),
|
|
RotorVariant::I => (mappings(VARIANT_I), vec![Letter::Q]),
|
|
RotorVariant::II => (mappings(VARIANT_II), vec![Letter::E]),
|
|
RotorVariant::III => (mappings(VARIANT_III), vec![Letter::V]),
|
|
RotorVariant::IV => (mappings(VARIANT_IV), vec![Letter::J]),
|
|
RotorVariant::V => (mappings(VARIANT_V), vec![Letter::Z]),
|
|
RotorVariant::VI => (mappings(VARIANT_VI), vec![Letter::Z, Letter::M]),
|
|
RotorVariant::VII => (mappings(VARIANT_VII), vec![Letter::Z, Letter::M]),
|
|
RotorVariant::VIII => (mappings(VARIANT_VIII), vec![Letter::Z, Letter::M]),
|
|
};
|
|
|
|
let position = Letter::A;
|
|
|
|
Rotor {
|
|
variant,
|
|
mappings,
|
|
position,
|
|
notches,
|
|
}
|
|
}
|
|
|
|
pub fn all() -> Vec<Rotor> {
|
|
vec![
|
|
Rotor::variant(RotorVariant::I),
|
|
Rotor::variant(RotorVariant::II),
|
|
Rotor::variant(RotorVariant::III),
|
|
Rotor::variant(RotorVariant::IV),
|
|
Rotor::variant(RotorVariant::V),
|
|
Rotor::variant(RotorVariant::VI),
|
|
Rotor::variant(RotorVariant::VII),
|
|
Rotor::variant(RotorVariant::VIII),
|
|
Rotor::variant(RotorVariant::Identity),
|
|
]
|
|
}
|
|
|
|
pub fn set_position(&mut self, position: Letter) {
|
|
self.position = position;
|
|
}
|
|
|
|
pub fn forwards(&self, letter: Letter) -> Letter {
|
|
*self
|
|
.mappings
|
|
.get((letter + self.position) as usize)
|
|
.expect(&format!("Rotor is missing mapping for a letter: {:?}", letter).to_string())
|
|
- self.position
|
|
}
|
|
|
|
pub fn backwards(&self, letter: Letter) -> Letter {
|
|
Letter::from(
|
|
self.mappings
|
|
.iter()
|
|
.enumerate()
|
|
.filter(|(_, l)| (**l - self.position) == letter)
|
|
.next()
|
|
.unwrap()
|
|
.0,
|
|
) - self.position
|
|
}
|
|
|
|
pub fn at_notch(&self) -> bool {
|
|
self.notches.contains(&self.position)
|
|
}
|
|
|
|
pub fn rotate(&mut self) {
|
|
self.position = Letter::from((self.position as usize + 1) % AMOUNT_OF_LETTERS);
|
|
}
|
|
}
|
|
|
|
const IDENTITY: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
const VARIANT_I: &'static str = "EKMFLGDQVZNTOWYHXUSPAIBRCJ";
|
|
const VARIANT_II: &'static str = "AJDKSIRUXBLHWTMCQGZNPYFVOE";
|
|
const VARIANT_III: &'static str = "BDFHJLCPRTXVZNYEIWGAKMUSQO";
|
|
const VARIANT_IV: &'static str = "ESOVPZJAYQUIRHXLNFTGKDCMWB";
|
|
const VARIANT_V: &'static str = "VZBRGITYUPSDNHLXAWMJQOFECK";
|
|
const VARIANT_VI: &'static str = "JPGVOUMFYQBENHZRDKASXLICTW";
|
|
const VARIANT_VII: &'static str = "NZJHGRCXMYSWBOUFAIVLPEKQDT";
|
|
const VARIANT_VIII: &'static str = "FKQHTLXOCBJSPDZRAMEWNIUYGV";
|
|
|
|
#[non_exhaustive]
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub enum RotorVariant {
|
|
Identity,
|
|
I,
|
|
II,
|
|
III,
|
|
IV,
|
|
V,
|
|
VI,
|
|
VII,
|
|
VIII,
|
|
}
|
|
|
|
impl fmt::Display for RotorVariant {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
match self {
|
|
RotorVariant::Identity => f.write_str("Identity"),
|
|
RotorVariant::I => f.write_str("I"),
|
|
RotorVariant::II => f.write_str("II"),
|
|
RotorVariant::III => f.write_str("III"),
|
|
RotorVariant::IV => f.write_str("IV"),
|
|
RotorVariant::V => f.write_str("V"),
|
|
RotorVariant::VI => f.write_str("VI"),
|
|
RotorVariant::VII => f.write_str("VII"),
|
|
RotorVariant::VIII => f.write_str("VIII"),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn mappings(input: &'static str) -> Vec<Letter> {
|
|
let mut mappings = vec![];
|
|
|
|
for c in input.chars() {
|
|
mappings.push(Letter::from(c));
|
|
}
|
|
|
|
mappings
|
|
}
|