205 lines
5.3 KiB
C++
205 lines
5.3 KiB
C++
#include <cctype>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
using namespace std;
|
|
|
|
const map<char, string> morse_map = {
|
|
{'A', ".-"}, {'B', "-..."}, {'C', "-.-."}, {'D', "-.."},
|
|
{'E', "."}, {'F', "..-."}, {'G', "--."}, {'H', "...."},
|
|
{'I', ".."}, {'J', ".---"}, {'K', "-.-"}, {'L', ".-.."},
|
|
{'M', "--"}, {'N', "-."}, {'O', "---"}, {'P', ".--."},
|
|
{'Q', "--.-"}, {'R', ".-."}, {'S', "..."}, {'T', "-"},
|
|
{'U', "..-"}, {'V', "...-"}, {'W', ".--"}, {'X', "-..-"},
|
|
{'Y', "-.--"}, {'Z', "--.."}, {'0', "-----"}, {'1', ".----"},
|
|
{'2', "..---"}, {'3', "...--"}, {'4', "....-"}, {'5', "....."},
|
|
{'6', "-...."}, {'7', "--..."}, {'8', "---.."}, {'9', "----."},
|
|
{'.', ".-.-.-"}, {',', "--..--"}, {'?', "..--.."}, {'!', "-.-.--"},
|
|
{'\'', ".----."}, {'/', "-..-."}, {'(', "-.--."}, {')', "-.--.-"},
|
|
{'&', ".-..."}, {':', "---..."}, {';', "-.-.-."}, {'=', "-...-"},
|
|
{'+', ".-.-."}, {'-', "-....-"}, {'_', "..--.-"}, {'"', ".-..-."},
|
|
{'$', "...-..-"}, {'@', ".--.-."}};
|
|
|
|
bool should_exit = false;
|
|
|
|
bool is_exit(const string &s) {
|
|
return s.length() == 4 && tolower(s[0]) == 'e' && tolower(s[1]) == 'x' &&
|
|
tolower(s[2]) == 'i' && tolower(s[3]) == 't';
|
|
}
|
|
|
|
string read_input(const string &prompt) {
|
|
cout << prompt;
|
|
string line;
|
|
if (!getline(cin, line) || line.empty())
|
|
return "";
|
|
if (is_exit(line)) {
|
|
should_exit = true;
|
|
return "";
|
|
}
|
|
return line;
|
|
}
|
|
|
|
class MorseDecoder {
|
|
private:
|
|
static const map<string, char> &get_morse_to_char() {
|
|
static map<string, char> morse_to_char;
|
|
static bool initialized = false;
|
|
if (!initialized) {
|
|
for (const auto &[ch, code] : morse_map) {
|
|
morse_to_char[code] = ch;
|
|
}
|
|
initialized = true;
|
|
}
|
|
return morse_to_char;
|
|
}
|
|
|
|
public:
|
|
optional<char> decode(const string &morse) const {
|
|
const auto &morse_to_char = get_morse_to_char();
|
|
auto it = morse_to_char.find(morse);
|
|
if (it == morse_to_char.end())
|
|
return nullopt;
|
|
return it->second;
|
|
}
|
|
};
|
|
|
|
class MorseEncoder {
|
|
private:
|
|
const map<char, string> &char_to_morse;
|
|
|
|
public:
|
|
MorseEncoder() : char_to_morse(morse_map) {}
|
|
|
|
string encode(char c) {
|
|
auto it = char_to_morse.find(toupper(c));
|
|
return it != char_to_morse.end() ? it->second : "";
|
|
}
|
|
|
|
string get_full_sequence(const string &text) {
|
|
string sequence;
|
|
sequence.reserve(text.length() * 5);
|
|
bool need_space = false;
|
|
|
|
for (char c : text) {
|
|
if (c == ' ') {
|
|
sequence += " / ";
|
|
need_space = false;
|
|
} else {
|
|
string morse = encode(c);
|
|
if (!morse.empty()) {
|
|
if (need_space)
|
|
sequence += " ";
|
|
sequence += morse;
|
|
need_space = true;
|
|
}
|
|
}
|
|
}
|
|
return sequence;
|
|
}
|
|
|
|
void print_morse_pattern(const string &text) {
|
|
for (char c : text) {
|
|
if (c == ' ') {
|
|
cout << "\n[Space]\n";
|
|
} else {
|
|
string morse = encode(c);
|
|
if (!morse.empty()) {
|
|
cout << c << " -> " << morse << "\n";
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void decode_mode() {
|
|
MorseDecoder decoder;
|
|
cout << "Decode mode: Enter morse sequence to decode. Press 'e' to switch to "
|
|
"encode mode, 'exit' to exit.\n\n";
|
|
|
|
while (!should_exit) {
|
|
string input = read_input("Enter morse sequence: ");
|
|
if (input.empty())
|
|
continue;
|
|
|
|
if (tolower(input[0]) == 'e')
|
|
return;
|
|
|
|
string decoded_message;
|
|
bool has_invalid_tokens = false;
|
|
bool has_unknown_codes = false;
|
|
|
|
istringstream stream(input);
|
|
string token;
|
|
while (stream >> token) {
|
|
if (token == "/") {
|
|
if (!decoded_message.empty() && decoded_message.back() != ' ')
|
|
decoded_message += ' ';
|
|
continue;
|
|
}
|
|
|
|
if (token.find_first_not_of(".-") != string::npos) {
|
|
has_invalid_tokens = true;
|
|
cout << token << " -> [ignored: invalid characters]\n";
|
|
continue;
|
|
}
|
|
|
|
optional<char> decoded = decoder.decode(token);
|
|
if (!decoded) {
|
|
has_unknown_codes = true;
|
|
cout << token << " -> [unknown]\n";
|
|
continue;
|
|
}
|
|
|
|
cout << token << " -> " << *decoded << "\n";
|
|
decoded_message += *decoded;
|
|
}
|
|
|
|
if (has_invalid_tokens)
|
|
cout << "\nWarning: Tokens with invalid characters were ignored.\n";
|
|
if (has_unknown_codes)
|
|
cout << "Warning: Unknown Morse codes were skipped.\n";
|
|
|
|
cout << "\nFinal message: " << decoded_message << "\n\n";
|
|
}
|
|
}
|
|
|
|
void encode_mode() {
|
|
MorseEncoder encoder;
|
|
cout << "Encode mode: Enter text to see Morse code patterns. Press 'd' to "
|
|
"switch to decode mode, 'exit' to exit.\n\n";
|
|
|
|
while (!should_exit) {
|
|
string input = read_input("Enter text to encode: ");
|
|
if (input.empty())
|
|
continue;
|
|
|
|
if (tolower(input[0]) == 'd')
|
|
return;
|
|
|
|
cout << "\n";
|
|
encoder.print_morse_pattern(input);
|
|
cout << "\nFinal sequence: " << encoder.get_full_sequence(input) << "\n\n";
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
cout << "dotdash - Morse code playground\n";
|
|
cout << "Starting in decode mode...\n\n";
|
|
|
|
bool decode = true;
|
|
while (!should_exit) {
|
|
decode ? decode_mode() : encode_mode();
|
|
if (!should_exit) {
|
|
decode = !decode;
|
|
cout << "\nSwitched to " << (decode ? "decode" : "encode")
|
|
<< " mode.\n\n";
|
|
}
|
|
}
|
|
|
|
cout << "\nExiting...\n";
|
|
return 0;
|
|
}
|