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