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