#!/usr/bin/env python3 """Reproduces the 154-sonnet letter-skip (ELS) null-test in cipher-arguments.html on shakespeare-enquiry.org. Reads sonnets-1041.txt (Project Gutenberg eBook #1041, 154 sonnets, poem text only, editorial numbering ignored), reduces it to A-Z, and runs a single-pass equidistant-letter search (both directions, no wrap-around).""" import re, os from collections import Counter TEXT = os.path.join(os.path.dirname(__file__), "sonnets-1041.txt") L = re.sub(r'[^A-Za-z]', '', open(TEXT, encoding='utf-8').read()).upper() N = len(L) def min_skip(target): m = len(target); rt = target[::-1] for s in range(1, (N-1)//(m-1) + 1): for r in range(s): line = L[r::s] if target in line or rt in line: return s return None def present(word): # appears as an ELS at some skip <=120, either direction for s in range(1, 121): for r in range(s): line = L[r::s] if word in line or word[::-1] in line: return True return False if __name__ == "__main__": c = Counter(L) print(f"letters: {N} X={c['X']} A={c['A']} S={c['S']}") for t in ["VERE","HENRY","DEVERE","BASSANO","EMILIA","LANIER","BACON", "MARLOWE","NIXON","OBAMA","ELVIS","OXFORD","WRIOTHESLEY"]: print(f" {t:12} {min_skip(t)}") S = set() for s in range(1, 121): for r in range(s): line = L[r::s] for i in range(len(line)-3): w = line[i:i+4]; S.add(w); S.add(w[::-1]) print(f"distinct 4-letter strings (skip<=120, both dir): {len(S)} of 456976 ({100*len(S)/456976:.1f}%)") print("examples present:", {w: present(w) for w in ["VERE","BASS","FAPP","MECK"]})