use crate::*; use std::fmt; #[derive(Debug, Clone)] pub struct Rotor { pub variant: RotorVariant, pub mappings: Vec, pub position: Letter, pub notches: Vec, } 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 { 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 { let mut mappings = vec![]; for c in input.chars() { mappings.push(Letter::from(c)); } mappings }