*Written by Juliette Woodrow, Brahm Capoor, Parth Sarin, And Zheng Lian*

If you'd like to try your solutions in PyCharm, download a starter project to import here. We've included some doctests for you to test with, but you should also add more.

## Questions About Doctests

In class this week, we discussed *doctests*: ways of specifying the
expected output of a function on certain parameters, which provide a
convenient way of testing our functions as we write them. Doctests are
an incredibly effective tool for programmers, but require careful
consideration as we write them. As you go through the quarter, you'll
develop a stronger sense of how to test your code, but it's never to
early to start thinking about it. While you go through your section
problems, consider adding doctests to ensure your code handles all
inputs properly.

**Syntax for Doctests**:

```
>>> name_of_function(param1, param2)
'output of function goes here'
```

As shown above, the syntax is three greater than signs followed by a space and then the name of the function and the specific parameters you want to test. On the next line you put the output you expect from those parameters. To run a doctest, right click on the greater than signs and hit "Run 'Doctest name_of_function'".

## Opening the Black Box

In this program, you will tackle a series of problems intended to increase your familiarity with parameters and return statements. Implement the following functions and include at least one doc test per function:

`def in_range(n, low, high)`

, which takes in three integer parameters and returns True if n is between low and high (inclusive of both ends of the range) and False otherwise.`def is_even(n)`

, which takes in an integer parameter n and returns True if n is even and False. You may wish to use the % operator, which returns the remainder when dividing one number by the other. For instance, 7 % 3 evaluates to 1, since the remainder when dividing 7 by 3 is 1.- Note: to solve this problem you will need to use the % operator,
known as the mod operator. Check out the modulus section of the
Python
reader.
Mod will
**not**be on the first quiz.

- Note: to solve this problem you will need to use the % operator,
known as the mod operator. Check out the modulus section of the
Python
reader.
Mod will
`def only_one_even(num1, num2)`

, which takes in two integer parameters and returns True if and only if exactly one of them is even.**(challenge)**def is_prime(n), which takes in an integer parameter n and returns True if n is prime and False otherwise. As a reminder, a prime number is a number which has no factors other than 1 and itself.

```
def in_range(n, low, high):
if n >= low and n <= high:
return True
return False
def is_even(n):
if n % 2 == 0:
return True
return False
def only_one_even(num1, num2):
if (num1 % 2 == 0 and num2 % 2 == 1) or (num1 % 2 == 1 and num2 % 2 == 0):
return True
return False
def longer_str(str1, str2):
if len(str1) > len(str2):
return str1
return str2
def is_phone_number(str1):
if not str1.isdigit():
return False
if len(str1) != 9 and len(str1) != 10:
return False
return True
def is_prime(n):
# Note that there are more efficient solutions to this problem!
if n <= 1:
return False
for i in range(2, n):
if n % i == 0:
return False
return True
```

## Playing with Strings

#### Remove All Occurrences

Write the following function: def remove_all_occurrences(s, to_remove) which removes all occurences of the length-one string to_remove from the string s. Do not use the replace function, instead build up a new string. Here are some sample inputs and outputs for this function:

```
>>> remove_all_occurrences('This is a test', 't')
'This is a es'
>>> remove_all_occurrence('----O----', '-')
'O'
```

#### Palindrome Checker

Write the following function: def is_palindrome(s) which returns True if s is a palindrome and False otherwise.

We say that a word is a *palindrome* if it reads the same forwards as
backwards. For example, "Abba" is a palindrome because it is the same
word read forwards and backwards. Here are some more examples:

- racecar
- kayak
- mr owl ate my metal worm

Here are some examples of Palindromes in other languages:

- حلب قلعة تحت تعلق ب (Dates hang underneath a castle in Halab)
- 여보, 안경 안보여 (Honey, I can't see my glasses)
- कड़क (a loud thunderous sound)

Here are some sample inputs and outputs for this function:

```
>>> is_palindrome('juliette')
False
>>> is_palindrome('maps spam')
True
>>> is_palindrome('Maps spam')
False # uppercase 'M' and lowercase 'm' are not the same character
```

#### Exclaim

Juliette loves to type text messages with lots of punctuation. She's very enthusiastic, so she'll often repeat the exclamation a bunch... Here's one of her recent text conversations:

```
Juliette: "Did you see Amanda Gorman at the inauguration?!?!?!?!"
"Yes, her poem was great. Did you like it?"
Juliette: "It was wicked cool!!!"
"Agreed! And she is only 22. What will you have accomplished by the age of 22?"
Juliette: "......."
```

Juliette is getting tired of repeating the punctuation so much. Help her out by writing a Python function that does it for her! The function should accept a message, msg, the ending punctuation, end, and the number of times to repeat the punctuation, n. The function definition looks as follows: def excalim(msg, end, n) The function should print out the resulting message to the terminal, so Juliette can copy it and paste it into her text messages. For example, calling exclaim('Did you see Amanda Gorman at the inauguration', '?!', 6) would print Did you see Amanda Gorman at the inauguration?!?!?!?!?!?! and calling exclaim('106A is awesome', '!', 5) would print 106A is awesome!!!!!.

```
def remove_all_occurrences(s, to_remove):
result = ''
for i in range(len(s)):
if s[i] != to_remove:
reuslt += s[i]
return result
def is_palindrome(s):
result = ''
# This is not the most efficient way. Can you think of a better one?
for i in range(len(s)):
if s[i] != s[len(s) - i - 1]
return False
return True
def exclaim(msg, end, n):
"""
Prints out the message with an exclamatory
ending which is printed n number of times.
Arguments:
msg -- The message to print out.
end -- The exclamation to add to the end of the message.
n -- The number of times to print the exclamation.
"""
output = msg
for i in range(n):
output += end
print(output)
```

## Grids

Bubble Up

*This is straight from an old CS106A midterm :) Grids will not be on
the first quiz.*

Suppose there is a grid where every square is either a bubble 'b',
rock 'r', or empty None. Write code for a `bubble_up(grid, y)`

function
that tries to move every bubble in a row up one square as follows: given
a grid and an in-bounds y value. Look at every square with that y. If
the square contains a bubble 'b', and the square above it is empty,
move the bubble up one square, changing its original square to be empty.

Here is an example run of `bubble_up(grid, y)`

for the row y=1 in Doctest
format:

```
>>> grid = Grid.build([[None, 'r', 'b'], ['b', 'b', 'b']])
>>> bubble_up(grid, 1)
[['b', 'r', 'b'], [None, 'b', 'b']]
```

```
def bubble_up(grid, x, y):
"""
>>> can_bubble_up(grid, 0, 1)
True
>>> can_bubble_up(grid, 0, 0)
False
>>> can_bubble_up(grid, 2, 1)
False
"""
# check if the square is a bubble
if grid.get(x, y) != 'b':
return False
# check if the square above it is in bounds and empty
if not grid.in_bounds(x, y-1) or grid.get(x, y-1) != None:
return False
# we know it can be bubbled up if we have made it here
return True
```