Chapter 18 – Hacking the Simple Substitution Cipher 277
- letterMapping[cipherword[i]].append(candidate[i])
The if statement on line 51 checks that the potential decryption letter is not already in the list of
potential decryption letters for the cipherletter. This prevents the list of potential decryption
letters in the cipherletter mapping from having duplicate letters in it. For example, we never want
the list to be a value like ['U', 'U'].
Line 52 adds the new potential decryption letter (that is, candidate[i]) to the list of potential
decryption letters in the cipherletter mapping (that is, letterMapping[cipherword[i]]).
simpleSubHacker.py
53. return letterMapping
After looping through all the indexes in cipherword, the additions to the cipherletter mapping
are complete and the dictionary in letterMapping is returned.
Intersecting Two Letter Mappings
simpleSubHacker.py
56. def intersectMappings(mapA, mapB):
57. # To intersect two maps, create a blank map, and then add only the
58. # potential decryption letters if they exist in BOTH maps.
59. intersectedMapping = getBlankCipherletterMapping()
60. for letter in LETTERS:
The intersectMappings() function will return a new cipherletter mapping that is an
intersection of the two cipherletter mappings passed for the mapA and mapB parameters. Line 59
creates a new cipherletter mapping by calling getBlankCipherletterMapping() and
storing the returned value in the intersectedMapping variable.
The for loop will loop through each of the uppercase letters in the LETTERS constant variable,
and the letter variable can be used for the keys of the mapA and mapB dictionaries.
simpleSubHacker.py
62. # An empty list means "any letter is possible". In this case just
63. # copy the other map entirely.
64. if mapA[letter] == []:
65. intersectedMapping[letter] = copy.deepcopy(mapB[letter])
66. elif mapB[letter] == []:
67. intersectedMapping[letter] = copy.deepcopy(mapA[letter])