Practical Exam 1 CSC_1F001, Groups 1-5, 10:15-12:15
Objectives
What we will evaluate today: Everything!
Setup: Before You Start
Launch Spyder (open a terminal, then type
spyder and press Enter). If you see a “Spyder update”
message, just click OK and ignore it.
Before you start: create a new
project, called PracticalExam_1 (using “New
Project” from the “Projects” menu). This will ensure that files from
previous and future weeks do not get mixed up together.
Now create a new file named
pixel_art.py. This is the file in which you will be writing
your code today.
Introduction
In today’s practical exam, you will learn to manipulate
minimalist ASCII pictures — simple images made only of
spaces ' ' and hashes '#'.
These pictures are stored in plain text files, where each line
represents a single horizontal row of pixels.
Data files
Before you start, you need to download the following
data files from Moodle: integers1.txt,
integers2.txt, invader.txt,
pac_man.txt, frog.txt,
small_art.txt, cat.txt, and
pumpkin.txt. Save them to in your PracticalExam_1
project directory.
Check and make sure that all files have appeared in your PracticalExam_1 project in Spyder.
Part 1: Run-length encoding
We first consider simple images made only of spaces ' '
and hashes '#'. In this part your main task will be to
encode and decode such pictures by converting them between:
- a visual representation with
' 'and'#', and - a numerical representation with integers.
We want to encode a picture line by line, so that every line is coded
as a sequence of integers obtained by gathering blocks of identical
consecutive symbols starting with spaces. For instance the line
' # # ### ' will be coded by the integers
3 1 2 1 4 3 1. If the string starts with #,
the first integer will be 0. The remaining integers will
always be positive. For example '## #' will be encoded by
0 2 3 1.
This process is known as run-length encoding — a simple and efficient compression method that represents consecutive identical symbols by their count rather than by repetition. It is often used in image compression (for example in some bitmap or fax file formats) because it significantly reduces the size of images that contain large uniform regions.
Exercise 1: Converting a string of digits into a list
To begin we define a function to convert a string of digital
characters separated by spaces into a list of numbers.
Write a new function run_length_line which
takes as input a string representing a series of numerical values,
separated by spaces, and returns the list of these numerical values as
integers.
Copy the following function stub into your file and complete it:
def run_length_line(string):
"""
Converts a space-separated string of integers into a list of integers.
"""
pass # remove this line and replace with your own codeTesting
Now test your code by doing this in the console:
In [1]: run_length_line("3 2 1")
Out[1]: [3, 2, 1]
In [2]: run_length_line(" 20 1 1 2")
Out[2]: [20, 1, 1, 2]Note: It is important to test your function in the console as there is no grader feedback.
Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Exercise 2: Decoding a run-length line
Implement and test the function decoding_run_length,
that converts a list of non-negative integers into a string of
alternating blocks (spaces then hashes). Note that, if the list starts
with 0, the string should start with a hash.
Copy the following function stub into your file and complete it:
def decoding_run_length(integers_list):
"""
Converts a list of integers into a string made of alternating
blocks of spaces and hashes, starting with spaces.
"""
pass # remove this line and replace with your own codeTesting
Now test your code by doing this in the console:
In [3]: decoding_run_length([3, 1, 2, 1, 4, 3, 1])
Out[3]: ' # # ### '
In [4]: decoding_run_length([0, 2, 1])
Out[4]: '## 'Hint: you can concatenate strings in Python using the
+ operator. For example:
In [5]: 'a' + 'b'
Out[5]: 'ab'We also remind that you can check if a number is even or odd by
computing the remainder of its division by 2 with
a % 2.
Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Exercise 3: From file of digits to pixel art!
Implement and test the function integers_to_pixel_art,
that given a file of integer lines, write the corresponding picture into
the target file.
Copy the following function stub into your file and complete it:
def integers_to_pixel_art(infilename, outfilename):
"""
Reads a file with space-separated integers and
writes the corresponding pixel art using
alternating blocks of spaces and hashes.
"""
pass # remove this line and replace with your own codeUsing the functions you have written for the two previous exercises may be a very good idea.
Testing
Now test your code by doing this in the console:
In [6]: integers_to_pixel_art("integers1.txt", "pixel_art1.txt")
In [7]: integers_to_pixel_art("integers2.txt", "pixel_art2.txt")You can open the produced files pixel_art1.txt and
pixel_art2.txt directly in Spyder. The file
pixel_art1.txt should contain this:
# #
# #
#######
## ### ##
###########
# ####### #
# # # #
## ##
while pixel_art2.txt should contain that:
# # # # #
# # # #
# #
# # #
# #
# # #
# # # # # # # # # # # # #
# # # # # # # # # #
# # # # # # # # # # # # #
# # #
# #
# #
# #
# # # #
# # # # #
Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Exercise 4: Converting a line of symbols into a list of integers
Implement and test the function pattern_to_run_length,
that converts a string of alternating blocks (spaces then hashes) into
the corresponding list of integers where the first integer is allowed to
be zero (if the string starts with #) and all others must
be positive.
Copy the following function stub into your file and complete it:
def pattern_to_run_length(line):
"""
Converts a string made of alternating blocks of
spaces and hashes, starting with spaces,
into a list of integers representing
the lengths of these consecutive blocks.
"""
pass # remove this line and replace with your own codeTesting
Now test your code by doing this in the console:
In [8]: pattern_to_run_length(' # # ### ')
Out[8]: [3, 1, 2, 1, 4, 3, 1]
In [9]: pattern_to_run_length(' ##')
Out[9]: [1, 2]
In [10]: pattern_to_run_length('### ##')
Out[10]: [0, 3, 1, 2]Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Exercise 5: Integer representation of a pixel art
Implement and test the function pixel_art_to_run_length,
that converts a picture made of spaces and hashes into its run-length
encoded integer representation.
Copy the following function stub into your file and complete it:
def pixel_art_to_run_length(infilename, outfilename):
"""
Reads a picture file made of spaces ' ' and hashes '#' and
converts each line of that picture into a line of integers
representing the run lengths of consecutive blocks of characters.
Then writes those integer sequences into an output file.
"""
pass # remove this line and replace with your own codeHint: The lines you read from file will contain the endline
caracter '\n' at the end. You can remove it by
s.strip('\n').
Testing
Now test your code by doing this in the console:
In [11]: pixel_art_to_run_length("pixel_art1.txt", "runlength1.txt")
In [12]: pixel_art_to_run_length("pixel_art2.txt", "runlength2.txt")Alternatively, if you did not succeed in producing the files
picture1.txt and picture2.txt you can use
invader.txt and pac_man.txt as follows:
In [13]: pixel_art_to_run_length("invader.txt", "runlength1.txt")
In [14]: pixel_art_to_run_length("pac_man.txt", "runlength2.txt")You can open the produced files runlength1.txt and
runlength2.txt directly in Spyder. As expected they should
be the same as integers1.txt and
integers2.txt. In details the file
runlength1.txt should contain this:
15
4 1 5 1 4
5 1 3 1 5
4 7 4
3 2 1 3 1 2 3
2 11 2
2 1 1 7 1 1 2
2 1 1 1 5 1 1 1 2
5 2 1 2 5
15while runlength2.txt should contain that:
14 1 1 1 1 1 1 1 1 1 46
10 1 1 1 11 1 1 1 42
8 1 19 1 40
6 1 13 1 9 1 38
6 1 23 1 38
4 1 21 1 1 1 40
4 1 15 1 1 1 1 1 17 1 1 1 1 1 5 1 1 1 1 1 5 1 1 1 1 1 2
4 1 9 1 1 1 1 1 23 1 3 1 5 1 3 1 5 1 3 1 2
4 1 15 1 1 1 1 1 17 1 1 1 1 1 5 1 1 1 1 1 5 1 1 1 1 1 2
4 1 21 1 1 1 40
6 1 23 1 38
6 1 23 1 38
8 1 19 1 40
10 1 1 1 11 1 1 1 42
14 1 1 1 1 1 1 1 1 1 46You can also test your code on two larger pictures:
cat.txt and pumpkin.txt.
Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Part 2: Transformations
In this second part we implement basic transformations on our 2D pictures:
Exercise 6: Horizontal mirror
Write a function horizontal_mirror that produces the
horizontal mirror (symmetry with respect to a
horizontal axis) of a pixel art.
In other words, the image must be flipped upside down:
the top line becomes the bottom line, and vice versa.
Your function should open infilename for reading and
outfilename for writing.
Then, read all the lines of the input file, reverse
their order, and write them back (unchanged) to the output file.
Copy the following function stub into your file and complete it:
def horizontal_mirror(infilename, outfilename):
"""
Read a pixel-art file (spaces and '#') and write its horizontal mirror.
The image is flipped upside down (top <-> bottom).
"""
pass # remove this line and replace with your own codeTesting
Now test your code in the console:
In [15]: horizontal_mirror("invader.txt", "invader2.txt")
In [16]: horizontal_mirror("pac_man.txt", "pac_man2.txt")Open the produced files invader2.txt and
pac_man2.txt directly in Spyder.
You should see that the two images are flipped upside down. In details
the file invader2.txt should contain this:
## ##
# # # #
# ####### #
###########
## ### ##
#######
# #
# #
then your mirrored file pac_man2.txt should look like
this:
# # # # #
# # # #
# #
# #
# #
# # #
# # # # # # # # # # # # #
# # # # # # # # # #
# # # # # # # # # # # # #
# # #
# #
# # #
# #
# # # #
# # # # #
Once your code runs correctly, upload your
pixel_art.py file to the Moodle
assignment corresponding to this exam.
(You can upload pixel_art.py multiple times, but
only your last version will be graded. Upload a preliminary version
early to avoid missing the deadline.)
Exercise 7: Vertical mirror
Write a function vertical_mirror produces the
vertical mirror (symmetry with respect to a vertical
axis) of a pixel art : for each line, reverse the order of characters
while preserving the line length and all spaces. Your function should
open infilename for reading and outfilename for writing.
Copy the following function stub into your file and complete it:
def vertical_mirror(infilename, outfilename):
"""
Read a pixel-art file (spaces and '#') and write its vertical mirror.
Each output line is the input line reversed (excluding the newline).
"""
pass # remove this line and replace with your own codeHint: The lines you read from file will contain the endline
caracter '\n' at the end. You can remove it by
s.strip('\n').
Testing
Now test your code by doing this in the console:
In [17]: vertical_mirror("invader.txt","invader3.txt")
In [18]: vertical_mirror("pac_man.txt","pac_man3.txt")You can open the produced files invader3.txt and
pac_man3.txt directly in Spyder. As expected the file
invader3.txtshould be the same as invader.txt
(since the invader is vertically symmetrical) but
pac_man3.txt is different from pac_man.txt. In
details the file invader3.txt should contain this:
# #
# #
#######
## ### ##
###########
# ####### #
# # # #
## ##
while pac_man3.txt should contain that:
# # # # #
# # # #
# #
# # #
# #
# # #
# # # # # # # # # # # # #
# # # # # # # # # #
# # # # # # # # # # # # #
# # #
# #
# #
# #
# # # #
# # # # #
Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Exercise 8: Converting a pixel art file into a list of lists
Write a function pixels_to_lol(infilename) that reads a
text file representing a pixel-art image and converts it into a
list of lists of characters.
Each line in the input file becomes a list of characters (including spaces), and the function should return a list containing all these lists.
Copy and complete the following function stub:
def pixels_to_lol(infilename):
"""
Read a pixel-art file and return it as a list of lists of characters.
Each line becomes a list of characters.
"""
pass # replace with your codeHint: The lines you read from file will contain the endline
caracter '\n' at the end. You can remove it by
s.strip('\n').
Testing
Now test your code by doing this in the console:
In [19]: pixels_to_lol("small_art.txt")
Out[20]: [[' ', '#', '#', ' '], ['#', ' ', ' ', '#'], [' ', '#', '#', ' ']]Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Exercise 9: Rotating a list of lists
Write a function rotate_lol(lol) that takes a list of
lists of equal length (a rectangular 2D grid) and returns a
rotated version (90° counter clockwise).
Copy and complete the following function stub:
def rotate_lol(lol):
"""
Rotate the list of lists 90° counter clockwise.
"""
new_lol = [[] for l in lol[0]]
passHint: The length of the new lol will be equal to the length of any of the lists in the original lol. You can create first a list of this many empty lists (as in the code above) and then go through the original lol line by line filling the new lol column by column.
Testing
Now test your code by doing this in the console:
In [21]: lol = [['a','b','c'],['d','e','f']]
In [22]: rotate_lol(lol)
Out[23]: [['c', 'f'], ['b', 'e'], ['a', 'd']]
In [24]: rotate_lol(pixels_to_lol("small_art.txt"))
Out[113]: [[' ', '#', ' '], ['#', ' ', '#'], ['#', ' ', '#'], [' ', '#', ' ']]Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)
Exercise 10: Rotating a pixel-art file
Finally, write a function
rotate(infilename, outfilename) that reads a pixel-art
file, rotates it 90° counter clockwise using your previous functions,
and writes the rotated image into outfilename.
Copy and complete the following function stub:
def rotate(infilename, outfilename):
"""
Read a pixel-art file, rotate it 90° counter clockwise,
and write the result to the output file.
"""
pass # replace with your codeYour function should:
- Use
pixels_to_lol(infilename)to read the file into a list of lists.
- Use
rotate_lol(lol)to rotate that list of lists.
- Join each inner list into a string and write all lines to
outfilename.
Testing
You can test your program step by step in the console:
In [25]: rotate("frog.txt", "frog2.txt")
In [26]: rotate("invader.txt", "invader4.txt")You can open the produced files frog2.txt and
invader4.txt directly in Spyder, you should see your images
correctly rotated 90° counter clockwise. In details the file
frog2.txt should contain this:
###
# # ##
# ## #
#### # # #
#### ######### #
# # ###
# ## # #### ##
# ## # # #
# # # #
# # ###
# # #
# # #
# # ###
# # # #
# ## # # #
# ## # #### ##
# # ###
#### ######### #
#### # # #
# ## #
# # ##
###
while invader4.txt should contain that:
###
##
# #####
## ## #
#### #
####
#### #
## ## #
# #####
##
###
You may also want to test the rotation on the Pac Man picture!
Now take a moment to upload your pixel_art.py file to the moodle
assignment corresponding to this exam.
(You can upload pixel_art.py several times, but only
your final upload will be graded - don’t wait until the last moment to
upload a preliminary version, in case you miss the cut-off!)