exercise7_template

  1from cs110_ex7 import *
  2from random import choice
  3########################## CANVAS SETUP CODE ##############################
  4# initialize window
  5gui = Tk()
  6gui.title("SUPER Wordle!")
  7
  8canvas = Canvas(gui,background="white")
  9setup_window(canvas)
 10
 11# the next thing is a list of all the functions in this file. It"s so we can
 12# generate that cool web version of the documentation. You don"t need to
 13# worry about it.
 14__all__ = [
 15    "get_difficulty", "read_in_words", "generate_hint", "finalize_guess",
 16    "show_past_guess", "show_game_board", "handle_typing" 
 17]
 18########################## GAMEPLAY FUNCTIONS ##############################
 19
 20# Dictionary to store all of the game data
 21GAME_DATA = {
 22  "solution": "",      # a string that is the secret solution
 23  "current_guess": "", # a string that contains the current guess
 24  "past_guesses": [],  # a list that contains all of the past guesses
 25  "word_list": [],     # a list that will contain all the valid n letter words
 26  "num_letters": 5,    # how many letters does each solution contain
 27  }
 28
 29
 30def get_difficulty():
 31    """
 32    Uses a pop-up window to ask the user to input the desired difficulty (length of words).
 33  
 34
 35    Returns:
 36      * `int`: The number of letters (the difficulty) to use for the secret word
 37      * or `"invalid"`: the string `"invalid" indicating that the person did not enter a valid number
 38    """
 39  
 40    user_input = simpledialog.askstring(
 41        title="Difficulty Level", prompt="What length word should we use?"
 42    )
 43
 44    ## TODO: Use try-except to try and see if user_input is a number
 45        ## TODO: If they did, check to see if it"s at least 2 or at most 15.
 46            ## TODO: If it is, then return that number
 47        ## TODO: In all other cases, return the string "invalid"
 48
 49
 50def read_in_words(file_path, num_letters):
 51    """
 52    Function that reads in a list of words and adds them to the `GAME_DATA`. Then,
 53    picks a random word to set as the "solution" key in the `GAME_DATA` dictionary.
 54    
 55    Args:
 56      * file_path (`str`): The file to be read in
 57      * num_letters (`int`): How many letters should be in a word
 58
 59    Returns:
 60      * a `list` continaing the words with the correct number of letters
 61    """
 62    list_of_words = []
 63    
 64    ## TODO: Open the file stored in the file_path variable
 65    
 66    ## TODO: loop through each line of the file
 67        ## TODO: Split the line by " " using the split method of the String class
 68        ## TODO: If the number of letters in that word matches num_letters
 69            ## TODO Append the 0th element of that list into list_of_words
 70
 71    ## TODO: Close the file!
 72
 73    # You can print out the list of valid words if you need to for debugging
 74    # print("A random word in our list:", choice(list_of_words))
 75    # print("Number of valid words:", len(list_of_words))
 76    
 77    return list_of_words
 78
 79    
 80def generate_hint(guess, solution):
 81    """
 82    Generates a hint from a guess and a solution.
 83
 84    A hint string will be however many letters long the guess
 85    and solution are, where each character represents the "correctness"
 86    of the guess:
 87      1. 🟩 for correct letters
 88      2. 🟨 for partially correct letters
 89      3. ⬜ for incorrect letters
 90
 91    Args:
 92      * guess (`str`): The guess to be evaluated
 93      * solution (`str`): The solution to be compared to
 94
 95    Returns:
 96      * `hint` (`str`): The hint for the user
 97    """
 98
 99    # Loop through each letter of the entry and build a hint for each
100    # letter in our guess by comparing it to our solutions. Then return the hint.
101    hint = ""
102
103    ## TODO: Change this range to account for the fact that the solution / guess
104    ##         could have more or less than 5 letters.
105    for i in range(0, 5, 1):
106        pass ## TODO: remove this pass once you"re working here
107    
108        # TODO: If that letter matches the corresponding one in the solution
109        # then add a 🟩 to our hint (hint = hint + "🟩")
110        # Here"s an example of comparing specific letters
111        #   guess[i] == solution[i]
112
113        # TODO: Else-if that letter is IN that word anywhere,
114        # then add a 🟨 to our hint (use the `in` operator!)
115
116        # TODO: Else, that letter isn"t in our word so add an ⬜ to our hint
117
118    return hint
119
120def finalize_guess(guess, hint):
121    """
122    Finalizes a valid user guess.
123
124    This function does a few things:
125      1. It saves the current guess as a past guess
126      2. It clears out the current guess
127      3. It checks to see if the guess matches the solution
128      4. It checks to see if the user has reached the max number of guesses
129
130    Args:
131      * guess (`str`): The guess to be showed on the screen.
132      * hint (`str`): The evaluated hint so that we can color the blocks correctly.
133
134    Side-Effects:
135      * Appends a guess to GAME_DATA["past_guesses"] and checks to see if the game is over.
136
137    """
138    # Append the inputted guess to the past_guesses list in GAME_DATA
139    GAME_DATA["past_guesses"].append(guess)
140
141    # Clear out the current guess
142    GAME_DATA["current_guess"] = ""
143
144    ## TODO: Change the one line below to account for the fact that a guess might have
145    ##         greater or fewer than 5 letters
146    if hint == "🟩" * 5:
147        game_over(happy=True)
148        
149    elif len(GAME_DATA["past_guesses"]) == 6:
150        game_over()
151
152
153def show_past_guess(past_guess, guess_number, hint):
154    """
155    Shows a past guess on the screen.
156
157    Parameters:
158      * past_guess (`str`): The past guess to be showed (you can assume it"s valid and the correct length)
159      * guess_number (`int`): The number of the guess to be drawn (y-coordinate)
160      * hint (`str`): The hint string that was generated from that guess
161
162    Side-Effect:
163      * Draws to the screen
164    """
165    ## TODO: Change the one line below to account for the fact that a guess might have
166    ##         greater or fewer than 5 letters
167    for i in range(0, 5):
168
169        if hint[i] == "🟩":
170            color_a_grid_square(CORRECT_COLOR, (i, guess_number))
171
172        elif hint[i] == "🟨":
173            color_a_grid_square(PARTIAL_COLOR, (i, guess_number))
174        else:
175            color_a_grid_square(WRONG_COLOR, (i, guess_number))
176
177        draw_letter_in_grid(past_guess[i], (i, guess_number), past_guess=True)
178
179def show_game_board():
180    """
181    Shows the game board.
182
183    Side-Effect:
184      * Draws to the screen
185    """
186    # Clear the screen.
187    delete("all")
188
189    # Resize the window to accommodate for the correct number of characters
190    ## TODO: Change the one line below to account for the fact that a guess might have
191    ##         greater or fewer than 5 letters
192    screen_width = 100 * 5
193    screen_height = 600
194
195    ## TODO: Change the one line below to account for the fact that a guess might have
196    ##         greater or fewer than 5 letters
197    canvas.config(width=100 * 5, height=600)
198
199    # Draw the grid
200    make_grid(screen_width, screen_height)
201
202    # Load in the current guess from our GAME_DATA dictionary
203    current_guess = GAME_DATA["current_guess"]
204
205    # Load in the list of past guesses from our GAME_DATA dictionary
206    past_guesses = GAME_DATA["past_guesses"]
207
208    # Calculate how many guesses there have been by finding the length of the
209    # past_guesses list in our GAME_DATA dictionary
210    guess_count = len(GAME_DATA["past_guesses"])
211
212    # Loop through all of the past guesses
213    for i in range(0, guess_count, 1):
214        show_past_guess(past_guesses[i], i, generate_hint(past_guesses[i], GAME_DATA["solution"]))
215
216    # Now loop through each letter of the current guess and draw it to the board
217    for i in range(0, len(current_guess), 1):
218        color_a_grid_square(DEFAULT_COLOR, (i, guess_count))
219        draw_letter_in_grid(current_guess[i], (i, guess_count))
220
221    # Update the game board
222    canvas.mainloop()
223
224########################## EVENT HANDLERS ##############################
225def handle_typing(event):
226    """
227    Event handler for key presses in Wordle.
228
229    We need to handle 3 specific types of key presses:
230      1. `event.keysym == "BackSpace"`
231      2. `event.keysym == "Return"`
232      3. `len(event.keysym) == 1` (single character keys)
233
234    Args:
235      * `event`: The event to process.
236
237    Side-Effect:
238      * Draws to the screen and updates current_guess inside of GAME_DATA
239    """
240    # If the player hits BackSpace, delete the last character from the
241    # "current_guess" key in the GAME_DATA dictionary
242    if event.keysym == "BackSpace":
243        GAME_DATA["current_guess"] = GAME_DATA["current_guess"][:-1]
244
245    # If the player hits Return...
246    elif event.keysym == "Return":
247        # First check that right num letters have been entered
248        ## TODO: Change the one line below to account for the fact that a guess might have
249        ##         greater or fewer than 5 letters
250        if len(GAME_DATA["current_guess"]) != 5:
251            print("not enough letters")
252            # Next check if it"s a valid word in our word list
253        elif GAME_DATA["current_guess"] not in GAME_DATA["word_list"]:
254            print("not a valid word")
255        # If we make it past those two checks, it"s a valid guess
256        else:
257            # First generate a hint, then finalize the guess
258            hint = generate_hint(GAME_DATA["current_guess"], GAME_DATA["solution"])
259            finalize_guess(GAME_DATA["current_guess"], hint)
260
261    # If the player hits any other letter/number/symbol on the keyboard
262    elif len(event.keysym) == 1:
263        # If the user hasn"t entered the right num letters, add the entered symbol
264        # to the current guess (make sure to convert it to upper case!)
265        ## TODO: Change the one line below to account for the fact that a valid guess might have
266        ##         greater or fewer than 5 letters
267        if len(GAME_DATA["current_guess"]) < 5:
268            GAME_DATA["current_guess"] += event.keysym.upper()
269
270    # As long as the user hasn"t made 6 guesses, show the game board
271    if len(GAME_DATA["past_guesses"]) < 7:
272        show_game_board()
273
274
275########################## GAME SETUP AND PLAY ##!!##########################
def get_difficulty():
31def get_difficulty():
32    """
33    Uses a pop-up window to ask the user to input the desired difficulty (length of words).
34  
35
36    Returns:
37      * `int`: The number of letters (the difficulty) to use for the secret word
38      * or `"invalid"`: the string `"invalid" indicating that the person did not enter a valid number
39    """
40  
41    user_input = simpledialog.askstring(
42        title="Difficulty Level", prompt="What length word should we use?"
43    )
44
45    ## TODO: Use try-except to try and see if user_input is a number
46        ## TODO: If they did, check to see if it"s at least 2 or at most 15.
47            ## TODO: If it is, then return that number
48        ## TODO: In all other cases, return the string "invalid"

Uses a pop-up window to ask the user to input the desired difficulty (length of words).

Returns:

  • int: The number of letters (the difficulty) to use for the secret word
  • or "invalid": the string `"invalid" indicating that the person did not enter a valid number
def read_in_words(file_path, num_letters):
51def read_in_words(file_path, num_letters):
52    """
53    Function that reads in a list of words and adds them to the `GAME_DATA`. Then,
54    picks a random word to set as the "solution" key in the `GAME_DATA` dictionary.
55    
56    Args:
57      * file_path (`str`): The file to be read in
58      * num_letters (`int`): How many letters should be in a word
59
60    Returns:
61      * a `list` continaing the words with the correct number of letters
62    """
63    list_of_words = []
64    
65    ## TODO: Open the file stored in the file_path variable
66    
67    ## TODO: loop through each line of the file
68        ## TODO: Split the line by " " using the split method of the String class
69        ## TODO: If the number of letters in that word matches num_letters
70            ## TODO Append the 0th element of that list into list_of_words
71
72    ## TODO: Close the file!
73
74    # You can print out the list of valid words if you need to for debugging
75    # print("A random word in our list:", choice(list_of_words))
76    # print("Number of valid words:", len(list_of_words))
77    
78    return list_of_words

Function that reads in a list of words and adds them to the GAME_DATA. Then, picks a random word to set as the "solution" key in the GAME_DATA dictionary.

Args:

  • file_path (str): The file to be read in
  • num_letters (int): How many letters should be in a word

Returns:

  • a list continaing the words with the correct number of letters
def generate_hint(guess, solution):
 81def generate_hint(guess, solution):
 82    """
 83    Generates a hint from a guess and a solution.
 84
 85    A hint string will be however many letters long the guess
 86    and solution are, where each character represents the "correctness"
 87    of the guess:
 88      1. 🟩 for correct letters
 89      2. 🟨 for partially correct letters
 90      3. ⬜ for incorrect letters
 91
 92    Args:
 93      * guess (`str`): The guess to be evaluated
 94      * solution (`str`): The solution to be compared to
 95
 96    Returns:
 97      * `hint` (`str`): The hint for the user
 98    """
 99
100    # Loop through each letter of the entry and build a hint for each
101    # letter in our guess by comparing it to our solutions. Then return the hint.
102    hint = ""
103
104    ## TODO: Change this range to account for the fact that the solution / guess
105    ##         could have more or less than 5 letters.
106    for i in range(0, 5, 1):
107        pass ## TODO: remove this pass once you"re working here
108    
109        # TODO: If that letter matches the corresponding one in the solution
110        # then add a 🟩 to our hint (hint = hint + "🟩")
111        # Here"s an example of comparing specific letters
112        #   guess[i] == solution[i]
113
114        # TODO: Else-if that letter is IN that word anywhere,
115        # then add a 🟨 to our hint (use the `in` operator!)
116
117        # TODO: Else, that letter isn"t in our word so add an ⬜ to our hint
118
119    return hint

Generates a hint from a guess and a solution.

A hint string will be however many letters long the guess and solution are, where each character represents the "correctness" of the guess:

  1. 🟩 for correct letters
  2. 🟨 for partially correct letters
  3. ⬜ for incorrect letters

Args:

  • guess (str): The guess to be evaluated
  • solution (str): The solution to be compared to

Returns:

  • hint (str): The hint for the user
def finalize_guess(guess, hint):
121def finalize_guess(guess, hint):
122    """
123    Finalizes a valid user guess.
124
125    This function does a few things:
126      1. It saves the current guess as a past guess
127      2. It clears out the current guess
128      3. It checks to see if the guess matches the solution
129      4. It checks to see if the user has reached the max number of guesses
130
131    Args:
132      * guess (`str`): The guess to be showed on the screen.
133      * hint (`str`): The evaluated hint so that we can color the blocks correctly.
134
135    Side-Effects:
136      * Appends a guess to GAME_DATA["past_guesses"] and checks to see if the game is over.
137
138    """
139    # Append the inputted guess to the past_guesses list in GAME_DATA
140    GAME_DATA["past_guesses"].append(guess)
141
142    # Clear out the current guess
143    GAME_DATA["current_guess"] = ""
144
145    ## TODO: Change the one line below to account for the fact that a guess might have
146    ##         greater or fewer than 5 letters
147    if hint == "🟩" * 5:
148        game_over(happy=True)
149        
150    elif len(GAME_DATA["past_guesses"]) == 6:
151        game_over()

Finalizes a valid user guess.

This function does a few things:

  1. It saves the current guess as a past guess
  2. It clears out the current guess
  3. It checks to see if the guess matches the solution
  4. It checks to see if the user has reached the max number of guesses

Args:

  • guess (str): The guess to be showed on the screen.
  • hint (str): The evaluated hint so that we can color the blocks correctly.

Side-Effects:

  • Appends a guess to GAME_DATA["past_guesses"] and checks to see if the game is over.
def show_past_guess(past_guess, guess_number, hint):
154def show_past_guess(past_guess, guess_number, hint):
155    """
156    Shows a past guess on the screen.
157
158    Parameters:
159      * past_guess (`str`): The past guess to be showed (you can assume it"s valid and the correct length)
160      * guess_number (`int`): The number of the guess to be drawn (y-coordinate)
161      * hint (`str`): The hint string that was generated from that guess
162
163    Side-Effect:
164      * Draws to the screen
165    """
166    ## TODO: Change the one line below to account for the fact that a guess might have
167    ##         greater or fewer than 5 letters
168    for i in range(0, 5):
169
170        if hint[i] == "🟩":
171            color_a_grid_square(CORRECT_COLOR, (i, guess_number))
172
173        elif hint[i] == "🟨":
174            color_a_grid_square(PARTIAL_COLOR, (i, guess_number))
175        else:
176            color_a_grid_square(WRONG_COLOR, (i, guess_number))
177
178        draw_letter_in_grid(past_guess[i], (i, guess_number), past_guess=True)

Shows a past guess on the screen.

Parameters:

  • past_guess (str): The past guess to be showed (you can assume it"s valid and the correct length)
  • guess_number (int): The number of the guess to be drawn (y-coordinate)
  • hint (str): The hint string that was generated from that guess

Side-Effect:

  • Draws to the screen
def show_game_board():
180def show_game_board():
181    """
182    Shows the game board.
183
184    Side-Effect:
185      * Draws to the screen
186    """
187    # Clear the screen.
188    delete("all")
189
190    # Resize the window to accommodate for the correct number of characters
191    ## TODO: Change the one line below to account for the fact that a guess might have
192    ##         greater or fewer than 5 letters
193    screen_width = 100 * 5
194    screen_height = 600
195
196    ## TODO: Change the one line below to account for the fact that a guess might have
197    ##         greater or fewer than 5 letters
198    canvas.config(width=100 * 5, height=600)
199
200    # Draw the grid
201    make_grid(screen_width, screen_height)
202
203    # Load in the current guess from our GAME_DATA dictionary
204    current_guess = GAME_DATA["current_guess"]
205
206    # Load in the list of past guesses from our GAME_DATA dictionary
207    past_guesses = GAME_DATA["past_guesses"]
208
209    # Calculate how many guesses there have been by finding the length of the
210    # past_guesses list in our GAME_DATA dictionary
211    guess_count = len(GAME_DATA["past_guesses"])
212
213    # Loop through all of the past guesses
214    for i in range(0, guess_count, 1):
215        show_past_guess(past_guesses[i], i, generate_hint(past_guesses[i], GAME_DATA["solution"]))
216
217    # Now loop through each letter of the current guess and draw it to the board
218    for i in range(0, len(current_guess), 1):
219        color_a_grid_square(DEFAULT_COLOR, (i, guess_count))
220        draw_letter_in_grid(current_guess[i], (i, guess_count))
221
222    # Update the game board
223    canvas.mainloop()

Shows the game board.

Side-Effect:

  • Draws to the screen
def handle_typing(event):
226def handle_typing(event):
227    """
228    Event handler for key presses in Wordle.
229
230    We need to handle 3 specific types of key presses:
231      1. `event.keysym == "BackSpace"`
232      2. `event.keysym == "Return"`
233      3. `len(event.keysym) == 1` (single character keys)
234
235    Args:
236      * `event`: The event to process.
237
238    Side-Effect:
239      * Draws to the screen and updates current_guess inside of GAME_DATA
240    """
241    # If the player hits BackSpace, delete the last character from the
242    # "current_guess" key in the GAME_DATA dictionary
243    if event.keysym == "BackSpace":
244        GAME_DATA["current_guess"] = GAME_DATA["current_guess"][:-1]
245
246    # If the player hits Return...
247    elif event.keysym == "Return":
248        # First check that right num letters have been entered
249        ## TODO: Change the one line below to account for the fact that a guess might have
250        ##         greater or fewer than 5 letters
251        if len(GAME_DATA["current_guess"]) != 5:
252            print("not enough letters")
253            # Next check if it"s a valid word in our word list
254        elif GAME_DATA["current_guess"] not in GAME_DATA["word_list"]:
255            print("not a valid word")
256        # If we make it past those two checks, it"s a valid guess
257        else:
258            # First generate a hint, then finalize the guess
259            hint = generate_hint(GAME_DATA["current_guess"], GAME_DATA["solution"])
260            finalize_guess(GAME_DATA["current_guess"], hint)
261
262    # If the player hits any other letter/number/symbol on the keyboard
263    elif len(event.keysym) == 1:
264        # If the user hasn"t entered the right num letters, add the entered symbol
265        # to the current guess (make sure to convert it to upper case!)
266        ## TODO: Change the one line below to account for the fact that a valid guess might have
267        ##         greater or fewer than 5 letters
268        if len(GAME_DATA["current_guess"]) < 5:
269            GAME_DATA["current_guess"] += event.keysym.upper()
270
271    # As long as the user hasn"t made 6 guesses, show the game board
272    if len(GAME_DATA["past_guesses"]) < 7:
273        show_game_board()

Event handler for key presses in Wordle.

We need to handle 3 specific types of key presses:

  1. event.keysym == "BackSpace"
  2. event.keysym == "Return"
  3. len(event.keysym) == 1 (single character keys)

Args:

  • event: The event to process.

Side-Effect:

  • Draws to the screen and updates current_guess inside of GAME_DATA