A document from MCS 275 Spring 2021, instructor David Dumas. You can also get the notebook file.

Worksheet 1 Solutions

MCS 275 Spring 2021 -- David Dumas

Part II: Python Calisthenics

This section gives a series of exercises (of roughly increasing complexity) in which you'll write programs that are based on things you are expected to have seen in a prerequisite course. We'll talk about these in Lectures 2-3 as well, and the first quiz will cover the same kind of review material.

6. Squares

Create a simple program squares.py that prints the squares of the first 10 positive integers, so its output should look like

1
4
9
...
100

Then, add a feature to this program where it accepts an optional command line argument which is the largest integer whose square should be printed (while 10 remains the default if no argument is given). Recall that command line arguments appear in the list sys.argv which is accessible after you import the sys module.

Thus, for example, your modified program would print just

1
4
9

if run with the command

python squares.py 3
In [ ]:
# MCS 275 Spring 2021 Worksheet 1 problem 6
# Jennifer Vaccaro
# I declare that I am the sole author of this program and
# that I followed the rules given on the quiz and the
# course syllabus.

import sys

# Check if there's a second input
if len(sys.argv) > 1:
    max_number = int(sys.argv[1])
else:
    # or default to 10
    max_number = 10

for i in range(1,max_number+1):
    print(i**2)

7. Getting to know our coding standards

Now that you've written a simple program from scratch, and have a full Python setup working, it's time to get acquainted with some code style rules.

All code you submit for credit needs to follow the rules described in the coding standards document on the course web page. These rules enforce good coding practices and ensure your programs are readable to both humans and computers.

Read that document now. Take your time, and ask the TA for help if you are unsure about any part of it.

Then, take the program below (which works!) and fix it so that it does the same thing but complies with the MCS 275 rules. (Note: The rules say you need to add a declaration stating that the program is your own work, or that it is derived solely from a template provided by the instructor. That's because all graded work in MCS 275 is done individually. Since this is a worksheet, collaboration is allowed, and in this case your declaration should instead list your collaborators.)

# Program that doesn't follow MCS 275 coding guidelines
# Please fix me.
def thing(x):
 return "{} is one greater than {}".format(x,x-1)

def thing2(x):
 return "{} is one less than {}".format(x,x+1)

L = list(range(5))
LL = [ x+5 for x in L ]
L3 = [ 10*x for x in LL ]

for i in range(len(L3)):
    m = 'Some things that are true:\n' + thing(L3[i]) + "\n" + thing2(L3[i]) + '\n\n'
    print(m)
In [ ]:
# MCS 275 Spring 2021 Worksheet 1 problem 7
# Jennifer Vaccaro
# I declare that I changed this code given from a problem in 
# accordance with course policy.

def string_less_one(n):
    '''Given an input number n, returns a statement like
    $n is one greater than $n+1'''
    return "{} is one greater than {}".format(n,n-1)

def string_plus_one(n):
    '''Given an input number n, returns a statement like
    $n is one less than $n-1'''
    return "{} is one less than {}".format(n,n+1)

# Create an integer list 50, 60, ..., 90
int_list_size = list(range(5))
int_list_shifted = [ x+5 for x in int_list_size ]
int_list = [ 10*x for x in int_list_shifted ]

# Print out the corresponding strings with line spacing
for x in int_list:
    print('Some things that are true:')
    print(string_less_one(x))
    print(string_plus_one(x),"\n")

8. First two digits of squares

Let's write a slightly more complex program now that uses more Python concepts.

Consider the squares of all the 4-digit positive integers (the numbers 1000, 1001, ..., 9999).

What pairs of digits can appear as the first two digits in one of these numbers? For example, since 2187*2187=4782969, we know that 47 is one of the possibilites. What are the others? Do you get all two-digit combinations this way?

Write a program that answers this question, and which also determines how many times each two-digit combination arises in the list of squares of 1000...9999.

Have it print the result in a format like this:

There are NN two-digits combinations that appear as the first two digits of squares of the integers from 1000 to 9999.  Here is a table of them, with the number of times each one occurs:

Digits  Number of times
-----------------------
10      XXX
11      YYY
...

Here is the recommended structure for your program:

  • Make a dictionary that has all the two-character strings corresponding to pairs of digits as keys, and the integer 0 as each value.

  • Use a for loop to iterate over integers from 1000 to 9999. In the body of the loop, square the integer, convert it to a string, and extract the first two characters into a string. Then use this as a key in the dictionary, and increment the associated value.

In [ ]:
# MCS 275 Spring 2021 Worksheet 1 problem 8
# Jennifer Vaccaro
# I declare that I am the sole author of this program and
# that I followed the rules given on the quiz and the
# course syllabus.

# Create a dictionary where
# the keys are 10-99 as strings
# the values are all 0
num_str_dict = {}
for i in range(10,100):
    num_str = str(i)
    num_str_dict[num_str] = 0

# iterate through the four-digit numbers 1000-9999
total_combos = 0
for i in range(1000,9999):
    # square i, and convert it to a string
    i_squared = i**2
    i_squared_str = str(i_squared)

    # extract the key (first two digits) and
    # add one to the corresponding value
    i_key = i_squared_str[0:2]
    num_str_dict[i_key] += 1
    # If the first one, add to the total num of combos
    if num_str_dict[i_key] == 1:
        total_combos += 1

# Print out a table of all of the keys/values
print("There are {} two-digits combinations that appear as the first two digits of squares of the integers from 1000 to 9999.".format(total_combos))
print("Here is a table of them, with the number of times each one occurs:")
print("Digits  Number of times")
print("-----------------------")
for i in range(10,100):
    num_str = str(i)
    if num_str_dict[num_str] > 0:
        print("{} {}".format(num_str, num_str_dict[num_str]))

9. Chess board text file

Write a program board.py that expects two command line arguments. The first, sys.argv[1], will be the the output filename. The second will be a positive integer which we'll call N.

The program should open the output file for writing, and then write lines of text to that file that create an 8x8 chess board. The white squares should be represented by NxN blocks of the character #, and the black squares should be filled with spaces.

So, for example, the command

python board.py board1.txt 1

should result in a file board1.txt being created that contains the following text, exactly:

# # # # 
 # # # #
# # # # 
 # # # #
# # # # 
 # # # #
# # # # 
 # # # #

while the command

python board.py board2.txt 2

should result in a file board2.txt being created that contains the following text, exactly:

##  ##  ##  ##  
##  ##  ##  ##  
  ##  ##  ##  ##
  ##  ##  ##  ##
##  ##  ##  ##  
##  ##  ##  ##  
  ##  ##  ##  ##
  ##  ##  ##  ##
##  ##  ##  ##  
##  ##  ##  ##  
  ##  ##  ##  ##
  ##  ##  ##  ##
##  ##  ##  ##  
##  ##  ##  ##  
  ##  ##  ##  ##
  ##  ##  ##  ##

Recommended structure of your program:

There are only two different lines of text that appear in the file, but each appears many times.

First, generate both of the lines of text you'll need, then use a loop to print them the right number of times and in the right order.

To generate the line, you can use the fact that multiplication of a string by an integer will repeat the string a certain number of times. For example, "foo"*3 evaluates to "foofoofoo".

Put the part of the program that writes the chess board to a file into a function which accepts a file object as its only argument. That function should expect the file to already be opened for writing.

Then, the main program would parse the command line arguments, open the output file, and call the function that saves the board.

In [ ]:
# MCS 275 Spring 2021 Worksheet 1 problem 9
# Jennifer Vaccaro
# I declare that I am the sole author of this program and
# that I followed the rules given on the quiz and the
# course syllabus.

import sys

output_fn = sys.argv[1]
N = int(sys.argv[2])

# Create the lines that will be included in the file
line1 = ("#"*N + " "*N)*4
line2 = line1[::-1]   #  line1 reversed; could also use (" "*N + "#"*N)*4

# Add the lines to the file
output_fo = open(output_fn, "w")
for i in range(4):
    for j in range(N):
        output_fo.write(line1+"\n")
    for j in range(N):
        output_fo.write(line2+"\n")
output_fo.close()

Bonus round

Work on this more challenging exercise if you finish the rest of the worksheet before discussion ends.

10. Parse grade statements

Write a program that reads a text file specified as a command line argument which contains statements written in the following format

Student ddumas scored 1 out of 23 on CoordinationTest.
Student ncomaneci scored 23 out of 23 on CoordinationTest.
Student enoether scored 11 out of 10 on AlgebraQuiz.

That is, the lines are all of the form

Student NAME scored POINTS out of MAXPOINTS on NAME_OF_ASSESSMENT.

where the all-caps items are placeholders that in the actual lines will be replaced by an integer (for POINTS or MAXPOINTS) or a string with no spaces (NAME or NAME_OF_ASSESSMENT).

The program should compute the percentage score for each student on each assessment and store them in a dictionary (with the name of the assessment as a key). Then, it should print the scores for each assessment in increasing order, as percentages.

For example, the input above would give output:

Scores on CoordinationTest:
ddumas 4.3%
ncomaneci 100.0%

Scores on AlgebraQuiz:
enoether 110.0%
In [ ]:
# MCS 275 Spring 2021 Worksheet 1 problem 10
# Jennifer Vaccaro
# I declare that I am the sole author of this program and
# that I followed the rules given on the quiz and the
# course syllabus.

import sys

input_fn = sys.argv[1]
input_fin = open(input_fn, "r")

# Create a dictionary of dictionaries
# key: assignment
# value: dict with keys students, values percentages
assignments_dict = {}
for line in input_fin:
    words = line.split()
    if len(words) != 9:
        continue
    student = words[1]
    assignment = words[8][:-1] # Take out the last character, which is a period
    grade = int(words[3])
    out_of = int(words[6])
    if assignment in assignments_dict:
        assignments_dict[assignment][student] = grade/out_of
    else:
        new_dict = {student: grade/out_of}
        assignments_dict[assignment] = new_dict

for assignment in assignments_dict:
    print("Scores on {}".format(assignment))
    for student in assignments_dict[assignment]:
        print("{} {:.1f}%".format(student, assignments_dict[assignment][student]*100.0))
    print("")
In [ ]: