CS 111
Summer 1 2020

Problem Set 2

due by 9:00 p.m. EDT on Saturday, May 23, 2020

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.

Important note regarding test cases and Gradescope:

  • You must 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, inside the if __name__ == '__main__' control struture. For example:

      if __name__ == '__main__':
      
          print("mystery(6,7) returned", mystery(6,7))
      

      These tests 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.

  • You must not leave any print statements in the global scope. This will cause an error with the Gradescope autograder. Make sure all of your print statements are inside a function scope or insude the if __name__ == '__main__' control struture.

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 convert_to_inches(yards, feet) that takes two numeric inputs yards and feet that together represent a single length broken up into yards and feet, and that returns the corresponding length in inches.

    For example:

    >>> convert_to_inches(4, 2)  # 4 yards + 2 feet = 168 inches
    168                        
    >>> print(convert_to_inches(1, 1))  # 1 yard + 1 foot = 48 inches
    48
    

    If either input is negative, it should be replaced with a 0 in your computation. For example:

    >>> convert_to_inches(-4, 2)  # replace -4 with 0, 2 feet = 24 inches
    24                         
    >>> convert_to_inches(3, -5)  # replace -5 with 0, 3 yards = 108 inches
    108
    

    Hints:

    • 1 foot is 12 inches, and 1 yard is 3 feet or 36 inches.

    • You should use conditional execution to handle cases in which an input is less than 0.

  4. Write a function area_sq_inches(height_yds, height_ft, width_yds, width_ft) that takes four numeric inputs:

    • height_yds and height_ft that together represent the height of a rectangle
    • width_yds and width_ft that together represent the width of a rectangle

    Based on these inputs, the function should return the area of the rectangle in square inches. In other words, it should:

    • determine the height of the rectangle in inches
    • determine the width of the rectangle in inches
    • return the product of those two values

    Examples:

    >>> area_sq_inches(1, 2, 3, 1)  # (1 yd, 2 ft) x (3 yds, 1 ft) = 7200 sq inches
    7200
    >>> print(area_sq_inches(2, 0, 1, 2))  # (2 yds, 0 ft) x (1 yd, 2 ft) = 4320 sq inches
    4320
    

    Notes:

    • We strongly encourage you to start by making two calls to the convert_to_inches function that you wrote earlier—one call to compute the height in inches, and one call to compute the width in inches–and store the results of those calls in variables. Then you can use those variables to compute the area.

    • If any of the inputs are negative, they should be replaced with a 0. However, if you are calling convert_to_inches, you can let that other function handle the replacements for you!

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: Program flow and variable scope

25 points; individual-only

Try to do this part before class!

Begin by downloading this text file: ps2pr2.txt. Edit this file, and save your work in this part 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 = 5
    b = 3
    print(a, b)
    a = foo(a, b)
    print(a, b)
    foo(b, a)
    print(a, b)
    

    In section 2-2 of ps2pr2, we have given you tables like the ones shown below:

    global variables (ones that belong to the global scope)
      a  |  b  
    -----------
      5  |  3     
         |
    
    local variables (ones that belong to foo)
      a  |  b  
    -----------
         |       
         |
    
    output (the lines printed by the program)
    ------
    5 3
    

    We have started the first and third tables for you. You should:

    • complete the first and second tables so that they illustrate how the values of the variables change over time
    • complete the third table so that it shows the output of the program (i.e., the values that are printed).

    You may not need all of the rows provided in the tables.

  3. Consider the following Python program:

    def wow(a):
        b = a * 2
        print('wow:', a, b)
        return b
    
    def yay(b):
        a = wow(b) + wow(b + 2)
        print('yay:', a, b)
        return a
    
    a = 4
    b = 3
    print(a, b)
    b = wow(b)
    print(a, b)
    yay(a)
    print(a, b)
    

    In section 2-3 of ps2pr2, we have given you tables like the ones shown below:

    global variables (ones that belong to the global scope)
      a  |  b  
    -----------
      4  |  3     
         |
    
    wow's local variables
      a  |  b  
    -----------
         |       
         |
    
    yay's local variables
      a  |  b  
    -----------
         |       
         |
    
    output (the lines printed by the program)
    ------
    4 3
    

    We have started the first and fourth tables for you. You should:

    • complete the first three tables so that they illustrate how the values of the variables change over time
    • complete the last table so that it shows the output of the program (i.e., the values that are printed).

    You may not need all of the rows provided in the tables.

Problem 3: Functions on strings and lists, part I

30 points; individual-only

In IDLE, use the File -> New File menu option to open a new editor window for your program, and save it using the the name ps2pr3.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 1.

  1. Write a function first_and_last(values) that takes a list values and returns a new list containing the first value of the original list followed by the last value of the original list. You may assume that the original list has at least one value.

    Although this function could be completed in one line, you must use the following template:

    def first_and_last(values):
        """ put your docstring here """
        first = ________ 
        last = ________
        return [first, last]
    

    Here are some examples of how the function should work:

    >>> first_and_last([1, 2, 3, 4])
    [1, 4]
    >>> first_and_last([7])        # 7 is both first and last!
    [7, 7]
    >>> print(first_and_last(['how', 'are', 'you?']))
    ['how', 'you?']
    

    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, with the exception of the optional test functions that you may include for testing your code.

  2. Write a function longer_len(s1, s2) that takes as inputs two string values s1 and s2, and that returns the length of the longer string. For example:

    >>> longer_len('computer', 'compute')
    8
    >>> longer_len('hi', 'hello')
    5
    >>> print(longer_len('begin', 'on'))
    5
    

    Your function must use conditional execution, and it should not use Python’s built-in max function. You may use other built-in functions as needed.

  3. Write a function move_to_end(s, n) that takes as inputs a string value s and an integer n, and that returns the a new string in which the first n characters of s have been moved to the end of the string. For example:

    >>> move_to_end('computer', 3)    # move 'com' after 'puter'
    'putercom'
    >>> move_to_end('computer', 5)    # move 'compu' after 'ter'
    'tercompu'
    >>> print(move_to_end('computer', 0))
    computer
    

    Special case: If n (the second input) is greater than or equal to the length of s (the first input), then the function should simply return the original s without changing it:

    >>> move_to_end('hi', 5)    # 5 > len('hi')
    'hi'
    

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 4: Functions on strings and lists, part II

20 points; individual-only

In IDLE, use the File -> New File 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.

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

  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 is_mirror(s) that takes as input a string s and returns True if s is a mirrored string (i.e., a string that could have been produced by your mirror function) and False otherwise. Examples:

    >>> is_mirror('baconnocab')
    True
    >>> print(is_mirror('baconnoca'))
    False
    

    Warning

    Your function should return a boolean value – either True or False, without any quotes around them. If you see quotes around the result when you make the first call above from the Shell, you must fix your function to remove the quotes.

    Hints:

    • You may find it helpful to compute the value len(s) // 2 as part of this function.
    • You may also find it helpful to call your previous mirror function, although doing so is not required.
  3. Write a function replace_end(values, new_end_vals) that takes as inputs a list values and another list new_end_vals, and that returns a new list in which the elements in new_end_vals have replaced the last n elements of the list values, where n is the length of new_end_vals. For example:

    >>> replace_end([1, 2, 3, 4, 5], [7, 8, 9])     
    [1, 2, 7, 8, 9]
    

    In the above example, the second input has a length of 3, so we replace the last 3 elements of the first input (the elements [3, 4, 5]) with the elements specified by the second input ([7, 8, 9]).

    Other examples:

    >>> replace_end([1, 2, 3, 4, 5], [10, 11])
    [1, 2, 3, 10, 11]
    >>> print(replace_end([1, 2, 3, 4, 5], [12]))
    [1, 2, 3, 4, 12]
    

    Special case: If the length of the second input is greater than or equal to the length of the first input, then the function should simply return the original second input:

    >>> replace_end([0, 2, 4, 6], [4, 3, 2, 1])
    [4, 3, 2, 1]
    >>> replace_end([0, 2, 4, 6], [4, 3, 2, 1, 0])
    [4, 3, 2, 1, 0]
    

    Hint: Begin by computing the length of new_end_vals and storing it in an appropriately named variable. Then use that variable in the rest of your code.

  4. Write a function repeat_elem(values, index, num_times) that takes as inputs a list values, an integer index (which you may assume is a valid index for one of the elements in values), and a positive integer num_times, and that returns a new list in which the element of values at position index has been repeated num_times times. For example:

    >>> repeat_elem([10, 11, 12, 13], 2, 4)   
    [10, 11, 12, 12, 12, 12, 13]
    

    In the above example, the second input is 2 and the third input is 4, so we take the element at position 2 of the list (the 12) and repeat it 4 times.

    Other examples:

    >>> repeat_elem([10, 11, 12, 13], 2, 6)    # repeat element 2 six times
    [10, 11, 12, 12, 12, 12, 12, 12, 13]
    >>> print(repeat_elem([5, 6, 7], 1, 3))    # repeat element 1 three times
    [5, 6, 6, 6, 7]
    

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.


Submitting Your Work

You should use Gradesope to submit the following files:

Warnings

  • Make sure to use these exact file names, or Gradescope will not accept your files. If Gradescope 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, Gradescope will accept your file, but it will not be able to auto-grade it. 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.

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.