Merge branch 'temp-solutions' into solutions
[cipher-training.git] / cipher.py
1 """A set of ciphers with implementations for both enciphering and deciphering
2 them. See cipherbreak for automatic breaking of these ciphers
3 """
4
5 import string
6 import collections
7 from language_models import unaccent, sanitise
8
9
10 def caesar_encipher_letter(accented_letter, shift):
11 """Encipher a letter, given a shift amount
12
13 >>> caesar_encipher_letter('a', 1)
14 'b'
15 >>> caesar_encipher_letter('a', 2)
16 'c'
17 >>> caesar_encipher_letter('b', 2)
18 'd'
19 >>> caesar_encipher_letter('x', 2)
20 'z'
21 >>> caesar_encipher_letter('y', 2)
22 'a'
23 >>> caesar_encipher_letter('z', 2)
24 'b'
25 >>> caesar_encipher_letter('z', -1)
26 'y'
27 >>> caesar_encipher_letter('a', -1)
28 'z'
29 >>> caesar_encipher_letter('A', 1)
30 'B'
31 >>> caesar_encipher_letter('é', 1)
32 'f'
33 """
34 letter = unaccent(accented_letter)
35 if letter in string.ascii_letters:
36 if letter in string.ascii_uppercase:
37 alphabet_start = ord('A')
38 else:
39 alphabet_start = ord('a')
40 return chr(((ord(letter) - alphabet_start + shift) % 26) +
41 alphabet_start)
42 else:
43 return letter
44
45 def caesar_decipher_letter(letter, shift):
46 """Decipher a letter, given a shift amount
47
48 >>> caesar_decipher_letter('b', 1)
49 'a'
50 >>> caesar_decipher_letter('b', 2)
51 'z'
52 """
53 return caesar_encipher_letter(letter, -shift)
54
55 def caesar_encipher(message, shift):
56 """Encipher a message with the Caesar cipher of given shift
57
58 >>> caesar_encipher('abc', 1)
59 'bcd'
60 >>> caesar_encipher('abc', 2)
61 'cde'
62 >>> caesar_encipher('abcxyz', 2)
63 'cdezab'
64 >>> caesar_encipher('ab cx yz', 2)
65 'cd ez ab'
66 >>> caesar_encipher('Héllo World!', 2)
67 'Jgnnq Yqtnf!'
68 """
69 enciphered = [caesar_encipher_letter(l, shift) for l in message]
70 return ''.join(enciphered)
71
72 def caesar_decipher(message, shift):
73 """Decipher a message with the Caesar cipher of given shift
74
75 >>> caesar_decipher('bcd', 1)
76 'abc'
77 >>> caesar_decipher('cde', 2)
78 'abc'
79 >>> caesar_decipher('cd ez ab', 2)
80 'ab cx yz'
81 >>> caesar_decipher('Jgnnq Yqtnf!', 2)
82 'Hello World!'
83 """
84 return caesar_encipher(message, -shift)
85
86
87 if __name__ == "__main__":
88 import doctest
89 doctest.testmod()