Transposition cipher code not completely working

Pages: 12

Input into array

O N E O F T H E
E A R L I E S T
K N O W N U S E S
O F T R A N S P
O S I T I O N C O
D E S W A S D E
S I G N E D B Y
T H E S P A R T A
N S # # # # # # # #
# # # # # # # # # #

Output array order

1 2 4 7 11 16 22 29 37 46
3 5 8 12 17 23 30 38 47 56
6 9 13 18 24 31 39 48 57 65
10 14 19 25 32 40 49 58 66 73
15 20 26 33 41 50 59 67 74 80
21 27 34 42 51 60 68 75 81 86
28 35 43 52 61 69 76 82 87 91
36 44 53 62 70 77 83 88 92 95
45 54 63 71 78 84 89 93 96 98
55 64 72 79 85 90 94 97 99 100

This code is supposed to take a sentence from a user and then encrypt it with a transposition cipher. It works for the most part, but some characters are out of place. For example, if you input the sentence "ONE OF THE EARLIEST KNOWN USES OF TRANSPOSITION CODES WAS DESIGNED BY THE SPARTANS", and output it with the cipher, the character in the ninth row and ninth column of the output should be a '#'. Since that spot should output the 98th character from the original sentence, but it does not.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <iostream>

using namespace std;

class Functions
{
    private:
        char cipherArray[10][10];
        char cipherArrayTwo[10][10];
        int initialOnes[10]{};
        int input{};
        int counter{};
        int row{};
        int ones{};
        int holder{};
        int increment{};
        int incrementTwo=1;;
        string sentance;

    public:
        void arrayInitialize (char (&tempArray)[10][10])
        {
            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                    tempArray[j][i]='#';
                }
            }
        }

        void intArrayInitialize (int (&tempArray)[10])
        {
            for (int i=0;i<10;i++)
            {
                if (i==0)
                {
                    tempArray[i]=0;
                }

                else
                {
                    incrementTwo++;
                    tempArray[i]+=incrementTwo+tempArray[i-1];
                }
            }
        }

        void userInput (string &tempString)
        {
            cout << "Enter a sentance: ";
            getline (cin, tempString);
            cout << endl;
        }

        void transposition ()
        {
            for (int k=0;k<10;k++)
            {
                increment=k;
                ones=initialOnes[k];

                for (int i=0;i<10;i++)
                {
                    if (ones<10)
                    {
                        cipherArrayTwo[k][i]=cipherArray[row][ones];
                        increment++;
                        ones+=increment;
                    }

                    else if (ones>=10)
                    {
                        holder=ones;
                        row=ones/10;
                        ones=holder%10;

                        cipherArrayTwo[k][i]=cipherArray[row][ones];
                        ones=holder;
                        row=0;
                        increment++;
                        ones+=increment;
                    }
                }
            }
        }

        void stringArrayDisplay (char tempArray[10][10])
        {
            cout << "Encrypted Chart Form:" << endl << endl;

            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                   cout << cipherArrayTwo[j][i] << "\t";
                }
                cout << endl;
            }

            cout << endl << "Encrypted Regular Form: ";

            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                    cout << tempArray[j][i];
                }
            }
            cout << endl << endl;
        }

        void arrayFill (char (&tempArray)[10][10])
        {
            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                    tempArray[j][i]=sentance[counter];
                    counter++;

                    if (counter==sentance.length())
                    {
                        break;
                    }
                }

                if (counter==sentance.length())
                {
                    break;
                }
            }

        }

        void menu ()
        {
            while (input!=3)
            {
                cout << "1. Transposition cipher" << endl;
                cout << "2. Code breaker" << endl << endl;
                cout << "Enter the number of the option you want to proceed with: ";
                cin >> input;
                cout << endl;
                cin.ignore();

                switch (input)
                {
                    case 1:
                        arrayInitialize(cipherArray);
                        userInput(sentance);
                        arrayFill(cipherArray);
                        arrayInitialize(cipherArrayTwo);
                        intArrayInitialize(initialOnes);
                        transposition();
                        stringArrayDisplay(cipherArrayTwo);
                        break;
                }
            }
        }

};

int main()
{
    Functions program;
    program.menu();

    return 0;
}

  
The "transposition" function is supposed to encrypt the sentence into a new array.
This is a badly designed C++ program. It's almost as if you are trying to make C++ look like Java. If that's the case, stop! C++ is very different from Java. Your "design" (such as it is) is really just a way of using global variables while pretending not to. You'll never learn C++ that way.
Last edited on
How should I set up the variables then?
Get rid of the class and just have all of those functions as stand-alone functions.
Make the "menu" function your main.
Don't use any global variables.
Declare them all locally to the functions that use them and pass them to the functions through parameters.
Thats what I had before but I thought it was good practice to do it like this to get the hang of classes?
That's not how classes are used. Get a decent book and work through it if you want to learn about classes.
Apart from classes, could you please describe better the algorithm you are using?
Is there some web page where it's described or has it got a name?
1. The user enters a sentence which is stored into a 2D array "cipherArray" [10][10] of characters.

2. The cipherArray is sent to the transposition function to fill a new 2D array "cipherArrayTwo" [10][10] that arranges the characters in a different order.

3. The initial value of 'increment' is set to the value of the counter in the outer loop.

4. 'ones' is the index value of the character in the original array that will be stored into cipherArrayTwo.

5. Before the inner loop beings, ones is set to the index value from the original array that will fill the first spot in that row for the new array. (e.g. row 1=0, row 2=2, row 3=5, row 4=9)

6. If the value of ones becomes greater than 10, row becomes the 10's digit from ones, and ones becomes the ones digit.

7. once the spot is filled, rows becomes 0 and ones becomes its original value.

8. After every inner loop, increment is increased by 1, and that value is added to 'ones'
Last edited on
arranges the characters in a different order

Ok, I wasn't looking for a description of your code, but of the algorithm itself.
Did you devise it by your own or is it known by any name?

What I've understood so far is the algorithm takes a string of characters and applies <some calculation> on each of them. Is it correct? Next question is: what calculation?
For example:
- if the character is the first, it adds +1 to it; if it's the second, it adds +2, and so on.
Or:
- it swaps every odd character with the correspondent one from the last but one, and so on backwards...
A description like these.

I'm not a native English speaker, but I hope I explained myself: I'd like not a description of your solution, but of the problem.

And could you please specify if this is an assignment or not?
Your code seems overly-complicated.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

string encode(string s) {
    string out;
    int row_start = 0;
    for (int r = 0; r < 10; r++) {
        int n = row_start += r+1, col_inc = r, inc = 1;
        for (int c = 0; c < 10; c++) {
            if (col_inc > 9) {
                col_inc = 9;
                inc = -inc;
            }
            //cout << setw(3) << n << ' ';
            out += (n > int(s.size()) ? '#' : s[n-1]);
            n += col_inc;
            col_inc += inc;
        }
        //cout << '\n';
    }
    return out;
}

int main() {
    string line = "ONEOFTHEEARLIESTKNOWNUSESOFTRANSPOSITION"
                  "CODESWASDESIGNEDBYTHESPARTANS";
    cout << encode(line) << '\n';
}

Shezshade wrote:
5. Before the inner loop beings, ones is set to the index value from the original array that will fill the first spot in that row for the new array. (e.g. row 1=0, row 2=2, row 3=5, row 4=9)

This part is confusing me, and not just because it says "beings" ;D

I think part of my confusion (and I guess Enoizat's) is that it appears you're explaining your own solution (with "increment", "ones" variables etc) instead of just the general algo.

I see you're initializing an array to the values 0 2 5 9 14 20 27 35 44 54, which you're using to seed possible values for this "ones" index. Then in later steps there is some ambiguity as to which 'row' is changed (the source or the destination?). tpb's solution may very well be correct, but I'm sure it'd help if you clarified things a bit.

I think I see the pattern now, from the very first post.

You take the text and write it diagonally downward, from right to left, onto any open spaces you have. If we're using zero-based array indices, input of

 0   1   2   3   4   5   6   7   8   9
10  11  12  13  14  15  16  17  18  19
20  21  22  23  24  25  26  27  28  29
30  31  32  33  34  35  36  37  38  39
40  41  42  43  44  45  46  47  48  49
50  51  52  53  54  55  56  57  58  59
60  61  62  63  64  65  66  67  68  69
70  71  72  73  74  75  76  77  78  79
80  81  82  83  84  85  86  87  88  89
90  91  92  93  94  95  96  97  98  99


turns into
 0   1   3   6  10  15  21  28  36  45
 2   4   7  11  16  22  29  37  46  55
 5   8  12  17  23  30  38  47  56  64
 9  13  18  24  31  39  48  57  65  72
14  19  25  32  40  49  58  66  73  79
20  26  33  41  50  59  67  74  80  85
27  34  42  51  60  68  75  81  86  90
35  43  52  61  69  76  82  87  91  94
44  53  62  70  77  83  88  92  95  97
54  63  71  78  84  89  93  96  98  99


Now it's a lot clearer to me what "0 2 5 9 14 20 27 35 44 54" meant -- the elements at these source locations become the first in each of the destination rows.

Now it's a matter of translating typical (r,c) format into a transposed variation of the linear (columns*r + c) as you iterate over r and c from 0 to 9.

Edit: btw, when I initially tried something similar to Shezshade's attempt/description, careful to set source_row to (holder%100)/10 so that even if holder is three digits, source_row will still be the tens digit. The answer I got had the top-left triangle correct, but bottom-right was wrong.
Last edited on
Here's a possible solution, using the same idea of seeding the first elements of each row, though that part (seeds and diffs) is currently hard-wired for 10x10 matrices specifically. Edit: abstracted this now -- change the SIDE variable at the top for different results.

Since it's easier to iterate over rows and then columns, the seeding definitely helps. I kept everything in terms of the source row and column (src_r, src_c). I found that the differences between elements in each row incrementally increase by one, but after two +9s, it keeps decreasing by one. For example, zero-based row 4 looks like this:

(1,4) (1,9) (2,5) (3,2) (4,0) (4,9) (5,8) (6,6) (7,3) (7,9)
    +5    +6    +7    +8    +9    +9    +8    +7    +6


And so sometimes you need to increase incrementally increase the difference, and then the opposite, once you've run across two +9s. And so, a solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#include <iostream>
#include <array>

using namespace std;

const int SIDE = 10;                        // Matrix width and height
typedef array<array<char,SIDE>, SIDE> Mat;  // Helpful alias

// Add '#' to end for a total string size of SIDE*SIDE
void RightPad(string& input)
{
    int diff = SIDE*SIDE - input.size();
    if (diff <= 0)
        return;
    
    input = input + string(diff, '#');
}

// Converts the input to the blocky matrix format
void ConvertInputToMatrix(const string& input, Mat& a)
{
    if (input.size() < SIDE*SIDE)
        return;
    
    for (int r=0; r<SIDE; ++r)
        for (int c=0; c<SIDE; ++c)
            a[r][c] = input[r*SIDE + c];
}

// Source (r,c) pairs which correspond to first elements 
//   of each destination row
array<pair<int,int>, SIDE> GenerateSeeds()
{
    array<pair<int,int>, SIDE> seeds;
    for (int i=0, r=0, c=0, inc=2; i<SIDE; ++i, inc+=1)
    {
        seeds[i] = make_pair(r,c);
        c += inc;
        if (c>=SIDE)
        {
            r += 1;
            c %= SIDE;
        }
    }
    return seeds;
}

// Pattern of differences across elements within a row
array<int,SIDE> GenerateDiffs()
{
    array<int, SIDE> diffs;
    for (int i=0; i<SIDE; ++i)
    {
        diffs[i] = i+1;
    }
    diffs[SIDE-1] = SIDE-1;
    return diffs;
}

// Returns new transposed matrix with characters arranged 
//   right to left, diagonally downward
Mat CipherTranspose(const Mat& a)
{
    Mat m;
    auto seeds = GenerateSeeds();
    auto diffs = GenerateDiffs();
    int src_r, src_c;
    int di;           // Index for diffs
    bool increasing;  // Whether to increase or decrease di
    
    for (int r=0; r<SIDE; ++r)
    {
        src_r = seeds[r].first;
        src_c = seeds[r].second;
        m[r][0] = a[src_r][src_c];
        di = r;
        increasing = true;
        for (int c=1; c<SIDE; ++c)
        {
            src_c += diffs[di];
            if (src_c >= SIDE)
            {
                src_r += src_c/SIDE;
                src_c %= SIDE;
            }
            m[r][c] = a[src_r][src_c];
            
            if (increasing)
            {
                di += 1;
                if (di == SIDE)
                {
                    di = SIDE-3;
                    increasing = false;
                }
            }
            else
            {
                di -= 1;
                if (di == -1)
                {
                    // Currently unused since it happens on the
                    //  last element, but might matter for rects
                    di = 1;
                    increasing = true;
                }
            }
        }
    }
    return m;
}

void Show(const Mat& a)
{
    for (int r=0; r<SIDE; ++r)
    {
        for (int c=0; c<SIDE; ++c)
            cout << a[r][c] << ' ';
        cout << endl;
    }
    cout << endl << endl;
}

int main() 
{
    string input("ONE OF THE EARLIEST KNOWN USES OF "
                 "TRANSPOSITION CODES WAS DESIGNED BY THE SPARTANS");
    RightPad(input);
    
    Mat mat;
    ConvertInputToMatrix(input, mat);
    Show(mat);

    Mat encrypted = CipherTranspose(mat);
    Show(encrypted);
    
    return 0;
}


Can test at https://repl.it/repls/HarmoniousNervousForce

O N E   O F   T H E 
  E A R L I E S T   
K N O W N   U S E S 
  O F   T R A N S P 
O S I T I O N   C O 
D E S   W A S   D E 
S I G N E D   B Y   
T H E   S P A R T A 
N S # # # # # # # # 
# # # # # # # # # # 


O N       I N E A O 
E O T E E O S N N A 
F H A S W   S   S E 
E R T N O P C   D E 
L     F O O D     A 
K U   S D E B S N # 
S T I E S Y P S # # 
R T S I   A # # # # 
I   G T R # # # # # 
W N H T # # # # # # 

Last edited on
Thank you so much. Mine began to work after I breaked when the last letter of the sentence was rearranged. I'm still curious though as to why the initial code did not work?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#include <iostream>

using namespace std;

class Functions
{
    private:
        char cipherArray[10][10];
        char cipherArrayTwo[10][10];
        int initialOnes[10]{};
        int input{};
        int counter{};
        int row{};
        int ones{};
        int holder{};
        int increment{};
        int incrementTwo=1;;
        string sentance;

    public:
        void arrayInitialize (char (&tempArray)[10][10])
        {
            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                    tempArray[j][i]='#';
                }
            }
        }

        void intArrayInitialize (int (&tempArray)[10])
        {
            for (int i=0;i<10;i++)
            {
                if (i==0)
                {
                    tempArray[i]=0;
                }

                else
                {
                    incrementTwo++;
                    tempArray[i]+=incrementTwo+tempArray[i-1];
                }
            }
        }

        void userInput (string &tempString)
        {
            cout << "Enter a sentance: ";
            getline (cin, tempString);
            cout << endl;
        }

        void transposition ()
        {
            for (int k=0;k<10;k++)
            {
                increment=k;
                ones=initialOnes[k];

                if (ones>sentance.length())
                {
                    break;
                }

                for (int i=0;i<10;i++)
                {
                    if (ones>sentance.length())
                    {
                        break;
                    }

                    if (ones<10)
                    {
                        cipherArrayTwo[k][i]=cipherArray[row][ones];
                        increment++;
                        ones+=increment;
                    }

                    else if (ones>=10)
                    {
                        holder=ones;
                        row=ones/10;
                        ones=holder%10;

                        cipherArrayTwo[k][i]=cipherArray[row][ones];
                        ones=holder;
                        row=0;
                        increment++;
                        ones+=increment;
                    }
                }
            }
        }

        void stringArrayDisplay (char tempArray[10][10])
        {
            cout << "Encrypted Chart Form:" << endl << endl;

            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                   cout << cipherArrayTwo[j][i] << "\t";
                }
                cout << endl;
            }

            cout << endl << "Encrypted Regular Form: ";

            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                    cout << tempArray[j][i];
                }
            }
            cout << endl << endl;
        }

        void arrayFill (char (&tempArray)[10][10])
        {
            for (int j=0;j<10;j++)
            {
                for (int i=0;i<10;i++)
                {
                    tempArray[j][i]=sentance[counter];
                    counter++;

                    if (counter==sentance.length())
                    {
                        break;
                    }
                }

                if (counter==sentance.length())
                {
                    break;
                }
            }

        }

        void menu ()
        {
            while (input!=3)
            {
                cout << "1. Transposition cipher" << endl;
                cout << "2. Code breaker" << endl << endl;
                cout << "Enter the number of the option you want to proceed with: ";
                cin >> input;
                cout << endl;
                cin.ignore();

                switch (input)
                {
                    case 1:
                        arrayInitialize(cipherArray);
                        userInput(sentance);
                        arrayFill(cipherArray);
                        arrayInitialize(cipherArrayTwo);
                        intArrayInitialize(initialOnes);
                        transposition();
                        stringArrayDisplay(cipherArrayTwo);
                        break;
                }
            }
        }

};

int main()
{
    Functions program;
    program.menu();

    return 0;
}


Last edited on
Your lower-right "triangle" half is still off. After changing your tab to a space, since it's easier to see, for the same sentence ONE OF THE EARLIEST KNOWN USES OF TRANSPOSITION CODES WAS DESIGNED BY THE SPARTANS, I got:

O N       I N E A O 
E O T E E O S N N S 
F H A S W   S     Y 
E R T N O P C D   S 
L     F O O E T # # 
K U   S D S H # # # 
S T I E I E # # # # 
R T S G   # # # # # 
I   N S # # # # # # 
W E P # # # # # # #


See how it's going wrong at "WAS", the end of "DESIGNED", the "BY", and "SPARTANS"
Last edited on
Yeah you're right, do you have any idea as to why that could be?
I guess something with your algorithm logic isn't lining up with the actual pattern. Maybe it's the increasing->decreasing transition?

When I was coming up w/ my algo, I actually took a paper and wrote out the source rows and columns and tried to make sure those same (r,c) numbers would be generated in the transposition. Add print statements in your loop right before the assignments (line 76, line 87). You chose some unusual variable names; I guess it'd look like
cout << "k: "<<k<<", i: "<<i<<" from source ("<<row<<", "<<ones<<")\n";

Make sure, for example, your zero-based row 4 (k=4) looks like the one I posted before my solution.
I incorrectly identified the pattern. I thought the number increases by 1 more than the previous time it increased when it goes down the row. But near the end of the row that doesn't happen, hence why near the end of the rows my encryption didn't work. Could you please send what you drew? I'm a little unsure how to draw out an algorithm but I'd like to start.
icy1 wrote:
I actually took a paper and wrote out the source rows and columns and tried to make sure those same (r,c) numbers would be generated in the transposition

What I'm saying here is I wrote out 10 rows of stuff that looked like the row 4 I posted earlier, just (row, column) pairs of the source. Then you'd have something concrete to compare those cout debug statements against.
Pages: 12