Newer
Older
"""This class holds a list of words. You can use (word in wordlist)
to check if a word is in the list, or wordlist.lookup(prefix)
to see if prefix starts any of the words in the list."""
def __init__(self, file, min_len=3):
lines = file.read().upper().split()
self.words = [word for word in lines if len(word) >= min_len]
self.words.sort()
self.bounds = {}
for c in ALPHABET:
c2 = chr(ord(c) + 1)
self.bounds[c] = (bisect.bisect(self.words, c),
bisect.bisect(self.words, c2))
def lookup(self, prefix, lo=0, hi=None):
"""See if prefix is in dictionary, as a full word or as a prefix.
Return two values: the first is the lowest i such that
words[i].startswith(prefix), or is None; the second is
True iff prefix itself is in the Wordlist."""
words = self.words
i = bisect.bisect_left(words, prefix, lo, hi)
if i < len(words) and words[i].startswith(prefix):
return i, (words[i] == prefix)
return None, False
return self.lookup(word)[1]
return len(self.words)
# _____________________________________________________________________________
class BoggleFinder:
"""A class that allows you to find all the words in a Boggle board."""
wordlist = None # A class variable, holding a wordlist
def __init__(self, board=None):
if BoggleFinder.wordlist is None:
BoggleFinder.wordlist = Wordlist(open_data("EN-text/wordlist.txt"))
self.found = {}
if board:
self.set_board(board)
def set_board(self, board=None):
"""Set the board, and find all the words in it."""
if board is None:
board = random_boggle()
self.board = board
self.neighbors = boggle_neighbors(len(board))
self.found = {}
for i in range(len(board)):
lo, hi = self.wordlist.bounds[board[i]]
self.find(lo, hi, i, [], '')
return self
def find(self, lo, hi, i, visited, prefix):
"""Looking in square i, find the words that continue the prefix,
considering the entries in self.wordlist.words[lo:hi], and not
revisiting the squares in visited."""
return
wordpos, is_word = self.wordlist.lookup(prefix, lo, hi)
if wordpos is not None:
self.found[prefix] = True
visited.append(i)
c = self.board[i]
prefix += c
self.find(wordpos, hi, j, visited, prefix)
visited.pop()
scores = [0, 0, 0, 0, 1, 2, 3, 5] + [11] * 100
def score(self):
"""The total score for the words found, according to the rules."""
return sum([self.scores[len(w)] for w in self.words()])
def __len__(self):
return len(self.found)
# _____________________________________________________________________________
def boggle_hill_climbing(board=None, ntimes=100, verbose=True):
"""Solve inverse Boggle by hill-climbing: find a high-scoring board by
starting with a random one and changing it."""
finder = BoggleFinder()
if board is None:
board = random_boggle()
best = len(finder.set_board(board))
for _ in range(ntimes):
i, oldc = mutate_boggle(board)
new = len(finder.set_board(board))
if new > best:
best = new
print_boggle(board)
return board, best
def mutate_boggle(board):
i = random.randrange(len(board))
oldc = board[i]
# random.choice(boyan_best)
board[i] = random.choice(random.choice(cubes16))
return i, oldc
# ______________________________________________________________________________
# Code to compare searchers on various problems.
class InstrumentedProblem(Problem):
"""Delegates to a problem, and keeps statistics."""
self.problem = problem
self.succs = self.goal_tests = self.states = 0
self.found = None
def actions(self, state):
self.succs += 1
return self.problem.actions(state)
def result(self, state, action):
self.states += 1
return self.problem.result(state, action)
def goal_test(self, state):
self.goal_tests += 1
result = self.problem.goal_test(state)
self.found = state
return result
def path_cost(self, c, state1, action, state2):
return self.problem.path_cost(c, state1, action, state2)
def value(self, state):
return self.problem.value(state)
def __getattr__(self, attr):
def __repr__(self):
return '<{:4d}/{:4d}/{:4d}/{}>'.format(self.succs, self.goal_tests,
def compare_searchers(problems, header,
searchers=[breadth_first_tree_search,
breadth_first_search,
depth_first_graph_search,
iterative_deepening_search,
depth_limited_search,
recursive_best_first_search]):
def do(searcher, problem):
p = InstrumentedProblem(problem)
searcher(p)
return p
table = [[name(s)] + [do(s, p) for p in problems] for s in searchers]
print_table(table, header)
def compare_graph_searchers():
compare_searchers(problems=[GraphProblem('Arad', 'Bucharest', romania_map),
GraphProblem('Oradea', 'Neamt', romania_map),
GraphProblem('Q', 'WA', australia_map)],
header=['Searcher', 'romania_map(Arad, Bucharest)',
'romania_map(Oradea, Neamt)', 'australia_map'])