Scytale enciphering working, but have to think about what to do with a 16 character...
authorNeil Smith <neil.github@njae.me.uk>
Fri, 25 Oct 2013 18:59:19 +0000 (19:59 +0100)
committerNeil Smith <neil.github@njae.me.uk>
Fri, 25 Oct 2013 18:59:19 +0000 (19:59 +0100)
cipher.py

index 2ce1c929c7f06f5f081ec70802be5832b01ca03b..6a138a075e2fa570260fdff8b4c1d8f10b93351c 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -2,6 +2,7 @@ import string
 import collections
 import norms
 import logging
+import math
 from itertools import zip_longest
 from segment import segment
 
@@ -304,6 +305,40 @@ def keyword_decipher(message, keyword, wrap_alphabet=0):
     cipher_translation = ''.maketrans(cipher_alphabet, string.ascii_lowercase)
     return message.lower().translate(cipher_translation)
 
+def scytale_encipher(message, rows):
+    """Enciphers using the scytale transposition cipher
+    
+    >>> scytale_encipher('thequickbrownfox', 3)
+    'tcnhkfeboqrxuoiw'
+    >>> scytale_encipher('thequickbrownfox', 4)
+    'tubnhirfecooqkwx'
+    >>> scytale_encipher('thequickbrownfox', 5)
+    'tubnhirfecooqkwx'
+    >>> scytale_encipher('thequickbrownfox', 6)
+    'tqcrnxhukofeibwo'
+    >>> scytale_encipher('thequickbrownfox', 7)
+    'tqcrnxhukofeibwo'
+    """
+    row_length = math.ceil(len(message) / rows)
+    slices = [message[i:i+row_length] for i in range(0, len(message), row_length)]
+    return ''.join([''.join(r) for r in zip_longest(*slices, fillvalue='')])
+
+def scytale_decipher(message, rows):
+    """Deciphers using the scytale transposition cipher
+    
+    >>> scytale_decipher('tcnhkfeboqrxuoiw', 3)
+    'thequickbrownfox'
+    """
+    cols = math.ceil(len(message) / rows)
+    if len(message) % rows == 0:
+        part_cols = 0
+    else:
+        part_cols = rows - len(message) % rows
+    full_cols = cols - part_cols
+    columns = [message[i:i+rows] for i in range(0, full_cols * rows, rows)] + \
+              [message[i:i+rows-1] for i in range(full_cols * rows, len(message), rows - 1)]
+    return ''.join([''.join(c) for c in zip_longest(*columns, fillvalue='')])
+
 
 def caesar_break(message, metric=norms.euclidean_distance, target_frequencies=normalised_english_counts, message_frequency_scaling=norms.normalise):
     """Breaks a Caesar cipher using frequency analysis