CS 111
Summer 2 2018

Problem Set 2

due by 9:00 p.m. on Wednesday, July 04, 2018

Preliminaries

In your work on this assignment, make sure to abide by the collaboration policies of the course.

If you have questions while working on this assignment, please come to office hours, post them on Piazza, or email cs111-staff@cs.bu.edu.

Make sure to submit your work on Apollo, following the procedures found at the end of the assignment.

For each problem in this problem set, we will be writing or evaluating some Python code. In today’s class, we will introduce the Python IDLE development environment.


Problem 1: Functions with numeric inputs, part I

25 points; pair-optional See the rules for working with a partner on pair-optional problems for details about how this type of collaboration must be structured.

In this problem you will write a collection of simple functions that operate on numeric inputs.

Begin by downloading this file: ps2pr1.py. Open it in IDLE, following the procedure outlined in class.

Important guidelines:

  • Your functions must have the exact names that we have specified, or we won’t be able to test them. Note in particular that the case of the letters matters (all of them should be lowercase), and that you should use an underscore character (_) wherever we have specified one (e.g., in convert_from_inches).
  • If a function takes more than one input, you must keep the inputs in the order that we have specified.
  • Each of your functions should include a docstring that describes what your function does and what its inputs are. See our example function for a model.
  • Make sure that your functions return the specified value, rather than printing it. None of these functions should use a print statement.
  • You should not use any Python features that we have not discussed in lecture or read about in the textbook.
  • Your functions do not need to handle bad inputs – inputs with a type or value that doesn’t correspond to the description of the inputs provided in the problem.
  • Test each function after you write it. Here are two ways to do so:
    • Run your ps2pr1.py file after you finish a given function. Doing so will bring you to the Shell, where you can call the function using different inputs and check to see that you obtain the correct outputs.
    • Add test calls to the bottom of your ps2pr1.py file. These will be called every time that you run the file, which will save you from having to enter the tests yourself. We have given you an example of one such test in the starter file.

Here are the descriptions of the functions:

  1. (example) Write a function opposite(x) that takes a number x as its input and returns the opposite of its input. We have given you this example function in the starter file.

  2. Write a function cube(x) that takes a number x as its input and returns the cube of its input (i.e., x raised to the power of 3). For example:

    >>> cube(2)
    8
    >>> print(cube(-5))
    -125
    

    Warning

    Make sure that your function returns the correct value rather than printing it. If your function is printing the return value, you will see the word None as part of the output for the second test above. If you are seeing None in your output, you must fix your function so that it uses a return statement rather than a print statement. This same warning applies to all of the functions that you will write for this assignment.

    Note: You should leave one or two blank lines between functions to make things more readable, and make sure to include a docstring like the one in our example function.

    Warning

    Make sure that you use the correct amount of indentation. In particular, your docstrings should be indented by 4 spaces as shown in our code for opposite, so that they line up with the code inside the function.

  3. Write a function slope(x1, y1, x2, y2) that takes four numeric inputs that specify the coordinates of two points (x1, y1) and (x2, y2) in the Cartesian plane, and that returns the slope of the line formed by those two points. Recall that slope is given by the following formula:

             y2 - y1
    slope = ---------
             x2 - x1
    

    If x1 and x2 are the same (meaning the line is vertical, and thus the slope is undefined), the function should execute the following line:

    return float('nan')
    

    This line will cause the function to return a special value called nan to indicate that the result is not a number (which is what nan stands for!).

    Examples:

    >>> slope(2, 3, 4, 7)     # line between (2,3) and (4,7)
    2.0
    >>> slope(7, 2, 3, 4)     # line between (7,2) and (3,4)
    -0.5
    >>> print(slope(2, 3, 5, 3))
    0.0
    >>> slope(2, 5, 2, -3)    # vertical line (both x values are 2)
    nan
    

    Note: In Python, if you divide 0 by a negative number using the / operator, the result is -0.0. You don’t need to worry if your slope function returns -0.0 for cases in which the slope is 0.

  4. Write a function make_change(cents) that takes a nonnegative integer cents that represents an amount of money in cents and returns a list of four integers in which that amount has been broken up into quarters, dimes, nickels, and pennies. Although there are many ways to make change for a given number of cents, the values returned by the function should minimize the total number of coins. For example:

    >>> make_change(347)         # 347 cents = 13 quarters, 2 dimes, 0 nickels, 2 pennies
    [13, 2, 0, 2]         
    >>> print(make_change(84))   # 84 cents = 3 quarters, 0 dimes, 1 nickel, 4 pennies
    [3, 0, 1, 4]
    

    Here’s the beginning of one possible template that you could use:

    def make_change(cents):
        """ put your docstring here
        """
        quarters =                  # number of quarters
        cents =                     # leftover number of cents
        dimes =                     # number of dimes
        cents =                     # leftover number of cents
        # add more code here!
        return [quarters, dimes, nickels, pennies]
    

    Hint: The integer division (//) and modulus (%) operators will come in handy for this problem.

Don’t forget to test your functions using the approaches mentioned at the start of the problem.

You may also find it helpful to use the Python Tutor Visualizer to trace through the execution of your functions – either to verify that they’re working as expected, or to determine why they’re not working! Paste your function definition into the Visualizer’s code box, and follow the definition with code that calls the function. Then click the Visualize Execution button below the code box to begin the visualization. For example, to test the circle_area function that we discussed in lecture, you could paste the following into the Visualizer:

def circle_area(diam):
    radius = diam / 2
    area = 3.14159 * (radius**2)
    return area

test = circle_area(10)
print('test is', test)


Problem 2: Tracing program execution

10 points; individual-only

Try to do this part before class!

Create a new text file called ps2pr2.txt, and save your work in this program into that file.

  1. Consider the following Python program:

    x = 11
    y = 5
    x = x + 6
    z = y + x
    x = x // 7
    y = z % 3
    

    Copy the table shown below into your text file for this problem, and fill in the missing values to illustrate how the values of the variables change over the course of the program. We’ve given you the values of the variables after the first two lines of code. You should complete the remaining rows of the table.

    line of code   | x  | y  | z  |
    --------------------------------
    x = 11         | 11 |    |    |
    y = 5          | 11 | 5  |    |   
    x = x + 6      |    |    |    |
    z = y + x      |    |    |    |
    x = x // 7     |    |    |    |
    y = z % 3      |    |    |    |
    
  2. Consider the following Python program:

    def foo(a, b):
        b = b - 2
        a = a - b
        print('foo', a, b)
        return a
    
    a = 7
    b = 4
    a = foo(a, b)
    print(a, b)
    foo(b, a)
    print(a, b)
    

    Trace the execution of this program. Your answer should include:

    • a table for the variables in the global scope that illustrates how their values change over time. You can begin it as follows:

        a  |  b
      -----------
        7  |  4
      
    • one or more separate tables that illustrate the changes in the local variables that belong to the function foo; you can either use a different table for each function call, or one table for the function as a whole

    • a separate section that specifies the output of the program (i.e., the values that are printed).


Problem 3: Tracing function calls

10 points; individual-only

Try to do this part before class!

Put your answers for this problem in a plain-text file named ps2pr3.txt.

  1. Consider the following Python program:

    def decide(a, b, c):
        if a <= c:
            if b > c:
                a = a * 3
            else:
                b = b + 4
        elif b >= c:
            if b == a:
                c = c + 2
            else:
                a = a + 3
        b = b * 5
        print('decide', a, b, c)
        return b
    
    a = 1
    b = 3
    c = 2
    decide(a, b, c)
    print(a, b, c)
    c = decide(b, a, a)
    print(a, b, c)
    

    Trace the execution of this program. Your answer should include:

    • a table for the variables in the global scope that illustrates how their values change over time. You can begin it as follows:

        a  |  b  |  c 
      -----------------
        1  |  3  |  2
      
    • one or more separate tables that illustrate the changes in the local variables that belong to the function; you can either use a different table for each function call, or one table for the function as a whole

    • a separate section that specifies the output of the program (i.e., the values that are printed).

  2. Consider the following Python program:

    def foo(a):
        b = bar(a) + bar(a - 2)
        print('foo:', a, b)
        return b
    
    def bar(b):
        a = b * 2
        print('bar:', a, b)
        return a
    
    a = 3
    b = 2
    bar(b)
    print(a, b)
    a = foo(a)
    print(a, b)
    

    Trace the execution of this program. Your answer should include the same components specified above for the first part of the problem. Make sure to include separate tables for each function.

Problem 4: Functions with numeric inputs, part II

5 points; pair-optional
See the rules for working with a partner on pair-optional problems for details about how this type of collaboration must be structured.

This problem involves more practice in writing functions.

In IDLE, use the File -> New Window menu option to open a new editor window for your program, and save it using the the name ps2pr4.py. Make sure to specify the .py extension.

  1. Write a function compare(num1, num2) that takes two numeric inputs num1 and num2 and returns a value that is based on how the numbers compare. More specifically, it should:

    • return 1 if num1 is greater than num2

    • return -1 if num1 is less than num2

    • return 0 if num1 is equal to num2

    Here are some examples of how it should work:

    >>> compare(5, 2)     
    1
    >>> compare(2, 5)     
    -1
    >>> print(compare(2, 2))
    0
    

Problem 5: Functions on strings and lists, part I

25 points; individual-only

This problem involves more practice in writing functions.

In IDLE, use the File -> New Window menu option to open a new editor window for your program, and save it using the the name ps2pr5.py. Make sure to specify the .py extension.

Include comments at the top of the file that are similar to the ones that we gave you at the top of ps2pr1.py.

Follow the same guidelines that we gave you for problem set 1.

  1. Write a function front3(s) that takes an input string s and follows the specifications given in the problem of that name on the CodingBat website. Here is a screenshot of the problem:

    CodingBat

    Write this function in your ps2pr5.py file. In addition, we encourage you to try entering your function into the CodingBat website, because it will test your function for you. (Note: You may need to remove your docstring when testing the function on CodingBat.)

    In general, CodingBat is a great way to reinforce what you have learned. If you would like some additional practice on the material that we’ve covered thus far, you can find some (entirely optional!) additional problems here.

  2. Write a function reverse(values) that takes a list values and returns a new list in which the elements from values have been reversed. Here are some examples:

    >>> reverse([1, 2, 3, 4])
    [4, 3, 2, 1]
    >>> reverse(['hello', 'world'])
    ['world', 'hello']
    >>> print(reverse([0, 5, 10]))
    [10, 5, 0]
    

    Hint: Use skip-slicing!

    Warning

    Remember that your functions should return the correct value rather than printing it. If your function is printing the return value, you will see the word None as part of the output for the last test above. If you are seeing None in your output, you must fix your function so that it uses a return statement rather than a print statement. This same warning applies to all of the functions that you will write for this assignment.

    Remember that you should not use Python features that we have not discussed in lecture. In particular, you should not use the built-in Python reverse method!

  3. Write a function ends_with(word, suffix) that takes as inputs two string values word and suffix, and that returns True if the string word ends with the string suffix, and False otherwise. For example:

    >>> ends_with('computer', 'ter')
    True
    >>> ends_with('computer', 'tar')
    False
    >>> ends_with('begin', 'in')
    True
    >>> print(ends_with('begin', 'on'))
    False
    

    Warning

    Your function should return a boolean value – either True or False, without any quotes around them.

    Remember that you should not use Python features that we have not discussed in lecture. In particular, you should not use the built-in Python endswith method!

    Hint: Begin by computing the length of suffix and storing it in an appropriately named variable. Then use that variable as part of a test to determine if word ends with suffix.

  4. Write a function has_vowel(s) that takes as input a string s and returns True if s contains at least one vowel (a, e, i, o, or u), and False otherwise. For example:

    >>> has_vowel('computer')
    True
    >>> print(has_vowel('wxyz'))
    False
    

    You may assume that s contains only lower-case letters, which means that you do not need to worry about upper-case vowels like A or E.

    Hint: Use the in operator, which allows you to test for the presence of one string in another. For example:

    >>> word = 'python'
    >>> 't' in word          # 'python' does have a 't'
    True
    >>> 'b' in word          # 'python' does not have a 'b'
    False
    

Don’t forget to test your functions using the approaches mentioned at the start of Problem 3. You may also find it helpful to use the Python Tutor visualizer to trace through the execution of your functions, as described at the end of Problem 3.


Problem 6: Functions on strings and lists, part II

25 points; individual-only

This problem involves more practice in writing functions.

In IDLE, use the File -> New Window menu option to open a new editor window for your program, and save it using the the name ps2pr6.py. Make sure to specify the .py extension.

Follow the same guidelines that we gave you for problem 5.

  1. Write a function mirror(s) that takes as input a string s and returns a mirrored version of s that is twice the length of the original string. For example:

    >>> mirror('bacon')
    'baconnocab'
    >>> print(mirror('XYZ'))
    XYZZYX
    

    Hint: Use skip-slicing!

  2. Write a function front_back(values) that takes a list values as input and returns a new list in which the first and last elements of the original list have been exchanged. For example:

    >>> front_back([0, 2, 4, 6, 8])
    [8, 2, 4, 6, 0]
    >>> print(front_back(['a', 'b', 'c', 'd']))
    ['d', 'b', 'c', 'a']
    

    Note that you will need a special case for lists with fewer than two elements, since those lists should be left unchanged:

    >>> front_back([1])
    [1]
    
  3. Write a function replace_prefix(word, n, prefix) that takes as inputs a string word, an integer n, and a string prefix, and that returns a string in which the first n characters of word have been replaced by prefix. For example:

    >>> replace_prefix('undo', 2, 're')     
    'redo'
    

    In the above example, the second input is 2, so we replace the first 2 characters of 'undo' with 're'. Note, however, that the number of characters in the new prefix does not need to be the same as the number of characters being replaced:

    >>> replace_prefix('protagonist', 3, 'an')
    'antagonist'
    >>> print(replace_prefix('autocrat', 4, 'techno'))
    technocrat
    

    Special case: If n (the second input) is larger than the length of word (the first input), then the function should simply return the original word without changing it:

    >>> replace_prefix('undo', 5, 're')    # 5 > len('undo')
    'undo'
    

    Warning

    Remember that you should not use Python features that we have not discussed in lecture. In particular, you should not use the built-in Python replace method!

  4. Write a function swap_halves(s) that takes a string input s and returns a string whose first half is s‘s second half and whose second half is s‘s first half. If len(s) (the length of s) is odd, the first half of the input string should have one fewer character than the second half, and thus the second half of the output string will be one character shorter in such cases. For example:

    >>> swap_halves('homework')
    'workhome'
    >>> print(swap_halves('carpets'))
    petscar
    

    Hint: We strongly recommend computing len(s)//2 (using the integer-division operator //) and storing the result in an appropriately named variable. You will need to use that value twice in your function, and using the variable in both places with save you from recomputing it.

Don’t forget to test your functions using the approaches mentioned at the start of Problem 2. You may also find it helpful to use the Python Tutor Visualizer to trace through the execution of your functions, as described at the end of Problem 2.


Submitting Your Work

You should use Apollo to submit the following files:

Warnings

  • Make sure to use these exact file names, or Apollo will not accept your files. If Apollo reports that a file does not have the correct name, you should rename the file using the name listed in the assignment or on the Apollo upload page.

  • If you make any last-minute changes to one of your Python files (e.g., adding additional comments), you should run the file in IDLE after you make the changes to ensure that it still runs correctly. Even seemingly minor changes can cause your code to become unrunnable.

  • If you submit an unrunnable file, Apollo will accept your file, but it will print a warning message. If time permits, you are strongly encouraged to fix your file and resubmit. Otherwise, your code will fail most if not all of our tests.

Here are the steps:

  1. Login to Apollo, using the link in the left-hand navigation bar. You will need to use your Kerberos user name and password.
  2. Find the appropriate problem set section on the main page and click “Upload files”.
  3. For each file that you want to submit, find the matching upload section for the file. Make sure that you use the right section for each file. You may upload any number of files at a time.
  4. Click the “Upload” button at the bottom of the page.
  5. Review the upload results. If Apollo reports any issues, return to the upload page by clicking the link at the top of the results page, and try the upload again, per Apollo’s advice.
  6. Once all of your files have been successfully uploaded, return to the upload page by clicking the link at the top of the results page. The upload page will show you when you uploaded each file, and it will give you a way to view or download the uploaded file. Click on the link for each file so that you can ensure that you submitted the correct file.

Warning

Apollo will automatically close submissions for a given file when its final deadline has passed. We will not accept any file after Apollo has disabled its upload form, so please check your submission carefully following the instructions above.

Note: If you encounter problems with Apollo, close your browser and try again. If possible, you may also want to wait an hour or two before retrying. If you are unable to submit and it is close to the deadline, email your homework before the deadline to cs111-staff@cs.bu.edu.