Project #4 – Creating Wordle Step-by-Step
Implement multiple helper functions to recreate the game Wordle.
Your Task
Your task is to implement a simple version of the game Wordle. This document will contain # steps, instructions for functions to build to help us run our Wordle game. All parts should be written in the same python file with the name Project4.py.
Wordle is a type of word guessing game that became popular in 2021. You have 6 chances to guess a 5-letter word, each guess you are given feedback on your guess. If a letter is highlighted green, then that letter is in the word and in the correct spot (index). If a letter is highlighted yellow, then that letter is in the word but it is not in the correct spot. If a letter is not highlighted, then the letter is not in the word in any spot.
There are 7 TODO's that will be described below, I recommend attempting them in the order they are presented. Each TODO might be described in a different way, some will be English sentences, some will be flowcharts to convert, and one is almost done but has a few parts you'll need to fill in. Make sure the name of each function matches exactly as the autograder will be testing each function directly.
I would recommend reading the whole todo list before you start making any programming. Your individual solutions will all be different, but when something is output, it needs to match exactly or the autograder will yell at you.
There will be no autograder for the extra credit parts, so be sure you know it works by testing it yourself before the deadline. You will still be able to submit as many times as you want before the due date, but gradescope will provide no feedback.
Like project 3, here are slides breaking this down: Project 4 Instruction Breakdown
You must include a comment at the top of your program containing your name, “Project #4”, and the date you turn it in.
Save your program as Project4.py. This is the only file that you need to submit to gradescope.
Tasks & Testing
slides: Project 4 Instruction Breakdown
TODO 1 get_word:
This function should pick a word from a list of all lowercase options, and return the picked word. It must be called get_word. It should return the word that gets selected. This is the code we have so far, but there are 4 errors that need to be fixed before it will work correctly.
import random
def getwrd()->str:
all_words = ['above','blame','corny','dress','EMAIL','flail','glass','horse','igloo','judge','kebab','lilac','moose','never','olive','prize','query','react','shrub','toxic','untie','vigor','wordleword','yield','zesty']
my_word = random.choice(all_words)
return 'hello'
Right now our word list is small, but we could grow this by adding more items to the list, importing a very large list from a file, or randomly generating 5 letters.
Running the following code should print out the word 'email':
if __name__ == '__main__':
random.seed(1)
print(get_word())
(Hopefully, but random number generation can be weird. if it's not 'email' it should at least be consistent every time you try to run the program)
You should write any code you are using to test your program inside this weird if statement! Just continue writing the lines indented below the print(get_word()) line!
TODO 2: get_guess()
In this function, we want to get input from the user, make it lower case, and return that value. This function must be called get_guess, accepts no parameters, and returns a string.
We want to make it lowercase to avoid complications later in the file. Note how if our word is 'hello' but the user types 'Hello' a simple == check would return false as 'h' does not equal 'H'.
When using the input function, pass it the string "Your Guess: " so it matches exactly.
HINT: To make a lowercase version of a string, use the .lower() string function [info: https://www.w3schools.com/python/ref_string_lower.asp]
Example of the function running:
Code:
|
Result:
|
#user types 'hello' when prompted
guess = get_guess()
print(guess)
|
Your Guess: hello
hello
|
#user types 'PyThN' when prompted
print(get_guess())
|
Your Guess: PyThN
pythn
|
get_guess('hello')
|
ERROR
|
TODO 3: print_guess
In this function, we want to accept a string as a parameter to the function, and print it out (should return nothing). The print out should be all on a single line, and between each letter there should be two spaces. Your function must be called print_guess and accept one value as the parameter, and return nothing.
Here is an example header to get you started:
def print_guess(value:str)->None:
Example of the function running:
Code:
|
Result:
|
print_guess("hello")
|
h e l l o
|
#user types 'PyThN' when prompted
x = print_guess(get_guess())
print(x)
|
Your Guess: PyThN
p y t h n
None
|
print_guess()
|
ERROR
|
TODO 4: get_diff
For this function you should follow the flowchart provided below. Make sure your function is named get_diff, it should take two values as parameters (the first is the answer word and the second is the guessed word), and should return a list of strings.
The goal of this function is to create a list of five elements. Each element should be a single character either 'r', 'y', or 'g'.
If the first character of the guessed word matches the first character of the answer word, the first element of the list should be 'g'.
If the second character of the guessed word doesn't match the second character of the answer word, but it is somewhere else in the answer word, the second element of the list should be a 'y'.
If the third character of the guessed word is not in the answer word at all, the third element of the list should be a 'r'
Once we finish checking the first character of ans against the first character of guess, we need to increase the index variable i by 1, this needs to be inside the while loop to avoid an infinite loop (note the block i=i+1 is inside the green section.
Code:
|
Result:
|
diff = get_diff("hello", "hello")
print(diff)
|
['g','g','g','g','g']
|
diff = get_diff("pleat", "plate")
print(diff)
|
['g','g','y','y','y']
|
print(get_diff("hello", "rodeo"))
|
['r','y','r','y','g']
|
print(get_diff("corny", "email"))
|
['r','r','r','r','r']
|
TODO 5: print_diff
The function print_diff will accept a list, and print out the correct series of '��' , '��' , '��' emojis, and return nothing. Corresponding to a 'r', 'y', and 'g' in the list. The print out should have a single space between each emoji. Note that to print an emoji in python, it's just like printing any other string: print(" �� ") will print �� to output.
Our code will look somewhat similar to TODO 4's get_diff, and you can use that flowchart as a starting point. One approach to solving this would be to create a blank string named to_print, loop through every element in the given list, and add the appropriate emoji using an if-elif-else branch to the end of to_print. Then once the loop has ended, a simple print(to_print) will have the desired effect.
Code:
|
Result:
|
print_diff(['r', 'g', 'y', 'y', 'r'])
|
�� �� �� �� ��
|
print_diff(get_diff('hello','hellh')
|
�� �� �� �� ��
|
print_diff('yggyg')
|
�� �� �� �� ��
|
TODO 6: play_turn
Create a function called play_turn. The function should accept one parameter, the word that the player is trying to guess. It should return True if the player guessed correctly, and should return false if the player did not guess correctly. You can use the definition of the function below to get started.
The goal of this function is to run a single turn of our wordle game. We should get the guess from the user, print that guess out to them formatted correctly, create the diff list for the guessed word and the correct word, print out that diff list with correct formatting, and finally return True if they guessed exactly correctly, or False otherwise.
Remember you can use the functions you have already created by calling them. We can do this inside our play_turn function. This specific function should be rather small <10 lines of code, if you find yourself writing more than that something has gone wrong.
def play_turn(answer:str)->bool:
Code:
|
Result:
|
play_turn('email')
|
Your Guess: ialme
i a l m e
�� �� �� �� ��
|
x = play_turn("hello")
print(x)
|
Your Guess: heros
h e r o s
�� �� �� �� ��
False
|
print(play_turn("bowie"))
|
Your Guess: bowie
b o w i e
�� �� �� �� ��
True
|
TODO 7: play_game
Create a function called play_game. It should accept no parameters, and should return none (though many things will be printed out during execution). This function will bring all the other functions together in order to play an entire wordle game. It picks a word, and keeps playing turns until the player guesses the word, or runs out of turns.
You can use the following flowchart as a starting point, although there are several missing parts you will have to figure out for yourself, marked by ??? in the diagram. I'd recommend copy and pasting the prints, so they match exactly what the autograder is expecting.
print(f"Out of turns, the word was: {correct_word}")
print(f"\nTURN {turn}:")
print(f"you've won! it took {turn} turns")
IF YOU ARE GETTING AN EOF ERROR: MAKE SURE YOU COMMENT OUT ALL THE TESTING CODE YOU WROTE BEFORE SUBMISSION. YOUR SUBMISSION SHOULD JUST BE THE FUNCTIONS NOT ANYTHING RUNNING THE FUNCTIONS
Testing
slides ( ~slide 19): Project 4 Instruction Breakdown
Test your program completely. Run it several times: verify that any of the extra credits you have implemented are working, and the game plays how you are expecting it to. None of the extra credits will be graded by the autograder, they will all be graded by hand.
YOU MUST COMMENT OUT ANY CODE CALLING YOUR FUNCTIONS, YOUR SUBMISSION SHOULD ONLY BE THE FUNCTION DEFINITIONS/IMPLEMENTATIONS.
I recommend that you test each individual function as you go, including any tests provided here as well as making your own. You should use the provided tests and outputs as an example to build your own. The autograder for this project will be testing all the functions individually, as well as how they work together. Read the descriptions/outputs for each test in gradescope. If you fail one of them they should offer a little guidance on where to start looking to fix the problem.
Code:
|
Result:
|
random.seed(1)
#email should be picked
play_game()
|
TURN 1:
Your Guess: hello
h e l l o
�� �� �� �� ��
TURN 2:
Your Guess: claws
c l a w s
�� �� �� �� ��
TURN 3:
Your Guess: meale
m e a l e
�� �� �� �� ��
TURN 4:
Your Guess: email
e m a i l
�� �� �� �� ��
you've won! it took 4 turns
|
Extra Credit
slides (at end): Project 4 Instruction Breakdown
There are five places in this project where extra credit can be gained. You may do any, all, or none of these. You will not be penalized, but you won’t get any extra credit, if you attempt an extra credit and it doesn’t work correctly. I recommend at least attempting the extra credit, as some parts will be straightforward, and finishing them will lead to a better completed game in the end.
Extra Credit #1
Currently the player is allowed to type in incorrect inputs and potentially crash our program. For this extra credit we will make a new function called get_guess_extra() to tell the user they tried to type in an invalid guess, and allow them to try again until a correct guess is given. For now, incorrect guesses are any guesses that aren't exactly 5 characters, and that contain non-alphabetic characters. Use the following flowchart to modify your original code for get_guess. Note: .isalpha() is a function that can be called on a string and will return True if the string is only alphabetic characters. "hello".isalpha() produces True, '7 hel ) o'.isalpha() produces False.
Extra Credit #2
Currently, the player always has 6 turns to guess the word. We could make a copy of play_game() called play_game_extra2() that accepts a single parameter, the number of turns, that would allow us to make the game easier or harder. We would also have to change the if statement that checks to see if the player just used their last turn. The last thing to change would be to set the number 6 as the default value for the new parameter. If you have having trouble setting a default argument value this article should help:
https://www.geeksforgeeks.org/default-arguments-in-python/
Extra Credit #3
Currently whether the player wins or loses the game simply ends. We could modify the code we use to start a game (ie the line play_game()) so that a new game is played immediately after the last game ends. I recommend writing a new function called play_infinite_game()
HINT: The simplest solution would be to use an infinite loop somehow to call the play_game function until the user kills the process.
Extra Credit #4 (Requires #3)
Currently no score is kept keeping track of how many games the player has played/won. Once Extra Credit 3 is completed, we could make another (play_infinite_game4()) to keep track of two variables, games_played, and games_won, and print out those values after a game ends and before the next game begins. To do this, it might make sense to modify what the play_game function returns. Currently it returns None no matter what, we could have it return 1 if the player wins and return 0 if the player loses.
Extra Credit #5
Currently only one person can play a game. We could create a new play_game_2_player function that allows for two players to play the game. This function will look largely similar to play_game, with the only difference being how the word to guess is picked. Instead of picking a word from a list, we will allow a user to type in the word that the other player will attempt to guess. We should ensure that the word the player types in is a valid word before continuing on with the function. The word must be 5 characters long, and contain only alphabetic characters (see extra credit #1).
Submission
When you are done, turn in the assignment via Gradescope, you should submit only your .py file. It must be called Project4.py exactly. You can submit to gradescope as many times as you want before the due date.
IF YOU ARE GETTING AN EOF ERROR: MAKE SURE YOU COMMENT OUT ALL THE TESTING CODE YOU WROTE BEFORE SUBMISSION.
SO A LINE LIKE: play_game() needs to be commented out
Again, make sure you read the results from all the tests if gradescope is showing you some of the tests failed.
Grading
In the report of your grade, you will see a score and a set of letter codes explaining what you did wrong. If you get 10 points, there will be no associated letter codes.
The grading codes A-G are defined and will be the same for all programs that you turn in. A summary of those codes is as follows (see the linked document for a full explanation):
A: -10 Student’s name is missing from the top of the program.
B: -100 Program cannot run due to syntax errors.
C: -100 Program crashes before finishing.
D: -100 Program runs to completion but does not solve the intended problem.
E: -50 Program runs to completion but does not solve all of the assigned problems.
F: -50 Program uses overly advanced methods not covered in class
G: -50 Program works correctly, but majorly changes the assignment in order to do it.
In addition, penalties for this assignment only will be incurred for the following infractions (which may supersede some of the generic codes listed above):
H: -10 Solution deviates too far from the described solution
J: -10 Required code is omitted (like omitting a Print statement, for example, either in part or in its entirety).
K: -10 Starter code has been changed in such a way that makes the program less functional in some way
L: -10 Python shortcuts and/or advanced code is used that makes other parts of the starter code redundant. This supersedes code F above.
Each of the three extra credit items are worth +3.33 points added to the score only if implemented correctly. Incorrect implementation will not be penalized.