Skip to content

Instantly share code, notes, and snippets.

@hkurokawa
Last active January 13, 2022 13:13
Show Gist options
  • Save hkurokawa/72d89f8edb83f90a662588d527e044b0 to your computer and use it in GitHub Desktop.
Save hkurokawa/72d89f8edb83f90a662588d527e044b0 to your computer and use it in GitHub Desktop.
Wordle solver
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