File size: 4,571 Bytes
38ae408
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import random

import streamlit as st
from a3c.play import get_play_model_path, suggest
from wordle_env.wordle import get_env
from wordle_env.words import complete_vocabulary, target_vocabulary


def initial_config() -> None:
    """
    Function to configure the app
    """
    st.title("Wordle Game 🔠")
    if "secret_word" not in st.session_state:
        st.session_state["secret_word"] = random.choice(target_vocabulary)
    if "guesses" not in st.session_state:
        st.session_state["guesses"] = []
    if "won" not in st.session_state:
        st.session_state["won"] = False


def reset_state() -> None:
    """
    Deletes all the game state to start again
    """
    for key in st.session_state.keys():
        del st.session_state[key]


def game_not_finished() -> bool:
    """
    Condition that tells if the game is finished or not
    It could because there are not more attempts or because the user won
    """
    return not st.session_state.get("won") and len(st.session_state.guesses) < 6


def get_ai_guess() -> str:
    """
    Call the AI to make a guess based on the game state
    """
    env = get_env()
    model_path = get_play_model_path()
    words = list(map(lambda guess: guess[0], st.session_state.get("guesses")))
    states = list(map(lambda guess: guess[2], st.session_state.get("guesses")))
    ai_guess = suggest(env, words, states, model_path)
    return ai_guess


def render() -> None:
    """
    Function to render the app
    """
    st.markdown(
        "<style>.big-font {font-size:30px; display: inline-block; margin: 2px; padding: 10px; border-radius: 5px; text-align: center;}</style>",
        unsafe_allow_html=True,
    )

    if game_not_finished():
        guess_input = st.text_input("Enter your guess:", key="guess_input")
        col1, col2 = st.columns([0.2, 1])
        with col1:
            st.button("Submit", on_click=lambda: process_guess(guess_input))
        with col2:
            st.button("Ask AI ✨", on_click=lambda: process_guess(get_ai_guess()))
    elif st.session_state.get("won"):
        st.success("Congratulations! You guessed the word!")
    else:
        st.error("Game Over! The word was: " + st.session_state.secret_word)

    # Display guesses and feedback centered
    display_guesses()


def process_guess(guess: str) -> None:
    """
    Process the user guess and sets if the user won or not
    """
    guess = guess.upper()
    if not len(guess) == 5 or not guess.isalpha():
        st.warning("Please enter a valid 5-letter word.")
    elif guess not in complete_vocabulary:
        st.warning("That is not a valid word.")
    else:
        if guess == st.session_state.secret_word:
            st.session_state["won"] = True
        feedback, state = check_guess(guess)
        st.session_state.guesses.append((guess, feedback, state))


def display_guesses() -> None:
    """
    Display the user guesses with the feedback in a pretty format
    """
    for guess, feedback, _ in st.session_state.guesses:
        guess_display = '<div style="text-align: center;">'
        for i, letter in enumerate(guess):
            color = feedback[i]
            guess_display += f'<span class="big-font" style="background-color: {color};">{letter}</span>'
        guess_display += "</div>"
        st.markdown(guess_display, unsafe_allow_html=True)

    if game_not_finished():
        st.write("You have {} guesses left.".format(6 - len(st.session_state.guesses)))
    else:
        if st.button("Reset game"):
            reset_state()
            st.rerun()


def check_guess(guess: str) -> tuple[list[str], list[str]]:
    """
    Takes a guess and returns the guess feedback
    depending if the letters are in the right place or not
    """
    feedback = ["grey"] * 5
    word_list = list(st.session_state.secret_word)
    processed_letters = []
    state = ["0"] * 5

    # Check for correct position (green)
    for i, letter in enumerate(guess):
        if letter == word_list[i]:
            feedback[i] = "green"
            state[i] = "2"
            processed_letters.append(letter)

    # Check for correct letter but wrong position (yellow)
    for i, letter in enumerate(guess):
        if (
            feedback[i] == "grey"
            and letter in word_list
            and word_list.count(letter) > processed_letters.count(letter)
        ):
            feedback[i] = "yellow"
            state[i] = "1"
            processed_letters.append(letter)

    return feedback, state


# Main function
if __name__ == "__main__":
    initial_config()
    render()