Last active
January 13, 2022 13:13
-
-
Save hkurokawa/72d89f8edb83f90a662588d527e044b0 to your computer and use it in GitHub Desktop.
Wordle solver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import collections | |
import random | |
def is_alphabet(s): | |
return all('a' <= ch <= 'z' for ch in s.strip().lower()) | |
class Problem: | |
def __init__(self, answer=None): | |
if answer is not None: | |
self.answer = answer | |
return | |
with open("/usr/share/dict/words") as file: | |
self.answer = random.choice([s.strip().lower() for s in file if len(s) == 6 and is_alphabet(s)]) | |
def guess(self, word): | |
if len(word) != 5 or not is_alphabet(word): | |
raise ValueError(f"Unexpected guess: {word}") | |
return "".join( | |
['C' if word[i] == self.answer[i] else 'E' if word[i] in self.answer else '.' for i in range(len(word))]) | |
class Guesser: | |
def __init__(self): | |
with open("/usr/share/dict/words") as file: | |
self.possible_answers = [s.strip().lower() for s in file if len(s) == 6 and is_alphabet(s)] | |
self.possible_guesses = self.possible_answers.copy() | |
self.round = 0 | |
def think(self, guess, result): | |
if result == "CCCCC": | |
return | |
self.possible_guesses.remove(guess) | |
for i in range(len(result)): | |
ch = guess[i] | |
res = result[i] | |
if res == ".": | |
self.possible_answers = list(filter(lambda word: ch not in word, self.possible_answers)) | |
elif res == "E": | |
self.possible_answers = list(filter(lambda word: ch in word and word[i] != ch, self.possible_answers)) | |
else: | |
self.possible_answers = list(filter(lambda word: word[i] == ch, self.possible_answers)) | |
def guess(self): | |
self.round += 1 | |
if self.round == 1: | |
return "oates" # Most efficient guess for the 1st time | |
if len(self.possible_answers) == 1: | |
return self.possible_answers[0] | |
def bonus(word): | |
return 1 if word in self.possible_answers else 0 | |
return max(self.possible_guesses, key=lambda guess: self.score(guess) + bonus(guess)) | |
def score(self, guess): | |
def hint(word, answer): | |
return "".join( | |
['C' if word[i] == answer[i] else 'E' if word[i] in answer else '.' for i in range(len(word))]) | |
counter = collections.Counter() | |
for a in self.possible_answers: | |
counter[hint(guess, a)] += 1 | |
return len(self.possible_answers) - counter.most_common(1)[0][1] | |
class Round: | |
def __init__(self, answer=None): | |
self.problem = Problem(answer) | |
self.guesser = Guesser() | |
self.round = 0 | |
self.history = [] | |
def play_round(self): | |
self.round += 1 | |
word = self.guesser.guess() | |
result = self.problem.guess(word) | |
self.history.append((word, result)) | |
# print(f"Round {self.round}: Guess \"{word}\" -> {result}") | |
self.guesser.think(word, result) | |
if result == "CCCCC": | |
return True | |
else: | |
return False | |
def play(self): | |
while self.round < 6: | |
result = self.play_round() | |
if result: | |
return True, self.round | |
return False, self.round | |
def random_mode(): | |
N = 50 | |
num_solved = 0 | |
for _ in range(N): | |
r = Round() | |
(res, num_round) = r.play() | |
if res: | |
num_solved += 1 | |
print(f"Congratulations! You solved the problem in {num_round} round(s).") | |
else: | |
print(f"Failed to solve the problem. The answer was \"{r.problem.answer}\".") | |
print() | |
print(f"Number of correct answer: {num_solved} / {N}") | |
print(f"Correct answer rate: {num_solved * 100.0 / N}%") | |
def exhaustive_mode(file=None): | |
if file is None: | |
file = "all.txt" | |
with open(file) as f: | |
problems = [s.strip().lower() for s in f if len(s) == 6 and is_alphabet(s)] | |
num_solved = 0 | |
for p in problems: | |
r = Round(p) | |
(res, num_round) = r.play() | |
if res: | |
num_solved += 1 | |
else: | |
for h in r.history: | |
print(f"\"{h[0]}\" -> {h[1]}") | |
print(f"Answer was \"{p}\"") | |
print() | |
print(f"Number of correct answer: {num_solved} / {len(problems)}") | |
print(f"Correct answer rate: {num_solved * 100.0 / len(problems)}%") | |
def interactive_mode(): | |
guesser = Guesser() | |
for _ in range(6): | |
guess = guesser.guess() | |
print(f"Guess: {guess}") | |
result = input("Input the result in C/E/.: ").strip() | |
if result == "CCCCC": | |
break | |
guesser.think(guess, result) | |
if __name__ == '__main__': | |
# random_mode() | |
exhaustive_mode() | |
# interactive_mode() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment