Added tests for enigma machine and bombe
[cipher-training.git] / enigma.py
index cb57f7a26fd33a43bbddabac7bb9b9093ed3bf66..8c72f22bf558887842061541b64bfbb7918139f2 100644 (file)
--- a/enigma.py
+++ b/enigma.py
@@ -63,24 +63,6 @@ class LetterTransformer(object):
     """A generic substitution cipher, that has different transforms in the 
     forward and backward directions. It requires that the transforms for all
     letters by provided.
-
-    >>> lt = LetterTransformer([('z', 'a')] + [(l, string.ascii_lowercase[i+1]) \
-            for i, l in enumerate(string.ascii_lowercase[:-1])], \
-            raw_transform = True)
-    >>> lt.forward_map
-    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0]
-    >>> lt.backward_map
-    [25, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]
-
-    >>> lt = LetterTransformer(cat(collections.OrderedDict.fromkeys('zyxwc' + string.ascii_lowercase)))
-    >>> lt.forward_map
-    [25, 24, 23, 22, 2, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21]
-    >>> lt.backward_map
-    [5, 6, 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 3, 2, 1, 0]
-    >>> cat(lt.forward(l) for l in string.ascii_lowercase)
-    'zyxwcabdefghijklmnopqrstuv'
-    >>> cat(lt.backward(l) for l in string.ascii_lowercase)
-    'fgehijklmnopqrstuvwxyzdcba'
     """
     def __init__(self, specification, raw_transform=False):
         if raw_transform:
@@ -136,16 +118,6 @@ class Plugboard(LetterTransformer):
     """A plugboard, a type of letter transformer where forward and backward
     transforms are the same. If a letter isn't explicitly transformed, it is 
     kept as it is.
-
-    >>> pb = Plugboard('ua pf rq so ni ey bg hl tx zj'.upper())
-    >>> pb.forward_map
-    [20, 6, 2, 3, 24, 15, 1, 11, 13, 25, 10, 7, 12, 8, 18, 5, 17, 16, 14, 23, 0, 21, 22, 19, 4, 9]
-    >>> pb.forward_map == pb.backward_map
-    True
-    >>> cat(pb.forward(l) for l in string.ascii_lowercase)
-    'ugcdypblnzkhmisfrqoxavwtej'
-    >>> cat(pb.backward(l) for l in string.ascii_lowercase)
-    'ugcdypblnzkhmisfrqoxavwtej'
     """
     def parse_specification(self, specification):
         return [tuple(clean(p)) for p in specification.split()]
@@ -170,16 +142,6 @@ class Plugboard(LetterTransformer):
 
 class Reflector(Plugboard):
     """A reflector is a plugboard that requires 13 transforms.
-
-    >>> reflector_b = Reflector(reflector_b_spec)
-    >>> reflector_b.forward_map == reflector_b.backward_map
-    True
-    >>> reflector_b.forward_map
-    [24, 17, 20, 7, 16, 18, 11, 3, 15, 23, 13, 6, 14, 10, 12, 8, 4, 1, 5, 25, 2, 22, 21, 9, 0, 19]
-    >>> cat(reflector_b.forward(l) for l in string.ascii_lowercase)
-    'yruhqsldpxngokmiebfzcwvjat'
-    >>> cat(reflector_b.backward(l) for l in string.ascii_lowercase)
-    'yruhqsldpxngokmiebfzcwvjat'
     """
     def validate_transform(self, transform):
         if len(transform) != 13:
@@ -208,52 +170,6 @@ class SimpleWheel(LetterTransformer):
     Letter inputs and outputs are given relative to the frame holding the wheel,
     so if the wheel is advanced three places, an input of 'p' will enter the 
     wheel on the position under the wheel's 'q' label.
-
-    >>> rotor_1_transform = list(zip(string.ascii_lowercase, 'EKMFLGDQVZNTOWYHXUSPAIBRCJ'.lower()))
-    >>> wheel_1 = SimpleWheel(rotor_1_transform, raw_transform=True)
-    >>> cat(wheel_1.forward(l) for l in string.ascii_lowercase)
-    'ekmflgdqvzntowyhxuspaibrcj'
-    >>> cat(wheel_1.backward(l) for l in string.ascii_lowercase)
-    'uwygadfpvzbeckmthxslrinqoj'
-
-
-    >>> wheel_2 = SimpleWheel(wheel_ii_spec)
-    >>> cat(wheel_2.forward(l) for l in string.ascii_lowercase)
-    'ajdksiruxblhwtmcqgznpyfvoe'
-    >>> cat(wheel_2.backward(l) for l in string.ascii_lowercase)
-    'ajpczwrlfbdkotyuqgenhxmivs'
-
-    >>> wheel_3 = SimpleWheel(wheel_iii_spec)
-    >>> wheel_3.set_position('a')
-    >>> wheel_3.advance()
-    >>> cat(wheel_3.forward(l) for l in string.ascii_lowercase)
-    'cegikboqswuymxdhvfzjltrpna'
-    >>> cat(wheel_3.backward(l) for l in string.ascii_lowercase)
-    'zfaobrcpdteumygxhwivkqjnls'
-    >>> wheel_3.position
-    1
-    >>> wheel_3.position_l
-    'b'
-
-    >>> for _ in range(24): wheel_3.advance()
-    >>> wheel_3.position
-    25
-    >>> wheel_3.position_l
-    'z'
-    >>> cat(wheel_3.forward(l) for l in string.ascii_lowercase)
-    'pcegikmdqsuywaozfjxhblnvtr'
-    >>> cat(wheel_3.backward(l) for l in string.ascii_lowercase)
-    'nubhcqdterfvgwoaizjykxmslp'
-
-    >>> wheel_3.advance()
-    >>> wheel_3.position
-    0
-    >>> wheel_3.position_l
-    'a'
-    >>> cat(wheel_3.forward(l) for l in string.ascii_lowercase)
-    'bdfhjlcprtxvznyeiwgakmusqo'
-    >>> cat(wheel_3.backward(l) for l in string.ascii_lowercase)
-    'tagbpcsdqeufvnzhyixjwlrkom'
     """
     def __init__(self, transform, position='a', raw_transform=False):
         super(SimpleWheel, self).__init__(transform, raw_transform)
@@ -304,119 +220,6 @@ class Wheel(SimpleWheel):
     The peg_positions are the number of advances of this wheel before it will 
     advance the next wheel.
 
-    >>> wheel_3 = Wheel(wheel_iii_spec, wheel_iii_pegs, position='b', ring_setting=1)
-    >>> wheel_3.position
-    1
-    >>> wheel_3.peg_positions
-    [20]
-    >>> wheel_3.position_l
-    'b'
-    >>> wheel_3.advance()
-    >>> wheel_3.position
-    2
-    >>> wheel_3.peg_positions
-    [19]
-    >>> wheel_3.position_l
-    'c'
-
-    >>> wheel_6 = Wheel(wheel_vi_spec, wheel_vi_pegs, position='b', ring_setting=3)
-    >>> cat(wheel_6.forward(l) for l in string.ascii_lowercase)
-    'xkqhwpvngzrcfoiaselbtymjdu'
-    >>> cat(wheel_6.backward(l) for l in string.ascii_lowercase)
-    'ptlyrmidoxbswhnfckquzgeavj'
-    >>> wheel_6.position
-    25
-    >>> 11 in wheel_6.peg_positions
-    True
-    >>> 24 in wheel_6.peg_positions
-    True
-    >>> wheel_6.position_l
-    'b'
-
-    >>> wheel_6.advance()
-    >>> cat(wheel_6.forward(l) for l in string.ascii_lowercase)
-    'jpgvoumfyqbenhzrdkasxlictw'
-    >>> cat(wheel_6.backward(l) for l in string.ascii_lowercase)
-    'skxqlhcnwarvgmebjptyfdzuio'
-    >>> wheel_6.position
-    0
-    >>> 10 in wheel_6.peg_positions
-    True
-    >>> 23 in wheel_6.peg_positions
-    True
-    >>> wheel_6.position_l
-    'c'
-
-    >>> for _ in range(22): wheel_6.advance()
-    >>> cat(wheel_6.forward(l) for l in string.ascii_lowercase)
-    'mgxantkzsyqjcufirldvhoewbp'
-    >>> cat(wheel_6.backward(l) for l in string.ascii_lowercase)
-    'dymswobuplgraevzkqifntxcjh'
-    >>> wheel_6.position
-    22
-    >>> 1 in wheel_6.peg_positions
-    True
-    >>> 14 in wheel_6.peg_positions
-    True
-    >>> wheel_6.position_l
-    'y'
-
-    >>> wheel_6.advance()
-    >>> cat(wheel_6.forward(l) for l in string.ascii_lowercase)
-    'fwzmsjyrxpibtehqkcugndvaol'
-    >>> cat(wheel_6.backward(l) for l in string.ascii_lowercase)
-    'xlrvnatokfqzduyjphemswbigc'
-    >>> wheel_6.position
-    23
-    >>> 0 in wheel_6.peg_positions
-    True
-    >>> 13 in wheel_6.peg_positions
-    True
-    >>> wheel_6.position_l
-    'z'
-
-    >>> wheel_6.advance()
-    >>> cat(wheel_6.forward(l) for l in string.ascii_lowercase)
-    'vylrixqwohasdgpjbtfmcuznke'
-    >>> cat(wheel_6.backward(l) for l in string.ascii_lowercase)
-    'kqumzsnjepyctxiogdlrvahfbw'
-    >>> wheel_6.position
-    24
-    >>> 25 in wheel_6.peg_positions
-    True
-    >>> 12 in wheel_6.peg_positions
-    True
-    >>> wheel_6.position_l
-    'a'
-
-    >>> wheel_6.advance()
-    >>> cat(wheel_6.forward(l) for l in string.ascii_lowercase)
-    'xkqhwpvngzrcfoiaselbtymjdu'
-    >>> cat(wheel_6.backward(l) for l in string.ascii_lowercase)
-    'ptlyrmidoxbswhnfckquzgeavj'
-    >>> wheel_6.position
-    25
-    >>> 24 in wheel_6.peg_positions
-    True
-    >>> 11 in wheel_6.peg_positions
-    True
-    >>> wheel_6.position_l
-    'b'
-
-    >>> wheel_6.advance()
-    >>> cat(wheel_6.forward(l) for l in string.ascii_lowercase)
-    'jpgvoumfyqbenhzrdkasxlictw'
-    >>> cat(wheel_6.backward(l) for l in string.ascii_lowercase)
-    'skxqlhcnwarvgmebjptyfdzuio'
-    >>> wheel_6.position
-    0
-    >>> 23 in wheel_6.peg_positions
-    True
-    >>> 10 in wheel_6.peg_positions
-    True
-    >>> wheel_6.position_l
-    'c'
-
     """
     def __init__(self, transform, ring_peg_letters, ring_setting=1, position='a', raw_transform=False):
         self.ring_peg_letters = ring_peg_letters
@@ -442,489 +245,7 @@ class Wheel(SimpleWheel):
 class Enigma(object):
     """An Enigma machine.
 
-    >>> enigma = Enigma(reflector_b_spec, \
-                wheel_i_spec, wheel_i_pegs, \
-                wheel_ii_spec, wheel_ii_pegs, \
-                wheel_iii_spec, wheel_iii_pegs, \
-                1, 1, 1, \
-                '')
-    >>> enigma.set_wheels('a', 'a', 't')
-    >>> enigma.wheel_positions
-    (0, 0, 19)
-    >>> cat(enigma.wheel_positions_l)
-    'aat'
-    >>> enigma.peg_positions
-    ([16], [4], [2])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'puvioztjdhxmlyeawsrgbcqknf'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 0, 20)
-    >>> cat(enigma.wheel_positions_l)
-    'aau'
-    >>> enigma.peg_positions
-    ([16], [4], [1])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'baigpldqcowfyzjehvtsxrkumn'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 0, 21)
-    >>> cat(enigma.wheel_positions_l)
-    'aav'
-    >>> enigma.peg_positions
-    ([16], [4], [0])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'mnvfydiwgzsoablrxpkutchqej'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 1, 22)
-    >>> cat(enigma.wheel_positions_l)
-    'abw'
-    >>> enigma.peg_positions
-    ([16], [3], [25])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'ulfopcykswhbzvderqixanjtgm'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 1, 23)
-    >>> cat(enigma.wheel_positions_l)
-    'abx'
-    >>> enigma.peg_positions
-    ([16], [3], [24])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'qmwftdyovursbzhxaklejicpgn'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 1, 24)
-    >>> cat(enigma.wheel_positions_l)
-    'aby'
-    >>> enigma.peg_positions
-    ([16], [3], [23])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'oljmzxrvucybdqasngpwihtfke'
-
-
-
-
-    >>> enigma.set_wheels('a', 'd', 't')
-    >>> enigma.wheel_positions
-    (0, 3, 19)
-    >>> cat(enigma.wheel_positions_l)
-    'adt'
-    >>> enigma.peg_positions
-    ([16], [1], [2])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'zcbpqxwsjiuonmldethrkygfva'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 3, 20)
-    >>> cat(enigma.wheel_positions_l)
-    'adu'
-    >>> enigma.peg_positions
-    ([16], [1], [1])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'ehprawjbngotxikcsdqlzyfmvu'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 3, 21)
-    >>> cat(enigma.wheel_positions_l)
-    'adv'
-    >>> enigma.peg_positions
-    ([16], [1], [0])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'eqzxarpihmnvjkwgbfuyslodtc'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (0, 4, 22)
-    >>> cat(enigma.wheel_positions_l)
-    'aew'
-    >>> enigma.peg_positions
-    ([16], [0], [25])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'qedcbtpluzmhkongavwfirsyxj'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (1, 5, 23)
-    >>> cat(enigma.wheel_positions_l)
-    'bfx'
-    >>> enigma.peg_positions
-    ([15], [25], [24])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'iwuedhsfazqxytvrkpgncoblmj'
-
-    >>> enigma.advance()
-    >>> enigma.wheel_positions
-    (1, 5, 24)
-    >>> cat(enigma.wheel_positions_l)
-    'bfy'
-    >>> enigma.peg_positions
-    ([15], [25], [23])
-    >>> cat(enigma.lookup(l) for l in string.ascii_lowercase)
-    'baknstqzrmcxjdvygiefwoulph'
-
-
-    >>> enigma.set_wheels('a', 'a', 'a')
-    >>> ct = enigma.encipher('testmessage')
-    >>> ct
-    'olpfhnvflyn'
-
-    >>> enigma.set_wheels('a', 'd', 't')
-    >>> ct = enigma.encipher('testmessage')
-    >>> ct
-    'lawnjgpwjik'
-
-
-    >>> enigma.set_wheels('b', 'd', 'q')
-    >>> ct = enigma.encipher('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
-    >>> ct
-    'kvmmwrlqlqsqpeugjrcxzwpfyiyybwloewrouvkpoztceuwtfjzqwpbqldttsr'
-    >>> enigma.left_wheel.position_l
-    'c'
-    >>> enigma.middle_wheel.position_l
-    'h'
-    >>> enigma.right_wheel.position_l
-    'a'
-
-    # Setting sheet line 31 from http://www.codesandciphers.org.uk/enigma/enigma3.htm
-    # Enigma simulation settings are 
-    # http://enigma.louisedade.co.uk/enigma.html?m3;b;b153;AFTX;AJEU;AU-BG-EY-FP-HL-IN-JZ-OS-QR-TX
-    >>> enigma31 = Enigma(reflector_b_spec, \
-                wheel_i_spec, wheel_i_pegs, \
-                wheel_v_spec, wheel_v_pegs, \
-                wheel_iii_spec, wheel_iii_pegs, \
-                6, 20, 24, \
-                'ua pf rq so ni ey bg hl tx zj')
-
-    >>> enigma31.set_wheels('j', 'e', 'u')
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (4, 11, 24)
-    >>> cat(enigma31.wheel_positions_l)
-    'jev'
-    >>> enigma31.peg_positions
-    ([7], [21], [0])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'mvqjlyowkdieasgzcunxrbhtfp'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (4, 12, 25)
-    >>> cat(enigma31.wheel_positions_l)
-    'jfw'
-    >>> enigma31.peg_positions
-    ([7], [20], [25])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'sjolzuyvrbwdpxcmtiaqfhknge'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (4, 12, 0)
-    >>> cat(enigma31.wheel_positions_l)
-    'jfx'
-    >>> enigma31.peg_positions
-    ([7], [20], [24])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'qrxedkoywufmlvgsabpzjnicht'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (4, 12, 1)
-    >>> cat(enigma31.wheel_positions_l)
-    'jfy'
-    >>> enigma31.peg_positions
-    ([7], [20], [23])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'hpsukliagqefwvtbjxcodnmrzy'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (4, 12, 2)
-    >>> cat(enigma31.wheel_positions_l)
-    'jfz'
-    >>> enigma31.peg_positions
-    ([7], [20], [22])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'zevnbpyqowrtxdifhkulscjmga'
-
-
-    >>> enigma31.set_wheels('i', 'd', 'z')
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 3)
-    >>> cat(enigma31.wheel_positions_l)
-    'ida'
-    >>> enigma31.peg_positions
-    ([8], [22], [21])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'ikhpqrvcambzjondefwyxgsutl'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 4)
-    >>> cat(enigma31.wheel_positions_l)
-    'idb'
-    >>> enigma31.peg_positions
-    ([8], [22], [20])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'cdabskhgzwfmlqvunyexpojtri'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 5)
-    >>> cat(enigma31.wheel_positions_l)
-    'idc'
-    >>> enigma31.peg_positions
-    ([8], [22], [19])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'pcbwiqhgemyvjsuaftnroldzkx'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 6)
-    >>> cat(enigma31.wheel_positions_l)
-    'idd'
-    >>> enigma31.peg_positions
-    ([8], [22], [18])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'xcbfvdnouptmlghjzwykierasq'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 7)
-    >>> cat(enigma31.wheel_positions_l)
-    'ide'
-    >>> enigma31.peg_positions
-    ([8], [22], [17])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'xfvglbdynuseriwqpmkzjcoaht'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 8)
-    >>> cat(enigma31.wheel_positions_l)
-    'idf'
-    >>> enigma31.peg_positions
-    ([8], [22], [16])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'tfpqlbouynsewjgcdxkahzmriv'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 9)
-    >>> cat(enigma31.wheel_positions_l)
-    'idg'
-    >>> enigma31.peg_positions
-    ([8], [22], [15])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'cjaunvlwtbygzexrspqidfhokm'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 10)
-    >>> cat(enigma31.wheel_positions_l)
-    'idh'
-    >>> enigma31.peg_positions
-    ([8], [22], [14])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'yltxkrqvowebzpingfucshjdam'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 11)
-    >>> cat(enigma31.wheel_positions_l)
-    'idi'
-    >>> enigma31.peg_positions
-    ([8], [22], [13])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'myktluzrnxceaiqsohpdfwvjbg'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 12)
-    >>> cat(enigma31.wheel_positions_l)
-    'idj'
-    >>> enigma31.peg_positions
-    ([8], [22], [12])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'pynjrmiugdqxfcvakewzhoslbt'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 13)
-    >>> cat(enigma31.wheel_positions_l)
-    'idk'
-    >>> enigma31.peg_positions
-    ([8], [22], [11])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'mwvedyplnoxhaijgrqtszcbkfu'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 14)
-    >>> cat(enigma31.wheel_positions_l)
-    'idl'
-    >>> enigma31.peg_positions
-    ([8], [22], [10])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'qcbrfeutvoxpnmjladzhgiykws'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 15)
-    >>> cat(enigma31.wheel_positions_l)
-    'idm'
-    >>> enigma31.peg_positions
-    ([8], [22], [9])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'dnoahryetsmukbcvwfjilpqzgx'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 16)
-    >>> cat(enigma31.wheel_positions_l)
-    'idn'
-    >>> enigma31.peg_positions
-    ([8], [22], [8])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'nidcfehgbqsovalyjzkxwmutpr'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 17)
-    >>> cat(enigma31.wheel_positions_l)
-    'ido'
-    >>> enigma31.peg_positions
-    ([8], [22], [7])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'joifxdulcarhzpbntkwqgysevm'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 18)
-    >>> cat(enigma31.wheel_positions_l)
-    'idp'
-    >>> enigma31.peg_positions
-    ([8], [22], [6])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'ptnlsxvozmwdjchayuebrgkfqi'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 19)
-    >>> cat(enigma31.wheel_positions_l)
-    'idq'
-    >>> enigma31.peg_positions
-    ([8], [22], [5])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'slwopzqnmxybihdeguavrtcjkf'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 20)
-    >>> cat(enigma31.wheel_positions_l)
-    'idr'
-    >>> enigma31.peg_positions
-    ([8], [22], [4])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'hcbedwlamzogixkytsrqvufnpj'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 21)
-    >>> cat(enigma31.wheel_positions_l)
-    'ids'
-    >>> enigma31.peg_positions
-    ([8], [22], [3])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'odxbjwzrmelkisavuhnyqpfctg'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 22)
-    >>> cat(enigma31.wheel_positions_l)
-    'idt'
-    >>> enigma31.peg_positions
-    ([8], [22], [2])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'udgbfeclrwnhxksvtioqapjmzy'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 23)
-    >>> cat(enigma31.wheel_positions_l)
-    'idu'
-    >>> enigma31.peg_positions
-    ([8], [22], [1])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'nrdczqxmowvshaiufblypkjgte'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 10, 24)
-    >>> cat(enigma31.wheel_positions_l)
-    'idv'
-    >>> enigma31.peg_positions
-    ([8], [22], [0])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'hkifjdoacebqtzgulyvmpsxwrn'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 11, 25)
-    >>> cat(enigma31.wheel_positions_l)
-    'iew'
-    >>> enigma31.peg_positions
-    ([8], [21], [25])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'yptzuhofqvnmlkgbixwcejsrad'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 11, 0)
-    >>> cat(enigma31.wheel_positions_l)
-    'iex'
-    >>> enigma31.peg_positions
-    ([8], [21], [24])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'vkdcwhqfjibzsptngumoraeyxl'
-
-    >>> enigma31.advance()
-    >>> enigma31.wheel_positions
-    (3, 11, 1)
-    >>> cat(enigma31.wheel_positions_l)
-    'iey'
-    >>> enigma31.peg_positions
-    ([8], [21], [23])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'wenpbqrouxlkychdfgzvitajms'
-
-
-    >>> enigma31.set_wheels('i', 'z', 'd')
-    >>> enigma31.encipher('verylongtestmessagewithanextrabitofmessageforgoodmeasure')
-    'apocwtjuikurcfivlozvhffkoacxufcekthcvodfqpxdjqyckdozlqki'
-    >>> enigma31.wheel_positions
-    (4, 9, 10)
-    >>> cat(enigma31.wheel_positions_l)
-    'jch'
-    >>> enigma31.peg_positions
-    ([7], [23], [14])
-    >>> cat(enigma31.lookup(l) for l in string.ascii_lowercase)
-    'mopnigfuesqwadbcktjrhylzvx'
 
-    >>> enigma31.set_wheels('i', 'z', 'd')
-    >>> enigma31.decipher('apocwtjuikurcfivlozvhffkoacxufcekthcvodfqpxdjqyckdozlqki')
-    'verylongtestmessagewithanextrabitofmessageforgoodmeasure'
     """
     def __init__(self, reflector_spec,
                  left_wheel_spec, left_wheel_pegs,