Class: EnigmaMachine::Rotor

Inherits:
Object
  • Object
show all
Defined in:
lib/enigma_machine/rotor.rb

Constant Summary collapse

STANDARD_ROTORS =
{
  :i      => "EKMFLGDQVZNTOWYHXUSPAIBRCJ_Q",
  :ii     => "AJDKSIRUXBLHWTMCQGZNPYFVOE_E",
  :iii    => "BDFHJLCPRTXVZNYEIWGAKMUSQO_V",
  :iv     => "ESOVPZJAYQUIRHXLNFTGKDCMWB_J",
  :v      => "VZBRGITYUPSDNHLXAWMJQOFECK_Z",
  :vi     => "JPGVOUMFYQBENHZRDKASXLICTW_MZ",
  :vii    => "NZJHGRCXMYSWBOUFAIVLPEKQDT_MZ",
  :viii   => "FKQHTLXOCBJSPDZRAMEWNIUYGV_MZ",
  :beta   => "LEYJVCNIXWPBQMDRTAKZGFUHOS_", # The beta and gamma rotors caould only go 
  :gamma  => "FSOKANUERHMBTIYCWLQPZXVGJD_", # in position 4, and hence have no notches.
}

Instance Method Summary collapse

Constructor Details

#initialize(rotor_spec, ring_setting, decorated) ⇒ Rotor

Construct a new rotor

Examples:

Rotor.new(:ii, 12, @next)
Rotor.new("BDFHJLCPRTXVZNYEIWGAKMUSQO_V", 15, @next)

When specifying a custom rotor_spec, the letters after the _ indicate the notch positions

Parameters:

  • rotor_spec (Symbol, String)

    A symbol representing one of the standard rotors or a string specifying the mapping and notch positions (see Examples)

  • ring_setting (Integer)

    The ring setting for the rotor.

  • decorated (#translate)

    The next component in the processing chain (the next rotor, or the reflector)

Raises:

  • (ConfigurationError)

    if an invalid rotor_spec is passed in (unrecognised standard rotor)



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/enigma_machine/rotor.rb', line 30

def initialize(rotor_spec, ring_setting, decorated)
  if rotor_spec.is_a?(Symbol)
    raise ConfigurationError unless STANDARD_ROTORS.has_key?(rotor_spec)
    rotor_spec = STANDARD_ROTORS[rotor_spec]
  end
  mapping, notch_positions = rotor_spec.split('_', 2)
  @mapping = mapping.each_char.map {|c| ALPHABET.index(c) }
  @notch_positions = notch_positions.split('')
  @ring_offset = ring_setting - 1
  @decorated = decorated
  self.position = 'A'
end

Instance Method Details

#advance_positionvoid

This method returns an undefined value.

Advance the position of the rotor.



57
58
59
# File 'lib/enigma_machine/rotor.rb', line 57

def advance_position
  @position = (@position + 1).modulo(26)
end

#at_notch?Boolean

Is the rotor currently at a notch position.

Returns:

  • (Boolean)


62
63
64
# File 'lib/enigma_machine/rotor.rb', line 62

def at_notch?
  @notch_positions.include?(self.position)
end

#forward(letter) ⇒ String

Perform the forward translation of a letter (i.e. the path towards the reflector)

Parameters:

  • letter (String)

    the letter to be translated

Returns:

  • (String)

    the translated letter



70
71
72
73
74
# File 'lib/enigma_machine/rotor.rb', line 70

def forward(letter)
  index = add_offset ALPHABET.index(letter)
  new_index = sub_offset @mapping[index]
  ALPHABET[new_index]
end

#positionString

Returns the current position of the rotor.

Returns:

  • (String)

    the current position of the rotor



51
52
53
# File 'lib/enigma_machine/rotor.rb', line 51

def position
  ALPHABET[@position]
end

#position=(letter) ⇒ void

This method returns an undefined value.

Set the position of the rotor

Parameters:

  • letter (String)

    the letter position to set the rotor to



47
48
49
# File 'lib/enigma_machine/rotor.rb', line 47

def position=(letter)
  @position = ALPHABET.index(letter)
end

#reverse(letter) ⇒ String

Perform the reverse translation of a letter (i.e. the path returning from the reflector)

Parameters:

  • letter (String)

    the letter to be translated

Returns:

  • (String)

    the translated letter



80
81
82
83
84
# File 'lib/enigma_machine/rotor.rb', line 80

def reverse(letter)
  index = add_offset ALPHABET.index(letter)
  new_index = sub_offset @mapping.index(index)
  ALPHABET[new_index]
end

#translate(input) ⇒ String

Translate a letter

This performs a forward substitution, calls the next component to do the rest of the translation, and then reverse substitutes the result on the way back out.

Parameters:

  • letter (String)

    the letter to be translated

Returns:

  • (String)

    the translated letter



93
94
95
96
97
# File 'lib/enigma_machine/rotor.rb', line 93

def translate(input)
  step = forward(input)
  step = @decorated.translate(step)
  reverse(step)
end