Created separate library
[riddle-generator.git] / riddle-solver.md
diff --git a/riddle-solver.md b/riddle-solver.md
deleted file mode 100644 (file)
index 9aa58d7..0000000
+++ /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
-
-```