1

I have pin-pointed where I think the error is. Parts of the program are also explained through the comments I have written below.

The logical error is that the entire encrypted message is a single letter, which is the first letter (i.e. string[0]) of the plaintext that the user enters. There must be a problem with the for loop that inserts the plaintext into the row arrays not iterating through the plaintext string correctly.

row1 = [' ', ' ', ' ', ' ', ' ', ' '] #initialise the rows as arrays
row2 = [' ', ' ', ' ', ' ', ' ', ' ']
row3 = [' ', ' ', ' ', ' ', ' ', ' ']
row4 = [' ', ' ', ' ', ' ', ' ', ' ']
row5 = [' ', ' ', ' ', ' ', ' ', ' ']
row6 = [' ', ' ', ' ', ' ', ' ', ' ']
def updateRow(aList, text, index): #function for removing spaces and inserting plaintext letters
    indexOfText = text[index]
    for i in range(1,7): #logic error in this loop
        aList.remove(' ')
        aList.insert(i, indexOfText)
    return aList
def createColumn(row1, row2, row3, row4, row5, row6, index): #function for creating columns by adding the rows with the same index
    column = row1[index] + row2[index] + row3[index] + row4[index] + row5[index] + row6[index]
    return column
def encrypt(col1, col2, col3, col4, col5, col6): #function for adding the columns together to produce the enciphered message
    cipher = col1 + col2 + col3 + col4 + col5 + col6
    return cipher  
while True:
    plaintext = input("Enter you message:") #input plaintext
    row1Pop = updateRow(row1, plaintext, 0) #populate rows with plaintext
    ... #continues
    row6Pop = updateRow(row6, plaintext, 0)
    column1 = createColumn(row1Pop, row2Pop, row3Pop, row4Pop, row5Pop, row6Pop, 0) #create required columns
    ... #continues   
    column6 = createColumn(row1Pop, row2Pop, row3Pop, row4Pop, row5Pop, row6Pop, 5)
    ciphertext = encrypt(column1, column2, column3, column4, column5, column6) #create final encrypted message
    print(ciphertext) #display encrypted message
    break

An example input would be:

this is my first attempt at it today

And the output for this becomes:

tttttttttttttttttttttttttttttttttttt

The output is meant to be this (if the program was working correctly):

tsit  h rtatimsetosytm d   piaifatty
Alice
  • 588
  • 1
  • 8
  • 25
  • What is `updateRow` supposed to do? If you are just trying to replace `'_'` by characters drawn from the plaintext -- just assign the plaintext character to the appropriate position. There is no reason at all to remove one element and then insert another. – John Coleman Jan 05 '17 at 13:19
  • @John Coleman I understand, that line of code may be redundant. That function is merely meant to iterate through the `plaintext` string and place each value of the string (which represents each individual letter) into the lists initialized above, such as `row1`. When one list is full, it moves to the next one and does the same until there are no plaintext letters left to iterate through. In that case, the spaces assigned to the rest of the lists stay as they are. – Alice Jan 05 '17 at 13:23

1 Answers1

2

If you want to achieve what you are trying to do with just standard Python, you could do:

def encrypt(p):
    #assumes len(p) <= 36
    #larger message needs to be broken into blocks of 36

    p += ' '*(36-len(p)) #pad with spaces if needed
    rows = [p[6*i:6*i+6] for i in range(6)] #slice into substrings of length 6
    columns = zip(*rows) #zip processes the rows in parallel
    return ''.join(''.join(column) for column in columns)

#test:

print(encrypt('this is my first attempt at it today'))

#prints 'tsit  h rtatimsetosytm d   piaifatty'

I don't expect you to fully follow that, but it gives a flavor of how Python works. As much as possible, lists should be assembled via comprehensions. In order to process a string character by character it isn't necessary to read the characters into a list. In the code above rows is just a list of 6 strings of length 6. If you aren't comfortable with list comprehensions yet, you could build it up in a loop like thus:

rows = []
for i in range(6):
    rows.append(p[6*i:6*i+6])

The way the cipher text is built up is a bit harder to explain. If you want to do so in a more elementary way, use nested for loops (note the order of the two loops):

ciphertext = ''
for j in range(6) #iterate over the columns
    for i in range(6) #iterate over rows
        ciphertext += rows[i][j]
return ciphertext

As far as your original code, I am not quite sure how to save it. The for loop that you mentioned is quite odd and you are correct that it has a bug. Note that indexOfText is not updated during the loop itself. Thus you are replacing aList by 6 copies of indexOfText. You don't need to remove an element from a list and then insert a new one. Instead, simply

aList[i] =  indexOfText #but use 0-based indexing

Rather than the 2-step

aList.remove(' ')
aList.insert(i, indexOfText)

though you still would have the logic error of using the same indexOfText for all i.

By the way, ecrypt can be made even shorter by using the optional step field in the slice operator:

def encrypt2(p):
    p += ' '*(36-len(p))
    return ''.join(p[i:36:6] for i in range(6))

this is functionally equivalent to encrypt. There is really no need to explicitly assemble the rows and columns, just slice out the characters you want in the order you want, join them together, and return.

Community
  • 1
  • 1
John Coleman
  • 51,337
  • 7
  • 54
  • 119
  • Thank you very much for this answer! May I ask you a few more questions about the syntax you used in your example? – Alice Jan 05 '17 at 15:15
  • @Arbiter Yes, of course though I am off to work in a bit and might not be able to answer right away – John Coleman Jan 05 '17 at 15:21
  • That's fine. 1) I don't fully understand list comprehensions, what are the 2 `i` for in `[p[6*i:6*i+6]` and what do the operations (`*` and `+`) do within that? 2) What does `zip(*rows)` do? (I don't understand the terminology 'zip processes') 3) is `.join()` similar to `.format()` and concatenation? I've never used `.join()` before. – Alice Jan 05 '17 at 15:30
  • 1
    @Arbiter 1) No easy short answer, any book or tutorial should explain them. 2) When `i = 0`, the slice `p[6*i:6*i+6]` is the same as `p[0:6]` when `i = 1` it is `p[6:12]`, etc. See the link to the question which discusses slices. 3) too involved for a comment, see a tutorial, 4) `join()` takes a list or iterable of strings and joins them into a single string. For example `'/'.join(['a','b','c'] == 'a/b/c'` and `''.join(['a','b','c']) = 'abc'`. It is idiomatic in Python to assemble the components of a string in the list and then assemble it in the end. If you haven't seen `join` yet, you will. – John Coleman Jan 05 '17 at 17:20