Week 7: Top-Down Design

Class Recordings

To access recordings, sign in with your @swarthmore.edu account.

Monday

Section 1 (Joshua)

Section 2 (Kevin)

Wednesday

Section 1 (Joshua)

Section 2 (Kevin)

Friday

Section 1 (Joshua)

Section 2 (Kevin)

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

Monday

Memory Diagrams/Stack Traces for Objects

We will continue to use stack diagrams to trace through programs and understand how they work. This is an essential skill to being able to think computationally and write effective programs. In duplicate.py, we have a program that wants to create two circles, one red and one green, of the same size. The program does not work; work with a partner and trace through the program to see why.

Grid Coordinates: Tic-Tac-Toe Example

You may have noticed that the default coordinate system for the graphics library is a bit odd — it treats the top left corner as (0, 0), and positive offsets move to the right (x direction) and down (y direction). Since this format is different from what you’re likely used to from math courses, it probably feels unnatural. Fortunately, the graphics library gives us a way to change it: a window object has a setCoords() method.

The setCoords() method lets you redefine the number associated with the lower left and upper right corners of a graphics window. This is useful for two reasons:

  1. It lets you redefine the lower left corner to be (0, 0), which better matches intuition.

  2. It lets you redefine how the window is divided into a grid, which for some problems, makes it easier to reason about shape placement.

For example, consider a tic tac toe game board (3 x 3 grid). If you window dimensions aren’t divisible by 3, it would be a pain to divide it up into a 3x3 grid. The setCoords() method allows you redefine the window into exactly what you want — a 3x3 window.

Let’s walk through an example in tictactoe.py.

Functions and Objects

Objects interact with functions in same way as basic types (ints, floats, strings, and lists). This means that we can return graphics objects we create and also send them in as arguments/parameters.

Exercise: create rectangles and find the tallest

In createRectangles.py, we have a partially completed program. The end goal is to write a program that allows the user to draw rectangles of various sizes, finds the tallest one, and colors it in.

Complete the task in this order:

  1. Pair up and explain each line of the program as is. Ask a ninja if you are not sure what a part of the program is doing.

  2. Write a function to give a color to a rectangle, and call that function from main to change the rectangle’s color.

  3. Change the main function of the program to create multiple rectangles (e.g., 3), and save them in a list.

  4. Lastly, write a function to find the tallest rectangle and return it. In main, change the code to only color the tallest rectangle.

Wednesday

Top Down Design

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

  • Start with general description of problem

  • 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))

Friday

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.

Nested Loops

We’ve seen the classic for loop many times now:

for i in range(10):
    <LOOP BODY>

We know that the LOOP BODY can contain anything: print statements, calls to input(), if / else conditionals, and many other things. But what if we put another for loop inside the body of a loop?

Putting one loop in the body of another is called a nested loop, and it’s a common (and very helpful!) repetition pattern. Let’s look at some examples in nested.py.