-
Notifications
You must be signed in to change notification settings - Fork 0
/
wordleSolverBackend.py
213 lines (147 loc) · 5.92 KB
/
wordleSolverBackend.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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
import string
import os
# Configuration constants
WORD_LENGTH = 5 # Length of the word used in the game
MAX_RETRIES = 6 # Maximum number of attempts allowed
ERROR = -1 # Error code
SUCCESS = 1 # Success code
DICT_NAME = "CSW19.txt" # Name of the dictionary file
# Initialize dictionary and character frequency map
dictionary = []
characters = {}
# Utility functions to apply color formatting for terminal output
def DarkGray(
string: str) -> str: return "\033[1;30;40m" + string + "\033[0;37;40m"
def Red(string: str) -> str: return "\033[1;31;40m" + string + "\033[0;37;40m"
def Green(
string: str) -> str: return "\033[1;32;40m" + string + "\033[0;37;40m"
def Yellow(
string: str) -> str: return "\033[1;33;40m" + string + "\033[0;37;40m"
def Blue(string: str) -> str: return "\033[1;34;40m" + string + "\033[0;37;40m"
def Magenta(
string: str) -> str: return "\033[1;35;40m" + string + "\033[0;37;40m"
def Cyan(string: str) -> str: return "\033[1;36;40m" + string + "\033[0;37;40m"
def White(
string: str) -> str: return "\033[1;37;40m" + string + "\033[0;37;40m"
# Filters out words based on "gray" rule: removes words containing a specific character
def removeGray(char: str, index: int, softRemove: bool = False):
i = 0
while i < len(dictionary):
word = dictionary[i]
if (softRemove and word[index] != char) or (char in word):
dictionary.pop(i)
else:
i += 1
# Filters out words based on "yellow" rule: removes words missing the character at any index
def removeYellow(char: str, index: int):
i = 0
while i < len(dictionary):
word = dictionary[i]
if char in word and word[index] != char:
i += 1
else:
dictionary.pop(i)
# Filters out words based on "green" rule: removes words that don't have the character at the exact index
def removeGreen(char: str, index: int):
i = 0
while i < len(dictionary):
word = dictionary[i]
if char in word and word[index] == char:
i += 1
else:
dictionary.pop(i)
# Checks for duplicate characters in a word
def lookforDuplicate(word: str) -> bool:
word = word.replace("?", "") # Exclude placeholder characters
return len(set(word)) < len(word)
# Evaluates the guessed word and filters the dictionary
def evaluateAttempt(word: str):
previous = False
char_index = 0
for index, char in enumerate(word):
if previous: # Skip processing for placeholders
previous = False
continue
softRemove = False
if char == "?":
removeYellow(word[index + 1], char_index)
previous = True
elif char == "!":
removeGreen(word[index + 1], char_index)
previous = True
else:
if lookforDuplicate(word):
softRemove = True
removeGray(char, char_index, softRemove)
char_index += 1
# Checks if the guessed word exists in the dictionary
def isInDictionary(word: str) -> bool:
return word in dictionary
# Validates the input word and ensures it follows the game's rules
def validateAttempt(word: str = "") -> tuple[int, str]:
letterWord = "".join(filter(str.isalpha, word))
if len(letterWord) != WORD_LENGTH:
return ERROR, printToBashCommand("Red", f"\nWord must be {WORD_LENGTH} letters long")
if not isInDictionary(letterWord):
return ERROR, printToBashCommand("Red", f"\nWord \"{letterWord.upper()}\" does not belong to dictionary!")
for i in range(len(word) - 1):
if word[i] in "?!" and not word[i + 1].isalpha():
return ERROR, printToBashCommand("Red", f"\nInvalid placement of \"{word[i]}\"")
return SUCCESS, word
# Resets the character frequency map
def resetCharacters():
global characters
characters = dict.fromkeys(string.ascii_lowercase, 0)
# Counts the occurrences of each character in the dictionary
def countCharacters():
for word in dictionary:
for char in word:
characters[char] += 1
# Selects the "most valuable" word based on character frequency
def selectWord(look_duplicate=False) -> str:
resetCharacters()
countCharacters()
maxValuableWord = ""
maxCount = 0
for word in dictionary:
if not look_duplicate and lookforDuplicate(word):
continue
count = sum(characters[char] for char in word)
if count > maxCount:
maxCount = count
maxValuableWord = word
return maxValuableWord
# Loads the dictionary from a file
def getDictionary():
global dictionary
with open(DICT_NAME, 'r') as file:
dictionary = [line.strip().lower() for line in file if len(
line.strip()) == WORD_LENGTH and line.strip().isalpha()]
# Returns the number of words remaining in the dictionary
def wordsLeft() -> int:
return len(dictionary)
# Main backend function for Wordle logic
def processWordleAttempt(string: str = "") -> tuple[int, str]:
try:
errorNumber, attempt = validateAttempt(string)
if errorNumber == ERROR:
return errorNumber, attempt
evaluateAttempt(attempt)
with open('words.txt', 'w') as wordFile:
wordFile.write("\n".join(dictionary))
if len(dictionary) == 1:
return 0, printToBashCommand("Red", f"\nCongratulations! Today's word was {dictionary[0].upper()}.")
return SUCCESS, attempt
except IndexError:
return ERROR, printToBashCommand("Red", "\nNo words available!")
except KeyboardInterrupt:
return ERROR, printToBashCommand("Red", "\nProgram terminated by force")
# Prints messages to Bash with colored output
def printToBashCommand(color: str, string: str) -> str:
bashCommand = f"powershell write-host -fore {color} {string}"
os.system(bashCommand)
return string
# Entry point
if __name__ == "__main__":
getDictionary()
processWordleAttempt()