Deleted old copy of 'find caesar break params'
[cipher-tools.git] / cipher.py
index 6f72c26a48d35dc3689f33731e820dcc66f41da6..7feaedf90fd289b9fda1da60f0dea9565e1108d1 100644 (file)
--- a/cipher.py
+++ b/cipher.py
@@ -1,11 +1,7 @@
 import string
 import collections
-# import norms
 import logging
-# import math
-from itertools import zip_longest, repeat, cycle
-# from segment import segment
-# from multiprocessing import Pool
+from itertools import zip_longest, cycle
 
 
 logger = logging.getLogger(__name__)
@@ -84,6 +80,22 @@ def combine_every_nth(split_text):
     return ''.join([''.join(l) 
                     for l in zip_longest(*split_text, fillvalue='')])
 
+def chunks(text, n, fillvalue=None):
+    """Split a text into chunks of n characters
+
+    >>> chunks('abcdefghi', 3)
+    ['abc', 'def', 'ghi']
+    >>> chunks('abcdefghi', 4)
+    ['abcd', 'efgh', 'i']
+    >>> chunks('abcdefghi', 4, fillvalue='!')
+    ['abcd', 'efgh', 'i!!!']
+    """
+    if fillvalue:
+        padding = fillvalue[0] * (n - len(text) % n)
+    else:
+        padding = ''
+    return [(text+padding)[i:i+n] for i in range(0, len(text), n)]
+
 def transpose(items, transposition):
     """Moves items around according to the given transposition
     
@@ -94,7 +106,7 @@ def transpose(items, transposition):
     >>> transpose([10,11,12,13,14,15], (3,2,4,1,5,0))
     [13, 12, 14, 11, 15, 10]
     """
-    transposed = list(repeat('', len(transposition)))
+    transposed = [''] * len(transposition)
     for p, t in enumerate(transposition):
        transposed[p] = items[t]
     return transposed
@@ -109,18 +121,15 @@ def untranspose(items, transposition):
     >>> untranspose([13, 12, 14, 11, 15, 10], [3,2,4,1,5,0])
     [10, 11, 12, 13, 14, 15]
     """
-    transposed  = list(repeat('', len(transposition)))
+    transposed = [''] * len(transposition)
     for p, t in enumerate(transposition):
        transposed[t] = items[p]
     return transposed
 
-
-
 def deduplicate(text):
     return list(collections.OrderedDict.fromkeys(text))
 
 
-
 def caesar_encipher_letter(letter, shift):
     """Encipher a letter, given a shift amount
 
@@ -398,7 +407,8 @@ def transpositions_of(keyword):
         transpositions = tuple(key.index(l) for l in sorted(key))
         return transpositions
 
-def column_transposition_encipher(message, keyword, fillvalue=' '):
+def column_transposition_encipher(message, keyword, fillvalue=' ', 
+      columnwise=False):
     """Enciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
 
@@ -406,11 +416,19 @@ def column_transposition_encipher(message, keyword, fillvalue=' '):
     'hleolteher'
     >>> column_transposition_encipher('hellothere', 'cleverly', fillvalue='!')
     'hleolthre!e!'
+    >>> column_transposition_encipher('hellothere', 'clever', columnwise=True)
+    'htleehoelr'
     """
-    return column_transposition_worker(message, keyword, encipher=True, 
-                                       fillvalue=fillvalue)
+    transpositions = transpositions_of(keyword)
+    columns = every_nth(message, len(transpositions), fillvalue=fillvalue)
+    transposed_columns = transpose(columns, transpositions)
+    if columnwise:
+        return ''.join(transposed_columns)
+    else:
+        return combine_every_nth(transposed_columns)
 
-def column_transposition_decipher(message, keyword, fillvalue=' '):
+def column_transposition_decipher(message, keyword, fillvalue=' ', 
+      columnwise=False):
     """Deciphers using the column transposition cipher.
     Message is padded to allow all rows to be the same length.
 
@@ -418,29 +436,17 @@ def column_transposition_decipher(message, keyword, fillvalue=' '):
     'hellothere'
     >>> column_transposition_decipher('hleolthre!e!', 'cleverly', fillvalue='?')
     'hellothere!!'
-    """
-    return column_transposition_worker(message, keyword, encipher=False, 
-                                       fillvalue=fillvalue)
-
-def column_transposition_worker(message, keyword, 
-                                encipher=True, fillvalue=' '):
-    """Does the actual work of the column transposition cipher.
-    Message is padded with spaces to allow all rows to be the same length.
-
-    >>> column_transposition_worker('hellothere', 'clever')
-    'hleolteher'
-    >>> column_transposition_worker('hellothere', 'clever', encipher=True)
-    'hleolteher'
-    >>> column_transposition_worker('hleolteher', 'clever', encipher=False)
+    >>> column_transposition_decipher('htleehoelr', 'clever', columnwise=True)
     'hellothere'
     """
     transpositions = transpositions_of(keyword)
-    columns = every_nth(message, len(transpositions), fillvalue=fillvalue)
-    if encipher:
-        transposed_columns = transpose(columns, transpositions)
+    if columnwise:
+        columns = chunks(message, int(len(message) / len(transpositions)))
     else:
-        transposed_columns = untranspose(columns, transpositions)
-    return combine_every_nth(transposed_columns)
+        columns = every_nth(message, len(transpositions), fillvalue=fillvalue)
+    untransposed_columns = untranspose(columns, transpositions)
+    return combine_every_nth(untransposed_columns)
+
 
 def vigenere_encipher(message, keyword):
     """Vigenere encipher
@@ -462,6 +468,8 @@ def vigenere_decipher(message, keyword):
     pairs = zip(message, cycle(shifts))
     return ''.join([caesar_decipher_letter(l, k) for l, k in pairs])
 
+beaufort_encipher=vigenere_decipher
+beaufort_decipher=vigenere_encipher
 
 
 if __name__ == "__main__":