<commit_before>from collections import Counter
from itertools import permutations
from hashlib import md5


wordslist = []
anagram = None
target_md5 = None

with open("./words.txt", "r") as f:
    wordslist = [line.strip("\n") for line in f]

with open("./anagram.txt", "r") as f:
    anagram = f.readline().strip("\n")

with open("./md5.txt", "r") as f:
    target_md5 = [l.strip("\n") for l in f]

anagram_counter = Counter(anagram)
anagram_length = len(anagram)
anagram_letters = set(anagram)


class PoultryAndAnts:

    def find_match(self, node):
        (words, length, _, children) = node
        # we've reached a leaf node that has the right amount of letters
        if not children and length == anagram_length:
            # check for md5 of all permutations with white spaces
            for perm in permutations(words):
                digest = md5(" ".join(perm)).hexdigest()
                if digest in target_md5:
                    print "\n\nWINNER!! - %s \n\n" % list(perm)
        for child in children:
            self.find_match(child)


def word_contains(needle, haystack):
    return all(haystack[k] - v >= 0 for k,v in needle.items())


def add_node(node, new_word, new_word_counter):
    (words, length, counter, children) = node
    for c in children:
        add_node(c, new_word, new_word_counter)
    l = len(new_word)
    new_node_length = length + l
    new_node_counter = new_word_counter + counter
    if word_contains(new_node_counter, anagram_counter):
        children.append((words + [new_word], new_node_length, new_node_counter, []))


def nb_leaf_nodes(node, nb_leaves):
    (_, __, ___, children) = node
    if not children:
        return 1
    r = 0
    for c in children:
        r += nb_leaf_nodes(c, nb_leaves)
    return nb_leaves + r


if __name__ == "__main__":
    root = ([], 0, Counter(), [])

    print "Looking for %s: %s" % (anagram, anagram_counter)

    i = 0
    for word in set(wordslist):
        try:
            # If all letters of the word are in the anagram
            word_counter = Counter(word)
            if word_contains(word_counter, anagram_counter):
                add_node(root, word, word_counter)
            i += 1
            if i % 1000 == 0:
                print "done: ", i
                if i % 5000 == 0:
                    print "nb-leaves: %d" % nb_leaf_nodes(root, 0)
        except KeyboardInterrupt as e:
            break

    print "%s:%s" % (anagram, anagram_length)
    print "nb-leaves: %d" % nb_leaf_nodes(root, 0)

    PoultryAndAnts().find_match(root)<commit_msg>[ANTS] Move function into PoultryAndAnts class<commit_after>from collections import Counter
from itertools import permutations
from hashlib import md5


wordslist = []
anagram = None
target_md5 = None

with open("./words.txt", "r") as f:
    wordslist = [line.strip("\n") for line in f]

with open("./anagram.txt", "r") as f:
    anagram = f.readline().strip("\n")

with open("./md5.txt", "r") as f:
    target_md5 = [l.strip("\n") for l in f]

anagram_counter = Counter(anagram)
anagram_length = len(anagram)
anagram_letters = set(anagram)


class PoultryAndAnts:

    def find_match(self, node):
        (words, length, _, children) = node
        # we've reached a leaf node that has the right amount of letters
        if not children and length == anagram_length:
            # check for md5 of all permutations with white spaces
            for perm in permutations(words):
                digest = md5(" ".join(perm)).hexdigest()
                if digest in target_md5:
                    print "\n\nWINNER!! - %s \n\n" % list(perm)
        for child in children:
            self.find_match(child)

    def nb_leaf_nodes(self, node, nb_leaves):
        (_, __, ___, children) = node
        if not children:
            return 1
        r = 0
        for c in children:
            r += self.nb_leaf_nodes(c, nb_leaves)
        return nb_leaves + r


def word_contains(needle, haystack):
    return all(haystack[k] - v >= 0 for k,v in needle.items())


def add_node(node, new_word, new_word_counter):
    (words, length, counter, children) = node
    for c in children:
        add_node(c, new_word, new_word_counter)
    l = len(new_word)
    new_node_length = length + l
    new_node_counter = new_word_counter + counter
    if word_contains(new_node_counter, anagram_counter):
        children.append((words + [new_word], new_node_length, new_node_counter, []))


if __name__ == "__main__":
    root = ([], 0, Counter(), [])
    ants = PoultryAndAnts()

    print "Looking for %s: %s" % (anagram, anagram_counter)

    i = 0
    for word in set(wordslist):
        try:
            # If all letters of the word are in the anagram
            word_counter = Counter(word)
            if word_contains(word_counter, anagram_counter):
                add_node(root, word, word_counter)
            i += 1
            if i % 1000 == 0:
                print "done: ", i
                if i % 5000 == 0:
                    print "nb-leaves: %d" % ants.nb_leaf_nodes(root, 0)
        except KeyboardInterrupt as e:
            break

    print "%s:%s" % (anagram, anagram_length)
    print "nb-leaves: %d" % ants.nb_leaf_nodes(root, 0)

    ants.find_match(root)
{'fraction_non_alphanumeric': 0.11238313298988743, 'fraction_numerical': 0.009540164090822362, 'mean_word_length': 2.4038961038961038, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '57204', 'n_tokens_mistral': 1779, 'n_tokens_neox': 1673, 'n_words': 495}