-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpyrdle.py
executable file
·235 lines (179 loc) · 6.06 KB
/
pyrdle.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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#!/usr/bin/env python3
"""
Wordle Solver
A program that helps you solve wordle puzzles.
It solves by using your guess and result to filter the list
or words using a sieve to eliminate invalid words and then
present a set of word to pick from.
"""
import argparse
from typing import List
import sys
def main():
parser = argparse.ArgumentParser(
prog="pyrdle",
description="A Wordle Solver in Python",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
EXAMPLE
---------------------------
Enter your guess first.
For result:
use lowercase for yellow letters
use uppercase for green letters
use . for not found
Example: If the clue is "snake"
You guess: great
Enter result as: ..ea.
Next guess: place
Enter result as: ..A.E
Next guess: shake
Enter result as: S.AKE
ctrl-c to exit
""",
)
parser.add_argument("--info", action="store_true")
args = parser.parse_args()
print("---------------")
print(" Wordle Solver")
print("---------------")
print("")
with open("words.txt") as f:
all_words = {x.strip() for x in f}
with open("used.txt") as f:
used = {x.strip() for x in f}
# remove already used words
words = list(all_words - used)
if args.info:
print(f"Words: {len(words)}")
print()
for _ in range(6): # how many guesses/loops
# gather guess
try:
guess = input("Your guess? ")
# gather result
# . - letter not in word
# a - lowercase letter in word wrong pos
# A - uppercase letter in word right pos
result = input("Result : ")
print("")
except KeyboardInterrupt:
print("")
sys.exit()
# Remove all words that have invalid letters
# 1. What letters are invalid
# Using Python sets get the difference between guess/result
# This returns all letters in guess not in result
invalid = set(guess).difference(result.lower())
words = remove_invalid(invalid, words)
if args.info:
print(f"Words after invalid: {len(words)}")
# Remove words without required characters
required = result.replace(".", "").lower()
words = only_required(required, words)
if args.info:
print(f"Words after required: {len(words)}")
# Remove words with correct letter but wrong position
words = wrong_position(result, words)
if args.info:
print(f"Words after wrong pos: {len(words)}")
# Remove words with correct letter and right position
words = right_position(result, words)
if args.info:
print(f"Words after right pos: {len(words)}")
# Suggest 10 Words
print("Suggestions...")
for i, word in enumerate(words):
print(f" {word}")
if i > 4:
break
print("")
# Remove invalid words from list.
# - Loop through list of words
# - Check if word contains any letters in invalid string
# - If the word does not it is good append to valid list
def remove_invalid(invalid: str, words: List) -> List:
valid = []
# loop through list words
for word in words:
if has_valid_chars(word, invalid):
valid.append(word)
return valid
# Remove words that do not contain required characters
# - Convert guess to just chars, order doesn't matter
# - Use set difference
def only_required(required: str, words: List) -> List:
valid = []
# loop through words
for word in words:
if has_required(word, required):
valid.append(word)
return valid
# Remove words that do have the letter in the wrong pos.
# Right letter, wrong position
# - iterate over result
# - if character is lowercase (right word, wrong pos)
# - then loop over words add words that don't have
def wrong_position(result: str, words: List) -> List:
valid = []
for word in words:
if not is_wrong_position(result, word):
valid.append(word)
return valid
# Remove words that do not have letter in the right pos.
# Right letter, right position
# - iterate over result
# - if character is uppercase (right word, right pos)
# - then loop over words add words that have same
def right_position(result: str, words: List) -> List:
valid = []
for word in words:
if is_right_position(result, word):
valid.append(word)
return valid
# Checks if word contains only valid chars
# - chars passed in are invalid
def has_valid_chars(word: str, chars: str) -> bool:
# if the intersection is empty then no invalid
if set(word).intersection(chars) == set():
return True
# contains an invalid
return False
# Checks if word contains all required chars
def has_required(word: str, chars: str) -> bool:
# Nothing required
if chars == "":
return True
# intersection is not empty means that the word does contain a letter from
# required so need to loop both since all letters are required break if one
# character is produces empty
for ch in chars:
if set(word).intersection(ch) == set():
return False
return True
# Checks word for characters in result are in the wrong position
# Right letter. Wrong position.
# - iterate over result
# - only check lowercase letters
# - confirm word does not have letter there
def is_wrong_position(result: str, word: str) -> bool:
for i, ch in enumerate(result):
if ch.islower():
if word[i] == ch:
return True
return False
# Checks word for characters in result are in the right position
# Right letter. Right position.
# - iterate over result
# - only check uppercase letters
# - confirm word has letter there
# - confirm all letters, not just first
def is_right_position(result: str, word: str) -> bool:
k = True
for i, ch in enumerate(result):
if ch.isupper():
if word[i] != ch.lower():
k = False
return k
if __name__ == "__main__":
main()