파이썬, 점수 2638 2675 2676 2689 2699 2717
결과:
OXYPHENBUTAZONE for 615
MICROEARTHQUAKE for 525
FLAVOURDYNAMICS for 435
ADJUSTABILITIES for 375
PREINTERVIEWING for 360
WATERFLOODINGS for 308
EAGLE?OOD? for 100
Left-over word: E
2717
암호:
import time
from multiprocessing import Pool
start_tiles = "AAAAAAAAABBCCDDDDEEEEEEEEEEEEFFGGGHHIIIIIIIIIJKLLLLMMNNNNNNOOOOOOOOPPQRRRRRRSSSSTTTTTTUUUUVVWWXYYZ??"
start_tiles = {l: start_tiles.count(l) for l in set(start_tiles)}
values = {"A": 1,"B": 3,"C": 3,"D": 2,"E": 1,"F": 4,"G": 2,"H": 4,"I": 1,"J": 8,"K": 5,"L": 1,"M": 3,"N": 1,"O": 1,"P": 3,"Q": 10,"R": 1,"S": 1,"T": 1,"U": 1,"V": 4,"W": 4,"X": 8,"Y": 4,"Z": 10,"?": 0}
with open("sowpods.txt") as f:
full_dictionary = list(l.strip() for l in f if l.strip())
def num_wilds_needed(word, tiles):
return sum(max(0, word.count(l) - tiles[l]) for l in word)
def word_is_possible(word, tiles):
# never replace 1st letter with wild, for simplicity
if tiles[word[0]] <= 0:
return False
return num_wilds_needed(word, tiles) <= tiles['?']
def word_score(word):
return sum(values[c] for c in word) * len(word)
def final_score(words, tiles_left, print_leftover=False):
left_over_word = ""
for tile, counts in tiles_left.iteritems():
left_over_word += tile * counts
if print_leftover:
print "Left-over word: %s" % (left_over_word,)
return sum(word_score(word) for word in words) - word_score(left_over_word)
def filter_dictionary(dictionary, tiles_left, start_letters):
return [word for word in dictionary
if word[0] in start_letters and word_is_possible(word, tiles_left)]
def pick_word(next_word, start_letters, tiles_left, dictionary):
if not word_is_possible(next_word, tiles_left):
raise ValueError("Using word that is impossible: %s" % (next_word,))
next_letters = set(start_letters)
next_letters.remove(next_word[0])
next_tiles = dict(tiles_left)
for c in next_word:
next_tiles[c] -= 1
next_dictionary = filter_dictionary(dictionary, next_tiles, next_letters)
return next_letters, next_tiles, next_dictionary
class FakeResult:
def __init__(self, value):
self.value = value
def get(self, timeout=None):
return self.value
class FakePool:
def apply_async(self, f, args):
res = f(*args)
return FakeResult(res)
def proc_next_word(next_word,
start_letters, tiles_left, filtered_sorted_dictionary,
depth, picks, prefix):
score = word_score(next_word)
next_letters, next_tiles, next_dictionary = pick_word(
next_word, start_letters, tiles_left, filtered_sorted_dictionary)
if len(prefix) / 2 < 5:
print "%sDepth %d: ?, %s for %d, %d possible words left" % (
prefix, len(prefix) / 2, next_word, score, len(filtered_sorted_dictionary))
next_words, next_score = search(FakePool(), next_letters, next_tiles, next_dictionary,
depth-1, picks, prefix + " ")
if len(prefix) / 2 < 5:
print "%sDepth %d: %d, %s for %d" % (
prefix, len(prefix) / 2, score + next_score, next_word, score)
return [next_word] + next_words, score + next_score
def wildify(word, tiles_left):
# replace missing letters with wilds
while True:
for c in word:
if tiles_left[c] < word.count(c):
word = word[0] + word[1:].replace(c, '?', word.count(c) - tiles_left[c])
break
else:
break
return word
def search(pool, start_letters, tiles_left, filtered_sorted_dictionary, depth, picks, prefix=""):
if not filtered_sorted_dictionary:
# no words left - penalize for tiles left
return [], final_score([], tiles_left)
if depth == 0:
raise ValueError("Hit depth 0")
if tiles_left['?'] > 0:
# proc top few and re-calculate score based on wildcarding
best_word_candidates = [wildify(w, tiles_left) for w in filtered_sorted_dictionary[:10000]]
best_word_candidates.sort(key=word_score, reverse=True)
else:
# no wildification needed
best_word_candidates = filtered_sorted_dictionary
best_words = best_word_candidates[:picks]
if depth == 1:
# only look at 1 word since depth 0 will do nothing
best_words = [best_words[0]]
results = [pool.apply_async(proc_next_word, (next_word,
start_letters, tiles_left, filtered_sorted_dictionary,
depth, picks, prefix))
for next_word in best_words]
results = [result.get() for result in results]
return max(results, key=lambda (words, result): result)
if __name__ == "__main__":
start_letters = set("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
tiles_left = dict(start_tiles)
print "Preparing word list..."
dictionary = filter_dictionary(full_dictionary, tiles_left, start_letters)
dictionary.sort(key=word_score, reverse=True)
print "Starting search..."
pool = Pool(8)
words, _ = search(pool, start_letters, tiles_left, dictionary, 666, 5)
for word in words:
for c in word:
if tiles_left[c] <= 0:
raise ValueError("Invalid word list")
tiles_left[c] -= 1
print
print "\n".join(("%s for %s" % (word, word_score(word)) for word in words))
print final_score(words, tiles_left, True)
설명:
전체 트리를 검색하여 picks
각 단계에서 가장 좋은 단어를 선택하는 깊이 우선 검색 .
처음에 점수별로 단어 목록 전체를 한 번 정렬합니다. 각 단어를 선택한 후 다음 반복을 위해 더 이상 사용할 수없는 모든 단어를 필터링하여 순서를 유지하므로 각 단계에서 목록을 정렬 할 필요가 없습니다. 와일드 카드를 처리하기 위해 와일드 카드가 필요할 가능성이있는 경우 상위 10000 개의 후보자를 선택하고 필요한 경우 누락 된 문자를 와일드 카드로 바꾸고 새로운 (낮은) 점수를 기준으로 다시 정렬합니다.
이 출력은입니다 picks=5
및했습니다 8m01s
내 8 코어 시스템에서 실행합니다.