This assignment tests your understanding of and ability to apply the programming concepts we have covered throughout the unit. The concepts covered in the second half of the unit build upon the fundamentals covered in the first half of the unit.
You are required to design and implement two related programs:
The following pages describe the requirements of both programs in detail.
Starter files for both of these programs are provided along with this assignment brief, to help you get started and to facilitate an appropriate program structure. Please use the starter files.
As emphasised by the case study of Module 5, it is important to take the time to properly design a solution before starting to write code. Hence, this assignment requires you to write and submit pseudocode of your program design for "word_find.py", but not log_viewer.py (pseudocode is not very well suited to illustrating the design of an event-driven GUI program). Furthermore, while your tutors are happy to provide help and feedback on your work throughout the semester, they will expect you to be able to show your pseudocode and explain the design of your code.
You will gain a lot more benefit from pseudocode if you actually attempt it before trying to code your program - even if you just start with a rough draft to establish the overall program structure, and then revise and refine it as you work on the code. This back and forth cycle of designing and coding is completely normal and expected, particularly when you are new to programming. The requirements detailed on the following pages should give you a good idea of the structure of the program, allowing you to make a start on designing your solution in pseudocode.
See Reading 3.3 and the discussion board for further advice and tips regarding writing pseudocode.
Write a separate section of pseudocode for each function you define in your program so that the pseudocode for the main part of your program is not cluttered with function definitions. Ensure that the pseudocode for each of your functions clearly describes the parameters that the function receives and what the function returns back to the program. Pseudocode for functions should be presented after the pseudocode for the main part of your program.
It may help to think of the pseudocode of your program as the content of a book, and the pseudocode of functions as its appendices: It should be possible to read and understand a book without necessarily reading the appendices, however they are there for further reference if needed.
Three functions are required in "word_find.py" (detailed later in the assignment brief).
The following pages describe the requirements of both programs in detail.
"word_find.py" is a program with a Command-Line Interface (CLI) like that of the programs we have created throughout the first half of the unit. The program can be implemented in under 160 lines of code (although implementing optional additions may result in a longer program). This number is not a limit or a goal - it is simply provided to prompt you to ask your tutor for advice if your program significantly exceeds it. Everything you need to know in order to develop this program is covered in the first 7 modules. This program should be developed before log_viewer.py.
The program is a single-player word game, where the user enters as many words as they are able to think of using a selection of 9 letters.
The program first selects 9 letters of the alphabet at random. The same letter can appear multiple times, and the selection process uses the frequency of letters in the game of Scrabble when choosing letters, so that the 9 letters chosen are more likely to contain letters that are common in English words, e.g. the letters are much more likely to contain "E", I or A than Z, Q or X.
The program displays the 9 letters in a 3x3 grid and prompts the user for input: see image.
When prompted for input, the user has the following options (these should not be case-sensitive):
1. Enter a word, e.g. "TRAY" would be a valid word given the letters pictured above.
2. Enter "S" to randomly re-order the letters.
3. Enter "L" to display a list of the words that they have already entered during this game.
4. Enter "E" to end the game.
The program shows the grid of letters and prompts the user for input until they enter "E" to end the game. This allows them to keep entering words, shuffling the letters and viewing the list of words until they cannot think of any more words to enter, and choose to end the game.
Whenever the user enters a word, the program needs to check that:
1. The word has a minimum length of 3 characters.
2. The word has not already been used in this game.
3. The word is made up of the letters selected in this game.
4. The word is a recognised English word.
If the word is not valid, the program displays a message telling the user which piece of criteria was not met, and returns to the input prompt. If the word is valid, the user is awarded points using the letter values in the game of Scrabble, where less common letters are awarded more points, e.g. see image.
The program will use an online service provided by "Wordnik" to check if the word is a valid English word and to calculate the amount of points that it is worth. There will be a post on the Blackboard discussion board detailing this process, since it is not covered in the unit.
Once the user enters "E" to end the game, the program should show their final score.
If their score is at least 50, the program should congratulate the user and record a "log" of the game in a text file named logs.txt. Use the json module to read and write data from/to the text file in JSON format (see Reading 7.1). Each log of a game should be a dictionary consisting of three keys:
The logs should be stored in a list, resulting in the file containing a list of dictionaries. The example below demonstrates a list of two logs (the word list has been truncated to fit onto the page):
[
{
"letters": ["A", "A", "B", "D", "F", "I", "L", "O", "R"],
"words": ["AFRAID", "BALD", "BOAR", "BOLD", "DAB", "FAB", "FAIL", "FAR", ...],
"score": 102
},
{
"letters": ["B", "D", "I", "J", "L", "N", "O", "O", "S"],
"words": ["BIN", "BINS", "BOLD", "BOLDS", "DIN", "DINS", "JOB", "JOIN", ...],
"score": 76
}
]
The program should then show their final score, print "Thank you for playing!", and end.
To help you visualise the program/game, here is an annotated screenshot of it being played: see image.
In the following information, numbered points describe a requirement of the program, and bullet points (in italics) are additional details, notes and hints regarding the requirement. Ask your tutor if you do not understand the requirements or would like further information. The requirements are:
1. The first things the program should do welcome the user, and then create some variables that will be needed in the game. The following variables are needed:
2. The program should then enter a loop that will repeat until the user chooses to end the game. The body of this loop must:
2.1. Print the user's score and "Your letters are:", display the letters in a 3x3 grid, and then get input from the user with the following prompt:
"Enter a word, [s]huffle letters, [l]ist words, or [e]nd game): "
2.2. Start an "if/elif/else" statement to respond appropriately to the user's input. If the user enters E, print Ending game and end the loop (from Requirement 2).
2.3. Otherwise, if the user enters "S", print Shuffling letters and randomly re-order the letters list. This will re-position the letters in the 3x3 grid the next time it is displayed.
2.4. Otherwise, if the user enters "L", check if the used_words list is empty. If so, print an appropriate message. Otherwise, sort the list alphabetically and then print all of the words.
2.5. Otherwise, if the user's input is less than 3 characters long, print an appropriate message.
2.6. Otherwise, if the user's input is in the used_words list, print an appropriate message.
2.7. Otherwise, if the user's input is not valid, print an appropriate message.
2.8. Otherwise (this is the final "else" part of the if/elif/else statement), check if the user's input is a recognised English word and obtain its Scrabble score. This will be done by sending a request to an online service named Wordnik. If the word is recognised, print a word accepted message that tells the user how many points it is worth, and add the points to their score, and append the word to the used_words list.
If the word is not recognised, print an appropriate message.
3. Once the user ends the game, print their final score. If their score is 50 or more, congratulate them and record a log of the game as detailed on Page 4 of this assignment brief. This will involve first opening a text file in read mode to read existing log data, appending a log of the game to the data, and then writing the entire data to the file.
4. Finally, print "Thank you for playing!"
The program requirements above mentioned 3 user-defined functions - "select_letters()" (Requirement 1), display_letters() (Requirement 2.1), and validate_word() (Requirement 2.7). As part of word_find.py, you must define and use these functions.
1. The "select_letters()" function does not take any parameters. The function randomly selects 9 letters and returns them as a list of 9 strings. The same letter can appear multiple times, and the selection process uses the frequency of letters in Scrabble when choosing letters.
2. The "display_letters()" function takes one parameter named letters (the list of 9 letters selected at the start of the game). The function should print the letters in a 3x3 grid, as shown on Page 3 of this assignment brief. The function should not return anything.
3. The "validate_word()" function takes two parameters named word (the word that the user entered) and letters (the list of 9 letters selected at the start of the game). The function should check that the word is made up entirely of letters in the letters list. A letter cannot be used more times than it appears in the letters list. If the word is valid, the function should return True. If it is not valid, the function should return False.
The definitions of these functions should be at the start of the program (as they are in the starter file provided), and it should be called where needed in the program. Revise Module 4 if you are uncertain about defining and using functions, and be sure to implement them so that they receive and return values exactly as described above.
Ensure that the functions do exactly what is specified above and nothing more - it is important to adhere to the stated specifications of a function when working on a programming project.
You are welcome to write additional functions if you feel they improve your program, but be sure to consider the characteristics and ideals of functions as outlined in Lecture 4.
"log_viewer.py" is a program with a Graphical User Interface (GUI), as covered in Module 9. It should be coded in an Object Oriented style, as covered in Module 8. Everything you need to know in order to develop this program is covered in the first 9 modules of the unit. This program should be developed after word_find.py.
The entirety of this program can be implemented in under 125 lines of code (although implementing optional additions may result in a longer program). This number is not a limit or a goal - it is simply provided to prompt you to ask your tutor for advice if your program significantly exceeds it. You must use the "tkinter" module to create the GUI, and you will also need to use the tkinter.messagebox and json modules.
This program uses the data from the "logs.txt" file. The program should load all of the data from the file once only - when the program begins. The program simply allows the user to view the logs created by word_find.py. see image.
The only way that the user can interact with the program is by pressing the "Previous" and Next buttons, which change the log data that is currently displayed. If they click Previous when on the first log or Next when on the final log, a messagebox should appear, alerting them of the issue: see image.
The following pages detail how to implement the program.
The constructor (the "__init__" method) of your GUI class must implement the following:
1. Create the main window of the program and give it a title of "Word Find Log Viewer".
2. Try to open the "logs.txt" file in read mode and load the JSON data from the file into an attribute named self.logs, and then close the file.
3. Create a "self.current_log" attribute to keep track of which log is currently being displayed in the GUI, and set it to 0.
4. Use Frame, Label and Button and widgets from the "tkinter" module to implement the GUI depicted on the previous page.
5. Lastly, the constructor should end by calling the "show_log()" method to display a the first log in the GUI, and then call tkinter.mainloop() to start the main loop.
That is all that the constructor requires. The following pages detail the methods mentioned above, and some optional additions and enhancements. You are not required to submit pseudocode for your design of "log_viewer.py", as pseudocode is not particularly well suited to illustrating the design of an event-driven GUI program.
Your GUI class requires three methods to implement the functionality of the program - "show_log()", previous_log() and next_log(). As part of the GUI class of log_viewer.py, you must define and use these methods.
1. The "show_log()" method is responsible for displaying a the details of a log in the GUI. It displays the log at self.current_log's index number in the self.logs list. It is called at the end of the constructor, and by the previous_log() and next_log() methods.
2. The "previous_log()" method is called when the user clicks the Previous button. It should subtract 1 from self.current_log and then call the show_log() method, or show a messagebox if the program is already displaying the first log.
3. The "next_log()" method is called when the user clicks the Next button. It should add 1 to self.current_log and then call the show_log() method, or show a messagebox if the program is already displaying the last log.
These three methods are all that are required to implement the functionality of the program, but you may write/use additional methods if you feel they improve your program.
Note that it is possible (but trickier in some ways) to implement the functionality without the previous_log() and next_log() methods. You are welcome to do so if you are able!