X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=riddle-solver.md;fp=riddle-solver.md;h=0000000000000000000000000000000000000000;hb=ce34915246926441c163272e09f1343db3fd1955;hp=9aa58d7890f7d7b19aaee495408a800a1e4adaf6;hpb=ffbfb5b3117178a49a93946daed6c2689df3e1b8;p=riddle-generator.git diff --git a/riddle-solver.md b/riddle-solver.md deleted file mode 100644 index 9aa58d7..0000000 --- a/riddle-solver.md +++ /dev/null @@ -1,232 +0,0 @@ ---- -jupyter: - jupytext: - formats: ipynb,md - 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 ---- - -```python -import unicodedata -import re -from dataclasses import dataclass -from typing import Dict, Tuple, List, Set -from enum import Enum, auto -``` - -```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() - ] -dictionary[:5] -``` - -```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] -``` - -```python -from_ordinal('seventh') -``` - -```python -def tokenise(phrase: str) -> List[str]: - return [w.lower() for w in re.split(r'\W+', phrase) if w] -``` - -```python -tokenise("My first is in apple, but not in fish.") -``` - -```python -class RiddleValence(Enum): - Include = auto() - Exclude = auto() - -@dataclass -class RiddleElement: - valence : RiddleValence - letters : Set[str] - -Riddle = Dict[int, RiddleElement] -``` - -```python -stop_words = set('my is in within lies and also always you will find always the found'.split()) -negative_words = set('but not never'.split()) -``` - -```python -def parse_line(tokens: List[str]) -> Tuple[int, RiddleElement, RiddleElement]: - stripped_tokens = [t for t in tokens if t not in stop_words] - - position_word = [t for t in stripped_tokens if t in ordinals][0] - pos = from_ordinal(position_word) - - first_index, first_word = [(i, t) for i, t in enumerate(stripped_tokens) - if t not in ordinals - if t not in negative_words][0] - second_index, second_word = [(i, t) for i, t in enumerate(stripped_tokens) - if t not in ordinals - if t not in negative_words][1] - neg_indices = [i for i, t in enumerate(stripped_tokens) if t in negative_words] - - first_clue = None - second_clue = None - - if neg_indices: - if neg_indices[0] < first_index: - first_clue = RiddleElement(valence = RiddleValence.Exclude, - letters = set(first_word)) - if len(neg_indices) > 1: - second_clue = RiddleElement(valence = RiddleValence.Exclude, - letters = set(second_word)) - elif neg_indices[0] < second_index: - second_clue = RiddleElement(valence = RiddleValence.Exclude, - letters = set(second_word)) - - if first_clue is None: - first_clue = RiddleElement(valence = RiddleValence.Include, - letters = set(first_word)) - - if second_clue is None: - second_clue = RiddleElement(valence = RiddleValence.Include, - letters = set(second_word)) - - return (pos, first_clue, second_clue) -``` - -```python -e1 = parse_line(tokenise("My first is in apple, but not in pad.")) -e1 -``` - -```python -e2 = parse_line(tokenise("My second is in apple and also in banana.")) -e2 -``` - -```python -def collapse_riddle_elements(elems : List[Tuple[int, RiddleElement, RiddleElement]]) -> Dict[int, RiddleElement]: - def combine_elements(a: RiddleElement, b: RiddleElement) -> RiddleElement: - if a.valence == b.valence: - return RiddleElement(letters = a.letters | b.letters, valence = a.valence) - else: - if a.valence == RiddleValence.Include: - p, q = a, b - else: - p, q = b, a - return RiddleElement(letters = p.letters - q.letters, valence = RiddleValence.Include) - - return {i: combine_elements(a, b) for i, a, b in elems} -``` - -```python -collapse_riddle_elements([e1, e2]) -``` - -```python -sample_riddle_text = """My first is in shoat but not in oath -My second is in orate but not in ratter -My third is in preposition but not in osteoporosis -My fourth is in astern but not in taster -My fifth is in conscientiousness but not in suction -My sixth is in immorality but not in immorally""" - -sample_riddle_lines = [parse_line(tokenise(l)) for l in sample_riddle_text.split('\n')] -sample_riddle_lines -``` - -```python -sample_riddle = collapse_riddle_elements(sample_riddle_lines) -sample_riddle -``` - -```python -def parse_riddle(riddle_text: str) -> Dict[int, RiddleElement]: - riddle_lines = [parse_line(tokenise(l)) for l in riddle_text.split('\n')] - return collapse_riddle_elements(riddle_lines) -``` - -```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: Dict[int, RiddleElement], 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: Dict[int, RiddleElement]) -> str: - return [w for w in dictionary - if len(w) == len(riddle) - if matches_all_elements(riddle, w)] -``` - -```python -solve_riddle(sample_riddle) -``` - -```python -def parse_and_solve_riddle(riddle_text: str) -> List[str]: - riddle = parse_riddle(riddle_text) - return solve_riddle(riddle) -``` - -```python -sample_riddles = open('sample-riddles.txt').read().split('\n\n') -sample_riddles -``` - -```python -[parse_and_solve_riddle(r) for r in sample_riddles] -``` - -```python - -```