bgneal@4: // Copyright (C) 2012 by Brian Neal.
bgneal@4: // This file is part of Cpp-Enigma, the Enigma Machine simulation.
bgneal@4: // Cpp-Enigma is released under the MIT License (see License.txt).
bgneal@4: //
bgneal@4: // machine.cpp - The implementation file for the main Enigma machine class.
bgneal@4: 
bgneal@4: #include <cstddef>
bgneal@8: #include <sstream>
bgneal@4: #include "machine.h"
bgneal@4: #include "rotor.h"
bgneal@4: #include "rotor_factory.h"
bgneal@4: 
bgneal@4: using namespace enigma;
bgneal@4: 
bgneal@4: ////////////////////////////////////////////////////////////////////////////////
bgneal@4: 
bgneal@4: enigma_machine::enigma_machine(
bgneal@11:       const rotor_vector& rv,
bgneal@14:       const rotor& reflector,
bgneal@4:       const plugboard& pb)
bgneal@13:  : rotors(),
bgneal@11:    pb(pb)
bgneal@4: {
bgneal@14:    rotors.push_back(reflector);
bgneal@13:    for (const auto& r : rv)
bgneal@13:    {
bgneal@13:       rotors.push_back(*r);
bgneal@13:    }
bgneal@4:    rotor_count_check();
bgneal@4: }
bgneal@4: 
bgneal@4: ////////////////////////////////////////////////////////////////////////////////
bgneal@4: 
bgneal@4: enigma_machine::enigma_machine(
bgneal@11:       const rotor_vector& rv,
bgneal@14:       const rotor& reflector)
bgneal@13:  : rotors(),
bgneal@11:    pb()
bgneal@4: {
bgneal@14:    rotors.push_back(reflector);
bgneal@13:    for (const auto& r : rv)
bgneal@13:    {
bgneal@13:       rotors.push_back(*r);
bgneal@13:    }
bgneal@4:    rotor_count_check();
bgneal@4: }
bgneal@4: 
bgneal@4: ////////////////////////////////////////////////////////////////////////////////
bgneal@4: 
bgneal@4: enigma_machine::enigma_machine(
bgneal@4:       const std::vector<std::string>& rotor_types,
bgneal@4:       const std::vector<int>& ring_settings,
bgneal@4:       const std::string& reflector_name,
bgneal@4:       const std::string& plugboard_settings)
bgneal@4:  : rotors(),
bgneal@11:    pb(plugboard_settings)
bgneal@4: {
bgneal@13:    const auto ukw(create_reflector(reflector_name.c_str()));
bgneal@13:    rotors.push_back(*ukw);
bgneal@4:    for (const auto& name : rotor_types)
bgneal@4:    {
bgneal@13:       const auto r(create_rotor(name.c_str()));
bgneal@13:       rotors.push_back(*r);
bgneal@4:    }
bgneal@4:    rotor_count_check();
bgneal@4: 
bgneal@4:    // if ring settings are supplied, there has to be one for each rotor
bgneal@4:    if (!ring_settings.empty())
bgneal@4:    {
bgneal@13:       if (rotors.size() - 1 != ring_settings.size())
bgneal@4:       {
bgneal@4:          throw enigma_machine_error("rotor/ring setting count mismatch");
bgneal@4:       }
bgneal@4: 
bgneal@13:       for (std::size_t i = 1; i < rotors.size(); ++i)
bgneal@4:       {
bgneal@13:          rotors[i].set_ring_setting(ring_settings[i - 1]);
bgneal@4:       }
bgneal@4:    }
bgneal@4: }
bgneal@4: 
bgneal@4: ////////////////////////////////////////////////////////////////////////////////
bgneal@4: 
bgneal@4: void enigma_machine::rotor_count_check()
bgneal@4: {
bgneal@13:    // the first rotor is actually the reflector; so we should have a total
bgneal@13:    // of 4 or 5 rotors
bgneal@13:    if (rotors.size() != 4 && rotors.size() != 5)
bgneal@4:    {
bgneal@4:       throw enigma_machine_error("rotor count");
bgneal@4:    }
bgneal@4: 
bgneal@13:    if (rotors.size() == 4)
bgneal@4:    {
bgneal@13:       r_rotor = &rotors[3];
bgneal@13:       m_rotor = &rotors[2];
bgneal@13:       l_rotor = &rotors[1];
bgneal@4:    }
bgneal@4:    else
bgneal@4:    {
bgneal@13:       r_rotor = &rotors[4];
bgneal@13:       m_rotor = &rotors[3];
bgneal@13:       l_rotor = &rotors[2];
bgneal@4:    }
bgneal@4: }
bgneal@8: 
bgneal@8: ////////////////////////////////////////////////////////////////////////////////
bgneal@8: 
bgneal@8: std::string enigma_machine::str(bool army) const
bgneal@8: {
bgneal@8:    std::ostringstream os;
bgneal@8: 
bgneal@13:    os << rotors[0].name() << ' ';
bgneal@8: 
bgneal@13:    for (std::size_t i = 1; i < rotors.size(); ++i)
bgneal@8:    {
bgneal@13:       os << rotors[i].name() << '/' << rotors[i].get_ring_setting() << ' ';
bgneal@8:    }
bgneal@8: 
bgneal@8:    os << get_display() << ' ' << (army ? pb.army_str() : pb.navy_str());
bgneal@8: 
bgneal@8:    return os.str();
bgneal@8: }
bgneal@8: