X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=riddle_definitions.md;fp=riddle_definitions.md;h=fb025c46a224a986231653ec511512bb1cf6b3b2;hb=ce34915246926441c163272e09f1343db3fd1955;hp=0000000000000000000000000000000000000000;hpb=ffbfb5b3117178a49a93946daed6c2689df3e1b8;p=riddle-generator.git diff --git a/riddle_definitions.md b/riddle_definitions.md new file mode 100644 index 0000000..fb025c4 --- /dev/null +++ b/riddle_definitions.md @@ -0,0 +1,171 @@ +--- +jupyter: + jupytext: + formats: ipynb,md,py:percent + text_representation: + extension: .md + format_name: markdown + format_version: '1.3' + jupytext_version: 1.14.5 + kernelspec: + display_name: Python 3 (ipykernel) + language: python + name: python3 +--- + +# Definitions generally useful for the riddle solver + +```python +import unicodedata +import re +from dataclasses import dataclass +from typing import Dict, Tuple, List, Set +from enum import Enum, auto +import functools +import random +``` + +```python +stop_words = set('my is in within lies and also always you will find the found'.split()) +negative_words = set('but not never neither nor'.split()) +``` + +```python +ordinals : Dict[str, int] = { 'last': -1 + , 'first': 1 + , 'second': 2 + , 'third': 3 + , 'fourth': 4 + , 'fifth': 5 + , 'sixth': 6 + , 'seventh': 7 + , 'eighth': 8 + , 'ninth': 9 + , 'tenth': 10 + , 'eleventh': 11 + , 'twelfth': 12 + } + +reverse_ordinals : Dict[int, str] = {n: w for w, n in ordinals.items()} + +def from_ordinal(word: str) -> int: + return ordinals[word] + +def to_ordinal(number: int) -> str: + return reverse_ordinals[number] +``` + +These are the words that can be the solution to a riddle, and used as the clue for a riddle. + +```python +dictionary : List[str] = [unicodedata.normalize('NFKD', w.strip()).\ + encode('ascii', 'ignore').\ + decode('utf-8') + for w in open('/usr/share/dict/british-english').readlines() + if w.strip().islower() + if w.strip().isalpha() + if len(w.strip()) >= 5 + if w not in stop_words + if w not in negative_words + if w not in ordinals + ] +``` + +Some types that will be used throughout the library + +```python +class RiddleValence(Enum): + Include = auto() + Exclude = auto() + +@dataclass +class RiddleClue: + valence : RiddleValence + word : str + +@dataclass +class RiddleElement: + valence : RiddleValence + letters : Set[str] + +Riddle = Dict[int, Tuple[RiddleClue, RiddleClue]] +RiddleElems = Dict[int, RiddleElement] +``` + +```python +@functools.lru_cache +def edit_distance(s: str, t: str) -> int: + if s == "": + return len(t) + if t == "": + return len(s) + if s[-1] == t[-1]: + cost = 0 + else: + cost = 1 + + res = min( + [ edit_distance(s[:-1], t)+1 + , edit_distance(s, t[:-1])+1 + , edit_distance(s[:-1], t[:-1]) + cost + ]) + + return res +``` + +```python +def collapse_riddle_clues(elems : Dict[int, Tuple[RiddleClue, RiddleClue]]) -> RiddleElems: + def combine_clues(a: RiddleClue, b: RiddleClue) -> RiddleElement: + if a.valence == b.valence: + if a.valence == RiddleValence.Include: + return RiddleElement(letters = set(a.word) & set(b.word), + valence = RiddleValence.Include) + else: + return RiddleElement(letters = set(a.word) | set(b.word), + valence = RiddleValence.Exclude) + else: + if a.valence == RiddleValence.Include: + p, q = a, b + else: + p, q = b, a + return RiddleElement(letters = set(p.word) - set(q.word), + valence = RiddleValence.Include) + + return {i: combine_clues(a, b) for i, (a, b) in elems.items()} +``` + +```python + +``` + +```python +def matches_element(pos: int, elem: RiddleElement, word: str) -> bool: + if len(word) < pos: + return False + if elem.valence == RiddleValence.Include: + return word[pos-1] in elem.letters + else: + return word[pos-1] not in elem.letters +``` + +```python +def matches_all_elements(riddle: RiddleElems, word: str) -> bool: + if -1 in riddle: + last_elem = riddle[-1] + new_riddle = {p: e for p, e in riddle.items() if p != -1} + new_riddle[len(word)] = last_elem + else: + new_riddle = riddle + return all(matches_element(i, elem, word) for i, elem in new_riddle.items()) +``` + +```python +def solve_riddle(riddle: RiddleElems) -> List[str]: + return [w for w in dictionary + if len(w) == len(riddle) + if matches_all_elements(riddle, w)] +``` + +```python + +```