Im having a ton of trouble trying to figure out how to get my decrypt function to work. It works in ideal cases where the msg is divisible by 3, but after that i am totally lost
You can slice strings (or any other sequence) using a stride; you can select every 3rd character with that:
def threeRailEncrypt(plaintext):
return plaintext[::3] + plaintext[1::3] + plaintext[2::3]
To reverse the trend, slice up the ciphertext into three chunks and use itertools.zip_longest() to recombine them again:
from itertools import zip_longest, chain
def threeRailDecrypt(ciphertext):
stride, remainder = divmod(len(ciphertext), 3)
# how large was each of the three sections?
sizes = [stride] * 3
for i in range(remainder):
sizes[i] += 1
# slice ciphertext up into 3 sections again
pos = 0
pieces = []
for s in sizes:
pieces.append(ciphertext[pos:pos + s])
pos += s
# recombine the triplets
return ''.join(chain.from_iterable(zip_longest(*pieces, fillvalue='')))
Demo:
>>> threeRailEncrypt('Foo bar baz and all')
'F raa lob znaoab dl'
>>> threeRailDecrypt(threeRailEncrypt('Foo bar baz and all'))
'Foo bar baz and all'
The last part without zip_longest
would be:
# recombine the triplets
plaintext = []
for i in range(len(parts[0])):
for part in parts:
try:
plaintext.append(part[i])
except IndexError: # part too short
pass
return ''.join(plaintext)