Mercurial > public > cpp-enigma
diff 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 |
line wrap: on
line diff
--- a/enigma/rotor.cpp Thu Jun 21 21:05:26 2012 -0500 +++ b/enigma/rotor.cpp Fri Jun 22 20:15:11 2012 -0500 @@ -8,21 +8,37 @@ #include <array> #include <algorithm> #include "rotor.h" +#include "enigma_utils.h" using namespace enigma; +//////////////////////////////////////////////////////////////////////////////// + namespace { const char* const ucase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - const std::set<char> ucase_set(ucase, ucase + 26); + + // Turned into a function to avoid translation unit initialization order problems. + const std::set<char>& get_ucase_set() + { + static const std::set<char> the_set(ucase, ucase + 26); + return the_set; + } } +//////////////////////////////////////////////////////////////////////////////// + rotor::rotor(const char* name, const char* wiring, int ring_setting, const char* stepping) - : rotor_name(name), - wiring_str(wiring), - ring_setting(ring_setting), - pos(0), - rotations(0) + : rotor_name{name}, + wiring_str{wiring}, + ring_setting{ring_setting}, + pos{0}, + display_val{'A'}, + entry_map(), + exit_map(), + display_map(), + pos_map(), + step_map() { // check wiring length if (wiring_str.size() != 26) @@ -32,12 +48,13 @@ // ensure wiring contains only uppercase letters & every char must appear // exactly once: + const std::set<char>& ucase_set(get_ucase_set()); - std::array<int, 26> letter_counts {{ 0 }}; + // g++ 4.6.3 warns about missing braces unless we double them up, below: + std::array<int, 26> letter_counts = {{ 0 }}; for (int i = 0; i < 26; ++i) { - const char c(wiring_str[i]); - + const char c{wiring_str[i]}; if (ucase_set.find(c) == ucase_set.end()) { throw rotor_error("invalid wiring"); @@ -51,4 +68,58 @@ { throw rotor_error("invalid wiring; duplicate letter"); } + + if (ring_setting < 0 || ring_setting >= 26) + { + throw rotor_error("invalid ring setting"); + } + set_ring_setting(ring_setting); + + // Initialize our two arrays that describe the internal wiring. Arrays are used + // to do fast lookup from both entry (from the right) and exit (from the + // left). + + for (int i = 0; i < 26; ++i) + { + const int v = wiring_str[i] - 'A'; + entry_map[i] = v; + exit_map[v] = i; + } + + // Build a lookup table that tells us when the pawls are allowed to step. + // The index to this array is the current display letter [A-Z] - 'A'. + + if (stepping != nullptr) + { + for (char c = *stepping; *stepping != '\0'; ++stepping) + { + if (ucase_set.find(c) != ucase_set.end()) + { + step_map[c - 'A'] = true; + } + else + { + throw rotor_error("invalid stepping"); + } + } + } + + // set initial position + set_display('A'); } + +//////////////////////////////////////////////////////////////////////////////// + +void rotor::set_ring_setting(int n) +{ + ring_setting = n; + + // Build a mapping from window display values to positions + // and a reverse mapping of position to display value: + for (int i = 0; i < 26; ++i) + { + const int n = alpha_mod(i - ring_setting); + display_map[i] = n; + pos_map[n] = i + 'A'; + } +}