# Words by the Numbers 3, Exercise 2: breaking Caesar shifts with two rules for guessing e. import string from collections import Counter ALPHA = string.ascii_lowercase def shift(text, k): return "".join( ALPHA[(ALPHA.index(ch) + k) % 26] if ch in ALPHA else ch for ch in text ) # Method A assumes the commonest cipher letter is e. Method B tries each of the # three commonest cipher letters as e and keeps the shift that makes the most # of the common words "the", "and", "to" appear. JOBS = [ ("the river was wide and the water was cold", 5), ("we meet at noon by the clock tower", 12), ("hold the line until the signal comes", 19), ("bring bread and cheese to the market", 2), ("fly south before the first snow", 9), ] COMMON = (" the ", " and ", " to ") def method_a(cipher): top = Counter(ch for ch in cipher if ch in ALPHA).most_common(1)[0][0] return (ALPHA.index(top) - ALPHA.index("e")) % 26 def method_b(cipher): top3 = [ch for ch, _ in Counter(c for c in cipher if c in ALPHA).most_common(3)] best_k, best_score = 0, -1 for letter in top3: k = (ALPHA.index(letter) - ALPHA.index("e")) % 26 padded = " " + shift(cipher, -k) + " " score = sum(padded.count(word) for word in COMMON) if score > best_score: best_k, best_score = k, score return best_k wins_a = wins_b = 0 for plain, key in JOBS: cipher = shift(plain, key) a, b = method_a(cipher), method_b(cipher) wins_a += a == key wins_b += b == key print(f"key {key:2d} | A found {a:2d} | B found {b:2d} | {plain}") print("method A right:", wins_a, "of", len(JOBS), "| method B right:", wins_b, "of", len(JOBS)) # Output when run (Python 3.14; the documentation-text figures depend on the Python version): # key 5 | A found 5 | B found 5 | the river was wide and the water was cold # key 12 | A found 12 | B found 12 | we meet at noon by the clock tower # key 19 | A found 0 | B found 19 | hold the line until the signal comes # key 2 | A found 2 | B found 2 | bring bread and cheese to the market # key 9 | A found 10 | B found 10 | fly south before the first snow # method A right: 3 of 5 | method B right: 4 of 5