コード例 #1
0
ファイル: trie.py プロジェクト: lydiolectal/scrabble-rousers
class Trie:
    def __init__(self):
        self.root = TrieNode()
        self.scorer = Scorer()

    def insert(self, s):
        self.insert_helper(self.root, s, 0)

    def insert_helper(self, node, s, i):
        if i == len(s):
            node.is_word = True
        else:
            curletter = s[i]
            if curletter not in node.children:
                node.children[curletter] = TrieNode()
            self.insert_helper(node.children[curletter], s, i + 1)

    def contains(self, s):
        return self.contains_helper(self.root, s)

    def contains_helper(self, node, s):
        if s == "":
            return node.is_word
        curletter = s[0]
        if curletter in node.children:
            return self.contains_helper(node.children[curletter], s[1:])
        else:
            return False

    # return a StartSequence that includes the word template
    def get_plays_constrained(self, start_seq, tiles, board, dist):
        templates = self.get_words_constrained(start_seq, tiles, board)

        plays = []
        x, y = start_seq.x, start_seq.y
        ish = start_seq.ish
        for template in templates:
            if not all(c is None for c in template) and len(template) >= dist:
                play = StartSequence(x, y, template, ish)
                score = self.score_play(play, board)
                play.points = score
                plays.append(play)
        return plays

    def get_words(self, template):
        return self.get_words_helper(template, self.root)

    def get_chars(self, template):
        # check that there is only one None in the template; error if > 1
        from functools import reduce
        num_blanks = reduce((lambda n, c: n + int(not c)), template, 0)
        if num_blanks != 1:
            raise RuntimeError(f"Template should have 1 blank. {num_blanks} blanks.")
        return self.get_chars_helper(template, self.root)

    def get_words_constrained(self, start_seq, tiles, board):
        s_list = []
        self.get_words_constrained_helper(start_seq, self.root, tiles, board, s_list)
        return s_list

    def get_words_helper(self, template, node, s = ""):
        # while we still have spaces left to fill
        if template != []:
            curspot = template[0]
            if curspot:
                child_words = []
                if curspot in node.children:
                    temps = s + curspot
                    child_words = self.get_words_helper(template[1:],
                        node.children[curspot], temps)
                return child_words
            else:
                words = []
                for next in node.children:
                    temps = s + next
                    child_words = self.get_words_helper(template[1:],
                        node.children[next], temps)
                    if child_words:
                        words.extend(child_words)
                return words
        else:
            if node.is_word:
                return [s]

    # get possible characters for first blank
    def get_chars_helper(self, template, node, c = ""):
        # while we still have spaces left to fill
        if template != []:
            curspot = template[0]
            if curspot:
                child_words = []
                if curspot in node.children:
                    child_words = self.get_chars_helper(template[1:],
                        node.children[curspot], c)
                return child_words
            else:
                chars = []
                for next in node.children:
                    child_words = self.get_chars_helper(template[1:],
                        node.children[next], next)
                    if child_words:
                        chars.extend(child_words)
                return chars
        else:
            if node.is_word:
                return [c]

    def get_words_constrained_helper(self, start_seq, node, tiles, board, s_list, s = []):
        curX, curY = start_seq.x, start_seq.y
        template = start_seq.template
        ish = start_seq.ish

        if template != []:
            curspot = template[0]
            if curspot:
                if curspot in node.children:
                    temps = s + [None]
                    if ish:
                        temp_start_seq = StartSequence(curX + 1, curY, template[1:], ish)
                    else:
                        temp_start_seq = StartSequence(curX, curY + 1, template[1:], ish)
                    child_words = self.get_words_constrained_helper(temp_start_seq,
                        node.children[curspot], tiles, board, s_list, temps)
            else:
                if node.is_word:
                    s_list.append(s)
                crosscheck = board.crosschecks[curY][curX].v_check if ish else board.crosschecks[curY][curX].h_check
                to_traverse = list(crosscheck.intersection(set(tiles)))

                for next in to_traverse:
                    if next in node.children:
                        temps = s + [next]
                        if ish:
                            temp_start_seq = StartSequence(curX + 1, curY, template[1:], ish)
                        else:
                            temp_start_seq = StartSequence(curX, curY + 1 , template[1:], ish)
                        remaining_tiles = tiles[:]
                        remaining_tiles.remove(next)
                        self.get_words_constrained_helper(temp_start_seq,
                            node.children[next], remaining_tiles, board, s_list, temps)
        else:
            if node.is_word:
                s_list.append(s)

    def score_play(self, play, board):
        x, y = play.x, play.y
        ish = play.ish
        template = play.template
        dX, dY = (1, 0) if ish else (0, 1)
        mult_score = 0
        base_score = 0
        factor = 1
        for c in template:
            if not c:
                mult_score += self.scorer.get_score_old(board.tiles[y][x])
            else:
                square_score, square_factor = self.scorer.get_score_new(x, y, c)
                mult_score += square_score
                factor *= square_factor
                base_score += self.score_helper(Coord(x, y), board, ish)
            x += dX
            y += dY
        return (mult_score * factor) + base_score

    def score_helper(self, coord, board, ish):
        base_score = 0
        dX, dY = (0, 1) if ish else (1, 0)
        x, y = coord[0] - 1, coord[1] - 1
        while (x >= 0 and y >= 0) and board.tiles[y][x]:

            base_score += self.scorer.get_score_old(board.tiles[y][x])
            x -= dX
            y -= dY
        x, y = coord[0] + 1, coord[1] + 1
        while (x < board.size and y < board.size) and board.tiles[y][x]:
            base_score += self.scorer.get_score_old(board.tiles[y][x])
            x += dX
            y += dY
        return base_score

    scrabble_words = None

    @staticmethod
    def words():
        if Trie.scrabble_words is None:
            with open("assets/scrabble_dictionary.txt") as f:
                words = f.read().lower().splitlines()
            Trie.scrabble_words = Trie()
            for word in words:
                Trie.scrabble_words.insert(word)
        return Trie.scrabble_words