# Homework 6: For Loops¶

## Objectives¶

The goal of this assignment is to gain experience working with:

• for loops:
• Iterating over a collection
• Iterating over a range of integers

Submissions Limited

For HW6, you may submit each exercise up to 20 times. Before you submit to Gradescope, make sure that you:

1. Test your code, either in the shell or in the __main__ block.
2. Run !flake8, and resolve all PEP 8 and docstring issues.

Don't Use while

This homework is about for loops. Be sure not to use while loops (which we'll learn about next week) in any of the exercises. No while loops are permitted in this homework.

For this exercise you will write a function to help with generating street addresses in new housing developments. Create a file named addressing.py with a single function named generate_addresses. This function must take four arguments:

1. The name of the street
3. The upper bound of numerical address values (exclusive)
4. The interval between numerical addresses

The function must return a list of street addresses formatted with the number of the address, followed by a single space, followed by the name of the street. For example:

>>> print(generate_addresses('Carrier Drive', 1000, 1030, 10))
['1000 Carrier Drive', '1010 Carrier Drive', '1020 Carrier Drive']


## Exercise 6.2 Intervals¶

For this exercise, you will write a function that takes a list of floats and returns a new list containing only the numbers from that list that are within a designated interval. The file must be named interval.py and it must contain a single function named in_interval with four parameters:

• The first is a list of floats.
• The second is the lower bound of the interval.
• The third is the upper bound of the interval.
• The fourth is a Boolean indicating whether this is a closed interval. This parameter should have a default value of True indicating that the interval is closed.

The numbers in the returned list must be in the same order as they appeared in the original list. You may assume that the provided lower and upper values represent a valid interval.

Here are some examples illustrating the expected behavior:

>>> in_interval([20.1, 0.0, 2.5, 1.4, -6.0], 0.0, 5.0)   # Default is closed
[0.0, 2.5, 1.4]
>>> in_interval([20.1, 0.0, 2.5, 1.4, -6.0], 0.0, 5.0, False)
[2.5, 1.4]


## Exercise 6.3 Shift Cipher¶

One of the simplest forms of encryption is the Caesar Cipher, also known as a shift cipher. In this technique, each letter in the plaintext is replaced by a letter a fixed distance away in the alphabet, wrapping around at the end (or beginning) as necessary.

Shift cipher example

For example, if you encoded 'dog' by shifting two to the right, 'd' would be replaced by 'f', 'o' would be replaced by 'q', and 'g' would be replaced by 'i', so the final encoded text would be 'fqi'. 'zoo' would be encoded as 'bqq', because the 'z' would wrap around to the beginning of the alphabet again.

Create program called shift_cipher.py containing the function encode. The function should take as parameters the text to encode (in all lower case), and the number of letters to shift (guaranteed to be between -26 and 26). It should return the encoded text, and leave spaces and punctuation as-is, without changing them.

Hint: You will need to use ord() and chr() to convert letters to numbers and back again in order to shift them. You should also use the modulo operator (%), although you do not have to.

>>> print(encode("the quick brown fox.", 4))
xli uymgo fvsar jsb.


## Exercise 6.4 Count Rivers¶

It is useful to be able to find out what words you can make with a collection of letters, using each letter no more than once: for example, for playing scrabble or for creating a note by cutting out letters from a newspaper. In this problem, you will solve something similar.

Create a file called river.py and write a function called count_rivers which takes a str parameter letters and returns the number of times the word "river" can be formed from the letters in letters, using each letter at most once. You may assume that the letters in the letters parameter are lowercase.

Here are some examples. Notice in the second example, there are not enough r characters to make the word river twice.

>>> print(count_rivers("rrrriive dddddddddddive lllllllive"))
2
>>> print(count_rivers("rrriivedddddddddddive -- lllllllive"))
1

You must use a loop to solve this problem. No use of the count method or the Counter collection is permitted.

Hint: Consider using a dict to help you keep track of the number of letters.

## Exercise 6.5 Parking Lot¶

There's a major event happening at the fairgrounds, and cars are lining up from everywhere. We need a program to help vehicles find a parking space when they arrive. Since parking is limited, and not all of the spaces are the same size, we need to be careful to put smaller vehicles in the smaller spots so that we can save the larger spots for vehicles that need them.

For the sake of simplicity both cars and parking spots will be represented as a tuple which contains the width of the car/spot followed by the length of the car/spot. Define a function named best_fit in parking.py with the following arguments:

• a tuple representing the car that is trying to park
• a list of tuples representing the available parking spots

In order to fit in a parking spot, there must be at least 2 feet of space around all sides of the car when parked. This will allow people to safely enter and exit their cars, walk around the vehicles and load and unload items. The image below shows a car with tuple (6, 10) that exactly fits in a parking spot with tuple (10, 14), due to the 2 feet of space in all directions.

The function should return the position in the list of the parking spot which best fits this car, i.e. the spot with the least amount of total excess space around the car. In the case of ties, the spot with the larger index should be selected. If there is no spot that can accommodate the car, then the function must return None.

Here are some examples:

>>> print(best_fit((3, 4), [(5, 5), (10, 12), (7, 8), (7, 9), (8, 8)]))
2
>>> print(best_fit((3, 4), [(5, 5), (10, 12), (3, 4), (7, 9), (8, 8)]))
3
>>> print(best_fit((3, 4), [(5, 5), (10, 12), (3, 4), (7, 9), (7, 9)]))
4
>>> print(best_fit((9, 12), [(5, 5), (10, 12), (3, 4), (7, 9), (7, 9)]))
None