4 formats: ipynb,md,py:percent
9 jupytext_version: 1.14.5
11 display_name: Python 3 (ipykernel)
16 # Definitions generally useful for the riddle solver
21 from dataclasses import dataclass
22 from typing import Dict, Tuple, List, Set
23 from enum import Enum, auto
29 stop_words = set('my is in within lies and also always you will find the found'.split())
30 negative_words = set('but not never neither nor'.split())
34 ordinals : Dict[str, int] = { 'last': -1
49 reverse_ordinals : Dict[int, str] = {n: w for w, n in ordinals.items()}
51 def from_ordinal(word: str) -> int:
54 def to_ordinal(number: int) -> str:
55 return reverse_ordinals[number]
58 These are the words that can be the solution to a riddle, and used as the clue for a riddle.
61 dictionary : List[str] = [unicodedata.normalize('NFKD', w.strip()).\
62 encode('ascii', 'ignore').\
64 for w in open('/usr/share/dict/british-english').readlines()
65 if w.strip().islower()
66 if w.strip().isalpha()
67 if len(w.strip()) >= 5
68 if w not in stop_words
69 if w not in negative_words
74 Some types that will be used throughout the library
77 class RiddleValence(Enum):
83 valence : RiddleValence
88 valence : RiddleValence
91 Riddle = Dict[int, Tuple[RiddleClue, RiddleClue]]
92 RiddleElems = Dict[int, RiddleElement]
97 def edit_distance(s: str, t: str) -> int:
108 [ edit_distance(s[:-1], t)+1
109 , edit_distance(s, t[:-1])+1
110 , edit_distance(s[:-1], t[:-1]) + cost
117 def collapse_riddle_clues(elems : Dict[int, Tuple[RiddleClue, RiddleClue]]) -> RiddleElems:
118 def combine_clues(a: RiddleClue, b: RiddleClue) -> RiddleElement:
119 if a.valence == b.valence:
120 if a.valence == RiddleValence.Include:
121 return RiddleElement(letters = set(a.word) & set(b.word),
122 valence = RiddleValence.Include)
124 return RiddleElement(letters = set(a.word) | set(b.word),
125 valence = RiddleValence.Exclude)
127 if a.valence == RiddleValence.Include:
131 return RiddleElement(letters = set(p.word) - set(q.word),
132 valence = RiddleValence.Include)
134 return {i: combine_clues(a, b) for i, (a, b) in elems.items()}
142 def matches_element(pos: int, elem: RiddleElement, word: str) -> bool:
145 if elem.valence == RiddleValence.Include:
146 return word[pos-1] in elem.letters
148 return word[pos-1] not in elem.letters
152 def matches_all_elements(riddle: RiddleElems, word: str) -> bool:
154 last_elem = riddle[-1]
155 new_riddle = {p: e for p, e in riddle.items() if p != -1}
156 new_riddle[len(word)] = last_elem
159 return all(matches_element(i, elem, word) for i, elem in new_riddle.items())
163 def solve_riddle(riddle: RiddleElems) -> List[str]:
164 return [w for w in dictionary
165 if len(w) == len(riddle)
166 if matches_all_elements(riddle, w)]