comparison enigma/plugboard.h @ 3:f4e25e6b76c3

Created plugboard class and tests.
author Brian Neal <bgneal@gmail.com>
date Sat, 23 Jun 2012 23:28:17 -0500
parents
children 232dbe7a3fe0
comparison
equal deleted inserted replaced
2:713fa2a9ea9a 3:f4e25e6b76c3
1 #ifndef CPP_ENIGMA_PLUGBOARD_H
2 #define CPP_ENIGMA_PLUGBOARD_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 // plugboard.h - This file contains the plugboard class.
8
9 #include <vector>
10 #include <utility>
11 #include <string>
12 #include <cstddef>
13 #include "enigma_types.h"
14
15 namespace enigma
16 {
17 class plugboard_error : public enigma_error
18 {
19 public:
20 explicit plugboard_error(const std::string& what_arg)
21 : enigma_error(what_arg)
22 {}
23 };
24
25 // The plugboard allows the operator to swap letters before and after the
26 // entry wheel. This is accomplished by connecting cables between pairs of
27 // plugs that are marked with letters (Heer & Luftwaffe models) or numbers
28 // (Kriegsmarine). Ten cables were issued with each machine; thus up to 10 of
29 // these swappings could be used as part of a machine setup.
30
31 // Each cable swaps both the input and output signals. Thus if A is connected
32 // to B, A crosses to B in the keyboard to entry wheel direction and also in
33 // the reverse entry wheel to lamp direction.
34
35 class plugboard
36 {
37 public:
38 const static std::size_t max_pairs = 10;
39
40 typedef std::vector<std::pair<int, int>> pair_vector;
41
42 // Construct a plugboard with no connections:
43 plugboard();
44
45 // Construct from a vector of integer pairs that describe the
46 // connections. Each integer must be between [0-25], and the
47 // vector can have no more than max_pairs pairs. Each plug should
48 // be present at most once. A plugboard_error will be thrown if
49 // the pair_vector is invalid.
50
51 explicit plugboard(const pair_vector& pairs);
52
53 // Configure the plugboard according to a settings string as you may
54 // find on a key sheet.
55 //
56 // Two syntaxes are supported, the Heer/Luftwaffe and Kriegsmarine styles:
57 //
58 // In the Heer syntax, the settings are given as a string of
59 // alphabetic pairs. For example: 'PO ML IU KJ NH YT GB VF RE DC'
60 //
61 // In the Kriegsmarine syntax, the settings are given as a string of number
62 // pairs, separated by a '/'. Note that the numbering uses 1-26, inclusive.
63 // For example: '18/26 17/4 21/6 3/16 19/14 22/7 8/1 12/25 5/9 10/15'
64 //
65 // To specify no plugboard connections, settings can be an empty string.
66 //
67 // A PlugboardError will be raised if the settings string is invalid, or if
68 // it contains more than max_pairs pairs. Each plug should be present at
69 // most once in the settings string.
70
71 explicit plugboard(const std::string& settings);
72
73 // Return the current settings as a vector of pairs:
74 pair_vector get_pairs() const;
75
76 // Return the current settings as a string in Heer (army) format:
77 std::string army_str() const;
78
79 // Return the current settings as a string in Kriegsmarine (navy) format:
80 std::string navy_str() const;
81
82 // Simulate a signal entering the plugboard on wire n, where n must be
83 // an integer between 0 and 25.
84 //
85 // Returns the wire number of the output signal (0-25).
86 //
87 // Note that since the plugboard always crosses pairs of wires, it doesn't
88 // matter what direction (keyboard -> entry wheel or vice versa) the signal
89 // is coming from.
90
91 int signal(int n) const
92 {
93 return wiring_map[n];
94 }
95
96 //
97 // Functions to support hill-climbing:
98 //
99
100 // Return the internal state of the wiring:
101 alpha_int_array get_wiring() const
102 {
103 return wiring_map;
104 }
105
106 // Sets the internal state of the wiring:
107 void set_wiring(const alpha_int_array& wiring)
108 {
109 wiring_map = wiring;
110 }
111
112 // Returns true if connection n has a cable attached to it.
113 // 0 <= n < 26
114 bool is_wired(int n) const
115 {
116 return wiring_map[n] != n;
117 }
118
119 // Returns true if connection n has no cable attached to it.
120 // 0 <= n < 26
121 bool is_free(int n) const
122 {
123 return wiring_map[n] == n;
124 }
125
126 // Removes cable from plug number n [0-25].
127 void disconnect(int n)
128 {
129 const int x = wiring_map[n];
130 wiring_map[x] = x;
131 wiring_map[n] = n;
132 }
133
134 // Connects plug x to plug y, removing any existing connection first.
135 // x & y must be in [0-25].
136 void connect(int x, int y)
137 {
138 // disconnect any existing connections
139 const int m = wiring_map[x];
140 const int n = wiring_map[y];
141 wiring_map[m] = m;
142 wiring_map[n] = n;
143
144 wiring_map[x] = y;
145 wiring_map[y] = x;
146 }
147
148 // Returns true if plug x is connected to plug y.
149 // x & y must be in [0-25].
150 bool is_connected(int x, int y)
151 {
152 return wiring_map[x] == y && wiring_map[y] == x;
153 }
154
155 private:
156 alpha_int_array wiring_map;
157
158 // common constructor code:
159 void construct_wiring(const pair_vector& pairs);
160 };
161
162
163 // This class can be used to save & restore the state of a plugboard
164 // in RAII style:
165
166 class plugboard_state_saver
167 {
168 public:
169 explicit plugboard_state_saver(plugboard& pb)
170 : pb(pb)
171 {
172 state = pb.get_wiring();
173 }
174
175 ~plugboard_state_saver()
176 {
177 pb.set_wiring(state);
178 }
179
180 // disable copying & assignment
181 plugboard_state_saver(const plugboard_state_saver&) = delete;
182 plugboard_state_saver& operator=(const plugboard_state_saver&) = delete;
183
184 private:
185 plugboard& pb;
186 alpha_int_array state;
187 };
188
189 }
190
191 #endif