✨ add wordle
This commit is contained in:
parent
55c3307b74
commit
7943467f1c
2 changed files with 186 additions and 5 deletions
12
src/cli.py
12
src/cli.py
|
@ -15,6 +15,7 @@ from shiv.bootstrap import current_zipfile
|
||||||
import src
|
import src
|
||||||
from src.helpers import flip_char, load_config, write_config
|
from src.helpers import flip_char, load_config, write_config
|
||||||
from src.joplin import process_joplin_posts, get_folders, BASE_URL
|
from src.joplin import process_joplin_posts, get_folders, BASE_URL
|
||||||
|
from src.wordle import wordle
|
||||||
from src.art import BANNERS
|
from src.art import BANNERS
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,12 +28,12 @@ from src.art import BANNERS
|
||||||
@click.option(
|
@click.option(
|
||||||
"--update",
|
"--update",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
help="Check Gitea for a new version and auto-update.",
|
help="Check Forgejo for a new version and auto-update.",
|
||||||
)
|
)
|
||||||
def main(ctx, update):
|
def main(ctx, update):
|
||||||
"""Launch a utility or drop into a command line REPL if no command is given."""
|
"""Launch a utility or drop into a command line REPL if no command is given."""
|
||||||
if update:
|
if update:
|
||||||
update_from_gitea()
|
update_from_forgejo()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
elif ctx.invoked_subcommand is None:
|
elif ctx.invoked_subcommand is None:
|
||||||
banner = random.choice(BANNERS)
|
banner = random.choice(BANNERS)
|
||||||
|
@ -208,8 +209,8 @@ def get_saved_from_reddit() -> None:
|
||||||
_process(item)
|
_process(item)
|
||||||
|
|
||||||
|
|
||||||
def update_from_gitea():
|
def update_from_forgejo():
|
||||||
"""Get the newest release from Gitea and install it."""
|
"""Get the newest release from Forgejo and install it."""
|
||||||
status = Status("Checking for new release...")
|
status = Status("Checking for new release...")
|
||||||
status.start()
|
status.start()
|
||||||
|
|
||||||
|
@ -219,7 +220,7 @@ def update_from_gitea():
|
||||||
if response.status_code != 200:
|
if response.status_code != 200:
|
||||||
status.stop()
|
status.stop()
|
||||||
click.echo(
|
click.echo(
|
||||||
f"Something went wrong when talking to Gitea; got a"
|
f"Something went wrong when talking to Forgejo; got a"
|
||||||
f" {response.status_code} with the following content:\n"
|
f" {response.status_code} with the following content:\n"
|
||||||
f"{response.content}"
|
f"{response.content}"
|
||||||
)
|
)
|
||||||
|
@ -243,6 +244,7 @@ def update_from_gitea():
|
||||||
status.stop()
|
status.stop()
|
||||||
click.echo(f"Updated to {release_data['tag_name']}! 🎉")
|
click.echo(f"Updated to {release_data['tag_name']}! 🎉")
|
||||||
|
|
||||||
|
main.add_command(wordle)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|
179
src/wordle.py
Normal file
179
src/wordle.py
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
import random
|
||||||
|
|
||||||
|
import click
|
||||||
|
import httpx
|
||||||
|
from rich.status import Status
|
||||||
|
|
||||||
|
from src.helpers import base_folder
|
||||||
|
|
||||||
|
|
||||||
|
all_valid_guesses = "https://gist.githubusercontent.com/itsthejoker/7d4c0d10a4e97cc7493e765d9e848a53/raw/b3970cc79bf88c872dd67c3896d8a8673377b0fd/wordle-nyt-allowed-guesses-update-12546.txt"
|
||||||
|
all_answers = "https://gist.githubusercontent.com/itsthejoker/1c7b8b97c454ce464aa5ea7f187d81e9/raw/1a2e59929b833925af800298d1003e48d90b5898/wordle-nyt-answers-alphabetical.txt"
|
||||||
|
answers_path = base_folder / "opsbox_wordle_answers.txt"
|
||||||
|
guesses_path = base_folder / "opsbox_wordle_guesses.txt"
|
||||||
|
|
||||||
|
|
||||||
|
def download_wordle_data():
|
||||||
|
with httpx.Client() as client:
|
||||||
|
with open(answers_path, "w") as f:
|
||||||
|
f.write(client.get(all_answers).text)
|
||||||
|
with open(guesses_path, "w") as f:
|
||||||
|
f.write(client.get(all_valid_guesses).text)
|
||||||
|
|
||||||
|
|
||||||
|
def check_if_need_to_download_data():
|
||||||
|
if not answers_path.exists() or not guesses_path.exists():
|
||||||
|
download_wordle_data()
|
||||||
|
|
||||||
|
|
||||||
|
def load_data():
|
||||||
|
status = Status("Setting up game...")
|
||||||
|
status.start()
|
||||||
|
|
||||||
|
check_if_need_to_download_data()
|
||||||
|
with open(answers_path, "r") as f:
|
||||||
|
answers = f.read().splitlines()
|
||||||
|
with open(guesses_path, "r") as f:
|
||||||
|
guesses = f.read().splitlines()
|
||||||
|
guesses += answers # answers are valid guesses
|
||||||
|
|
||||||
|
status.stop()
|
||||||
|
return answers, guesses
|
||||||
|
|
||||||
|
|
||||||
|
def print_keyboard(guessed_word_list: list[str], keyboard_display: dict[str, int]):
|
||||||
|
first_row = "qwertyuiop"
|
||||||
|
second_row = "asdfghjkl"
|
||||||
|
third_row = "zxcvbnm"
|
||||||
|
click.echo()
|
||||||
|
all_letters_guessed = set("".join(guessed_word_list))
|
||||||
|
for count, item in enumerate([first_row, second_row, third_row]):
|
||||||
|
click.echo(" " * count if count != 2 else " " * 3, nl=False)
|
||||||
|
for letter in item:
|
||||||
|
click.echo(" ", nl=False)
|
||||||
|
if letter in all_letters_guessed and keyboard_display.get(letter) == 2:
|
||||||
|
click.echo(
|
||||||
|
click.style(letter.capitalize(), fg="green", bold=True), nl=False
|
||||||
|
)
|
||||||
|
elif letter in all_letters_guessed and keyboard_display.get(letter) == 1:
|
||||||
|
click.echo(
|
||||||
|
click.style(letter.capitalize(), fg="yellow", bold=True), nl=False
|
||||||
|
)
|
||||||
|
elif letter in all_letters_guessed:
|
||||||
|
click.echo(
|
||||||
|
click.style(letter.capitalize(), fg="white", bold=True), nl=False
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
click.echo(click.style(letter.capitalize(), fg="white"), nl=False)
|
||||||
|
click.echo("\n")
|
||||||
|
|
||||||
|
|
||||||
|
def print_word_matrix(
|
||||||
|
answer: str,
|
||||||
|
letter_counts: dict[str, int],
|
||||||
|
guessed_word_list: list[str],
|
||||||
|
keyboard_display: dict[str, int],
|
||||||
|
) -> None:
|
||||||
|
for guess in guessed_word_list:
|
||||||
|
guess_letter_counts = {}
|
||||||
|
click.echo(" ", nl=False)
|
||||||
|
for count, letter in enumerate(guess):
|
||||||
|
add_newline = count == 4
|
||||||
|
guess_letter_counts[letter] = guess_letter_counts.get(letter, 0) + 1
|
||||||
|
if letter == answer[count]:
|
||||||
|
click.echo(
|
||||||
|
click.style(letter.capitalize(), fg="green", bold=True),
|
||||||
|
nl=add_newline,
|
||||||
|
)
|
||||||
|
keyboard_display[letter] = 2
|
||||||
|
elif (
|
||||||
|
letter in answer
|
||||||
|
and guess_letter_counts[letter] <= letter_counts[letter]
|
||||||
|
):
|
||||||
|
click.echo(
|
||||||
|
click.style(letter.capitalize(), fg="yellow", bold=True),
|
||||||
|
nl=add_newline,
|
||||||
|
)
|
||||||
|
|
||||||
|
if keyboard_display.get(letter) != 2:
|
||||||
|
keyboard_display[letter] = 1
|
||||||
|
elif (
|
||||||
|
letter in answer and guess_letter_counts[letter] > letter_counts[letter]
|
||||||
|
):
|
||||||
|
click.echo(
|
||||||
|
click.style(letter.capitalize(), fg="white", bold=True),
|
||||||
|
nl=add_newline,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
click.echo(
|
||||||
|
click.style(letter.capitalize(), fg="white", bold=True),
|
||||||
|
nl=add_newline,
|
||||||
|
)
|
||||||
|
if len(guessed_word_list) < 6 and answer not in guessed_word_list:
|
||||||
|
click.echo()
|
||||||
|
click.echo("You have ", nl=False)
|
||||||
|
click.echo(
|
||||||
|
click.style(str(6 - len(guessed_word_list)), fg="white", bold=True),
|
||||||
|
nl=False,
|
||||||
|
)
|
||||||
|
click.echo(f" guess{'es' if len(guessed_word_list) != 4 else ''} left.")
|
||||||
|
|
||||||
|
|
||||||
|
def get_unique(sequence):
|
||||||
|
seen = set()
|
||||||
|
return [x for x in sequence if not (x in seen or seen.add(x))]
|
||||||
|
|
||||||
|
|
||||||
|
@click.command(help="Start a new game of Wordle!")
|
||||||
|
@click.option("--debug", is_flag=True, help="Debug mode")
|
||||||
|
def wordle(debug):
|
||||||
|
click.echo()
|
||||||
|
click.echo("Starting a new game of Wordle!")
|
||||||
|
click.echo("You have six tries to find a 5 letter word.")
|
||||||
|
click.echo(
|
||||||
|
"Gray letters are not in the word, yellow letters are in the word but in the"
|
||||||
|
" wrong place, and green letters are in the right place."
|
||||||
|
)
|
||||||
|
click.echo("Good luck!")
|
||||||
|
click.echo()
|
||||||
|
answers, guesses = load_data()
|
||||||
|
|
||||||
|
todays_word = random.choice(answers)
|
||||||
|
# every key is a letter, the value is 1 if it's yellow and 2 if it's green
|
||||||
|
keyboard_display = {}
|
||||||
|
if debug:
|
||||||
|
click.echo(f"Today's word is {todays_word}")
|
||||||
|
|
||||||
|
guessed_words = []
|
||||||
|
letter_set = get_unique(todays_word)
|
||||||
|
letter_counts = {letter: todays_word.count(letter) for letter in letter_set}
|
||||||
|
|
||||||
|
while True:
|
||||||
|
if len(guessed_words) == 6:
|
||||||
|
click.echo("You lose!")
|
||||||
|
click.echo("The word was: ", nl=False)
|
||||||
|
click.echo(click.style(str(6 - len(todays_word)), fg="white", bold=True))
|
||||||
|
click.echo("Better luck next time!")
|
||||||
|
break
|
||||||
|
|
||||||
|
guess = click.prompt("Enter a guess")
|
||||||
|
guess = guess.lower()
|
||||||
|
click.echo()
|
||||||
|
|
||||||
|
if len(guess) < 5 or len(guess) > 5:
|
||||||
|
click.echo("Guesses must be 5 letters.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if guess not in guesses:
|
||||||
|
click.echo("Sorry, that's not a valid guess. Try again!")
|
||||||
|
continue
|
||||||
|
|
||||||
|
guessed_words += [guess]
|
||||||
|
|
||||||
|
print_word_matrix(todays_word, letter_counts, guessed_words, keyboard_display)
|
||||||
|
print_keyboard(guessed_words, keyboard_display)
|
||||||
|
|
||||||
|
click.echo()
|
||||||
|
if guess == todays_word:
|
||||||
|
click.echo("You win!")
|
||||||
|
break
|
Loading…
Add table
Reference in a new issue