EnigmaMachineCore 0.1.0
A modular Enigma Machine simulation in C++20
Loading...
Searching...
No Matches
RotorBox.cpp
Go to the documentation of this file.
1
6#include <algorithm>
7#include <iostream>
8#include <ranges>
9#include <stdexcept>
10#include <string>
11#include <utility>
12
13#include "Reflector.hpp"
14#include "Rotor.hpp"
15#include "RotorBox.hpp"
16#include "config.hpp"
17
22RotorBox::RotorBox(ILogger* logger) : logger(logger) {
23 rotorCount = 3;
24 rotorPositions = std::vector<AlphabetIndex>(rotorCount, 0);
25
26 std::vector<RotorConfig> defaultRotors(rotorCount);
27 initTransformers(defaultRotors, ReflectorConfig{});
28}
29
35RotorBox::RotorBox(const std::vector<AlphabetIndex>& rotorPositions, const std::vector<RotorConfig>& rotors,
36 const ReflectorConfig& reflector, ILogger* logger)
37 : logger(logger) {
38 if (std::cmp_not_equal(rotorPositions.size(), rotors.size())) {
39 throw std::invalid_argument("Error: Number of rotors and number of rotor positions do not match.");
40 }
41
42 rotorCount = (int)rotorPositions.size();
43 this->rotorPositions = rotorPositions;
44
45 initTransformers(rotors, reflector);
46
47 for (int i = 0; i < rotorCount; i++) {
48 transformers.at(i)->setPosition(this->rotorPositions.at(i));
49 }
50}
51
52RotorBox::RotorBox(std::vector<AlphabetIndex>&& rotorPositions, std::vector<RotorConfig>&& rotors,
53 ReflectorConfig&& reflector, ILogger* logger)
54 : rotorCount((int)rotorPositions.size()), rotorPositions(std::move(rotorPositions)), logger(logger) {
55 if (std::cmp_not_equal(this->rotorPositions.size(), rotors.size())) {
56 throw std::invalid_argument("Error: Number of rotors and number of rotor positions do not match.");
57 }
58
59 // Optimization: avoid copying configs by moving them into the transformers
60 transformers.reserve(rotorCount + 1);
61 for (auto& rotorConfig : rotors) {
62 transformers.push_back(std::make_unique<Rotor>(std::move(rotorConfig)));
63 }
64 transformers.push_back(std::make_unique<Reflector>(std::move(reflector)));
65
66 for (int i = 0; i < rotorCount; i++) {
67 transformers.at(i)->setPosition(this->rotorPositions.at(i));
68 }
69}
70
71void RotorBox::registerObserver(IEnigmaObserver* observer) { observers.push_back(observer); }
72
74 auto iterator = std::ranges::remove(observers, observer).begin();
75 observers.erase(iterator, observers.end());
76}
77
85void RotorBox::initTransformers(const std::vector<RotorConfig>& rotors, const ReflectorConfig& reflector) {
86 transformers.clear();
87 transformers.reserve(rotorCount + 1);
88
89 for (const auto& rotorConfig : rotors) {
90 transformers.push_back(std::make_unique<Rotor>(rotorConfig));
91 }
92 transformers.emplace_back(std::make_unique<Reflector>(reflector));
93}
94
96 if (logger) {
97 for (size_t i = 0; i < transformers.size(); ++i) {
98 std::string msg = "Transformer " + std::to_string(i) +
99 " Type: " + std::to_string(static_cast<int>(transformers[i]->getType()));
100 logger->log(LogLevel::Info, msg);
101 }
102 }
103}
104
112AlphabetIndex RotorBox::keyTransform(AlphabetIndex input) {
113 updateRotors();
114
115 AlphabetIndex newPosition = input;
116 // transform through rotors forward
117 for (const auto& transformer : transformers | std::views::take(rotorCount)) {
118 newPosition = transformer->transformForward(newPosition);
119 }
120
121 // reflector
122 newPosition = transformers.at(rotorCount)->transformForward(newPosition);
123
124 // transform through rotors in reverse
125 for (const auto& transformer : transformers | std::views::take(rotorCount) | std::views::reverse) {
126 newPosition = transformer->transformReverse(newPosition);
127 }
128
129 return newPosition;
130}
131
132void RotorBox::setLogger(ILogger* log) { this->logger = log; }
133
143 if (rotorCount < 1) {
144 return;
145 }
146
147 // Storing notch states BEFORE stepping
148 std::vector<char> atNotch(rotorCount, 0);
149 std::ranges::transform(transformers | std::views::take(rotorCount), atNotch.begin(), [](const auto& transformer) {
150 const auto* rotor = static_cast<const Rotor*>(transformer.get());
151 return rotor->isNotchPosition(rotor->getPosition()) ? 1 : 0;
152 });
153
154 // Step rotors according to Enigma mechanics
155 for (int i = 0; i < rotorCount; i++) {
156 if (i == 0) { // Rightmost rotor always steps (i == 0)
157 transformers.at(i)->rotate();
158 if (logger) logger->log(LogLevel::Debug, "Rotor 0 stepped.");
159 continue;
160 }
161 bool carried = atNotch[i - 1] != 0;
162 bool doubleStep = (i < rotorCount - 1) && (atNotch[i] != 0);
163 if (carried || doubleStep) {
164 transformers.at(i)->rotate();
165 if (logger) {
166 std::string reason = carried ? "carry" : "double-step";
167 logger->log(LogLevel::Debug, "Rotor " + std::to_string(i) + " stepped due to " + reason + ".");
168 }
169 }
170 }
171
172 // Notify observers
173 std::ranges::for_each(std::views::iota(0, rotorCount), [this](int index) {
174 const int position = transformers.at(index)->getPosition();
175 std::ranges::for_each(observers,
176 [index, position](auto* observer) { observer->onRotorStepped(index, position); });
177 });
178}
Header file for the Reflector class.
Header file for the RotorBox class.
Defines the Rotor class, a concrete implementation of the Transformer interface.
void updateRotors()
Updates the positions of the rotors.
Definition RotorBox.cpp:142
int rotorCount
Definition RotorBox.hpp:26
void initTransformers(const std::vector< RotorConfig > &rotors, const ReflectorConfig &reflector)
Initializes the transformer vector with rotors and a reflector.
Definition RotorBox.cpp:85
RotorBox(ILogger *logger=nullptr)
Constructor for the RotorBox class. Initializes the rotor box with a default number of rotors (3) and...
Definition RotorBox.cpp:22
ILogger * logger
Definition RotorBox.hpp:30
std::vector< AlphabetIndex > rotorPositions
Definition RotorBox.hpp:27
void registerObserver(IEnigmaObserver *observer)
Registers an observer to receive notifications.
Definition RotorBox.cpp:71
std::vector< IEnigmaObserver * > observers
Definition RotorBox.hpp:29
void printTransformers() const
Prints the types of transformers in the transformer vector. This function iterates through the transf...
Definition RotorBox.cpp:95
std::vector< std::unique_ptr< Transformer > > transformers
Definition RotorBox.hpp:28
AlphabetIndex keyTransform(AlphabetIndex input)
Transforms the input key through the rotor box.
Definition RotorBox.cpp:112
void removeObserver(IEnigmaObserver *observer)
Removes an observer.
Definition RotorBox.cpp:73
void setLogger(ILogger *logger)
Sets the logger for the rotor box.
Definition RotorBox.cpp:132
Global configuration constants for the Enigma machine.
Interface for observing Enigma Machine events. Implement this interface to receive notifications abou...
Configuration structure for a Reflector.