Here is an update to my previous boggle solver. The new version has an almost instantaneous output, removing the need to limit the length of words being searched for.
Any comments on my general coding implementation or layout would be appreciated.
"""Boggle game solver"""
class Trie:
"""Trie class to speed up programme by stopping exploration of non-existent prefixes"""
def __init__(self):
"""Initialise the trie"""
self.child = {}
def insert(self, word):
"""Insert word into trie"""
current = self.child
for char in word:
if char not in current:
current[char] = {}
current = current[char]
def search(self, word):
"""Search the trie"""
current = self.child
for char in word:
if char not in current:
return False
current = current[char]
return True
def words_from(board, row, column, running_string, list_words):
"""Calculate all possible words from a given starting position [row, column]"""
if row in (4, -1) or column in (4, -1):
return
# Search the Trie
if not trie.search(running_string):
return
if board[row][column] != "-":
new_string = running_string + board[row][column]
board[row][column] = "-"
# Add new word
if len(new_string) >= 3:
list_words.append(new_string.lower())
# Find next word
next_move = [
(1, 1),
(-1, -1),
(1, -1),
(-1, 1),
(1, 0),
(0, 1),
(-1, 0),
(0, -1),
]
for dx, dy in next_move:
words_from(board, row + dx, column + dy, new_string, list_words)
board[row][column] = new_string[-1]
return list_words
def get_permutations(board):
"""Get all permutations """
set_permutations = set()
# Build Trie
global trie
trie = Trie()
with open("en-dict.txt", "r", encoding="utf8") as file:
for line in file:
trie.insert(line)
#Search for words from each starting position
for row in range(4):
for column in range(4):
# Search for words
words = words_from(board, row, column, running_string="", list_words=[])
if words:
for word in words:
set_permutations.add(word)
words = None
return sorted(list(set_permutations))
def dictionary_check(set_permuations):
"""Check set_permutations for valid English words"""
dictionary = {}
with open("en-dict.txt", "r", encoding="utf8") as file:
for line in file:
dictionary[line.strip()] = 0
counter = 0
for word in set_permuations:
if word.lower() in dictionary:
counter += 1
print(word)
print(f"======\n{counter} words")
def find_words(board):
"""Find words on the boggle board"""
set_permutations = get_permutations(board)
print("\nPerforming dictionary check....")
dictionary_check(set_permutations)
def build_board(string):
"""Build board from string"""
if len(string) != 16:
print("Error. Must enter 4*4 grid (16 characters)")
return
board = [[*string[0:4]], [*string[4:8]], [*string[8:12]], [*string[12:16]]]
find_words(board)
if __name__ == "__main__":
string_board = "playthiswordgame"
build_board(string_board)
list_words
inwords_from
in the first place, and therefore avoid needing the additionaldictionary_check
to take them out again afterwards. \$\endgroup\$