bgneal@3: #ifndef CPP_ENIGMA_PLUGBOARD_H bgneal@3: #define CPP_ENIGMA_PLUGBOARD_H bgneal@3: // Copyright (C) 2012 by Brian Neal. bgneal@3: // This file is part of Cpp-Enigma, the Enigma Machine simulation. bgneal@3: // Cpp-Enigma is released under the MIT License (see License.txt). bgneal@3: // bgneal@3: // plugboard.h - This file contains the plugboard class. bgneal@3: bgneal@3: #include bgneal@3: #include bgneal@3: #include bgneal@3: #include bgneal@3: #include "enigma_types.h" bgneal@3: bgneal@3: namespace enigma bgneal@3: { bgneal@3: class plugboard_error : public enigma_error bgneal@3: { bgneal@3: public: bgneal@3: explicit plugboard_error(const std::string& what_arg) bgneal@3: : enigma_error(what_arg) bgneal@3: {} bgneal@3: }; bgneal@3: bgneal@3: // The plugboard allows the operator to swap letters before and after the bgneal@3: // entry wheel. This is accomplished by connecting cables between pairs of bgneal@3: // plugs that are marked with letters (Heer & Luftwaffe models) or numbers bgneal@3: // (Kriegsmarine). Ten cables were issued with each machine; thus up to 10 of bgneal@3: // these swappings could be used as part of a machine setup. bgneal@3: bgneal@3: // Each cable swaps both the input and output signals. Thus if A is connected bgneal@3: // to B, A crosses to B in the keyboard to entry wheel direction and also in bgneal@3: // the reverse entry wheel to lamp direction. bgneal@3: bgneal@3: class plugboard bgneal@3: { bgneal@3: public: bgneal@3: const static std::size_t max_pairs = 10; bgneal@3: bgneal@3: typedef std::vector> pair_vector; bgneal@3: bgneal@3: // Construct a plugboard with no connections: bgneal@3: plugboard(); bgneal@3: bgneal@3: // Construct from a vector of integer pairs that describe the bgneal@3: // connections. Each integer must be between [0-25], and the bgneal@3: // vector can have no more than max_pairs pairs. Each plug should bgneal@3: // be present at most once. A plugboard_error will be thrown if bgneal@3: // the pair_vector is invalid. bgneal@3: bgneal@3: explicit plugboard(const pair_vector& pairs); bgneal@3: bgneal@3: // Configure the plugboard according to a settings string as you may bgneal@3: // find on a key sheet. bgneal@3: // bgneal@3: // Two syntaxes are supported, the Heer/Luftwaffe and Kriegsmarine styles: bgneal@3: // bgneal@3: // In the Heer syntax, the settings are given as a string of bgneal@3: // alphabetic pairs. For example: 'PO ML IU KJ NH YT GB VF RE DC' bgneal@3: // bgneal@3: // In the Kriegsmarine syntax, the settings are given as a string of number bgneal@3: // pairs, separated by a '/'. Note that the numbering uses 1-26, inclusive. bgneal@3: // For example: '18/26 17/4 21/6 3/16 19/14 22/7 8/1 12/25 5/9 10/15' bgneal@3: // bgneal@3: // To specify no plugboard connections, settings can be an empty string. bgneal@3: // bgneal@3: // A PlugboardError will be raised if the settings string is invalid, or if bgneal@3: // it contains more than max_pairs pairs. Each plug should be present at bgneal@3: // most once in the settings string. bgneal@3: bgneal@3: explicit plugboard(const std::string& settings); bgneal@3: bgneal@3: // Return the current settings as a vector of pairs: bgneal@3: pair_vector get_pairs() const; bgneal@3: bgneal@3: // Return the current settings as a string in Heer (army) format: bgneal@3: std::string army_str() const; bgneal@3: bgneal@3: // Return the current settings as a string in Kriegsmarine (navy) format: bgneal@3: std::string navy_str() const; bgneal@3: bgneal@3: // Simulate a signal entering the plugboard on wire n, where n must be bgneal@3: // an integer between 0 and 25. bgneal@3: // bgneal@3: // Returns the wire number of the output signal (0-25). bgneal@3: // bgneal@3: // Note that since the plugboard always crosses pairs of wires, it doesn't bgneal@3: // matter what direction (keyboard -> entry wheel or vice versa) the signal bgneal@3: // is coming from. bgneal@3: bgneal@3: int signal(int n) const bgneal@3: { bgneal@3: return wiring_map[n]; bgneal@3: } bgneal@3: bgneal@3: // bgneal@3: // Functions to support hill-climbing: bgneal@3: // bgneal@3: bgneal@3: // Return the internal state of the wiring: bgneal@3: alpha_int_array get_wiring() const bgneal@3: { bgneal@3: return wiring_map; bgneal@3: } bgneal@3: bgneal@3: // Sets the internal state of the wiring: bgneal@3: void set_wiring(const alpha_int_array& wiring) bgneal@3: { bgneal@3: wiring_map = wiring; bgneal@3: } bgneal@3: bgneal@3: // Returns true if connection n has a cable attached to it. bgneal@3: // 0 <= n < 26 bgneal@3: bool is_wired(int n) const bgneal@3: { bgneal@3: return wiring_map[n] != n; bgneal@3: } bgneal@3: bgneal@3: // Returns true if connection n has no cable attached to it. bgneal@3: // 0 <= n < 26 bgneal@3: bool is_free(int n) const bgneal@3: { bgneal@3: return wiring_map[n] == n; bgneal@3: } bgneal@3: bgneal@3: // Removes cable from plug number n [0-25]. bgneal@3: void disconnect(int n) bgneal@3: { bgneal@3: const int x = wiring_map[n]; bgneal@3: wiring_map[x] = x; bgneal@3: wiring_map[n] = n; bgneal@3: } bgneal@3: bgneal@3: // Connects plug x to plug y, removing any existing connection first. bgneal@3: // x & y must be in [0-25]. bgneal@3: void connect(int x, int y) bgneal@3: { bgneal@3: // disconnect any existing connections bgneal@3: const int m = wiring_map[x]; bgneal@3: const int n = wiring_map[y]; bgneal@3: wiring_map[m] = m; bgneal@3: wiring_map[n] = n; bgneal@3: bgneal@3: wiring_map[x] = y; bgneal@3: wiring_map[y] = x; bgneal@3: } bgneal@3: bgneal@3: // Returns true if plug x is connected to plug y. bgneal@3: // x & y must be in [0-25]. bgneal@3: bool is_connected(int x, int y) bgneal@3: { bgneal@3: return wiring_map[x] == y && wiring_map[y] == x; bgneal@3: } bgneal@3: bgneal@10: // Unplugs all cables bgneal@10: void unplug_all() bgneal@10: { bgneal@10: for (auto i = 0U; i < wiring_map.size(); ++i) bgneal@10: { bgneal@10: wiring_map[i] = i; bgneal@10: } bgneal@10: } bgneal@10: bgneal@3: private: bgneal@3: alpha_int_array wiring_map; bgneal@3: bgneal@3: // common constructor code: bgneal@3: void construct_wiring(const pair_vector& pairs); bgneal@3: }; bgneal@3: bgneal@3: bgneal@3: // This class can be used to save & restore the state of a plugboard bgneal@3: // in RAII style: bgneal@3: bgneal@3: class plugboard_state_saver bgneal@3: { bgneal@3: public: bgneal@3: explicit plugboard_state_saver(plugboard& pb) bgneal@3: : pb(pb) bgneal@3: { bgneal@3: state = pb.get_wiring(); bgneal@3: } bgneal@3: bgneal@3: ~plugboard_state_saver() bgneal@3: { bgneal@3: pb.set_wiring(state); bgneal@3: } bgneal@3: bgneal@3: // disable copying & assignment bgneal@3: plugboard_state_saver(const plugboard_state_saver&) = delete; bgneal@3: plugboard_state_saver& operator=(const plugboard_state_saver&) = delete; bgneal@3: bgneal@3: private: bgneal@3: plugboard& pb; bgneal@3: alpha_int_array state; bgneal@3: }; bgneal@3: bgneal@3: } bgneal@3: bgneal@3: #endif