I added a solver that creates a score based on the number of spaces and lower case vowels, I don't know if it works in all cases, it works on the 3 ciphers so far.
import random from dataclasses import dataclass, field from typing import Generator, List SYMBOLS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 !?." thelist = [ "qeFIP?eGSeECNNS,", "5coOMXXcoPSZIWoQI,", "avnl1olyD4l'ylDohww6DhzDjhuDil,", "z.GM?.cEQc. 70c.7KcKMKHA9AGFK,", "?MFYp2pPJJUpZSIJWpRdpMFY,", "ZqH8sl5HtqHTH4s3lyvH5zH5spH4t pHzqHlH3l5K", "Zfbi,!tif!xpvme!qspcbcmz!fbu!nfA", ] @dataclass(order=True) class CipherData: shift: str = field(compare=False) result: str = field(compare=False) score: float = field(default=0.0, compare=True) @dataclass class CipherLine: line: str cipher_data_possibilites: List[CipherData] def max_score_line(self): return max(self.cipher_data_possibilites) def top_3_score_lines(self): return sorted(self.cipher_data_possibilites, reverse=True)[:3] @dataclass class CeaserCipher: symbols: str def _shift_symbols_right(self, shift: int) -> str: return self.symbols[shift:] + self.symbols[:shift] def _shift_symbols_left(self, shift: int) -> str: shift = len(self.symbols) - shift return self.symbols[shift:] + self.symbols[:shift] def cipher(self, line: str, shift: int): shifted_sybols = self._shift_symbols_right(shift) result = line.translate(line.maketrans(self.symbols, shifted_sybols)) return CipherData(shift, result) def decipher(self, line: str, shift: int) -> str: shifted_sybols = self._shift_symbols_left(shift) result = line.translate(line.maketrans(self.symbols, shifted_sybols)) return CipherData(shift, result) def decipher_all_possibilties(self, line: str) -> Generator[CipherData, None, None]: for shift, _ in enumerate(self.symbols): yield self.decipher(line, shift) def cipher_random_shift(self, line: str) -> str: return self.cipher(line, random.randint(0, len(self.symbols))) def ceaser_cipher_solver(line: str) -> CipherLine: cipherer = CeaserCipher(SYMBOLS) cipher_lines = [] for cipher_data in cipherer.decipher_all_possibilties(line): cipher_data.score = float(cipher_data.result.count(" ")) or -10.0 cipher_data.score += sum(cipher_data.result.count(item) for item in ("aeiou")) cipher_lines.append(cipher_data) return CipherLine(line, cipher_lines) for line in thelist: cipher_line = ceaser_cipher_solver(line) print(cipher_line.max_score_line())
Output:CipherData(shift=34, result='I love my kitty,', score=6.0)
CipherData(shift=44, result='My kitty loves me,', score=7.0)
CipherData(shift=7, result="Together we're happy as can be,", score=14.0)
CipherData(shift=32, result='Though my head has suspicions,', score=13.0)
CipherData(shift=45, result='That I keep under my hat,', score=11.0)
CipherData(shift=11, result='Of what if I shrank to the size of a rat.', score=20.0)
CipherData(shift=1, result='Yeah, she would probably eat me.', score=15.0)
Edit: added from typing import List
so it works with pre 3.9 python versions