-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathwordle.py
107 lines (89 loc) · 3.99 KB
/
wordle.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File to play around with Wordle
# Automated version of worlde_user.py
import matplotlib.pyplot as plt
import numpy as np
import re
import inits
from wordfreq import word_frequency
char_arr = np.array([5012.0, 1346.0, 1551.0, 2060.0, 5429.0, 885.0, 1334.0, 1371.0, 3088.0, 264.0, 1295.0, 2652.0, 1660.0, 2377.0, 3684.0, 1652.0, 83.0, 3260.0, 5997.0, 2566.0, 2045.0, 541.0, 844.0, 251.0, 1649.0, 394.0])
char_score_arr = char_arr/np.sum(char_arr)
def validate_guess(word, guess):
used_arr = np.zeros(26)
for char in word: used_arr[ord(char)-ord('a')] += 1
res = np.zeros(5)
out_s = []
for i, char in enumerate(guess):
if char not in word:
res[i] = 0
out_s += ["_"]
continue
elif char == word[i]:
res[i] = 1
out_s += [char.upper()]
elif used_arr[ord(char)-ord('a')] > 0:
res[i] = 2
out_s += [char]
used_arr[ord(char)-ord('a')] -= 1
return res, "".join(out_s)
def check_letters(guess, mins, maxs):
# checks letters are within bounds
np_guess = np.array(list(guess))
res = [np.sum(np_guess == a) >= mins[ord(a)-ord('a')] and np.sum(np_guess == a) <= maxs[ord(a)-ord('a')] \
for a in guess]
return all(res)
def play_game(word, word_arr, win_arr, guess="soare"):
turn = 0
solved = False
max_count = np.repeat(5, 26)
while not solved:
#print(f"{turn}\tI think\t{guess.upper()} from {len(word_arr)} candidates")
turn += 1
cor_array, out_s = validate_guess(word, guess)
#print(f"{turn}\tResult\t{out_s}")
if np.all(cor_array == 1):
solved = True
#print(f"I found the answer in {turn} turns")
return turn
# revise guess
# 1 - keep only words with letters we know are(n't) in positions
r_str = ""
for char in out_s.replace("_", "."):
if char.islower():
r_str += f"[^{char}]"
else:
r_str += char.lower()
r = re.compile(r_str)
win_arr = np.array(list(filter(r.match, win_arr)))
word_arr = np.array(list(filter(r.match, word_arr)))
# 2 — axe words with(out) characters
min_count = np.zeros(26)
for i, char in enumerate(cor_array):
if char > 0:
min_count[ord(guess[i])-ord('a')] += 1
in_list = np.array(list(guess))[np.where(cor_array == 2)]
not_list = np.array(list(guess))[np.where(cor_array == 0)]
for char in np.array(list(guess))[(np.where((cor_array == 2) | (cor_array == 1)))]:
if char in not_list:
max_count[ord(char)-ord('a')] = np.sum(np.array(list(guess))[(np.where((cor_array == 2) | (cor_array == 1)))] == char)
not_list = np.array(list(set(not_list) - set(np.array(list(guess))[(np.where((cor_array == 1) | (cor_array == 2)))])))
win_arr = win_arr[[not any(np.isin(not_list, list(a))) \
and all(np.isin(in_list, list(a))) for a in win_arr]]
win_arr = win_arr[[check_letters(a, min_count, max_count) is True for a in win_arr]]
word_arr = word_arr[[not any(np.isin(not_list, list(a))) \
and all(np.isin(in_list, list(a))) for a in word_arr]]
word_arr = word_arr[[check_letters(a, min_count, max_count) is True for a in word_arr]]
# find best word to guess
if np.sum(cor_array) == 0:
# if totally blank, choose next most common word
word_scores = inits.find_best(word_arr, char_score_arr)
guess = word_arr[np.argmax(word_scores)]
else:
# otherwise, revise guess
try:
guess = win_arr[np.argmax([word_frequency(a, 'en', wordlist='large') for a in win_arr])]
except ValueError:
#print("Couldn't find the word.")
return -1
if turn >= 20:
print("GAME IS STUCK IN INFINITE LOOP")
return None