C++ Enigma::Decoding A Message - c++

Hey all im working on a program that has gives you the option of converting a message(string) into 3 different schemes: Prime Shift Encoding scheme, Shifty Encoding Scheme, and a Reverse Encoding scheme. I have figured out how to encode and decode the prime shift scheme and reverse scheme, but im having a little bit of trouble with the Shifty Encoding scheme. The rules for the Shifty scheme are these: Each character in the message is converted to its ASCII value. The value is subtracted from 1000, resulting in a triplet of numbers. Each digit of the triplet is then converted to the symbolic value on the keyboard above the numbers 1 – 0. The string of symbols is the encoded message.
For example, if the character’s value is 37, it is subtracted from 1000, resulting in a triplet of 963. The corresponding keyboard characters are (^#.
The encoded message is then stored in a text file along with the key, and the number that corresponds to the scheme. When the user clicks on the decode button a filechooser opens up and the user selects the text file to read in. Once he/she selects the file they want open the program reads in the encoded message the key and the scheme. So the program must be able to get the encoded message and convert it back to its original message.
I have figured out the code to encode the Shifty scheme and it encodes the message perfectly, but im lost on how to decode the message. I know i have to somehow obtain each of the triplet of digits back from the encoded string and then subtract 1000 from each one so i can get the correct ascii character, but im lost on how to do that. Any help would be appreciated.
so far i have this:
ShiftyEnigma::ShiftyEnigma()
{
keyBoard[0] = ')';
keyBoard[1] = '!';
keyBoard[2] = '#';
keyBoard[3] = '#';
keyBoard[4] = '$';
keyBoard[5] = '%';
keyBoard[6] = '^';
keyBoard[7] = '&';
keyBoard[8] = '*';
keyBoard[9] = '(';
}
void ShiftyEnigma::encode()
{
stringstream ss;
stringstream s1;
int value = 0;
for(unsigned int i = 0; i < codedMessage.length(); ++i)
{
int ascii = codedMessage.at(i);
//subtracting 1000 from ascii number of each character in message
value = 1000 - ascii;
//setting the value in string stream in order to convert each digit of
//triplet (ex 887) into values that match the keyboard array
ss << value;
for(unsigned int i = 0; i < ss.str().length(); ++i)
{
s1 << keyBoard[(int)ss.str().at(i)-48];
}
ss.str("");
}
codedMessage = s1.str();
}
void ShiftyEnigma::decode()
{
for(unsigned int i = 0; i < codedMessage.length(); ++i)
{
}
}

we start by creating a reverse-lookup for the symbols. I use 0 for the invalid number as the array is initialized to 0 by default, and use 10 to mark the number 0.
You loop over each character of the input and use reverse-lookup on the antiKeyboard array to see what digit it maps to. if the reverse lookup returns 0, then we found an invalid character. I choose to ignore it, but you could show an error message. Now we need to get 3 valid digits and combine them togeather. to combine 3-digits in a 3-digit number we can do this: number = digit1 * 100 + digit2 * 10 + digit. I do this in a loop.
int antiKeyboard[256]= {0};
antiKeyboard['!'] = 1;
antiKeyboard['#'] = 2;
antiKeyboard['#'] = 3;
antiKeyboard['$'] = 4;
antiKeyboard['%'] = 5;
antiKeyboard['^'] = 6;
antiKeyboard['&'] = 7;
antiKeyboard['*'] = 8;
antiKeyboard['('] = 9;
antiKeyboard[')'] = 10; //Note this is 0, but i put is as 10
int digits = 0, digit, number=0;
for(unsigned int i = 0; i < codedMessage.length(); ++i)
{
digit = antiKeyboard[codedMessage.at(i)];
if (digit >=1 && digit <=10){
++digits;
number = number * 10 + (digit % 10); //note modulo 10 converts 10 back to 0.
if (digits == 3){
printf("%c",1000-number);
digits = 0;
number = 0;
}
}else{ /*Invalid character, ignoring*/ }
}

Related

I'm having issues with converting an IP address from Decimal, to Binary, then to Dotted Decimal in C++

I'm currently writing a program that will take in any IP address be it decimal, dotted, or binary, then will convert it to it's dotted, decimal, or binary counterparts and display all 3.
Now I'm having some issues as to where in my code its going wrong. I don't get errors, just weird output. Anyways I thought maybe a fresh pair of eyes would do me some good as I've been at this all day and I'm getting tired.
Also a heads up, the whole point is to practice string manipulation so all input given to each function is a string and the function returns the results as a string.
**Code for converting a decimal saved a string into binary: **
//Converts a decimal address to a binary address.
string internet_address :: convertDecimaltoBinary(string decimal)
{
//Variable to convert the decimal address string to an int.
int dec = stoi(decimal);
//Instantiated variables
int remain = 0;
int count = 0;
string bin;
//While the decimal number doesn't equal 0
while(dec)
{
//Collects what the remainder would be of the current decimal divided by 2.
remain = dec % 2;
//Divides the current decimal by 2, stores the result back into the same variable.
dec /= 2;
//Increases the count variable.
count++;
//Appends the remainder variable to the binary string.
bin += to_string(remain);
//If the count variable is equal to 8, it resets the variable to 0 and appends a space to the
binary string.
if(count == 8)
{
count = 0;
bin += " ";
}
}
//Returns the Bin string that contains the binary address.
return bin;
}
**Code that converts the binary string into a Dotted Decimal string: **
//Converts a Binary address to a Dotted address
string internet_address :: convertBinarytoDotted(string binary)
{
//Initializing variables
string tempSect;
string dot;
long long binSect = 0;
int remain = 0;
int iterator = 0;
int index = 0;
int result;
int base;
//Runs until it completes every 8 digit section of the binary address.
while(iterator != 4)
{
remain = 0;
binSect = 0;
result = 0;
base = 1;
//Scans through and gets every indiviudal section in the binary address.
for(index; index < binary.length(); index++)
{
if(binary[index] == ' ')
{
index += 1;
break;
}
tempSect += binary[index];
}
//Converts the current binary section into a long variable type
binSect = stoll(tempSect);
//While the current section doesn't equal 0, it will conver the section into a number then append it
//To the dotted address string.
while(binSect)
{
remain = binSect % 10;
binSect /= 10;
result += remain*base;
base *= 2;
}
if(iterator != 3)
{
dot += to_string(result) + ".";
}
else
{
dot += to_string(result);
}
//Increases the iterator variable, indicating the first section of the
string is complete.
iterator++;
}
//Returns the completed dotted address.
return dot;
}

How do I print the elements of a char array?

I have to convert a decimal value into a string that shows the binary value, e.g. given 8, I need to print a string "1000". I have the conversion from decimal to binary, but when I print the values directly form the char array, I get little question marks instead of numbers. I know it has something to do with the way char arrays read values, but I can't figure out how to correct the issue.
void dec2Bin(int value, char binaryString[]) {
int remainder = 0;
int binDigit = 0;
int i = 0;
while (value != 0) {
binDigit = value % 2;
value /= 2;
binaryString[i] = char(binDigit);
i++;
}
for (int k = i - 1; k > 0; k--) {
cout << binaryString[k];
}
}
int main()
{
cout << "Enter a decimal number: ";
int num;
cin >> num;
char binaryString[20] = "";
dec2Bin(num, binaryString);
return 0;
}
When you do
binaryString[i] = char(binDigit);
you are assigning the decimal value 0 or 1 to binaryString[i]. That's okay, a char is basically nothing more than a small integer.
The problems comes when you want to print the value, as the only overloaded << operator to handle char treats the characters as a character, and in most encodings the values 0 and 1 are not printable.
There are two solutions:
Either you convert the character you want to print into a larger integer which won't be treated as a character:
cout << static_cast<int>(binaryString[k]);
Or you make the array contain actual printable characters instead:
binaryString[i] = binDigit + '0';

In c++, how can I grab the next few characters from a string?

My goal is to grab a specific part of a very large number and concatenate that part with another number, then continue. Since integers only go so high, I have a string of the number. I do NOT know what this number could be, so I can't input it in myself. I can use substr for the first part, but I am stuck shortly after.
An example
"435509590420924949"
I want to take the first 5 characters out, convert to integer, do my own calculation to them, then concatenate them with the rest of the string. So I will take 43550 out, do formula to get 49, then add 49 to another 5 in a row after the original string "95904" so the new answer will be "4995904".
This is my code for the first part I made up,
string temp;
int number;
temp = data.substr(0, 5);
number = atoi(temp.c_str());
This grabs the first first characters in the strings, converts to integers where I can calculate it, but I don't know how to grab the next 5 of the long string.
You can get the length of the string, so something like:
std::size_t startIndex = 0;
std::size_t blockLength = 5;
std::size_t length = data.length();
while(startIndex < length)
{
std::string temp = data.substr(startIndex, blockLength);
// do something with temp
startIndex += blockLength;
// TODO: this will skip the last "block" if it is < blockLength,
// so you need to modify it a bit for this case.
}
You can use loops. For example:
std::size_t subStrSize = 5;
for (std::size_t k = 0; k < data.size(); k+=subStrSize) {
std::size_t h = std::min(k + subStrSize - 1, data.size() - 1);
int number = 0;
for (std::size_t l = k; l <= h; ++l)
number = number * 10 + data[l] - '0';
//-- Some work with number --
}

Loop not processing the last character of a string

Basically, the (Vigenere) decryption works perfectly except for not including the final letter for the decryption. For instance, the decryption for m_text yields 48 letters instead of 49. I even tried to manipulate the loop but it doesn't work out well since i will get a out of range exception with .at(). Any help would be appreciated!
using namespace std;
#include <string>
#include <iostream>
int main()
{
string ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string m_text = "ZOWDLTRTNENMGONMPAPXVUXADRIXUBJMWEWYDSYXUSYKRNLXU";
int length = m_text.length();
string key = "DA";
string plainText = "";
int shift = 0;
int shift2 = 0;
//Loop that decrypts
for (int k = 0; k < length-1; k+=2)
{
//Key 1 shift
shift = m_text.at(k) - key.at(0);
//Key 2 shift
shift2 = m_text.at(k+1) - key.at(1);
if (shift >= 0)
{
plainText += ALPHABET.at(shift);
}
else
{
shift += 91;
plainText += (char)shift;
}
if (shift2 >= 0)
{
plainText += ALPHABET.at(shift2);
}
else
{
shift2 += 91;
plainText += (char)shift2;
}
}
cout << plainText << endl;
}
By the looks of things, you are decoding two characters at a time. So when you have 49 characters in your string, there is one left over (which doesn't get processed). If you make m_text 48 characters long, you will notice you get the correct result.
It might be easier to replicate your key to match the length of the message, then do character-by-character decoding.

Comparing a char

So, I am trying to figure out the best/simplest way to do this. For my algorithms class we are supposed read in a string (containing up to 40 characters) from a file and use the first character of the string (data[1]...we are starting the array at 1 and wanting to use data[0] as something else later) as the number of rotations(up to 26) to rotate letters that follow (it's a Caesar cipher, basically).
An example of what we are trying to do is read in from a file something like : 2ABCD and output CDEF.
I've definitely made attempts, but I am just not sure how to compare the first letter in the array char[] to see which number, up to 26, it is. This is how I had it implemented (not the entire code, just the part that I'm having issues with):
int rotation = 0;
char data[41];
for(int i = 0; i < 41; i++)
{
data[i] = 0;
}
int j = 0;
while(!infile.eof())
{
infile >> data[j+1];
j++;
}
for(int i = 1; i < 27; i++)
{
if( i == data[1])
{
rotation = i;
cout << rotation;
}
}
My output is always 0 for rotation.
I'm sure the problem lies in the fact that I am trying to compare a char to a number and will probably have to convert to ascii? But I just wanted to ask and see if there was a better approach and get some pointers in the right direction, as I am pretty new to C++ syntax.
Thanks, as always.
Instead of formatted input, use unformatted input. Use
data[j+1] = infile.get();
instead of
infile >> data[j+1];
Also, the comparison of i to data[1] needs to be different.
for(int i = 1; i < 27; i++)
{
if( i == data[1]-'0')
// ^^^ need this to get the number 2 from the character '2'.
{
rotation = i;
std::cout << "Rotation: " << rotation << std::endl;
}
}
You can do this using modulo math, since characters can be treated as numbers.
Let's assume only uppercase letters (which makes the concept easier to understand).
Given:
static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const std::string original_text = "MY DOG EATS HOMEWORK";
std::string encrypted_text;
The loop:
for (unsigned int i = 0; i < original_text.size(); ++i)
{
Let's convert the character in the string to a number:
char c = original_text[i];
unsigned int cypher_index = c - 'A';
The cypher_index now contains the alphabetic offset of the letter, e.g. 'A' has index of 0.
Next, we rotate the cypher_index by adding an offset and using modulo arithmetic to "circle around":
cypher_index += (rotation_character - 'A'); // Add in the offset.
cypher_index = cypher_index % sizeof(letters); // Wrap around.
Finally, the new, shifted, letter is created by looking up in the letters array and append to the encrypted string:
encrypted_text += letters[cypher_index];
} // End of for loop.
The modulo operation, using the % operator, is great for when a "wrap around" of indices is needed.
With some more arithmetic and arrays, the process can be expanded to handle all letters and also some symbols.
First of all you have to cast the data chars to int before comparing them, just put (int) before the element of the char array and you will be okay.
Second, keep in mind that the ASCII table doesn't start with letters. There are some funny symbols up until 60-so element. So when you make i to be equal to data[1] you are practically giving it a number way higher than 27 so the loop stops.
The ASCII integer value of uppercase letters ranges from 65 to 90. In C and its descendents, you can just use 'A' through 'Z' in your for loop:
change
for(int i = 1; i < 27; i++)
to
for(int i = 'A'; i <= 'Z'; i++)
and you'll be comparing uppercase values. The statement
cout << rotation;
will print the ASCII values read from infile.
How much of the standard library are you permitted to use? Something like this would likely work better:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
int rotation = 0;
std::string data;
std::stringstream ss( "2ABCD" );
ss >> rotation;
ss >> data;
for ( int i = 0; i < data.length(); i++ ) {
data[i] += rotation;
}
// C++11
// for ( auto& c : data ) {
// c += rotation;
// }
std::cout << data;
}
Live demo
I used a stringstream instead of a file stream for this example, so just replace ss with your infile. Also note that I didn't handle the wrap-around case (i.e., Z += 1 isn't going to give you A; you'll need to do some extra handling here), because I wanted to leave that to you :)
The reason your rotation is always 0 is because i is never == data[1]. ASCII character digits do not have the same underlying numeric value as their integer representations. For example, if data[1] is '5', it's integer value is actually 49. Hint: you'll need to know these values when handle the wrap-around case. Do a quick google for "ANSI character set" and you'll see all the different values.
Your determination of the rotation is also flawed in that you're only checking data[1]. What happens if you have a two-digit number, like 10?