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):
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 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], ))
[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.

You should use Gradesope to submit the following files:

• your modified `ps2pr1.py` file containing your solutions for Problem 1 if you worked with a partner, make sure that you each submit a copy of your joint work, and that you include comments at the top of the file specifying the name and email of your partner
• your `ps2pr2.txt` file containing your solutions for Problem 2
• your `ps2pr3.py` file containing your solutions for Problem 3
• your `ps2pr4.py` file containing your solutions for Problem 4

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`.