mirror of
https://github.com/ltcptgeneral/cse151b-final-project.git
synced 2024-12-28 02:49:09 +00:00
120 lines
3.8 KiB
Python
120 lines
3.8 KiB
Python
import contextlib
|
|
import pathlib
|
|
import random
|
|
from string import ascii_letters, ascii_lowercase
|
|
|
|
from rich.console import Console
|
|
from rich.theme import Theme
|
|
|
|
console = Console(width=40, theme=Theme({"warning": "red on yellow"}))
|
|
|
|
NUM_LETTERS = 5
|
|
NUM_GUESSES = 6
|
|
WORDS_PATH = pathlib.Path(__file__).parent / "wordlist.txt"
|
|
|
|
|
|
class Wordle:
|
|
|
|
def __init__(self) -> None:
|
|
self.word_list = WORDS_PATH.read_text(encoding="utf-8").split("\n")
|
|
self.n_guesses = 6
|
|
self.num_letters = 5
|
|
self.curr_word = None
|
|
self.reset()
|
|
|
|
def refresh_page(self, headline):
|
|
console.clear()
|
|
console.rule(f"[bold blue]:leafy_green: {headline} :leafy_green:[/]\n")
|
|
|
|
def start_game(self):
|
|
# get a new random word
|
|
word = self.get_random_word(self.word_list)
|
|
|
|
self.curr_word = word
|
|
|
|
def get_state(self):
|
|
return
|
|
|
|
def action_to_word(self, action):
|
|
# Calculate the word from the array
|
|
word = ''
|
|
for i in range(0, len(ascii_lowercase), 26):
|
|
# Find the index of 1 in each block of 26
|
|
letter_index = action[i:i+26].index(1)
|
|
# Append the corresponding letter to the word
|
|
word += ascii_lowercase[letter_index]
|
|
|
|
return word
|
|
|
|
def play_guess(self, action):
|
|
# probably an array of length 26 * 5 for 26 letters and 5 positions
|
|
guess = action
|
|
|
|
def get_random_word(self, word_list):
|
|
if words := [
|
|
word.upper()
|
|
for word in word_list
|
|
if len(word) == NUM_LETTERS
|
|
and all(letter in ascii_letters for letter in word)
|
|
]:
|
|
return random.choice(words)
|
|
else:
|
|
console.print(
|
|
f"No words of length {NUM_LETTERS} in the word list",
|
|
style="warning",
|
|
)
|
|
raise SystemExit()
|
|
|
|
def show_guesses(self, guesses, word):
|
|
letter_status = {letter: letter for letter in ascii_lowercase}
|
|
for guess in guesses:
|
|
styled_guess = []
|
|
for letter, correct in zip(guess, word):
|
|
if letter == correct:
|
|
style = "bold white on green"
|
|
elif letter in word:
|
|
style = "bold white on yellow"
|
|
elif letter in ascii_letters:
|
|
style = "white on #666666"
|
|
else:
|
|
style = "dim"
|
|
styled_guess.append(f"[{style}]{letter}[/]")
|
|
if letter != "_":
|
|
letter_status[letter] = f"[{style}]{letter}[/]"
|
|
|
|
console.print("".join(styled_guess), justify="center")
|
|
console.print("\n" + "".join(letter_status.values()), justify="center")
|
|
|
|
def guess_word(self, previous_guesses):
|
|
guess = console.input("\nGuess word: ").upper()
|
|
|
|
if guess in previous_guesses:
|
|
console.print(f"You've already guessed {guess}.", style="warning")
|
|
return guess_word(previous_guesses)
|
|
|
|
if len(guess) != NUM_LETTERS:
|
|
console.print(
|
|
f"Your guess must be {NUM_LETTERS} letters.", style="warning"
|
|
)
|
|
return guess_word(previous_guesses)
|
|
|
|
if any((invalid := letter) not in ascii_letters for letter in guess):
|
|
console.print(
|
|
f"Invalid letter: '{invalid}'. Please use English letters.",
|
|
style="warning",
|
|
)
|
|
return guess_word(previous_guesses)
|
|
|
|
return guess
|
|
|
|
def reset(self, guesses, word, guessed_correctly, n_episodes):
|
|
refresh_page(headline=f"Game: {n_episodes}")
|
|
|
|
if guessed_correctly:
|
|
console.print(f"\n[bold white on green]Correct, the word is {word}[/]")
|
|
else:
|
|
console.print(f"\n[bold white on red]Sorry, the word was {word}[/]")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|