## Announcements

• Lab 6 available now, due Saturday night

• You will likely need to work on lab 6 in the CS labs (not remotely)

## Week 7 Topics

• Top-Down Design

• Bottom-Up Implementation

### Top Down Design

Top Down Design (TDD) is a problem solving technique where we:

• Break it into several high-level steps

• Iteratively break the steps into smaller steps until you have steps that are easier to solve

Top-down design is a lot like creating a paper outline for a large paper where you start with the main sections, and iteratively refine each part with more and more detail until you are ready to start writing the paper.

When you use top-down design, your resulting program’s structure will match the above idea of an outline: the main function should have calls to a few high-level functions, one for each high-level step; high-level functions have calls to unctions that implement sub-steps of the high-level step; and so on.

#### Iterative Refinement

When writing a large program, programmers use iterative refinement: do some top-down design, write function stubs for this part of code and maybe some implementation, then test. Iteratively, add more functions to accomplish subproblems, and perhaps refine some of the steps using top-down design, and test, and so on. The idea is to write some code, test it, then write a little more code, and test it before writing even more. Usually, I write a function, then test it, write another function, test it, …​ This way if I’m careful about testing, I know that if there is a bug in my program it is with the new code I’ve just added.

### Function Prototyping

We often use prototyping to just put in function stubs so we can test the whole program’s flow of control without having to have a full implementation. For example, here is a stub for a function to compute square root (it doesn’t actually do anything related to the task, but we can call it from other parts of our program to see if the program’s flow matches the design):

``````def squareRoot(num):
"""
This function computes the square root of a number.
num: the number
returns: the square root of num
"""

print("inside squareRoot")

# TODO: implement this function

return 1  # a bogus return value, but it let's me run the program
# and make calls to this function stub to "see" program flow

def main():

# a sample call to our function to see if it works
test = squareRoot(16)

# for now, the program doesn't crash, but returns an incorrect result
# of the correct type. We can now go back an refine our function
print("Answer is: %.2f " % (test))``````

### Let’s try it out…​

We are going to walk through the process of designing a computer game to simulate the dice game Craps. The rules for a single game are as follows:

1. A player rolls a pair of six-sided dice.

2. If the initial roll in step 1. is a 2, 3, or 12, the player loses.

3. If the initial roll in step 1. is a 7 or an 11, the player wins.

4. Otherwise, the player must roll for point. In this case, the player keeps rolling until she re-rolls the initial roll in step 1. (a winning game), or rolls a 7 (a losing game).

What are the chances of winning a single game of craps? Instead of heading to the casino, let’s use our Computer Science top down design skills to see if this is a good game to play. Our program should ask the user for the number of craps games to simulate and then output the percentage of games won.

Working with a partner, think about how you can design `main` to be very short, maybe 5-10 lines with calls to 2-3 helper functions. How would you design main? What would the input parameters and return values of your helper functions be? Do not worry about the implementation of the helper functions at this point. Your discussion should focus on the high level concepts, not the low level python details.

### File Input/Output

A file is a sequence of data that is stored on your computer. For many tasks, especially tasks that use large amounts of data, input data will come from one or more files, and you will write output to a file instead of to the screen.

A file is typically made of many lines. There is a special newline character that is stored at the end of each line in a file: `"\n"`. However, it is not visible when you look at the file.

Today, we’ll use a running example using a file named `bestInShow.txt`. We’ll also look at an example file, `colors.txt` that has a list of color names.

First, let’s look at these file in atom:

• `colors.txt`:

```Almond
Antique Brass
Apricot
Aquamarine
Asparagus
Atomic Tangerine
Banana Mania
Beaver
Bittersweet
Black
...```
• `bestInShow.txt`:

```2018,Whippet,Whiskey
2017,Brussels Griffon,Newton
2016,Greyhound,Gia
2015,Skye Terrier,Charlie
2014,Bloodhound,Nathan
2013,American Foxhound,Jewel
...```

In this file, data about each winner is stored on a separate line. Each line has the same format:

Year,Breed,Name

To open a file, the syntax is: `<filevar> = open(<filename>, <mode>)`

• `<filevar>` is what your program will call the file.

• `<filename>` is the name of the file, in this case `colors.txt` or `bestInShow.txt`.

• `<mode>` is how you plan to use the file. "r" is for reading, "w" is for writing.

To close a file, execute: `<filevar>.close()`

There are a couple of ways that you can read data from a file. Here is perhaps the simplest:

``````infile = open("myfile", "r")
for line in infile:
# process one line of the file
infile.close()``````

You can also read all the lines in at once (be careful using this with large files!):

``````infile = open("myfile", "r")
# lines is now a list of strings, one for each line of the file
for line in lines:
# process one line at a time
infile.close()``````

Let’s start by just trying to see the contents of the file:

``````infile = open("colors.txt", "r")
for line in infile:
print(line)
infile.close()``````

Is the output of this code snippet what you expected? How is it different than the input file?

The first thing you’ll probably want to do with a file is remove the newline character from the end of the line. You can do this with the `strip()` method.

For files with multiple pieces of data per line, you’ll want to break the line up into those individual pieces. Do this with the `split()` method. This will take a single string and return a list of "words" — it treats spaces like dividers for different pieces of data.

#### Common String methods for file I/O

• `line.strip()` — remove trailing whitespace (e.g., spaces, tabs `"\t"`, newlines `"\n"`)

• `line.split()` — treat line as a list of strings separated by whitespace. return that list

• `line.split(<pattern>)` — like `line.split()`, but treat as list of strings separated by `<pattern>`

#### List of lists

We’ve talked over the semester how a lists can contain any type of data. Lists can even contain other lists. Lists of lists are common with when doing file I/O. If each line is a list of data, then its common to store load the entire contents of the file in to a big list, where each element is itself a list representing data from one line of the file.

Let’s modify our `winners.py` program to store our information in a list of lists called `winners`:

Each winner is a list containing year, breed, and name.

winners = [ ['2018', 'Whippet', 'Whiskey'], ['2017', 'Brussels Griffon', 'Newton'], ['2016', 'Greyhound', 'Gia'], …​ ]

What would `winners[0]` evaluate to? What about `winners[1]`?

You can use double indexing to get at the data inside the winners list.

• winners[0][0] yields `2018`

• winners[0][1] yields `Whippet`

• winners[1][1] yields `Brussels Griffon`

Let’s go back to our program and modify it to store the winners information in a list of lists:

``````infile = open("bestInShow.txt", "r")
winners = []
for line in infile:
winner = line.strip().split(",")
winners.append(winner)
infile.close()
print(winners)
print("There are %d winners in the list." % (len(winners)))``````

## Week 08

### Working with lists of lists

Last week we saw how to read and parse a text file into a list of lists. With the data in a more python friendly format, we can use the list of lists to explore the data.

Let’s start by writing a function `get_winners(winners, breed)` that prints all the winners that match a specified breed. Work with a partner to design, implement and test your function. One thing you will need to think about is how to get access to the breed of each winner in the list of lists, preferably in a loop. If there are no winners of a particular breed, you should print a helpful message instead of printing nothing.

Since lists are mutable, we can update our list of lists structure inside python. Let’s write an `add_winner(winners, year, breed, name)` function that adds a new winner to our winners list. Work with a partner to answer the questions below before writing your solution.

1. Does `add_winner` need to return anything?

2. What are the types of the parameters for the `add_winner` function?

3. How is each winner stored in the `winners` list?

4. How will you use the input parameters provided to perform the task of adding a new winner?

5. How can you test your function after writing it?

### More robust error handling with try/except

Our solution so far to this program started with the `load_winners("bestInShow.txt")` function call and assumed that the file `bestInShow.txt` existed in the current directory. But what would happen if this were not the case? Try changing the filename in your program to `missing.txt` and run the program. What happens?

One possible solution to this problem is to check if a filename exists before attempting to open it. While this is possible in python3, it requires importing some extra libraries. Not a big deal, but it’s just more specific library details to learn. Another option is to use python’s built-in `try/except` mechanism to detect the error and handle it a bit more gracefully than we do now.

The general format for `try/except` is

``````try:
#code that may generate an exception goes here
except <ErrorNameType> as <VAR>:
#exception handling code goes here``````

an example might be

``````try:
myfile=open(fname, 'r')
except FileNotFoundError as e:
return [] # return an empty list``````

When python encounters a `try/except` block, it tries to executes the code in the `try` block. If nothing goes wrong, the code continues to run as normal. If an exception happens inside the try block, python will check if the the exception type matches the `ErrorNameType` and if it does, it will run the body of the `except` block.

### Writing Files

Time permitting.

In addition to reading from files, you can also write files with python. We need to be a little careful here, because python can potentially overwrite important data. Opening a file for writing is similar to opening for reading.

`output = open("savedWinners.txt", 'w')`

We simply change the second parameter from `r` to `w`.

To write to a file, use the `write()` method to write a string to the file. Python does not automatically add a newline, so you usually need to add this manually.

Remember to close the file at the end of writing with the `close()` method.