X-Git-Url: https://git.njae.me.uk/?a=blobdiff_plain;f=riddle_creator_lazy.md;fp=riddle_creator_lazy.md;h=4af0f00d3e4a274df8f3dc45373a82f0f8fbf198;hb=95c4c545a4abe7ef5f222b674da8535739ef1fcb;hp=0000000000000000000000000000000000000000;hpb=52008779b0281639e17a6570271dc7d5a3227b03;p=riddle-generator.git diff --git a/riddle_creator_lazy.md b/riddle_creator_lazy.md new file mode 100644 index 0000000..4af0f00 --- /dev/null +++ b/riddle_creator_lazy.md @@ -0,0 +1,341 @@ +--- +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 +from riddle_definitions import * + +from typing import Dict, Tuple, List, Set +from enum import Enum, auto +import random +import gzip +``` + +```python +dictionary_neighbours = {} + +for line in gzip.open('dictionary_neighbours.txt.gz', 'rt').readlines(): + words = line.strip().split(',') + dictionary_neighbours[words[0]] = words[1:] + +possible_riddle_clues = list(dictionary_neighbours.keys()) +``` + +```python +len(dictionary_neighbours['sonnet']) +``` + +```python +def include_exclude_clue(letter: str, limit: int = 3) -> (RiddleClue, RiddleClue): + finished = False + while not finished: + + has_first = False + while not has_first: + with_letter = random.choice(possible_riddle_clues) + has_first = letter in with_letter + + others = dictionary_neighbours[with_letter][:] + random.shuffle(others) + + while not finished and others: + other = others[0] + + if letter not in other and edit_distance(with_letter, other) <= limit: + finished = True + else: + others = others[1:] + + return (RiddleClue(word=with_letter, valence=RiddleValence.Include), + RiddleClue(word=other, valence=RiddleValence.Exclude)) + +a, b = include_exclude_clue('s') +a, b, set(a.word) - set(b.word), edit_distance(a.word, b.word) +``` + +```python +def include_include_clue(letter: str, limit: int = 3) -> (RiddleClue, RiddleClue): + finished = False + while not finished: + + has_first = False + while not has_first: + with_letter = random.choice(possible_riddle_clues) + has_first = letter in with_letter + + others = dictionary_neighbours[with_letter][:] + random.shuffle(others) + + while not finished and others: + other = others[0] + + if letter in other and edit_distance(with_letter, other) <= limit: + finished = True + else: + others = others[1:] + + return (RiddleClue(word=with_letter, valence=RiddleValence.Include), + RiddleClue(word=other, valence=RiddleValence.Include)) + +a, b = include_include_clue('s') +a, b, set(a.word) | set(b.word), edit_distance(a.word, b.word) +``` + +```python +def exclude_exclude_clue(letter: str, limit: int = 3) -> (RiddleClue, RiddleClue): + finished = False + while not finished: + + has_first = False + while not has_first: + without_letter = random.choice(possible_riddle_clues) + has_first = letter not in without_letter + + others = dictionary_neighbours[without_letter][:] + random.shuffle(others) + + while not finished and others: + other = others[0] + + if letter not in other and edit_distance(without_letter, other) <= limit: + finished = True + else: + others = others[1:] + + + return (RiddleClue(word=without_letter, valence=RiddleValence.Exclude), + RiddleClue(word=other, valence=RiddleValence.Exclude)) + +a, b = exclude_exclude_clue('s') +a, b, set(a.word) | set(b.word), edit_distance(a.word, b.word) +``` + +```python +def random_clue( letter: str + , ie_limit: int = 3 + , ii_limit: int = 2 + , ee_limit: int = 2) -> (RiddleClue, RiddleClue): + clue_type = random.choices(['include_exclude', 'include_include', 'exclude_exclude'], + weights=[7, 2, 1], + k=1)[0] + if clue_type == 'include_exclude': + return include_exclude_clue(letter, limit=ie_limit) + elif clue_type =='include_include': + return include_include_clue(letter, limit=ii_limit) + else: + return exclude_exclude_clue(letter, limit=ee_limit) +``` + +```python +def random_riddle( word: str + , ie_limit: int = 3 + , ii_limit: int = 2 + , ee_limit: int = 2 + ) -> Riddle: + return {i+1 : + random_clue(l, + ie_limit=ie_limit, ii_limit=ii_limit, ee_limit=ee_limit) + for i, l in enumerate(word)} +``` + +```python +sample_riddle = random_riddle('teacup') +sample_riddle +``` + +```python +collapse_riddle_clues(sample_riddle) +``` + +```python +solve_riddle(collapse_riddle_clues(sample_riddle)) +``` + +```python +# write_riddle(sample_riddle) +``` + +```python +# sample_riddle = random_riddle('sonnet', limit=4) +# sample_riddle +``` + +```python +sample_riddle +``` + +```python +collapse_riddle_clues(sample_riddle) +``` + +```python +solve_riddle(collapse_riddle_clues(sample_riddle)) +``` + +```python +def valid_random_riddle(word: str) -> Riddle: + finished = False + while not finished: + riddle = random_riddle(word) + solns = solve_riddle(collapse_riddle_clues(riddle)) + finished = (len(solns) == 1) + return riddle +``` + +```python +import time +import csv +reports = [] +for _ in range(1000): + w1, c1 = time.perf_counter(), time.process_time() + r = valid_random_riddle(random.choice(possible_riddle_clues)) + w2, c2 = time.perf_counter(), time.process_time() + linecount = len(r) + reports.append({'wall_time': w2 - w1, + 'cpu_time': c2 - c1, + 'riddle_lines': linecount}) + +with open('metrics_lazy.csv', 'w', newline='') as csvfile: + fieldnames = list(reports[0].keys()) + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + + writer.writeheader() + for r in reports: + writer.writerow(r) +``` + +```python +def write_include_exclude_line(clue_a: RiddleClue, clue_b: RiddleClue) -> str: + line = f"is in {clue_a.word} but not in {clue_b.word}" + return line +``` + +```python +def write_include_include_line(clue_a: RiddleClue, clue_b: RiddleClue) -> str: + if random.randrange(2) == 0: + line = f"is in {clue_a.word} and also in {clue_b.word}" + else: + line = f"is in both {clue_a.word} and {clue_b.word}" + return line +``` + +```python +def write_exclude_exclude_line(clue_a: RiddleClue, clue_b: RiddleClue) -> str: + line = f"is neither in {clue_a.word} nor in {clue_b.word}" + return line +``` + +```python +def write_line(a: RiddleClue, b: RiddleClue) -> str: + if a.valence == RiddleValence.Include and b.valence == RiddleValence.Include: + return write_include_include_line(a, b) + elif a.valence == RiddleValence.Include and b.valence == RiddleValence.Exclude: + return write_include_exclude_line(a, b) + elif a.valence == RiddleValence.Exclude and b.valence == RiddleValence.Exclude: + return write_exclude_exclude_line(a, b) + else: + return "illegal line" +``` + +```python +def write_riddle(riddle: Riddle) -> List[str]: + output = [] + for i, (clue_a, clue_b) in sorted(riddle.items()): + pos = reverse_ordinals[i] + if i == len(riddle) and random.random() <= 0.3: + pos = reverse_ordinals[-1] + line = write_line(clue_a, clue_b) + full_line = f"My {pos} {line}" + output.append(full_line) + return output +``` + +```python + +``` + +```python +sample_riddle = valid_random_riddle("elephant") +sample_riddle +``` + +```python +write_riddle(sample_riddle) +``` + +```python +solve_riddle(collapse_riddle_clues(sample_riddle)) +``` + +```python +with open("generated-riddles-lazy.txt", 'w') as file: + between = False + for _ in range(10): + if between: + file.write('\n') + between = True + target = random.choice(possible_riddle_clues) + riddle = valid_random_riddle(target) + lines = write_riddle(riddle) + file.writelines(l + '\n' for l in lines) + file.write(f'Target: {target}\n') + +``` + +```python +print('\n'.join(write_riddle(valid_random_riddle("faster")))) +``` + +```python +len(dictionary_neighbours['sonnet']) +``` + +```python +ndls = sum(len(ws) for ws in dictionary_neighbours.values()) +ndls +``` + +```python +ndls / len(dictionary_neighbours) +``` + +```python +dn_trimmed = {w : [o for o in dictionary_neighbours[w] if edit_distance(w, o) <= 3] + for w in dictionary_neighbours} +``` + +```python +ndlts = sum(len(ws) for ws in dn_trimmed.values()) +ndlts +``` + +```python +ndlts / len(dn_trimmed) +``` + +```python +148 / 940 +``` + +```python +1/7 +``` + +```python +1/6 +``` + +```python + +```