In [ ]:

```
from __future__ import division, print_function
```

For what **value** of `x`

will the following code segment print `"yes"`

? Modify these lines to make this happen.

In [1]:

```
def printX(x):
if x == 5:
print("yes")
printX(1) # Modify this line to make this happen! e.g. what happens if you try printX(2), printX(3), etc..
```

What do you expect the following calls to *print*?

```
def foo():
if -10 == 10:
print('Hello world!')
else:
print('Goodbye world!')
foo()
```

In [ ]:

```
# Write your answer here!
```

How can you **verify** your solution using the **code** above?

In [2]:

```
# Write code here to verify!
```

```
def bar():
if -10 < 10:
print('Hello world!')
else:
print('Goodbye world!')
bar()
```

In [ ]:

```
# Write your answer here!
```

How can you **verify** your solution using the **code** above?

In [3]:

```
# Write code here to verify!
```

```
def foobar():
if -10 != 10:
print('Hello world!')
else:
print('Goodbye world!')
foobar()
```

In [ ]:

```
# Write your answer here!
```

How can you **verify** your solution using the **code** above?

In [ ]:

```
# Write code here to verify!
```

For what **value** of `x`

would this function print `"five"`

? `"six"`

? `"other"`

?

In [ ]:

```
def printX(x):
if x == 5:
print("five")
elif x == 6:
print("six")
else:
print("other")
printX(1) # Modify this line
# answer "five"
# answer "six"
# answer "other" Note: Are there many ways to get `"other"` or only one way?
```

We will present **incorrect functions** that takes an **integer test score between 0 and 100 as an input**, and **prints** the corresponding **letter grade**. You will be asked to fix the errors in the code.

(This process of finding and fixing the errors is called debugging.)

Here are the cutoffs:

```
90-100 A
80-89 B
70-79 C
60-69 D
0-60 F
```

Warmup: Daniel has gotten score 75 on an exam. What **letter grade** (from A to F) does this correspond to?

In [4]:

```
# Write your answer from A to F here
```

A student tried to write the code for this. Here is their attempt:

In [23]:

```
def printGradeIncomplete(x):
if x >= 90:
print("A")
elif x >= 80:
print("B")
elif x >= 70:
print("C")
elif x >= 60:
print("D")
```

This code, however, is **incomplete**. Can you see why?
What happens if a student gets 55? **Modify** the code above (**add** an `else`

statement to the `printGradeIncomplete`

function) to take care of this case.

Another student tries to code a different method. This however, is also **incorrect**.

In [23]:

```
def printGradeIncorrect(x):
if x >= 60:
print("D")
elif x >= 70:
print("C")
elif x >= 80:
print("D")
elif x >= 90:
print("A")
else:
print("F")
```

Can you **spot the error** in the code above? For what **input scores** will this print the right letter?

In [6]:

```
# Use this box to call the function `printGradeIncorrect(x)` and see what happens.
```

Now the student thinks he's got it. This also **does not work** as expected though.

In [23]:

```
def printGradeIncorrect2(x):
if x >= 90:
print("A")
if x >= 80:
print("B")
if x >= 70:
print("C")
if x >= 60:
print("D")
else:
print("F")
```

Can you **spot the error** in the code above? Again, for what **input scores** will this print the right letter?

In [7]:

```
# Use this box to call the function `printGradeIncorrect2(x)` and see what happens.
```

**Modify** the code above (`printGradeIncorrect2`

function) to make it **correct**. Make sure it only prints one letter grade for each input and that it prints the correct letter grade.

How can you **verify** that your function is correct? Write some test cases to verify your solution.

In [9]:

```
# Write some tests cases here (e.g. `printGradeIncorrect2(55) == 'F'` and more...)
```

Different **ages** correspond to different **school** in Ethiopia. This shows these categories:

```
0 - 5 No School
6 - 13 Elementary School
14 - 18 High School
19 - 22 University
23 - 100 No School
```

Write a variable for Daniel that stores his age (an integer between 0 and 100).

Now **using this variable**, how would you write a **conditional** to check if Daniel is in **elementary** school? If this is `True`

, **print** the string `"Elementary School"`

.

In [11]:

```
# Write code here to verify if Daniel is in "Elementary School" using conditionals (`if`, `elif`, `else`)
```

Similar to above, how would you write a **conditional** to check if Daniel is in the `"No School"`

category? Make sure to verify both cases (`"Elementary School"`

and `"No School"`

) and if the age is in those ranges, **print** the string `"No School"`

.

In [6]:

```
# Write code here to verify if Daniel is in "Elementary School" or "No School" using conditionals (`if`, `elif`, `else`)
```

Write a **function** `isInSchool(age)`

where `age`

is an integer between 0 and 100, that either returns `"No School"`

if the person is not in school or `"School"`

if the person is in school.

In [12]:

```
# Write a function here to verify if someone is in "School" or "No School" using conditional (`if`, `elif`, `else`)
```

Now using the code pieces you just wrote and your knowledge of **conditionals**, write a function `scoolCategory(age)`

that will take in an **age** integer between 0 - 100 and **prints** the category of school they are in (string). Try to do this using **only one if statement**.

In [14]:

```
def schoolCategory(age):
# Complete the function here using the code from 5.1 to 5.3
return
```

Create a **list** storing five (5) different **integers**. Store this in a **variable** called `x`

.

In [15]:

```
# Create the list here
```

Using **list indexing** print the **first** and **last** values in the list. For the **last** value, do this two ways:

1) using `-1`

2) NOT using `-1`

In [16]:

```
# Write code to print the first value here
# Write code to print the last value for method 1 here (using -1)
# Write code to print the last value for method 2 here (NOT using -1)
```

Using **slicing** on list `x`

make another list `y`

containing the second to fourth elements inclusive. **Print** `y`

and **verify** it is in fact the correct slicing.

In [17]:

```
# Write code to make another list `y` here
```

**Change** the first value of `y`

to be `"hello"`

, **without** making a new list.

In [18]:

```
# Write code to change the first value here
```

Using the `len()`

function, print the **length** of `x`

and the **length** of the **first element** of `y`

(which should now be the string `"hello"`

).

In [21]:

```
# Write code here to print the lengths of `x` and the first element of `y`
```

Using code show that `x`

and the first element of `y`

are the **same lengths**.

In [22]:

```
# Write code here to show the lengths of `x` and the first element of `y` are the same
```

However, also using code and the `type`

function, show they are **not the same type**.

In [23]:

```
# Write code here to show the lengths of `x` and the first element of `y` are not the same type
```

Write a function `verifyInteger(x)`

that takes in an integer `x`

and **prints** if it is `"positive"`

, `"negative"`

or `"zero"`

.

In [24]:

```
# Define your function verifyInteger here
```

Write a f**unction** `listLen(l)`

that takes in a list `l`

and returns the **length** of the list if the list **is not empty**. If the input is the empty list, return `"this is empty"`

.

In [25]:

```
# Define your function listLen(l) here
```

Write a **function** `allEqual(l)`

that takes in a list `l`

and returns `True`

if all the elements in the list **are equal** and `False`

otherwise. You do not need for loops for this.
Hint: You can **multiply** lists with integers and you can **compare** two lists to check if they are equal.

```
allEqual([1,1,1]) == True
allEqual([]) == True
allEqual([1,2]) == False
allEqual(["salaam", "salaam"]) == True
```

In [26]:

```
# Define your function allEqual(l) here
```

You are given two **lists of strings** called `names`

and `cities`

. The **first person** in `names`

lives in the **last city** in `cities`

, the second person lives in the second to last city, the third lives in the third to last, and so on. Write code to create a third list called `inOrder`

such that the even indexes (0, 2, 4, etc.) are the names of the people (in order) and that the odd indexes (1, 3, 5, etc.) are the cities. For a person in index $i$, their corresponding city should be in index $i+1$.

For example:

```
names = ["Daniel", "Nati", "Jelani"]
cities = ["Cambridge","Addis Ababa", "San Fransisco"]
```

In this case,

```
- Daniel lives in San Francisco
- Nati lives in Addis Ababa
- Jelani lives Cambridge
```

You should create the final list:

```
inOrder = ["Daniel","San Fransisco", "Nati", "Addis Ababa", "Jelani", "Cambridge"]
```

In [28]:

```
names = ["Timnit", "Binam", "Basi"]
cities = ["Harar", "Addis Ababa", "Gondar"]
```

In [27]:

```
# Write code to create `inOrder` list from `names` and `cities` lists
```

Write a **function** `round(x)`

that takes in a number `x`

and returns the **rounded** version of that number.

For example, `round(1.2) = 1`

Similarly, `round(2.6) = 3`

In [29]:

```
# Write the function `round(x)` here
```

Write a **function** `addFractions(l0, l1)`

that takes in 2 lists `l0`

and `l1`

where each list represents a fractional number where the **first** number is the **numerator** and the **second** is the **denominator**.

For example, $[2,1] => \frac{2}{1} = 2$, (Numerator is 2, denominator is 1)

For example, $[3,4] => \frac{3}{4} $, (Numerator is 3, denominator is 4)

**We want to return the sum of these two fractions.**

For example, `addFractions([3,4], [2,3])`

should return `[17, 12]`

because $\frac{3}{4} + \frac{2}{3} = \frac{17}{12}$

In [30]:

```
# Write your `addFractions(l0, l1)` function here
```

Write a **function** `costToM(n, m, upcost, downcost)`

that takes in four (4) **integers**, `n`

, `m`

, `upcost`

, `downcost`

. We want to know the cost to make `n`

a **multiple** of `m`

.It costs amount `upcost`

for every **increment** ($+$) of 1 and costs amount `downcost`

for every **decrement** ($-$) of 1.

**Return** the **cheapest** cost to get from `n`

to a multiple of `m`

.

For example, `costToM(14, 5, 1, 1)`

should return 1 because you can get to 15 (a multiple of 5) with cost 1 and you can get to 10 (a multiple of 5) with cost 4.

`costToM(14, 5, 20, 1)`

should return 4 because you can get to 15 (a multiple of 5) with cost 20 and you can get to 10 (a multiple of 5) with cost 4.

In [31]:

```
# Write your function `costToM(n, m, upcost, downcost)` here
```

Write a **function** `calcArea(p0, p1)`

that takes in 2 points `p0`

, `p1`

where the first is the bottom left coordinate (x0, y0) and the second is the top right coordinate (x1, y1) of a rectangle. Return the area of the rectangle.

For example, `calcArea((1,1), (4,5))`

should return $4*3 = 12$.

In [32]:

```
# Write function `calcArea(p0, p1)` here
```

Write a **function** `overlappingRectangles(l1, r1, l2, r2)`

that takes in 4 points `l1`

, `r1`

, `l2`

, `r2`

. The first 2 points are the **bottom left** coordinate and **top right** coordinates of the **first rectangle**. The second 2 points are the **bottom left** and **top right** coordinates of the **second rectangle**. Return `True`

if the 2 different rectangles overlap.

For example, with the image below we would call the function with inputs as such: `overlappingRectangles((2,2), (7,3), (8,5), (9,7))`

, and since they do overlap, return `True`

.

In [33]:

```
# Write overlappingRectangles(l1, r1, l2, r2) function here!
```

Write a **function** `areaOverlap(l1, r1, l2, r2)`

to compute the **area** of the overlapping rectangles. If the rectangles do not overlap, return 0.

In [34]:

```
# Write areaOverlap(l1, r1, l2, r2) functiono here!
```