COMP 202 - Foundations of Programming
Assignment 4
Fall 2024
Important notice
You will need to write three files for this assignment. Make sure that all file names and method names are spelled exactly as described in this document. Otherwise, a 50% penalty per question will be applied. You may make as many submissions as you like prior to the deadline, but we will only grade your final submission (all prior ones are automatically deleted). The following instructions are important:
• Please read the entire assignment guidelines and this PDF before starting. You must do this assignment individually.
• The work submitted for this assessment is expected to be your own. The use of technologies such as ChatGPT is prohibited and will be considered a violation of the Code of Student Conduct.
• Do not use functions that we didn’t mention in class.
• Do not use break and continue statements.
• Make sure to follow all the programming standards and to add docstrings with three examples for each method in the assignment (you may use only one example from this
document and you should think of another two examples of your own). The main learning objectives for this assignment are:
• Object-oriented programming: Defining classes, creating objects, and applying meth- ods to them;
• Nested lists;
• Dictionaries;
• Files: Working with files through Python built-in functions;
Figure 1: The file qrcode binary.txt opened in a text editor.
QR Code
A QR code (short for Quick Response Code) is a two-dimensional barcode that can store information, which can be quickly accessed by scanning it with a device like a smartphone, tablet, or dedicated QR code reader. Unlike traditional barcodes, which store data in a lin- ear fashion, QR codes use both horizontal and vertical dimensions to encode data, allowing them to hold much more information.
A QR code consists of black and white squares arranged in a grid. The black squares rep- resent the binary ”1” and the white squares represent the binary ”0” . The information is encoded in a format that is easily readable by devices with cameras.
In this assignment, binary representations of QR codes are stored in Txt files1. We will first implement some helper functions. Then we will create a TxtData class, which represents the data stored in the Txt files. Fianlly, we will implement a QR code class that represents a QR code (the data itself + other information and functionalities).
Figure 2: The file small data.txt opened in a text editor.
1 Question 1: Helper functions [25 points]
Define two functions and write your functions in a file called helper. py:
1.1 convert date [10 points]
A function that takes in an input date str (string) and returns a dictionary with ”Day”, ”Month”, and ”Year” as keys and strings as values. The input date str should have the for- mat ”dd/mm/yyyy” (2 digits/2 digits/4 digits) and this function should convert the string to the desired dictionary.
In your code, check that the input string has the right format. More specifically, check that it can be split into three parts by the ”/” character and that each part has the right length. You can assume that the input string has the correct format if it meets these re- quirements. Raise a ValueError if any of these requirements are not met.
>>> convert_date("09/01/2024")
{’Day’: ’09’, ’Month’: ’01’, ’Year’: ’2024’}
>>> convert_date("00/00")
Traceback (most recent call last):
ValueError: Input format incorrect!
>>> convert_date("9/1/2024")
Traceback (most recent call last):
ValueError: Input format incorrect!
1.2 get data [15 points]
A function that takes one input file path (string) and returns a nested list of integers representing the data in the file. The method should read the file located at file path. You can assume that the file exists.
The file should only contain ”0”s and ”1”s. Otherwise, raise a ValueError.
See below for an example. You can find the files small data and small data error can be found in figure 2 and 3.
Figure 3: The file small data error.txt opened in a text editor.
>>> get_data("small_data.txt")
[[0, 1], [1, 0]]
>>> get_data("small_data_error.txt")
Traceback (most recent call last):
ValueError: File should contain only 0s and 1s!
2 Question 2: Class TxtData [45 points]
Define a class TxtData that has three instance attributes:
• data: a nested list of integer representing the data;
• rows: an integer indicating the number of rows in data;
• cols: an integer indicating the number of columns in data;
Include the following instance methods and write your class in a file called txtdata. py. This file should import the helper. py file that you created in Question 1.
2.1 init [5 points]
A constructor that takes in data (2-D nested list) as explicit input. Make sure to make a deep copy of the input list with the help of the deepcopy function in the copy module. The data attribute should be initialized using the data input. The rows and cols attributes represent the number of rows and columns of data. You can assume that the input list has at least one row and one column, and that all nested lists (if there are more than one) have the same length.
Figure 1 shows you how qrcode binary.txt looks like.
>>> my_list_simple= [[1,2,3],[4,5,6]]
>>> my_txt_simple = TxtData(my_list_simple)
>>> my_txt_simple.rows
2
>>> my_txt_simple.cols
3
>>> my_list = get_data("qrcode_binary.txt")
>>> my_txt = TxtData(my_list)
>>> my_txt.rows
33
>>> my_txt.cols
33
2.2 str [5 points]
A str method that returns a string of the format ”This TxtData object has ROWS rows and COLS columns.” where ROWS and COLS refer to the appropriate instance attributes.
>>> my_list_simple = [[1,2,3],[4,5,6]]
>>> my_txt_simple = TxtData(my_list_simple)
>>> print(my_list_simple)
This TxtData object has 2 rows and 3 columns.
>>> my_list = get_data("qrcode_binary.txt")
>>> my_txt = TxtData(my_list)
>>> print(my_txt)
This TxtData object has 33 rows and 33 columns.
2.3 get pixels [5 points]
An instance method that takes in no explicit input and returns an integer indicating the total number of pixels in data - number of rows × number of columns.
>>> my_list_simple = [[1,2,3],[4,5,6]]
>>> my_txt_simple = TxtData(my_list_simple)
>>> my_txt_simple.get_pixels()
6
>>> my_list = get_data("qrcode_binary.txt")
>>> my_txt = TxtData(my_list)
>>> my_txt.get_pixels()
1089
2.4 get data at [5 points]
An instance method that takes in two explicit inputs row (integer) and col (integer) indi- cating the position and returns an integer indicating the value in data at that position.
A ValueError should be raised if row or col is out of bound.
>>> my_list_simple = [[1,2,3],[4,5,6]]
>>> my_txt_simple = TxtData(my_list_simple)
>>> my_txt_simple.get_data_at(0,0)
1
>>> my_txt_simple.get_data_at(3,0)
Traceback (most recent call last):
ValueError: Index out of bound!
>>> my_list = get_data("qrcode_binary.txt")
>>> my_txt = TxtData(my_list)
>>> my_txt.get_data_at(0,0)
0
>>> my_txt.get_data_at(6,8)
1
2.5 pretty save [10 points]
An instance method that takes one explicit input file name (string) and returns nothing. It converts the data to a prettier form so that it can be scanned by our cameras as a QR code.
”1”s are changed into ”” (two blocks) and ”0”s and changed into ” ” (two spaces). It then saves the prettier QR code into a new file named file name. You can assume that there is no file with the name file name that exists beforehand.
The block character has the Unicode U+2588. To get the character in Python, you can use either ”\u2588” or chr(0x2588). See figure 4 for an example of a file saved from this method.
Note: do not use the replace() method.
>>> my_list = get_data("qrcode_binary.txt")
>>> my_txt = TxtData(my_list)
>>> my_txt.pretty_save("qrcode_pretty.txt")
2.6 equals [5 points]
An instance method that takes in one explicit input another data (TxtData) and returns a boolean indicating if the two TxtData objects are equal.
Two TxtData objects are considered equal if the data attributes are the same.
In the example below, file qrcode binary copy . txt is an exact copy of file qrcode binary . txt, while qrcode binary 1 . txt has exactly one different value than qrcode binary . txt.
>>> my_list_simple = [[1,2,3],[4,5,6]]
>>> my_txt_simple_1 = TxtData(my_list_simple)
>>> my_txt_simple_2 = TxtData(my_list_simple)
>>> my_txt_simple_1.equals(my_txt_simple_2)
True
>>> my_txt = TxtData("qrcode_binary.txt")
>>> my_list = get_data("qrcode_binary.txt")
>>> my_txt = TxtData(my_list)
>>> my_txt_copy = TxtData("qrcode_binary_copy.txt")
Figure 4: The file saved from pretty save method opened in a text editor.
>>> my_txt.equals(my_txt_copy)
True
>>> my_list_1 = get_data("qrcode_binary_1.txt")
>>> my_txt_1 = TxtData(my_list_1)
>>> my_txt.equals(my_txt_1)
False
2.7 approximately equals [10 points]
An instance method that takes in two explicit inputs another data (TxtData) and precision (non-negative float) and returns a boolean indicating if the two TxtData objects are approx- imately equal.
Two TxtData objects are considered approximately equal if the inconsistent rate of the two data attributes is not greater than the input precision. The inconsistent rate can be cal- culated by getting the number of inconsistent values and dividing that by the total number of values (number of pixels).
In the examples below, qrcode binary 1 . txt has exactly one different value than qrcode binary . txt and qrcode binary 2 . txt has two different values.
>>> my_list_simple_1 = [[1,2,3],[4,5,6]]
>>> my_list_simple_2 = [[1,2,3],[7,8,9]]
>>> my_txt_simple_1 = TxtData(my_list_simple_1)
>>> my_txt_simple_2 = TxtData(my_list_simple_2)
>>> my_txt_simple_1.equals(my_txt_simple_2)
False
>>> my_txt_simple_1.approximately_equals(my_txt_simple_2, 0.5)
True
>>> my_txt = TxtData("qrcode_binary.txt")
>>> my_txt_1 = TxtData("qrcode_binary_1.txt")
>>> my_txt.equals(my_txt_1)
False
>>> my_txt.approximately_equals(my_txt_1, 1/my_txt.get_pixels())
True
>>> my_txt_2 = TxtData("qrcode_binary_2.txt")
>>> my_txt.approximately_equals(my_txt_2, 1/my_txt.get_pixels())
False