annotate enigma/machine.h @ 5:80debdaa4f65

Turn on optimization.
author Brian Neal <bgneal@gmail.com>
date Sun, 24 Jun 2012 19:22:06 -0500
parents 2792ca4ffa84
children db1216d380b3
rev   line source
bgneal@4 1 #ifndef CPP_ENIGMA_MACHINE_H
bgneal@4 2 #define CPP_ENIGMA_MACHINE_H
bgneal@4 3 // Copyright (C) 2012 by Brian Neal.
bgneal@4 4 // This file is part of Cpp-Enigma, the Enigma Machine simulation.
bgneal@4 5 // Cpp-Enigma is released under the MIT License (see License.txt).
bgneal@4 6 //
bgneal@4 7 // machine.h - This file contains the main Enigma machine class.
bgneal@4 8
bgneal@4 9 #include <memory>
bgneal@4 10 #include <string>
bgneal@4 11 #include <vector>
bgneal@4 12 #include <cassert>
bgneal@4 13 #include "enigma_types.h"
bgneal@4 14 #include "rotor.h"
bgneal@4 15 #include "plugboard.h"
bgneal@4 16
bgneal@4 17 namespace enigma
bgneal@4 18 {
bgneal@4 19 typedef std::vector<std::unique_ptr<rotor>> rotor_vector;
bgneal@4 20
bgneal@4 21 class enigma_machine_error : public enigma_error
bgneal@4 22 {
bgneal@4 23 public:
bgneal@4 24 explicit enigma_machine_error(const std::string& what_arg)
bgneal@4 25 : enigma_error(what_arg)
bgneal@4 26 {}
bgneal@4 27 };
bgneal@4 28
bgneal@4 29 class enigma_machine
bgneal@4 30 {
bgneal@4 31 public:
bgneal@4 32 // construct an Enigma machine from component parts:
bgneal@4 33 enigma_machine(rotor_vector rv,
bgneal@4 34 std::unique_ptr<rotor> reflector,
bgneal@4 35 const plugboard& pb);
bgneal@4 36
bgneal@4 37 // construct an Enigma machine with a default plugboard (no cables connected):
bgneal@4 38 enigma_machine(rotor_vector rv,
bgneal@4 39 std::unique_ptr<rotor> reflector);
bgneal@4 40
bgneal@4 41 // key-sheet style constructors:
bgneal@4 42 enigma_machine(const std::vector<std::string>& rotor_types,
bgneal@4 43 const std::vector<int>& ring_settings,
bgneal@4 44 const std::string& reflector_name = "B",
bgneal@4 45 const std::string& plugboard_settings = "");
bgneal@4 46
bgneal@4 47 // set the rotor display (starting position) - 3 rotor version
bgneal@4 48 void set_display(char left, char mid, char right)
bgneal@4 49 {
bgneal@4 50 assert(rotors.size() == 3);
bgneal@4 51
bgneal@4 52 rotors[0]->set_display(left);
bgneal@4 53 rotors[1]->set_display(mid);
bgneal@4 54 rotors[2]->set_display(right);
bgneal@4 55 }
bgneal@4 56
bgneal@4 57 // set the rotor display (starting position) - 4 rotor version
bgneal@4 58 void set_display(char c0, char c1, char c2, char c3)
bgneal@4 59 {
bgneal@4 60 assert(rotors.size() == 4);
bgneal@4 61
bgneal@4 62 rotors[0]->set_display(c0);
bgneal@4 63 rotors[1]->set_display(c1);
bgneal@4 64 rotors[2]->set_display(c2);
bgneal@4 65 rotors[3]->set_display(c3);
bgneal@4 66 }
bgneal@4 67
bgneal@4 68 // return the rotor display (starting position) as a string
bgneal@4 69 std::string get_display() const
bgneal@4 70 {
bgneal@4 71 std::string result;
bgneal@4 72 for (const auto& r : rotors)
bgneal@4 73 {
bgneal@4 74 result += r->get_display();
bgneal@4 75 }
bgneal@4 76 return result;
bgneal@4 77 }
bgneal@4 78
bgneal@4 79 // simulate front panel key press; returns the lamp character that is lit
bgneal@4 80 char key_press(char c)
bgneal@4 81 {
bgneal@4 82 step_rotors();
bgneal@4 83 return electric_signal(c - 'A') + 'A';
bgneal@4 84 }
bgneal@4 85
bgneal@4 86 // Process a buffer of text of length n, placing the result in an output buffer.
bgneal@4 87 void process_text(const char* input, char* output, std::size_t n)
bgneal@4 88 {
bgneal@4 89 for (std::size_t i = 0; i < n; ++i)
bgneal@4 90 {
bgneal@4 91 *output++ = key_press(*input++);
bgneal@4 92 }
bgneal@4 93 }
bgneal@4 94
bgneal@4 95 std::string process_text(const std::string& input)
bgneal@4 96 {
bgneal@4 97 std::string result;
bgneal@4 98 result.reserve(input.size());
bgneal@4 99
bgneal@4 100 for (const auto& c : input)
bgneal@4 101 {
bgneal@4 102 result += key_press(c);
bgneal@4 103 }
bgneal@4 104 return result;
bgneal@4 105 }
bgneal@4 106
bgneal@4 107 // for access to the plugboard for hill-climbing, etc
bgneal@4 108 plugboard& get_plugboard() { return pb; }
bgneal@4 109
bgneal@4 110 private:
bgneal@4 111 rotor_vector rotors;
bgneal@4 112 std::unique_ptr<rotor> reflector;
bgneal@4 113 plugboard pb;
bgneal@4 114 rotor* r_rotor; // rightmost rotor
bgneal@4 115 rotor* m_rotor; // 2nd to right rotor
bgneal@4 116 rotor* l_rotor; // 3rd to right rotor
bgneal@4 117
bgneal@4 118 void rotor_count_check();
bgneal@4 119
bgneal@4 120 void step_rotors()
bgneal@4 121 {
bgneal@4 122 // The right-most rotor's right-side ratchet is always over a pawl, and
bgneal@4 123 // it has no neighbor to the right, so it always rotates.
bgneal@4 124 //
bgneal@4 125 // The middle rotor will rotate if either:
bgneal@4 126 // 1) The right-most rotor's left side notch is over the 2nd pawl
bgneal@4 127 // or
bgneal@4 128 // 2) It has a left-side notch over the 3rd pawl
bgneal@4 129 //
bgneal@4 130 // The third rotor (from the right) will rotate only if the middle rotor
bgneal@4 131 // has a left-side notch over the 3rd pawl.
bgneal@4 132 //
bgneal@4 133 // Kriegsmarine model M4 has 4 rotors, but the 4th rotor (the leftmost)
bgneal@4 134 // does not rotate (they did not add a 4th pawl to the mechanism).
bgneal@4 135
bgneal@4 136 const bool l_rotate = m_rotor->notch_over_pawl();
bgneal@4 137 const bool m_rotate = l_rotate || r_rotor->notch_over_pawl();
bgneal@4 138
bgneal@4 139 r_rotor->rotate();
bgneal@4 140 if (m_rotate)
bgneal@4 141 {
bgneal@4 142 m_rotor->rotate();
bgneal@4 143 }
bgneal@4 144 if (l_rotate)
bgneal@4 145 {
bgneal@4 146 l_rotor->rotate();
bgneal@4 147 }
bgneal@4 148 }
bgneal@4 149
bgneal@4 150 // Simulate running an electric signal through the machine in order to
bgneal@4 151 // perform an encrypt or decrypt operation
bgneal@4 152 // signal_num - the wire (0-25) that the simulated current occurs on
bgneal@4 153 // Returns a lamp number to light (an integer 0-25).
bgneal@4 154 int electric_signal(int signal_num)
bgneal@4 155 {
bgneal@4 156 int pos = pb.signal(signal_num);
bgneal@4 157
bgneal@4 158 for (auto r = rotors.rbegin(); r != rotors.rend(); ++r)
bgneal@4 159 {
bgneal@4 160 pos = (*r)->signal_in(pos);
bgneal@4 161 }
bgneal@4 162
bgneal@4 163 pos = reflector->signal_in(pos);
bgneal@4 164
bgneal@4 165 for (const auto& r : rotors)
bgneal@4 166 {
bgneal@4 167 pos = r->signal_out(pos);
bgneal@4 168 }
bgneal@4 169
bgneal@4 170 return pb.signal(pos);
bgneal@4 171 }
bgneal@4 172 };
bgneal@4 173 }
bgneal@4 174
bgneal@4 175 #endif