# 6.00 Problem Set 2 # # Caesar Cipher Solution # WORDLIST_FILENAME = "words.txt" # ----------------------------------- # Helper code # (you don't need to understand this helper code) def load_words(): """ Returns a list of valid words. Words are strings of lowercase letters. Depending on the size of the word list, this function may take a while to finish. """ print "Loading word list from file..." # inFile: file inFile = open(WORDLIST_FILENAME, 'r', 0) # line: string line = inFile.readline() # wordlist: list of strings wordlist = line.split() print " ", len(wordlist), "words loaded." return wordlist WORDLIST = load_words() def get_words(text): """ Returns a tuple of the space-separated words in text. Does not check words for validity (i.e. that it's a real English word and not gibberish). text: string returns: tuple Example: get_words("abc def ghi dog cat fox bunny") returns ('abc', 'def', 'ghi', 'dog', 'cat', 'fox', 'bunny') """ return tuple(text.split()) def is_a_word(word): word = word.lower() word = word.strip(" !@#$%^&*()-_+={}[]|\:;'<>?,./\"") return word in WORDLIST # (end of helper code) # ----------------------------------- def build_coder(shift): """ Returns a dict that can apply a Caesar cipher to a letter. The cipher is defined by the shift value. Ignores non-letter characters like punctuation and numbers. shift: 0 <= int < 26 returns: dict Example: build_coder(3) returns: {'a': 'd', 'b': 'e', ... 'y': 'b', 'z': 'c', 'A': 'D', 'B': 'E', ... } (The order of the key-value pairs may be different.) """ lower_case_alphabet = "abcdefghijklmnopqrstuvwxyz" upper_case_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" coder = {} for i in range(26): if i + shift >= 26: coder[lower_case_alphabet[i]] = lower_case_alphabet[i + shift - 26] coder[upper_case_alphabet[i]] = upper_case_alphabet[i + shift - 26] else: coder[lower_case_alphabet[i]] = lower_case_alphabet[i + shift] coder[upper_case_alphabet[i]] = upper_case_alphabet[i + shift] return coder def apply_coder(text, coder): """ Applies the coder to the text. Returns the encoded text. For problem 1, apply_coder() accepts a coder created by build_coder(). For problem 2, apply_coder() accepts a decoder created by build_decoder(). The code for apply_coder() should be the same for both problems. text: string coder: dict returns: string Example: apply_coder("Hello, world!", build_coder(3)) returns: 'Khoor, zruog!' apply_coder("Khoor, zruog!", build_decoder(3)) returns: 'Hello, world!' """ codedText = "" for c in text: if c in coder: codedText = codedText + coder[c] else: codedText = codedText + c return codedText def build_decoder(shift): """ Returns a dict that can reverse a Caesar cipher that has been applied to a letter. The cipher is defined by the shift value. Ignores non-letter characters like punctuation and numbers. shift: 0 <= int < 26 returns: dict Example: build_decoder(3) returns: {'a': 'x', 'b': 'y', 'c': 'z', 'd': 'a' ... 'z': 'w', 'A': 'X', 'B': 'Y', ... } (The order of the key-value pairs may be different.) """ if shift == 0: # The specifications of build_coder() do not guarantee that # build_coder(26) will return the same thing as build_coder(0) return build_coder(0) else: return build_coder(26 - shift) def decode(cipherText): """ Decrypts the encoded ciphertext and returns the plaintext. cipherText: string returns: string Example: decode("Khoor, zruog!") returns 'Hello, world!' """ max_num_of_words = 0 best_decoded_text = None for shift in range(26): decoder = build_decoder(shift) decodedText = apply_coder(cipherText, decoder) num_of_words = 0 for word in get_words(decodedText): if is_a_word(word): num_of_words += 1 if num_of_words > max_num_of_words: max_num_of_words = num_of_words best_decoded_text = decodedText return best_decoded_text