diff --git a/.gitignore b/.gitignore index ed956bc..0bb5148 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ __pycache__ .#* +/build/* +*.html +*.pyd +/fits.c diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..27126cb --- /dev/null +++ b/setup.py @@ -0,0 +1,17 @@ +from setuptools import setup, find_packages +from Cython.Build import cythonize + +with open("requirements.txt") as file: + REQUIREMENTS = file.read().rstrip().split("\n") + +setup( + author="Raphael Roberts", + author_email="raphael.robets48@gmail.com", + description="Cheat for wordscape and wordscape like games", + entry_points=None, + ext_modules=cythonize("src/fits.pyx"), + install_requires=REQUIREMENTS, + name="wordscape_cheats", + packages=find_packages(), + version="1.0", +) diff --git a/src/c_fits.c b/src/c_fits.c new file mode 100644 index 0000000..05fb39e --- /dev/null +++ b/src/c_fits.c @@ -0,0 +1,30 @@ +int _fits(char* bottom, int len_bottom, char* top, int len_top) { + int bottom_letters[26]; + int top_letters[26]; + int letter_val; + int i; + for (i = 0; i < len_bottom; i++) { + letter_val = bottom[i]-96; + if (0 <= letter_val && letter_val <= 25) { + bottom_letters[letter_val] += 1; + } + else { + return 1; + } + } + for (i = 0; i < len_top; i++) { + letter_val = top[i]-96; + if (0 <= letter_val && letter_val <= 25) { + top_letters[letter_val] += 1; + } + else { + return 1; + } + } + for (i = 0; i < 26; i++ ) { + if (bottom_letters[i] < top_letters) { + return 0; + } + } + return 1; +} diff --git a/src/fits.pyx b/src/fits.pyx new file mode 100644 index 0000000..58d415e --- /dev/null +++ b/src/fits.pyx @@ -0,0 +1,6 @@ +cdef extern from "c_fits.c": + int _fits(char* bottom, int len_bottom, char* top, int len_top) + + +cpdef bint fits(str bottom, str top): + return _fits(bottom.encode(), len(bottom), top.encode(), len(top)) == 0 diff --git a/candidate_cache.py b/wordscape/candidate_cache.py similarity index 65% rename from candidate_cache.py rename to wordscape/candidate_cache.py index 51e7442..50508e9 100644 --- a/candidate_cache.py +++ b/wordscape/candidate_cache.py @@ -1,25 +1,23 @@ from collections import Counter -from dictionary import Dictionary, DICTS + +from wordscape.dictionary import Dictionary, DICTS +from wordscape.fits import fits def make_key(dictionary_name, letters): return (dictionary_name, frozenset(Counter(letters).items())) -def candidates(letters, dictionary: Dictionary, min=2, permutations=None): - letter_counter = Counter(letters) +def candidates(letters, dictionary: Dictionary): + letters = "".join(letters) possibilities = [] for word in dictionary.word_frequency.keys(): - word_counter = Counter(word) try: - add = all( - word_counter[key] <= letter_counter[key] for key in word_counter.keys() - ) - except KeyError: - add = False - if add: - possibilities.append(word) - return possibilities + if fits(letters, word): + possibilities.append(word) + except ZeroDivisionError: + breakpoint() + return word class CandidateCache: diff --git a/dictionary.py b/wordscape/dictionary.py similarity index 100% rename from dictionary.py rename to wordscape/dictionary.py diff --git a/main.py b/wordscape/main.py old mode 100755 new mode 100644 similarity index 95% rename from main.py rename to wordscape/main.py index 517ed74..eab5a3c --- a/main.py +++ b/wordscape/main.py @@ -6,9 +6,9 @@ import re import cmd2 -from candidate_cache import CandidateCache -from dictionary import DICTS -from word_remove_dialog import RemoveWordsActivity +from wordscape.candidate_cache import CandidateCache +from wordscape.dictionary import DICTS +from wordscape.word_remove_dialog import RemoveWordsActivity LOWERCASE = set(ascii_lowercase) @@ -137,5 +137,5 @@ class MainLoop(cmd2.Cmd): return -if __name__ == "__main__": +def main(): MainLoop().cmdloop() diff --git a/word_remove_dialog.py b/wordscape/word_remove_dialog.py similarity index 100% rename from word_remove_dialog.py rename to wordscape/word_remove_dialog.py