
/**
 * Zig-zag Cipher
 * Problem 2, AIC 2004 (Senior)
 * C++ Sample Solution
 */

/**
 * This solution deciphers the message by:
 *  - first determining the length of the original message, textLength;
 *  - encrypting the integers 0 .. textLength-1 according to the scheme in the
 *    question.
 *  - reading the numbers left-to-right, top-to-bottom from the step above to
 *    generate a table that links index in the encrypted text to an index in
 *    the plain text.
 *  - use this table to decrypt the message.
 *
 * For example, to decrypt COPATGAHRRY in 3 rows, we consider the 11 integers
 * 0, 1, 2, ... 11. Encrypting this into a 2-D array, dummyText, makes the
 * array look like:
 *
 *   0 5 6 11
 *   1 4 7 10
 *   2 3 8 9
 *
 * We can then generate a table, decryptMap, that matches the position in the
 * encrypted text to their index in the original text:
 *
 *            i  0    1    2    3    4    5    6    7    8    9   10   11
 * decryptMap[i] 0    5    6   11    1    4    7   10    2    3    8    9
 *
 * We can then read the original message by printing out the characters in the
 * order given by the table.
 *
 */

#include <fstream>
#include <string>

#define MAXMESSAGE 10000
#define MAXROWS 100

std::ifstream in("zigin.txt");
std::ofstream out("zigout.txt");

int decryptMap[MAXMESSAGE]; // decrypt[i] = ciphertext index for plaintext[i].

int dummyText[MAXROWS][MAXMESSAGE];
int rowLen[MAXROWS];

int rows;
std::string ciphertext;

int main() {
    // Read the number of rows the deciphered text will fill.
    in >> rows;

    // Clear the rowLen array - assume all rows are empty.
    for (int i = 0; i < rows; i++)
        rowLen[i] = 0;

    // Read in the first line of text.
    std::string text;
    in >> text;
    // If the current line of text is a "#", then we have the entire input.
    while (text != "#") {
        // We have a string which is not just a #
        // Append it to the existing string.
        ciphertext += text;

        // Read in the next line.
        in >> text;
    }

    // We know the length of the encrypted text and the number of rows that it
    // fills.
    //
    // Fill in the dummyText array with the encrypted version of the integers
    // 0 .. textLength-1.
    int currRow = 0; // Starting at row 0.
    int currDir = 1; // Heading down to begin with.
    for (int i = 0; i < ciphertext.length(); i++) {
        // Mark this position in the dummy array.
        dummyText[currRow][rowLen[currRow]] = i;
        rowLen[currRow]++;

        // Move to the next row for the next character.
        currRow += currDir;

        // If we are at the top or the bottom, change direction.
        if (currRow == rows - 1)
            currDir = -1;
        else if (currRow == 0)
            currDir = 1;
    }

    // Construct the decryptMap array from the dummyText.
    int pos = 0;
    for (currRow = 0; currRow < rows; currRow++)
        for (int i = 0; i < rowLen[currRow]; i++)
            decryptMap[dummyText[currRow][i]] = pos++;

    // We now know the order to print out the letters from the plain text.
    for (pos = 0; pos < ciphertext.length(); pos++)
        out << ciphertext[decryptMap[pos]];
    out << std::endl;

    return 0;
}

