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