Recent Question/Assignment
programming assignment
Programming Principles (CSP1150)
Assignment 2: Individual programming project (Joke Catalogue)
Assignment Marks: Marked out of 30, (30% of unit)
Due Date: 1 June 2020, 9:00AM Extended to 8 June 2020, 9:00AM
Background Information
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.
Assignment Overview
You are required to design and implement two related programs:
• “admin.py”, a CLI program that allows the user to manage a collection of simple “setup and punchline” jokes which are stored in a text file. This program is referred to as the “Main Program” in the marking rubric. Develop this program before “jokes.py”.
• “jokes.py”, a GUI program that uses the data in the text file to display the jokes and allows the user to rate them. This program is referred to as the “GUI Program” in the marking rubric. Develop this program after “admin.py”.
The following pages describe the requirements of both programs in detail.
Starter files for both 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.
Please read the entire brief carefully, and refer back to it frequently as you work on the assignment. If you do not understand any part of the assignment requirements, contact your tutor.
Be sure to visit the Blackboard discussion boards regularly for extra information, tips and examples.
Pseudocode
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 “admin.py”, but not “jokes.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 “admin.py” (detailed later in the assignment brief).
The following pages describe the requirements of both programs in detail.
Overview of “admin.py”
“admin.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 175 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 of the unit. This program should be developed before “jokes.py”.
This program allows the user to manage the details of a collection of jokes which are stored in a text file named “data.txt”. Use the “json” module to write data to the text file in JSON format and to read the JSON data from the file back into Python. See Reading 7.1 for details regarding this. This is an example of the file’s content in JSON format (which is almost identical to Python):
[
{
-setup-: -What do you call a group of 8 hobbits?-,
-punchline-: -A hobbyte.-,
-laughs-: 0,
-groans-: 0
},
{
-setup-: -Why do ducks make great detectives?-,
-punchline-: -They always quack the case.-,
-laughs-: 0,
-groans-: 0
}
] JSON
This example file contains two items in a list. Each of those items is a dictionary consisting of 4 items which have keys of “setup”, “punchline”, “laughs” and “groans”. If this file was to be read into a Python variable named data, then “data[0]” would refer to the dictionary containing the first joke (about hobbits), and “data[0][laughs]” would refer to the integer of 0.
Note: The “laughs” and “groans” values are used to record the responses that the joke has received when shown to the user in the “jokes.py” GUI program. Parts of the “admin.py” program interact with the values, however the values only increase via “jokes.py.
Of course, you can manually edit the values in the text file to test your code!
Understanding the structure of this data and how you can use it is very important in many aspects of this assignment – in particular, you will need to understand how to loop through the items of a list and how to refer to items in a dictionary. Revise Module 3 and Module 7 if you are unsure about how to interact with lists and dictionaries, and see the Blackboard discussion board for further help.
Output Example of “admin.py”
To help you visualise the program, here is a screenshot of it being used:
Requirements of “admin.py”
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 thing the program should do is try to open a file named “data.txt” in read mode, then load the data from the file into a variable named data and then close the file.
? The data in the file should be in JSON format, so you will need to use the “load()” function from the “json” module to read the data into your program. See the earlier page for details of the structure.
? If any exceptions occur (e.g. due to the file not existing, or it not containing valid JSON data), then simply set the data variable to be an empty list. This will occur the first time the program is run, since the data file will not exist yet. This ensures that you are always left with a list named data.
? This is the first and only time that the program should need to read anything from the file. After this point, the program uses the data variable, which is written to the file whenever a change is made.
2. The program should then print a welcome message and enter an endless loop which starts by printing a list of options: “Choose [a]dd, [l]ist, [s]earch, [v]iew, [d]elete or [q]uit.” and then prompts the user to enter their choice. Once a choice has been entered, use an “if/elif” statement to handle each of the different choices (detailed in the following requirements).
? This requirement has been completed for you in the starter file.
3. If the user enters “a” (add), prompt them to enter the setup and punchline of a joke, and use them to create a new dictionary with the structure shown on the earlier page. Append the dictionary to the data list, then write the entire list to the text file in JSON format.
? Use your “input_something()” function (detailed below) when prompting for the setup and punchline, to ensure that they are re-prompted until they enter something other than whitespace.
? The dictionary for the new joke should contain 4 key-value pairs – “setup” and “punchline” should contain what the user entered, and “laughs” and “groans” should be given values of 0.
? Once the dictionary for the new joke has been appended to the data list, call your “save_data()” function (detailed below) to write the data to the text file in JSON format.
4. If the user enters “l” (list), display a list of all the jokes (just the setup) in the data list, preceded by their index number.
? If the data list is empty, show a “No jokes saved” message instead.
? Use a “for” loop to iterate through the items in the data list. Remember: each item is a dictionary.
? You can use the “enumerate()” function to make sure you have a variable containing the index number of each joke as you loop through them (see Lecture 3).
5. If the user enters “s” (search), prompt them for a search term and then list the jokes whose setup or punchline contains the search term. Include the index number next to each result.
? If the data list is empty, show a “No jokes saved” message instead of prompting for a search term.
? Use your “input_something()” function (detailed below) when prompting for a search term, to ensure that the user is re-prompted until they enter something other than whitespace.
? The code to search will be similar to the code used to list, but this time the loop body needs an “if” statement to only print jokes that contain the search term (use the “in” operator – see Lecture 3).
? Convert the search term, joke setup and punchline to lowercase to find matches regardless of case.
6. If the user enters “v” (view), prompt them for an index number and then print the corresponding joke’s setup and punchline, including the joke’s “laughs” and “groans” values.
? If the data list is empty, show a “No jokes saved” message instead of prompting for an index number.
? Use your “input_int()” function (detailed below) when prompting for an index number, to ensure that the user is re-prompted until they enter an integer.
? Display an “Invalid index number” message if the index number entered doesn’t exist in the data list.
? If the joke’s “laughs” and “groans” keys both contain 0, show a “This joke has not been rated” message. Otherwise, display the number of “laughs” and “groans” that the joke has received, e.g.
7. If the user enters “d” (delete), prompt them for an index number and then delete the corresponding joke’s dictionary from the data list, then display a “Joke deleted” message.
? If the data list is empty, show a “No jokes saved” message instead of prompting for an index number.
? Use your “input_int()” function (detailed below) when prompting for an index number, to ensure that the user is re-prompted until they enter an integer.
? Display an “Invalid index number” message if the index number entered doesn’t exist in the data list.
? Once the joke has been deleted from the data list, call your “save_data()” function (detailed below) to write the data to the text file in JSON format..
8. If the user enters “q” (quit), print “Goodbye!” and break out of the loop to end the program.
9. If the user enters anything else, print an “Invalid choice” message (the user will then be reprompted for a choice on the next iteration of the loop).
This concludes the core requirements of “admin.py”. The following pages detail the functions mentioned above and optional additions and enhancements that can be added to the program. Remember that you are required to submit pseudocode for your design of “admin.py”. Use the starter file and requirements above as a guide to structure the design of your program.
Functions in “admin.py”
The requirements above mentioned 3 functions - “input_int()”, “input_something()”, and “save_data()”. As part of “admin.py”, you must define and use these functions.
1. The “input_int()” function takes 1 parameter named prompt. The function should repeatedly re-prompt the user (using the prompt parameter) for input until they enter an integer of 0 or more (i.e. minimum of 0). It should then return the value as an integer.
? See Workshop 4 for a task involving the creation of a very similar function.
2. The “input_something()” function takes 1 parameter named prompt. The function should repeatedly re-prompt the user (using the prompt parameter) for input until they enter a value which consists of at least 1 non-whitespace character (i.e. the input cannot be nothing or consist entirely of spaces, tabs, etc.). It should then return the value as a string.
? Use the “strip()” string method on a string to remove whitespace from the start and end.
If a string consists entirely of whitespace, it will have nothing left once you strip the whitespace away. ? Note that exception handling is not needed in this function.
3. The “save_data()” function takes 1 parameter named data_list (the data list from the main program). The function should open “data.txt” in write mode, then write the data_list parameter to the file in JSON format and close the file. This function does not return anything.
? This is the only part of the program that should be writing to the file, and it always overwrites the entire content of the file with the entirety of the current data.
? See Reading 7.1 for an example of using the “json” module. You can specify an additional indent parameter in the “dump()” function to format the JSON data nicely in the text file.
The definitions of these functions should be at the start of the program (as they are in the starter file provided), and they should be called where needed in the program. Revise Module 4 if you are uncertain about defining and using functions. 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.
In particular, remember that the “prompt” parameter of the input functions is for the text that you want to show as a prompt. Here is an example of the function being called and its output:
You are welcome to define and use 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.
Optional Additions and Enhancements for “admin.py”
Below are some suggestions for minor additions and enhancements that you can make to the program to further test and demonstrate your programming ability. They are not required and you can earn full marks in the assignment without implementing them.
? Add 1 to the index number of jokes whenever the list or search results are shown, so that the numbers begin at 1 instead of 0. Remember to subtract 1 from the user’s input when viewing or deleting jokes so that you reference the appropriate index of the data list.
- If you implement this, you can also change the “input_int()” function to accept a minimum value of 1, rather than 0, since the function is only used to enter index numbers.
? If the setup of a joke is longer than 50 characters, truncate it so that it fits into 50 characters with “...” added to the end whenever you list jokes or show search results.
- The “shorten()” function from the “textwrap” module can help with this.
? When searching for a joke, show a “No results found” message if the search term is not found in the setup or punchline of any of the jokes.
? When viewing a joke (Requirement 6), include a percentage next to the number of “laughs” and number of “groans”, e.g.
? When viewing a joke (Requirement 6), show an extra line of text under certain conditions:
- If the joke has at least five “laughs” and no “groans”, show “This joke is hilarious!”
- If the joke has at least five “groans” and no “laughs”, show “This joke is groantastic!” Alternatively, display the appropriate line when the ratio of the two values is at least 4:1.
? Add an additional menu option of “[t]op”, which displays the joke with the most “laughs” and the joke with the most “groans”.
? Allow users to use the search, view and delete options more efficiently by allowing input of “s search term ”, “v index number ” and “d index number ”. For example, instead of needing to type “s” and then “hobbit”, the user could type “s hobbit”, and instead of needing to type “v” then “2”, the user could type “v 2”.
- This feature takes a reasonable amount of extra thought and effort to implement efficiently.
Overview of “jokes.py”
“jokes.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 “admin.py”.
The entirety of this program can be implemented in under 110 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 “data.txt” file. Similar to the admin program, this program should load the data from the file once only - when the program begins. The program displays the first joke and a pair of buttons labelled “Laugh” and “Groan”, allowing the user to rate the joke.
The only way that the user can interact with the program is by pressing the “Laugh” or “Groan” button, which results in adding 1 to the corresponding value in the dictionary of the current joke. The updated list of joke data is then saved in the text file, and the next joke is shown. Once all jokes have been rated, the program ends.
The following pages detail how to implement the program.
Constructor of the GUI Class of “jokes.py”
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 “Joke Catalogue”.
? You are welcome to set other main window settings to make the program look/behave as desired.
2. Try to open the “data.txt” file in read mode and load the JSON data from the file into an attribute named “self.data”, and then close the file.
? If any exceptions occur (due to the file not existing, or it not containing valid JSON data), show an error messagebox with a “Missing/Invalid file” message and call the “destroy()” method on the main window to end the program. Include a “return” statement in the exception handler after destroying the main window to halt the constructor so that the program ends cleanly.
3. Create a “self.current_joke” attribute to keep track of which joke is currently being displayed in the GUI, and set it to 0.
? This attribute represents an index number in the list of jokes loaded from the text file (self.data).
4. Use Label and Button and Frame widgets from the “tkinter” module to implement the GUI depicted on the previous page.
? You will save time if you design the GUI and determine exactly which widgets you will need and how to lay them out before you start writing the code.
? You are welcome change the layout/appearance, as long as the functionality is implemented.
? See Reading 9.1 for information regarding various settings that can be applied to widgets to make them appear with the desired padding, colour, size, etc.
? Do not set the text for the labels that will contain the setup and punchline of the joke at this point. They will be set in the “show_joke()” method.
? Both the “Laugh” and “Groan” buttons will be calling the “rate_joke()” method when clicked, but need to pass it a different parameter value – a string of laughs for the “Laugh” button, or a string of groans for the “Groan” button. This can be tricky, so here is some example code to use:
tkinter.Button(..., text=Laugh, command=lambda: self.rate_joke(laughs))
tkinter.Button(..., text=Groan, command=lambda: self.rate_joke(groans))
5. Lastly, the constructor should end by calling the “show_joke()” method to display the first joke in the GUI, and then call “tkinter.mainloop()” to start the main loop.
? To call a method of the class, be sure to include “self.” at the start, e.g. “self.show_joke()”.
That is all that the constructor requires. The following pages detail the methods mentioned above, and some optional additions. You are not required to submit pseudocode for “jokes.py”.
Methods in the GUI class of “jokes.py”
This program requires you to define 2 methods to implement the functionality specified -
“show_joke()” and “rate_joke()”. These should be defined as part of the GUI class.
1. The “show_joke()” method is responsible for displaying the setup and punchline of the current joke in the GUI. It is called at the end of the constructor, and by the “rate_joke()” method. It uses self.current_joke to refer to an item in the self.data list.
? self.data is a list of dictionaries. Referring to a specific index number of the list will obtain the dictionary of that joke. See Page 3 for details regarding the keys of a joke dictionary.
? The “configure()” method (see Reading 9.1) can be used on a widget to change the text it displays. Alternatively, you can use a StringVar to control the text of a widget (see Lecture 9).
2. The “rate_joke()” method is called when the user clicks the “Laugh” or “Groan” button. It should add 1 to the corresponding key (“laughs” or “groans”) of the current joke’s dictionary, then open “data.txt”, write the self.data list to it in JSON format, and close the file.
Then, the method should check if the current joke is the final joke in the self.data list and show an appropriate messagebox as per the screenshots above. If it is the final joke, end the program. Otherwise, add 1 to self.current_joke and then call “show_joke()”.
? This method receives a parameter named “rating” that will contain a string of laughs or groans depending on which button was clicked. Use this value to add 1 to the appropriate dictionary key.
This can be done in a single line if you use rating to directly refer to the key of the dictionary!
? Writing data to the file will involve very similar code to the “save_data()” function of admin.py.
? Call the “destroy()” method on the main window to end the program if it is the last joke.
These 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.
Optional Additions and Enhancements for “jokes.py”
Below are some suggestions for minor additions and enhancements that you can make to the program to further test and demonstrate your programming ability. They are not required and you can earn full marks in the assignment without implementing them.
? After loading the data from the text file in the constructor, check if the self.data list is empty and end the program if so – there is no point continuing if there are no jokes to rate!
? Add an “Abstain” button between the “Laugh” and “Groan” buttons. Clicking it should simply proceed to the next joke without rating it.
? Show the current “laughs” and “groans” values somewhere in the GUI – either in the main window when displaying the joke, or in the messagebox that appears after rating the joke.
- Alternatively/Additionally, show a “New joke” message if the current joke has no ratings.
? Show “Joke X/Y” (e.g. “Joke 1/4”) somewhere in the GUI, to give the user an idea of their position in the list of jokes.
? Make sure that the setup and the punchline are shown in slightly different ways – e.g. a different font size or italics. You could also make the user click to reveal the punchline, or make it appear after a short delay – See Reading 9.2.
? Rather than always going through the list of jokes in the order that they are stored in the self.data list, go through them in a random order that never repeats the same joke. The program should still end after all of the jokes have been rated.
Submission of Deliverables
It is recommended that you send your work to your tutor for feedback at least once prior to submitting it. Once your assignment is complete, submit both the pseudocode for admin.py (“.pdf” file) and the source code for “admin.py” and “jokes.py” code (“.py” files) to the appropriate location in the Assessments area of Blackboard. Zipping the files is not required. An assignment cover sheet is not required, but be sure to include your name and student number at the top of all files (not just in the filenames).
Academic Integrity and Misconduct
The entirety of your assignment must be your own work (unless otherwise referenced) and produced for the current instance of the unit. Any use of unreferenced content you did not create constitutes plagiarism, and is deemed an act of academic misconduct. All assignments will be submitted to plagiarism checking software which includes previous copies of the assignment, and the work submitted by all other students in the unit.
Remember that this is an individual assignment. Never give anyone any part of your assignment – even after the due date or after results have been released. Do not work together with other students on individual assignments – you can help someone by explaining a concept or directing them to the relevant resources, but doing any part of the assignment for them or alongside them, or showing them your work is inappropriate. An unacceptable level of cooperation between students on an assignment is collusion, and is deemed an act of academic misconduct. If you are uncertain about plagiarism, collusion or referencing, simply contact your tutor, lecturer or unit coordinator.
You may be asked to explain and demonstrate your understanding of the work you have submitted. Your submission should accurately reflect your understanding and ability to apply the unit content.
Marking Key
Criteria Marks
Pseudocode
These marks are awarded for submitting pseudocode which suitably represents the design of your admin program. Pseudocode will be assessed on the basis of whether it clearly describes the steps of the program in English, and whether the program is well structured. 5
Functionality
These marks are awarded for submitting source code that implements the requirements specified in this brief, in Python 3. Code which is not functional or contains syntax errors will lose marks, as will failing to implement requirements as specified. 15
Main Program: 10
GUI Program: 5
Code Quality
These marks are awarded for submitting well-written source code that is efficient, wellformatted and demonstrates a solid understanding of the concepts involved. This includes appropriate use of commenting and adhering to best practise. 10
Main Program: 6 GUI Program: 4
Total: 30
See the “Rubric and Marking Criteria” document provided with this brief for further details!