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 }