Code Cracker | Word Solver [portable]

def solve(self, cipher_text): """ Solve a substitution cipher. cipher_text: string with letters (A-Z, a-z) and spaces/punctuation. Returns: (decoded_string, mapping_dict) """ # Normalize: keep uppercase for ciphertext letters, but work lowercase original = cipher_text cipher_words = re.findall(r'[A-Za-z]+', cipher_text) if not cipher_words: return cipher_text, {} # Work with lowercase cipher words cipher_words_lower = [w.lower() for w in cipher_words] # Possible mappings: cipher_char -> plain_char possible_maps = [{}] for cw in cipher_words_lower: pattern = get_word_pattern(cw) candidates = self.pattern_dict.get(pattern, []) if not candidates: # No word matches this pattern — puzzle may have errors continue # Filter candidates based on current possible mappings new_possible_maps = [] for pmap in possible_maps: for cand in candidates: if self._consistent(cw, cand, pmap): # Create new mapping extending pmap new_map = pmap.copy() valid = True for c, p in zip(cw, cand): if c in new_map: if new_map[c] != p: valid = False break else: new_map[c] = p if valid: new_possible_maps.append(new_map) possible_maps = new_possible_maps if not possible_maps: break # Choose the best mapping (most frequent letters resolved) if not possible_maps: return original, {} best_map = possible_maps[0] if len(possible_maps) > 1: # Heuristic: prefer mapping that decodes to real words best_score = -1 for pmap in possible_maps: decoded = self._apply_map(original, pmap) score = self._score_text(decoded) if score > best_score: best_score = score best_map = pmap decoded_text = self._apply_map(original, best_map) return decoded_text, best_map

def _consistent(self, cipher_word, plain_word, mapping): """Check if cipher_word can map to plain_word given existing mapping.""" for c, p in zip(cipher_word, plain_word): if c in mapping and mapping[c] != p: return False return True code cracker word solver

cracker = CodeCracker()