CS303E Project 3

Instructor: Dr. Bill Young
Due Date: Monday, May 2, 2022 at 11:59pm

WORDLE

From Wikipedia:
Wordle is a web-based word game created and developed by Welsh software engineer Josh Wardle, and owned and published by The New York Times Company since 2022. Players have six attempts to guess a five-letter word, with feedback given for each guess in the form of colored tiles indicating when letters match or occupy the correct position.

Wardle initially created the game for himself and his partner to play, eventually making it public in October 2021. The game gained a large amount of popularity in December 2021 after Wardle added the ability for players to copy their daily results as emoji squares, which were widely shared on Twitter. Many clones and variations of the game were also created, as were versions in languages besides English. The game was purchased by The New York Times Company in January 2022 for an undisclosed seven-figure sum, with plans to keep it free for all players; it was moved to their website in February 2022.

Assignment:

Your assignment is to implement a version of Wordle. The answer will be a 5-letter word that is selected randomly from a wordlist. We also include the ability for the user to specify the word; this makes it easier to debug your code. To simplify the implementation, we guarantee that no letter repeats in the answer.

Just as in the official game, the user will have 6 attempts to guess the answer and will be provided feedback on each guess. Letters in the guess will be marked (below) as follows:

   x means that the letter does not appear in the answer
   ^ means that the letter is correct and in the correct location
   + means that the letter is correct, but in the wrong location
Below is an example of how part of this looks. There are also more sample output below. The word selected by the system was "dingy".
Enter your guess (1): ringo
Guess must be a 5-letter word in the wordlist. Try again!
Enter your guess (1): fling
F  L  I  N  G  
x  x  +  +  +  
Enter your guess (2): ingot
I  N  G  O  T  
+  +  +  x  x  
Enter your guess (3): dingo
D  I  N  G  O  
^  ^  ^  ^  x  
Enter your guess (4): dingx
Guess must be a 5-letter word in the wordlist. Try again!
Enter your guess (4): dingy
D  I  N  G  Y  
^  ^  ^  ^  ^  
CONGRATULATIONS! You win!

>
By the way, no one would be that lucky; I knew in advance what word was chosen.

Notice that, for readability, we printed the guess in uppercase letters separated by spaces.

Your implementation must perform the following steps:

  1. Create the wordlist: If you did HW11 successfully, you've already done this step. The function you used to create the wordlist from HW11 is exactly what you'll need. So just use that same code. If you didn't already, make a separate boolean-valued function for the filtering criterion. See the programming tips below. An added wrinkle is that you need to accept the name of the file from the user. If an unknown filename is entered, say so and ask again. BTW: the function you wrote for HW11 returned the wordlist and length of the wordlist (the count). For this assignment, you don't use the count.

    If you didn't do HW11, here's what you need to do. File words file contains a very long sorted series of lowercase English words, one per line. You should copy/download this file to your own computer. (If you're on a Windows system, it may not allow you to create the file without a .txt extension. That's fine. When you run your program, you'll input your filename when asked; when the TAs run your program, they'll put in whatever name they're using.) Complete the following function, which reads words from the file, filters them, returns a list of words that pass the filter. Filtering means the following: discard any words that are not five letters long, any words that don't have 5 distinct letters, or that end in 's'. Your resulting list will be sorted if you add words to the end of the list. You can assume that there are no non-letters or upper case characters in any of the words. You should strip each word of extra whitespace. Finally, return a pair consisting of the wordlist and its length.

    def createWordlist(filename): 
        """ Read words from the provided file and store them in a list.
        The file contains only lowercase ascii characters, are sorted
        alphabetically, one word per line. Filter out any words that are
        not 5 letters long, have duplicate letters, or end in 's'. Return
        the list of words and the number of words as a pair. """
        ...
    
    
  2. Check if a word is on the wordlist: Write a function to determine whether or not a specific word is on the wordlist produced in the previous step. You must use the Binary Search function provided in slideset 10. There is no reason to write your own; that function will work as is. Just copy it to your file.

  3. Welcome message: Print an initial welcome message, shown below in the expected output.

  4. Get filename: Prompt the user for the name of the file containing the words that you will filter to create your wordlist. If any incorrect filename is supplied, prompt the user to try again. See the sample below.

  5. Select answer: Choose an answer word. This can either be specified in your main call or chosen randomly from the wordlist. Having the ability to specify an answer is useful for debugging. If the answer is specified in the main call, but is not on the wordlist, print an error and exit. Use the error message "Answer supplied is not legal." Use random.choice() to choose a random answer from the wordlist.

  6. Accept and parse guesses from the user: Loop to accept guesses from the user, compare them to the answer, and mark each letter in the guess appropriately. See the examples below. (You can use .lower() to force the user's guess to lowercase; if you don't do that and it has uppercase letters, it won't be on the wordlist.) If a user's guess is not on the wordlist, print an error message. Number each guess as shown.

  7. End the game: The game can end in either of two ways: the user guesses the word or uses all 6 guesses without guessing the word. Print an appropriate message in either case. Examples are shown below.
If helpful, in this assignment you can convert a string to a list or set of characters.

Do this project incrementally. Get steps 1 and 2 written and debugged before you move on the later steps.

BTW: in HW11, you wrote several functions related to Wordle. The only one you'll likely use in this assignment is createWordlist.

Expected Output:

Below is some sample output for this program. You should match this exactly for the given inputs.

For this first run, I set the word to "frank" by calling my main function playWordle( "frank" ) at the bottom of my Project3.py file.

> python Project3.py

Welcome to WORDLE, the popular word game. The goal is to guess a
five letter word chosen at random from our wordlist. None of the
words on the wordlist have any duplicate letters.

You will be allowed 6 guesses. Guesses must be from the allowed
wordlist. We'll tell you if they're not.

Each letter in your guess will be marked as follows:

   x means that the letter does not appear in the answer
   ^ means that the letter is correct and in the correct location
   + means that the letter is correct, but in the wrong location

Good luck!

Enter the name of the file from which to extract the wordlist: old-wordlist
File does not exist. Try again!
Enter the name of the file from which to extract the wordlist: new-wordlist

Enter your guess (1): beach
B  E  A  C  H  
x  x  ^  x  x  
Enter your guess (2): funky
F  U  N  K  Y  
^  x  +  +  x  
Enter your guess (3): farkl
Guess must be a 5-letter word in the wordlist. Try again!
Enter your guess (3): flank
F  L  A  N  K  
^  x  ^  ^  ^  
Enter your guess (4): frank
F  R  A  N  K  
^  ^  ^  ^  ^  
CONGRATULATIONS! You win!
For the next one I allowed the system to select the word by calling playWordle( ).
> python Project3.py

Welcome to WORDLE, the popular word game. The goal is to guess a
five letter word chosen at random from our wordlist. None of the
words on the wordlist have any duplicate letters.

You will be allowed 6 guesses. Guesses must be from the allowed
wordlist. We'll tell you if they're not.

Each letter in your guess will be marked as follows:

   x means that the letter does not appear in the answer
   ^ means that the letter is correct and in the correct location
   + means that the letter is correct, but in the wrong location

Good luck!

Enter the name of the file from which to extract the wordlist: new-wordlist

Enter your guess (1): beach
B  E  A  C  H  
x  x  +  +  x  
Enter your guess (2): craby
Guess must be a 5-letter word in the wordlist. Try again!
Enter your guess (2): carby
Guess must be a 5-letter word in the wordlist. Try again!
Enter your guess (2): cheap
C  H  E  A  P  
+  x  x  +  x  
Enter your guess (3): sleep
Guess must be a 5-letter word in the wordlist. Try again!
Enter your guess (3): cramp
C  R  A  M  P  
+  x  +  x  x  
Enter your guess (4): chump
C  H  U  M  P  
+  x  x  x  x  
Enter your guess (5): batch
B  A  T  C  H  
x  ^  +  +  x  
Enter your guess (6): frank
F  R  A  N  K  
x  x  +  x  +  
Sorry! The word was tacky. Better luck next time!

>
For this last sample, I specified a word "level" which is not legal (because of the repeated letter). But to see that we had to first generate the wordlist.
> python wordle.py

Welcome to WORDLE, the popular word game. The goal is to guess a
five letter word chosen at random from our wordlist. None of the
words on the wordlist have any duplicate letters.

You will be allowed 6 guesses. Guesses must be from the allowed
wordlist. We'll tell you if they're not.

Each letter in your guess will be marked as follows:

   x means that the letter does not appear in the answer
   ^ means that the letter is correct and in the correct location
   + means that the letter is correct, but in the wrong location

Good luck!

Enter the name of the file from which to extract the wordlist: new-wordlist

Answer supplied is not legal.

>
To play the game, make a call to your main function playWordle( answer ) You can either do this at the bottom of your Project3.py file or by running things interactively. The answer parameter allows the implementer to specify a value. This is very useful in debugging; have answer default to a value that could not be a legal answer, like None. If answer is that special value, then choose an answer randomly from the wordlist.

Programming Tips:

Write a filter function. The notion of filtering a long list of words is something you might want to do again at some point. Rather than build the filtering criteria into your createWordlist function, it would be much more modular to write a separate boolean-valued function wordOK( word ) that is the filtering criterion (e.g. word has 5 distinct letters and the last letter isn't 's'). That way, if you want to change the criterion, you only need to change this function, not root around in the code that's processing the file. BTW: the body of the filtering function for this assignment can be written in one line. If you're doing a bunch of looping, you're not doing it efficiently.

Your main function need not be called main. Calling your primary function main is just a convention. In some programming languages, such as C, you must have a function called main because that's how the system knows where to begin executing. This is called the entry point for the program. In C, you don't need an explicit call to main; the system generates one automatically. In Python, there isn't a default entry point. If you want to start executing by calling main you have to have an explicit call main(). But since you're telling the system where to begin executing, you can call any function you like. For this project, I called my "main" function playWordle. And just like any other function, you can have default parameters:

   def playWordle( answer = None ):
      ...
That way I can specify a choice of answer, which is helpful for debugging. If I don't specify, it defaults to None and my internal logic tells the system to choose randomly from the wordlist if answer == None.

Games: Games provide a great domain in which to hone your programming skill. Video games are a bigger business than movies and music combined. Computers now routinely beat the world (human) champions in games such as Chess and Go. Games have well defined rules, so provide a nice programming domain. When I taught CS313E, the successor to CS303E, one of my favorites assignments was to program a solver for the daily Jumble puzzle in the newspaper. My program can solve every Jumble in microseconds. Dr. Mitra adopted that project, so you just might see it next semester.

Turning in the Assignment:

The program should be in a file named Project3.py. Submit the file via Canvas before the deadline shown at the top of this page. Submit it to the assignment project3 under the assignments sections by uploading your python file.

Your file must compile and run before submission. It must also contain a header with the following format:

# File: Project3.py
# Student: 
# UT EID:
# Course Name: CS303E
# 
# Date:
# Description of Program: 

As usual, if you submit multiple times, Canvas will rename your file by adding a number to the end. That's fine; we'll grade the latest one.