Mercurial > public > cpp-enigma
comparison enigma/rotor.cpp @ 1:1459e74fda3f
Finished creating rotor class and factories.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Fri, 22 Jun 2012 20:15:11 -0500 |
parents | 74ebb2150658 |
children | 713fa2a9ea9a |
comparison
equal
deleted
inserted
replaced
0:74ebb2150658 | 1:1459e74fda3f |
---|---|
6 | 6 |
7 #include <set> | 7 #include <set> |
8 #include <array> | 8 #include <array> |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include "rotor.h" | 10 #include "rotor.h" |
11 #include "enigma_utils.h" | |
11 | 12 |
12 using namespace enigma; | 13 using namespace enigma; |
14 | |
15 //////////////////////////////////////////////////////////////////////////////// | |
13 | 16 |
14 namespace | 17 namespace |
15 { | 18 { |
16 const char* const ucase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | 19 const char* const ucase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
17 const std::set<char> ucase_set(ucase, ucase + 26); | 20 |
21 // Turned into a function to avoid translation unit initialization order problems. | |
22 const std::set<char>& get_ucase_set() | |
23 { | |
24 static const std::set<char> the_set(ucase, ucase + 26); | |
25 return the_set; | |
26 } | |
18 } | 27 } |
19 | 28 |
29 //////////////////////////////////////////////////////////////////////////////// | |
30 | |
20 rotor::rotor(const char* name, const char* wiring, int ring_setting, const char* stepping) | 31 rotor::rotor(const char* name, const char* wiring, int ring_setting, const char* stepping) |
21 : rotor_name(name), | 32 : rotor_name{name}, |
22 wiring_str(wiring), | 33 wiring_str{wiring}, |
23 ring_setting(ring_setting), | 34 ring_setting{ring_setting}, |
24 pos(0), | 35 pos{0}, |
25 rotations(0) | 36 display_val{'A'}, |
37 entry_map(), | |
38 exit_map(), | |
39 display_map(), | |
40 pos_map(), | |
41 step_map() | |
26 { | 42 { |
27 // check wiring length | 43 // check wiring length |
28 if (wiring_str.size() != 26) | 44 if (wiring_str.size() != 26) |
29 { | 45 { |
30 throw rotor_error("invalid wiring length"); | 46 throw rotor_error("invalid wiring length"); |
31 } | 47 } |
32 | 48 |
33 // ensure wiring contains only uppercase letters & every char must appear | 49 // ensure wiring contains only uppercase letters & every char must appear |
34 // exactly once: | 50 // exactly once: |
51 const std::set<char>& ucase_set(get_ucase_set()); | |
35 | 52 |
36 std::array<int, 26> letter_counts {{ 0 }}; | 53 // g++ 4.6.3 warns about missing braces unless we double them up, below: |
54 std::array<int, 26> letter_counts = {{ 0 }}; | |
37 for (int i = 0; i < 26; ++i) | 55 for (int i = 0; i < 26; ++i) |
38 { | 56 { |
39 const char c(wiring_str[i]); | 57 const char c{wiring_str[i]}; |
40 | |
41 if (ucase_set.find(c) == ucase_set.end()) | 58 if (ucase_set.find(c) == ucase_set.end()) |
42 { | 59 { |
43 throw rotor_error("invalid wiring"); | 60 throw rotor_error("invalid wiring"); |
44 } | 61 } |
45 ++letter_counts[c - 'A']; | 62 ++letter_counts[c - 'A']; |
49 letter_counts.end(), | 66 letter_counts.end(), |
50 [](int n) { return n != 1; }) != letter_counts.end()) | 67 [](int n) { return n != 1; }) != letter_counts.end()) |
51 { | 68 { |
52 throw rotor_error("invalid wiring; duplicate letter"); | 69 throw rotor_error("invalid wiring; duplicate letter"); |
53 } | 70 } |
71 | |
72 if (ring_setting < 0 || ring_setting >= 26) | |
73 { | |
74 throw rotor_error("invalid ring setting"); | |
75 } | |
76 set_ring_setting(ring_setting); | |
77 | |
78 // Initialize our two arrays that describe the internal wiring. Arrays are used | |
79 // to do fast lookup from both entry (from the right) and exit (from the | |
80 // left). | |
81 | |
82 for (int i = 0; i < 26; ++i) | |
83 { | |
84 const int v = wiring_str[i] - 'A'; | |
85 entry_map[i] = v; | |
86 exit_map[v] = i; | |
87 } | |
88 | |
89 // Build a lookup table that tells us when the pawls are allowed to step. | |
90 // The index to this array is the current display letter [A-Z] - 'A'. | |
91 | |
92 if (stepping != nullptr) | |
93 { | |
94 for (char c = *stepping; *stepping != '\0'; ++stepping) | |
95 { | |
96 if (ucase_set.find(c) != ucase_set.end()) | |
97 { | |
98 step_map[c - 'A'] = true; | |
99 } | |
100 else | |
101 { | |
102 throw rotor_error("invalid stepping"); | |
103 } | |
104 } | |
105 } | |
106 | |
107 // set initial position | |
108 set_display('A'); | |
54 } | 109 } |
110 | |
111 //////////////////////////////////////////////////////////////////////////////// | |
112 | |
113 void rotor::set_ring_setting(int n) | |
114 { | |
115 ring_setting = n; | |
116 | |
117 // Build a mapping from window display values to positions | |
118 // and a reverse mapping of position to display value: | |
119 for (int i = 0; i < 26; ++i) | |
120 { | |
121 const int n = alpha_mod(i - ring_setting); | |
122 display_map[i] = n; | |
123 pos_map[n] = i + 'A'; | |
124 } | |
125 } |