mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-11-30 16:31:08 +00:00
103 lines
3.1 KiB
Python
103 lines
3.1 KiB
Python
|
""" https://en.wikipedia.org/wiki/Rail_fence_cipher """
|
||
|
|
||
|
|
||
|
def encrypt(input_string: str, key: int) -> str:
|
||
|
"""
|
||
|
Shuffles the character of a string by placing each of them
|
||
|
in a grid (the height is dependent on the key) in a zigzag
|
||
|
formation and reading it left to right.
|
||
|
|
||
|
>>> encrypt("Hello World", 4)
|
||
|
'HWe olordll'
|
||
|
|
||
|
>>> encrypt("This is a message", 0)
|
||
|
Traceback (most recent call last):
|
||
|
...
|
||
|
ValueError: Height of grid can't be 0 or negative
|
||
|
|
||
|
>>> encrypt(b"This is a byte string", 5)
|
||
|
Traceback (most recent call last):
|
||
|
...
|
||
|
TypeError: sequence item 0: expected str instance, int found
|
||
|
"""
|
||
|
grid = [[] for _ in range(key)]
|
||
|
lowest = key - 1
|
||
|
|
||
|
if key <= 0:
|
||
|
raise ValueError("Height of grid can't be 0 or negative")
|
||
|
if key == 1 or len(input_string) <= key:
|
||
|
return input_string
|
||
|
|
||
|
for position, character in enumerate(input_string):
|
||
|
num = position % (lowest * 2) # puts it in bounds
|
||
|
num = min(num, lowest * 2 - num) # creates zigzag pattern
|
||
|
grid[num].append(character)
|
||
|
grid = ["".join(row) for row in grid]
|
||
|
output_string = "".join(grid)
|
||
|
|
||
|
return output_string
|
||
|
|
||
|
|
||
|
def decrypt(input_string: str, key: int) -> str:
|
||
|
"""
|
||
|
Generates a template based on the key and fills it in with
|
||
|
the characters of the input string and then reading it in
|
||
|
a zigzag formation.
|
||
|
|
||
|
>>> decrypt("HWe olordll", 4)
|
||
|
'Hello World'
|
||
|
|
||
|
>>> decrypt("This is a message", -10)
|
||
|
Traceback (most recent call last):
|
||
|
...
|
||
|
ValueError: Height of grid can't be 0 or negative
|
||
|
|
||
|
>>> decrypt("My key is very big", 100)
|
||
|
'My key is very big'
|
||
|
"""
|
||
|
grid = []
|
||
|
lowest = key - 1
|
||
|
|
||
|
if key <= 0:
|
||
|
raise ValueError("Height of grid can't be 0 or negative")
|
||
|
if key == 1:
|
||
|
return input_string
|
||
|
|
||
|
temp_grid = [[] for _ in range(key)] # generates template
|
||
|
for position in range(len(input_string)):
|
||
|
num = position % (lowest * 2) # puts it in bounds
|
||
|
num = min(num, lowest * 2 - num) # creates zigzag pattern
|
||
|
temp_grid[num].append("*")
|
||
|
|
||
|
counter = 0
|
||
|
for row in temp_grid: # fills in the characters
|
||
|
splice = input_string[counter : counter + len(row)]
|
||
|
grid.append([character for character in splice])
|
||
|
counter += len(row)
|
||
|
|
||
|
output_string = "" # reads as zigzag
|
||
|
for position in range(len(input_string)):
|
||
|
num = position % (lowest * 2) # puts it in bounds
|
||
|
num = min(num, lowest * 2 - num) # creates zigzag pattern
|
||
|
output_string += grid[num][0]
|
||
|
grid[num].pop(0)
|
||
|
return output_string
|
||
|
|
||
|
|
||
|
def bruteforce(input_string: str) -> dict:
|
||
|
"""Uses decrypt function by guessing every key
|
||
|
|
||
|
>>> bruteforce("HWe olordll")[4]
|
||
|
'Hello World'
|
||
|
"""
|
||
|
results = {}
|
||
|
for key_guess in range(1, len(input_string)): # tries every key
|
||
|
results[key_guess] = decrypt(input_string, key_guess)
|
||
|
return results
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
import doctest
|
||
|
|
||
|
doctest.testmod()
|