From 5e5626bd52223307c5535d15668692e142e65d52 Mon Sep 17 00:00:00 2001 From: Neil Smith Date: Thu, 10 Aug 2023 13:01:02 +0100 Subject: [PATCH] Tidying and documentation --- riddle_definitions.md | 25 ++++++++++++++++++++----- riddle_solver.md | 22 ++++++++++++---------- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/riddle_definitions.md b/riddle_definitions.md index fb025c4..402fd94 100644 --- a/riddle_definitions.md +++ b/riddle_definitions.md @@ -15,6 +15,8 @@ jupyter: # Definitions generally useful for the riddle solver +While this file is here as a Markdown file, it's intended that Jupytext will save this file as a "percent" Python file, so that it can be imported by other notebooks here. + ```python import unicodedata import re @@ -65,6 +67,7 @@ dictionary : List[str] = [unicodedata.normalize('NFKD', w.strip()).\ if w.strip().islower() if w.strip().isalpha() if len(w.strip()) >= 5 + if len(w.strip()) <= 12 if w not in stop_words if w not in negative_words if w not in ordinals @@ -75,20 +78,29 @@ Some types that will be used throughout the library ```python class RiddleValence(Enum): + """Does this part of the riddle include or exclude letters?""" Include = auto() Exclude = auto() @dataclass class RiddleClue: + """A half line of a riddle, like 'is in dreams' or 'not in octet'""" valence : RiddleValence word : str @dataclass class RiddleElement: + """A representation of the constraints that come from a whole line of + a riddle""" valence : RiddleValence letters : Set[str] +# A riddle that's been read and parsed. +# Note that the numbering is one-based, as per the numbers in the riddle text Riddle = Dict[int, Tuple[RiddleClue, RiddleClue]] + +# A riddle that's been processed ready for solving +# Note that the numbering is one-based, as per the numbers in the riddle text RiddleElems = Dict[int, RiddleElement] ``` @@ -114,7 +126,9 @@ def edit_distance(s: str, t: str) -> int: ``` ```python -def collapse_riddle_clues(elems : Dict[int, Tuple[RiddleClue, RiddleClue]]) -> RiddleElems: +def collapse_riddle_clues(elems : Riddle) -> RiddleElems: + """Combine the two parts of a riddle line into one element for solving. + This takes account of the valence of the two parts.""" def combine_clues(a: RiddleClue, b: RiddleClue) -> RiddleElement: if a.valence == b.valence: if a.valence == RiddleValence.Include: @@ -134,12 +148,11 @@ def collapse_riddle_clues(elems : Dict[int, Tuple[RiddleClue, RiddleClue]]) -> R 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: + """Does this element match this position of the the word? + Note that positions are one-based, as in the numbering system of the + puzzle.""" if len(word) < pos: return False if elem.valence == RiddleValence.Include: @@ -150,6 +163,7 @@ def matches_element(pos: int, elem: RiddleElement, word: str) -> bool: ```python def matches_all_elements(riddle: RiddleElems, word: str) -> bool: + """Do all the elements of a riddle match the appropriate parts of a word?""" if -1 in riddle: last_elem = riddle[-1] new_riddle = {p: e for p, e in riddle.items() if p != -1} @@ -161,6 +175,7 @@ def matches_all_elements(riddle: RiddleElems, word: str) -> bool: ```python def solve_riddle(riddle: RiddleElems) -> List[str]: + """Find all words that match this riddle""" return [w for w in dictionary if len(w) == len(riddle) if matches_all_elements(riddle, w)] diff --git a/riddle_solver.md b/riddle_solver.md index a9e3064..67b6298 100644 --- a/riddle_solver.md +++ b/riddle_solver.md @@ -37,12 +37,13 @@ def parse_line(tokens: List[str]) -> Tuple[int, Tuple[RiddleClue, RiddleClue]]: 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) + indexed_words = [(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] + if t not in negative_words] + + first_index, first_word = indexed_words[0] + second_index, second_word = indexed_words[1] + neg_indices = [i for i, t in enumerate(stripped_tokens) if t in negative_words] first_clue = None @@ -107,10 +108,10 @@ sample_riddle ```python def parse_riddle(riddle_text: str) -> Riddle: - riddle_lines = {i: elem - for i, elem in - [parse_line(tokenise(l)) for l in riddle_text.split('\n')]} - return collapse_riddle_clues(riddle_lines) + return {i: elem + for i, elem in + [parse_line(tokenise(l)) + for l in riddle_text.split('\n')]} ``` ```python @@ -120,7 +121,8 @@ solve_riddle(sample_riddle) ```python def parse_and_solve_riddle(riddle_text: str) -> List[str]: riddle = parse_riddle(riddle_text) - return solve_riddle(riddle) + elems = collapse_riddle_clues(riddle) + return solve_riddle(elems) ``` ```python -- 2.34.1