Skip to content

Commit ac86ae1

Browse files
committed
initial commit
0 parents  commit ac86ae1

File tree

2 files changed

+202
-0
lines changed

2 files changed

+202
-0
lines changed

README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Yourdle.py: A local CLI-based Wordle clone
2+
3+
This was written in about 2 hours while procrastinating. It is hacky and
4+
probably prone to errors. Caveat emptor.
5+
6+
Requires Python 3 and (initially) an internet connection to setup the wordlist file.
7+
8+
## Getting started
9+
10+
Run:
11+
12+
``` sh
13+
./yourdle.py
14+
```
15+
16+
On first run it will download and prepare a wordlist into `wordlist-en.txt` roughly ~95KB in size.
17+
18+
Some options include:
19+
20+
`--wordfile`: Specify an alternate wordfile to use. Must contain one word per line. It won't complain if there are words longer or shorter than 5 characters. That is up to you.
21+
22+
`--secret`: Provide a secret word to try and guess. Useful for debugging or challenging friends.
23+
24+
## Acknowledgements
25+
26+
Thanks to [ @dwyl ](https://github.com/dwyl/) for the
27+
[english-words](https://github.com/dwyl/english-words/) repository. This project
28+
makes use of `words_alpha.txt` to generate an english wordlist.
29+
30+
## Contributing
31+
32+
I am not planning on accepting any pull requests.
33+
34+
I encourage you to report issues, but above all to fork this and hack on it
35+
yourself. Citation is appreciated, but not necessary.
36+
37+
## FAQ
38+
39+
1. Where is the EXE???
40+
41+
> The use of EXE's is a crutch. This project does not provide one because it has
42+
> your best interests at heart. Hopefully by denying you the convenience of the
43+
> EXE you crave you will come to realise that the EXE was an illusion all along.
44+
> That when it came down to it, it was just a way for the powerful to maintain
45+
> control of your systems by keeping you ignorant and comfortable. Cast off the
46+
> shackles and rediscover how to use your machine. Seize the means of shaping
47+
> your own destiny through knowledge and effort. Embrace discomfort.
48+
49+
2. Why?
50+
51+
> I don't know. I have been musing about how to implement a Wordle clone for a
52+
> while now. It seemed the best way to scratch that itch. I still think there is
53+
> maybe a cool way to implement a tree-like data structure for efficient
54+
> searching/validation of ambiguous length Wordles, but I won't touch it anytime
55+
> soon.
56+
57+
3. I could have done this easily. This doesn't look so hard.
58+
59+
> Please do! I encourage you to implement your own version and let me know.
60+
> Maybe do it in $PROGLANG? Write it in pure x86 assembly? Overengineer it? Do
61+
> it. And you might find that it makes you feel something.

yourdle.py

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#!/usr/bin/python
2+
3+
import sys
4+
import random
5+
6+
import os
7+
8+
from argparse import ArgumentParser
9+
10+
import requests
11+
12+
__version__ = "0.0.2"
13+
14+
15+
def prepare_wordlist():
16+
response = requests.get(
17+
"https://raw.githubusercontent.com/dwyl/english-words/master/words_alpha.txt"
18+
)
19+
if response.ok:
20+
with open("wordlist-en.txt", "w") as f:
21+
for line in response.text.split("\n"):
22+
word = line.strip()
23+
if len(word) == 5:
24+
f.write(f"{word}\n")
25+
26+
27+
def valid_word(word):
28+
if len(word) == 5:
29+
return word in word_table.keys()
30+
else:
31+
return False
32+
33+
34+
def check_guess(guess, available_letters):
35+
guess = guess.lower()
36+
if guess == secret_word:
37+
return True, secret_word.upper()
38+
39+
feedback = "?????"
40+
secret_word_copy = secret_word
41+
42+
# Mark all correct letters and remove from secret_word_copy
43+
for i, c in enumerate(secret_word_copy):
44+
if c == guess[i]:
45+
feedback = feedback[:i] + c.upper() + feedback[i + 1 :]
46+
secret_word_copy = secret_word_copy[:i] + "*" + secret_word_copy[i + 1 :]
47+
guess = guess[:i] + "*" + guess[i + 1 :]
48+
49+
for i, c in enumerate(guess):
50+
if c == "*":
51+
continue
52+
53+
if c in secret_word_copy:
54+
feedback = feedback[:i] + c + feedback[i + 1 :]
55+
secret_word_copy = secret_word_copy.replace(c, "*", 1)
56+
else:
57+
feedback = feedback[:i] + "*" + feedback[i + 1 :]
58+
available_letters = available_letters.replace(c, "")
59+
60+
return False, feedback, available_letters
61+
62+
63+
def main(secret_word, word_table):
64+
attempts = 0
65+
max_attempts = 6
66+
67+
guesses = {}
68+
feedbacks = []
69+
available_letters = "abcdefghijklmnopqrstuvwxyz"
70+
71+
def show_grid():
72+
for i in range(max_attempts):
73+
if i < len(feedbacks):
74+
print(feedbacks[i])
75+
else:
76+
print("?????")
77+
78+
print(f"\nAttempt {attempts+1}/{max_attempts}")
79+
print(f"\n{available_letters}\n----")
80+
81+
# start yourdle
82+
while attempts < max_attempts:
83+
show_grid()
84+
guess = input("Your guess:").strip()
85+
if valid_word(guess):
86+
if guess not in guesses.keys():
87+
attempts += 1
88+
guesses[guess] = 1
89+
done, feedback, available_letters = check_guess(
90+
guess, available_letters
91+
)
92+
feedbacks.append(feedback)
93+
if done:
94+
print(
95+
f"You guessed the secret word: {secret_word.upper()} in {attempts} attempts"
96+
)
97+
show_grid()
98+
break
99+
else:
100+
if attempts >= max_attempts:
101+
print(f"You failed to guess the word: {secret_word.upper()}")
102+
break
103+
else:
104+
continue
105+
else:
106+
print(f"You have already guessed {guess.upper()}.")
107+
else:
108+
print(f"{guess.upper()} is not a valid word.")
109+
110+
111+
if __name__ == "__main__":
112+
parser = ArgumentParser(
113+
prog="yourdle.py", description="A basic Wordle for your terminal"
114+
)
115+
116+
parser.add_argument(
117+
"--word-file",
118+
help="Path to a wordlist with one 5 letter word per line",
119+
default="wordlist-en.txt",
120+
)
121+
parser.add_argument("--secret", help="A chosen word to try guess", default=None)
122+
123+
args = parser.parse_args()
124+
125+
if not os.path.exists(args.word_file):
126+
prepare_wordlist()
127+
128+
word_table = {}
129+
# load the words into a word_table
130+
with open(args.word_file, "r") as f:
131+
word = f.readline()
132+
while word:
133+
word_table[word.strip()] = 1
134+
word = f.readline()
135+
136+
if args.secret is None:
137+
secret_word = random.choice(list(word_table.keys()))
138+
else:
139+
secret_word = args.secret
140+
141+
main(secret_word, word_table)

0 commit comments

Comments
 (0)