Project 1: Wordle

Due: Monday, 30 September, 11:59 PM

Github Classroom Link: https://classroom.github.com/a/bYEAZCDY

Prof. Jed Rembold's alternate instructions


A. Starting Template [Show]

A. Starting Template [Hide]

This project is composed of 5 milestones, each roughly equivalent to a problem or part of a problem on a problem set. Distinct from problem sets, each of the problems works together to create one, single, more expansive assignment. Before getting the milestones, there are a few introductory remarks.

Additionally, this project will involve working with a "library" not unlike karel.py called WordleGraphics.py. This project specification will specify how to interact with this file.

There is an Web Demo. It seems a bit buggy to me in Firefox but should give an idea of the finished project.


Files:

  • Update (only) this file:
    • Wordle.py
  • You will also need:
    • pgl.py
    • WordleGraphics.py
    • english.py

The template file "Wordle.py" is initially as follows:


from WordleGraphics import *  # WordleGWindow, N_ROWS, ...
from english import * # ENGLISH_WORDS, is_english_word
import random

def wordle():
    # The main function to play the Wordle game.

    def enter_action():
        # What should happen when RETURN/ENTER is pressed.
        gw.show_message("You need to implement this method")


    gw = WordleGWindow()
    gw.add_enter_listener(enter_action)




# Startup boilerplate
if __name__ == "__main__":
    wordle()

You should be able to run Wordle.py as soon as you download the code. It will create a window, not unlikely Karel, with letter boxes and a keyboard. You can test out typing via keyboard or the onscreen keys, such as by typing RATES.


B. What is Wordle [Show]

B. What is Wordle [Hide]

Wordle is a word guessing game with six guesses. Type in a word (that must in the list of words provided), hit RETURN/ENTER, and the game gives you information about how close your guess is by coloring the background of the letters.

  • If the guessed letter and answer letter are the same, colors the letter green (CORRECT_COLOR).
  • If the guessed letter is in the answer, colors the letter yellow (PRESENT_COLOR)
  • If the guessed letter is not in the answer, colored the letter gray (MISSING_COLOR)

For example, suppose the answer is RELIC and the guess is RATES. The R is in the correct position, and the word contains an E, but not in the position guessed. The hidden word does not contain the letters T, A, and S. Wordle reports that information by changing the background color of the squares like this:

Repeated letters are special, and constitute the core learning objective of this project. Suppose, for example, that the answer is GLASS and the guess is SASSY:

The green S shows that there is an S in the fourth position, and the yellow S shows that a second S appears somewhere else in the hidden word. The S in the middle of SASSY, however, remains gray because the hidden word does not contain three instances of the letter S.


C. What is WordleGraphics.py [Show]

C. What is WordleGraphics.py [Hide]

Do not make any changes to WordleGraphics.py

The template file Wordle.py includes the following line:


gw = WordleGWindow()

In general, all tasks related to showing/displaying involve using the following commands related the provided gw variable.

Function Description
gw.set_square_letter(row, col, letter) Sets the letter in the specified row and column
gw.get_square_letter(row, col) Returns the letter in the specified row and column
gw.add_enter_listener(func) Specifies the function to be run when the ENTER key is pressed
gw.show_message(msg) Shows a message below the squares
gw.set_square_color(row, col, color) Sets the color of the specified square
gw.set_current_row(row_idx) Sets the row index in which typed characters appear
gw.get_current_row() Returns the current row index
gw.set_key_color(letter, color) Sets the color of the specified key letter
gw.get_key_color(letter) Returns the color of the specified key letter

0. Display a Word [Show]

0. Display a Word [Hide]

Milestone 0: Best By Tuesday

This is a familiarization task and will not be part of the final product.

Choose a word and display it within the WordleGWindow named gw. You will need to use gw.set_square_letter. You may choose whichever word you like - for example, I will use "AEGIS" because that is my first guess everyday, but you could just as easily use "RATES" or "HELLO" or "ALIEN".

Once you have displayed your word of choice, begin Milestone 1. You are highly encouraged to submit your code at each milestone on Github classroom.

Some Notes Though you have no obligation to do so, I wrote functions

  • word_to_row(word:str, row:int), and
  • word_from_row(row:int) -> str
while working on this milestone that served me well throughout the project.

D. Hint: Functions in wordle() [Show]

D. Hint: Functions in wordle() [Hide]

Like enter_action, I wrote these functions inside the wordle function - they are underneath the def wordle(): line and indented to one level, just like def enter_action():. This allows them to refer to gw, a variable that is named within wordle but not outside of it:


def wordle():
        # The main function to play the Wordle game.

        def enter_action():
            # What should happen when RETURN/ENTER is pressed.
            gw.show_message("To do: enter_action")
            
        def word_to_row(word:str, row:int):
            gw.show_message("To do: word_to_row")
            
        def word_from_row(row:int) -> str:
            gw.show_message("To do: row_to_word")
            return "" # placeholder

E. Hint: Capitalization [Show]

E. Hint: Capitalization [Hide]

Be advised, words from ENGLISH_WORDS are all (ironically) lower-case and all displayed letters in Wordle are capitalized (upper-case). You don't need to work with ENGLISH_WORDS yet but I recommend doing something like the following:


# to see if a word is in ENGLISH_WORDS, make it lower case.
guess_str = "Hello"
guess_low = guess_str.lower()
guess_cap = guess_str.upper()
print(guess_str, guess_str in ENGLISH_WORDS) # Hello False
print(guess_low, guess_low in ENGLISH_WORDS) # hello True
print(guess_cap, guess_cap in ENGLISH_WORDS) # HELLO False

# places 'H' in the upper left
gw.set_square_letter(0,0,guess_cap[0])

While it differs from typical Python variable name conventions, it could be helpful to use variable names like:


Guess = "Hello"
guess = Guess.lower()
GUESS = Guess.upper()

1. Check Guess Validity [Show]

1. Check Guess Validity [Hide]

Milestone 1: Best By Wednesday

This task writes the first part of the enter_action function.

The provided "Wordle.py" allows typing in a guess but does nothing when ENTER is pressed. For this milestone, we will add code to the enter_action function such that:

  • If the entered word is in ENGLISH_WORDS, then:
    • gw.show_message(affirmation) # affirmation of your choice
  • else:
    • gw.show_message("Not in word list")

Once your "Wordle.py" can assess guessed words in this manner, begin Milestone 2. You are highly encouraged to submit your code at each milestone on Github classroom.


2. Color Letters [Show]

2. Color Letters [Hide]

Milestone 2: Best By Thursday

This task writes the next part of the enter_action function.

This is the core problem-solving part of this assignment, in that it involves thinking about and writing down a solution to particular, challenging problem: determining what color to assign to each letter.

As a recommended strategy, you could

  • Find and color the correct (green) letters first
    • Avoid coloring a letter yellow if it is in the correct position.
    • Track if there's double letters - maintain a string of remaining letters, perhaps.
  • Find and color the present (yellow) letters next.
    • Track if there's double letters - maintain a string of remaining letters, perhaps.
  • Color remaining letters gray.
  • Test your code rigorously:
    • Use the guess = "Sassy" and answer = "Glass" example.

Personally, I wrote a function color_row(row:int, answer:str) that, given a row and an answer, colors the letters in that row approriately.

Once "Wordle.py" may color a guess based on some provided answer, begin Milestone 3. You are highly encouraged to submit your code at each milestone on Github classroom.

Some Notes The following would place an "H" in the upper left and color the "H" green, as if the guess was "Hello" and the answer was "Hasty".


answr_str = "Hasty" # you set this "manually" in Wordle.py
guess_str = "Hello" # ideally get this via "word_from_row"
guess_cap = guess_str.upper()
gw.set_square_letter(0,0,guess_cap[0])
gw.set_square_color(0,0,CORRECT_COLOR)

We provide the following colors, that you may use due to the from WordleGraphics import * line in Wordle.py including them, much like using move() after import karel.

Color Description
CORRECT_COLOR A shade of green
PRESENT_COLOR A shade of brownish yellow
MISSING_COLOR A shade of gray
UNKNOWN_COLOR Initial white color

3. Random Word [Show]

3. Random Word [Hide]

Milestone 3: Best By Friday

This tasks implements answer word selection

For this task, we introduce some useful functions provided by import random.

For this task:

  • Generate a random 5-letter word.
    • Use something from import random - examples below.
  • Hold this word in a variable, such as answr_str or whatever worked for you.
  • Evaluate a guess against this answer.
  • Test your code more than once to ensure the word changes.
    • You may wish to share the answer via a gw.show_message() while you are testing.

Personally, I wrote a new function, random_five_letter_word() -> str.

Once "Wordle.py" may color a guess based on a random answer, begin Milestone 4. You are highly encouraged to submit your code at each milestone on Github classroom.

Some Notes The following takes ENGLISH_WORDS, which is alphabetical order, and causes it to be in a random order from then on. It could, for example, be part of random_five_letter_word.


random.shuffle(ENGLISH_WORDS) # de-alphabetizes
for word in ENGLISH_WORDS:
    print(word) # prints words in a random order

4. Change Rows [Show]

4. Change Rows [Hide]

Milestone 4: Best By Saturday

This tasks implements game progress.

For this task:

  • After a guess, move to the next row.
    • Use gw.set_current_row(row_idx) and gw.get_current_row().
  • If the guess is equal to the answer:
    • Say something nice via gw.show_message()
    • Stop reading new guess via gw.set_current_row(N_ROWS).
      • N_ROWS is included via from WordleGraphics import *
  • If the current row number is equal to N_ROWS without a successful guess...
    • Share the answer via a gw.show_message().

Once "Wordle.py" may color a guess based on a random answer, begin Milestone 5. You are highly encouraged to submit your code at each milestone on Github classroom.


5. Color Keys [Show]

5. Color Keys [Hide]

Milestone 5: Best By Sunday

This tasks implements a nicety.

For this task, when evaluating a guess:

  • If a letter is in the correct position:
    • Use gw.set_key_color to color the corresponding key to CORRECT_COLOR
  • If a letter is present:
    • If the letter has not yet been guessed in the correct position:
      • Use gw.set_key_color to color the corresponding key to PRESENT_COLOR
  • If a letter is not present:
    • Use gw.set_key_color to color the corresponding key to MISSING_COLOR

Once you have completed Milestone 5, submit your code via Github classroom. You will probably want to test a bit more, and also consider doing extensions, which are outline by Prof. Jed Rembold here