-
Notifications
You must be signed in to change notification settings - Fork 0
/
wordle_helper.py
176 lines (142 loc) · 6.08 KB
/
wordle_helper.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import re
WORD_LIST_FILE = "data/wordbank.txt"
# This function reads in the file and creates a list of all the words
def get_word_list() -> list:
result = []
file = WORD_LIST_FILE
with open(file) as fp:
result.extend([word.strip() for word in fp.readlines()])
return result
# Prints the menu for character validation
def validate_menu():
print("Validate characters with the following format: ")
print("c - Correct Character")
print("w - Wrong spot")
print("x - Character is not in answer")
print("Ex: cwcxx")
# This function obtains an input from the user and validates it
def get_guesses() -> tuple:
input_word = ""
input_guess = ""
word_match = False
guess_match = False
word_regex = re.compile("^[a-z]{5}$")
guess_regex = re.compile("^[cwx]{5}$")
while not (word_match and guess_match):
print("\nEnter word: ")
input_word = input()
validate_menu()
input_guess = input()
input_word = input_word.lower()
input_guess = input_guess.lower()
word_match = word_regex.match(input_word)
guess_match = guess_regex.match(input_guess)
if not word_match:
print("Word is not a valid 5 character guess")
if not guess_match:
print("Guess validation does not match the format")
return input_word, input_guess
# This is what processes the input and stores the letters in the correct locations
def assign_letters(input_guess, input_word, correct_letters, maybe_letters, invalid_letters):
for index, current_character in enumerate(input_word):
if input_guess[index] == "c":
if current_character not in correct_letters[0]:
correct_letters[0] += current_character
correct_letters[1][index] = current_character
if current_character in maybe_letters:
maybe_letters.remove(current_character)
if current_character in invalid_letters[0]:
invalid_letters[0].remove(current_character)
elif input_guess[index] == "w":
if current_character not in maybe_letters:
maybe_letters += current_character
invalid_letters[1][index] += current_character
if current_character in invalid_letters[0]:
invalid_letters[0].remove(current_character)
else:
if current_character in invalid_letters[1][index]:
continue
elif current_character in correct_letters[0]:
invalid_letters[1][index] += current_character
elif current_character not in invalid_letters[0] and current_character not in maybe_letters:
invalid_letters[0] += current_character
invalid_letters[1][index] += current_character
# This function removes all of the invalid words based on the letters guessed
def remove_invalid_words(list_of_words, correct_letters, maybe_letters, invalid_letters) -> list:
new_list = []
for word in list_of_words:
valid = True
for index, letter in enumerate(word):
if letter != correct_letters[1][index] and correct_letters[1][index] != ".":
valid = False
break
elif letter in invalid_letters[0] or letter in invalid_letters[1][index]:
valid = False
break
if not all(letter in word for letter in maybe_letters):
valid = False
if valid:
new_list.append(word)
return new_list
# This function weights words based off the frequency that the characters appear
# Then it scores the word and returns the 5 words with the highest score
def rank_words(word_list) -> list:
# Get letter frequency
char_freq_list = [{} for sub in range(5)]
for w in word_list:
for index, ch in enumerate(w):
char_freq_list[index][ch] = char_freq_list[index].get(ch, 0) + 1
# Score the word
new_list = [[]]
for w_index, w in enumerate(word_list):
score = 0
used_characters = ''
for index, ch in enumerate(w):
score_modifier = 1 if ch not in used_characters and word_list else 0.75
used_characters += ch
score = score + (char_freq_list[index].get(ch) / word_list.__len__() * score_modifier)
new_list.insert(w_index, [w, score])
new_list.pop()
# Return 5 most common
return [word[0] for word in sorted(new_list, key=lambda x: x[1], reverse=True)[:5]]
# Prints all the words in the input list
def print_words(word_list):
for index in range(word_list.__len__()):
print(word_list[index], end=' ')
if (index + 1) % 20 == 0:
print("\n", end='')
print("\n")
# Main driver of the program
def wordle_helper(list_of_words):
# Data structures for the individual characters
correct_letters = [[], [".", ".", ".", ".", "."]]
maybe_letters = []
invalid_letters = [[], {0: [], 1: [], 2: [], 3: [], 4: []}]
number_of_guesses = 0
end = False
# loop until the max number of guesses or the word is found
while not end:
input_word, input_guess = get_guesses()
assign_letters(input_guess, input_word, correct_letters, maybe_letters, invalid_letters)
validated_words = remove_invalid_words(list_of_words, correct_letters, maybe_letters, invalid_letters)
print("\nThere are " + str(validated_words.__len__()) + " possible words:")
validated_words.sort()
print_words(validated_words)
if validated_words.__len__() > 5:
best_greens = rank_words(validated_words)
print("\nThese are the 5 best guesses:")
print_words(best_greens)
number_of_guesses += 1
# End cases
if validated_words.__len__() == 1:
print("You found it!")
end = True
elif validated_words.__len__() == 0:
print("There is no answer")
end = True
elif number_of_guesses == 6:
print("You have reached your max number of guesses\n")
end = True
if __name__ == '__main__':
words = get_word_list()
wordle_helper(words)