diff --git a/candidates.py b/candidates.py new file mode 100644 index 0000000..7603240 --- /dev/null +++ b/candidates.py @@ -0,0 +1,18 @@ +import itertools +import re + +from dictionary import Dictionary + + +def candidates(letters, dictionary: Dictionary, excludes, min=2): + possibilities = [] + for length in range(min, len(letters) + 1): + for comb in itertools.combinations(letters, length): + for perm in itertools.permutations(comb): + word = "".join(perm) + possibilities.append(word) + return dictionary.filter(possibilities, excludes) + + +def filter_possibilities(possibilities, regex): + return set(filter(regex.match, possibilities)) diff --git a/main.py b/main.py index 123f1cd..8aed775 100755 --- a/main.py +++ b/main.py @@ -1,8 +1,13 @@ import argparse from string import ascii_lowercase import cmd2 +import re +import os +from candidates import candidates, filter_possibilities from dictionary import DEFAULT, ALTERNATE +from word_remove_dialog import RemoveWordsActivity + LOWERCASE = set(ascii_lowercase) DICTS = {"default": DEFAULT, "alt": ALTERNATE} @@ -15,7 +20,10 @@ commands.add_argument( commands.add_argument("-s", "--switch", help="Dictionary to swap to") letter_set_manage = argparse.ArgumentParser() -letter_set_manage.add_argument("new_letters") +letter_set_manage.add_argument("letter", nargs="+") + +guessing = argparse.ArgumentParser() +guessing.add_argument("pattern", help="Pattern to match") class MainLoop(cmd2.Cmd): @@ -23,14 +31,22 @@ class MainLoop(cmd2.Cmd): """ - prompt = "?$ " + prompt = "<{}> $ " def __init__(self): self.dict = "default" - self.letters = [l for l in input("Enter letters: ").lower() if l in LOWERCASE] - self.prompt = ", ".join(self.letters) + " " + MainLoop.prompt + self.excludes = set() + self.init_letters(input("Enter letters: ")) super().__init__() + def init_letters(self, letters): + if not isinstance(letters, str): + letters = "".join(letters) + letters = letters.lower() + self.letters = [l for l in letters if l in LOWERCASE] + self.prompt = MainLoop.prompt.format(", ".join(self.letters)) + self.candidates = candidates(self.letters, DICTS[self.dict], self.excludes) + @cmd2.with_argparser(dictionary_manage_parser) def do_dict(self, args): """list/switch dict""" @@ -49,7 +65,22 @@ class MainLoop(cmd2.Cmd): @cmd2.with_argparser(letter_set_manage) def do_change_letters(self, args): - pass + """Change the letters on the board""" + self.init_letters(args.letter) + + @cmd2.with_argparser(guessing) + def do_find(self, args): + """Find words that match a pattern""" + pattern = re.compile(args.pattern + "$") + matching_words = filter_possibilities(self.candidates, pattern) + app = RemoveWordsActivity(matching_words, self.excludes) + if os.name == "nt": + app.run(fork=False) + else: + app.run() + was_canceled, new_exludes = app.get_results() + if not was_canceled: + self.excludes.update(new_exludes) if __name__ == "__main__": diff --git a/word_remove_dialog.py b/word_remove_dialog.py index 647a7f1..737da1f 100644 --- a/word_remove_dialog.py +++ b/word_remove_dialog.py @@ -32,7 +32,10 @@ class AddRemoveForm(npyscreen.ActionFormV2): max_height=10, ) self.to_remove = self.add( - BoxedRemovableMulti, values=[], name="Words to remove", max_height=10 + BoxedRemovableMulti, + values=sorted(self.parentApp.starting_excludes), + name="Words to remove", + max_height=10, ) self.keepers.entry_widget.register_oppisite(self.to_remove.entry_widget) @@ -47,9 +50,10 @@ class AddRemoveForm(npyscreen.ActionFormV2): class RemoveWordsActivity(npyscreen.NPSAppManaged): - def __init__(self, starting_values, *args, **kwargs): + def __init__(self, words, excludes, *args, **kwargs): super().__init__(*args, **kwargs) - self.starting_values = starting_values + self.starting_values = words + self.starting_excludes = excludes def onStart(self): self.addForm(