In the Explorations so far, you have used two different styles of program design. In Exploration #2, when you were experimenting with different angles to find the one needed to draw a "perfect" polygon, you were using what is called "bottom up" design. You didn't know ahead of time exactly what you needed to do, so you tried different angles until you found the right one to use. Bottom up design is a trial-and-error, exploratory approach to writing a computer program. In Exploration #4 you were using what is called "top down" design. You knew ahead of time that you would first write a superprocedure that asked the user for input values, then you would write a subprocedure to draw a design based upon this information, and that you would use the poly procedure that you had already written as a subprocedure to do the actual drawing. You know that both the do.design procedure and the poly procedure would use the Total Turtle Trip Theorem to ensure that the petals were properly drawn and that they were spaced evenly in the design. You could turn to the flip side and write the three procedures, knowing ahead of time what the effect of executing design would be.
When planning procedures to solve original problems, programmers usually use a combination of these two approaches, what you might call a "middle out" style. They begin by organizing the pattern of superprocedures and subprocedures they think they will need, but they allow for experimentation and trial-and-error when it comes to creating each of the individual subprocedures. Some Logo programmers lean more toward bottom-up design, others more toward top-design design. There is no "right way." What is important is that the finished program be easily readable by the Interpreter and by others with whom you share your work. The snowperson procedure that follows is a good example of how "middle out" program design proceeds.
I began with a general idea of the complete picture I wished to draw. I sketched a snowperson with a big round body, a smaller round head on top of the body, and three round buttons down the front of the body. Next, I divided the program up into parts and chose what I thought was a logical order in which to draw each part. Then I wrote a top-level procedure that called a series of subprocedures, each of which creates one part of the drawing. My top-level procedure looked like this:
TO SNOWPERSONNext, I thought about the subprocedures, one by one. Since they all involve circles of different sizes, I thought it would be a good idea to have each subprocedure call a circle subprocedure to do the actual drawing. I planned that circle would have a local variable, :SIZE, and that each subprocedure could provide circle with an appropriate :SIZE value to use. body would provide circle with the largest number as input, head would give it a smaller number, and buttons would give it a very small number. I was confident from my explorations in Unit #2 that I knew how to write a circle procedure with an input variable that drew in a clockwise direction. Just to be sure, I wrote a circle :SIZE procedure and tested it out with various values for the variable.
My next concern was with the spatial relationships among the three parts of the snowperson. I wanted the head centered above the body and the buttons spaced evenly down the front of the body. I thought it would be a good idea if the turtle started and ended her drawing of each part at the same place in the picture, so I could keep track of where she was in case I wanted to change something or add more features to the drawing later on. After some thinking and experimenting with my paper-and-pencil sketch, I decided that it would be best to start the turtle at the snowperson's neck and return her there after drawing the body, the head and the buttons.
Without worrying yet about the buttons, I wrote procedures to draw the body and the head. Since I didn't know ahead of time what values to use for the :SIZE variable, I experimented with different numbers that I thought would be reasonable. I knew from my pencil-and-paper experimenting that the turtle would have to be pointing East before starting to draw the body and West before starting to draw the head, so that the same clockwise circle procedure could be used and so that these parts would be lined up below and above the snowperson's neck. I thought it would be helpful to use a new setheading (abbreviated seth) command to position the turtle before starting to draw. seth points the turtle to a particular point of the compass, regardless of the direction in which she was previously pointing.
A look at a compass showed me that East is a 90-degree heading and West is a 270-degree heading. I wrote these body and head subprocedures on the flip side of the page, along with the snowperson procedure that was already there:
TO CIRCLE :SIZE
repeat 30 [fd :size rt 360 / 30]
I tested them by typing snowperson in the command center. The Interpreter ran these parts of the program. When it reached the buttons subprocedure, the Interpreter returned an error message because I had not yet defined buttons. I expected this to happen; I knew I would get to buttons in due course. But first, I needed to adjust the body and head sizes, which were obviously too big. So I returned to the flip side and edited body and head by assigning smaller values for the :SIZE variable.
Eventually I decided that a body size of 10 and a head size of 6 fit pretty well on the page. I also found that I needed to start the turtle a bit lower in order to move the snowperson to the bottom of the page, so I added a new line at the beginning of snowperson. One thing that surprised me was that the head and the body were not lined up exactly. The head was too far to the left (or the body was too far to the right ... or both!) I hadn't expected this bug. A close look at the circle procedure eventually showed me why this happens: when the turtle draws the body, she moves due East before turning for the first time, and when the turtle draws the head she moves due West before turning for the first time. So, naturally, the body is a bit too far East and head is a bit too far West.
I discovered that this effect could be minimized by changing the circle
procedure so that, instead of moving the entire :SIZE distance before turning,
the turtle moves only half the distance, turns, and then moves the other
half of :SIZE. This wasn't a perfect "fix," but it was close enough. It's
the sort of bug-fix that programmers call a "kluge" (rhymes with "scrooge".)
I made all these changes on the flip side of the page so that my program
looked like this:
TO CIRCLE :SIZENow I turned my attention to drawing the buttons. Since there are three of them, I decided to use the repeat primitive with inputs of 3 and an instruction list that would move the turtle down a little and then draw a circle. Since the turtle was back at the snowperson's neck after drawing the head, I thought she was in a good position to start this sequence; all I had to do was to point her in the right direction. I didn't occur to me at first that each button would have to be drawn starting at the top rather than the side in order to be centered, but my first trial (not included below) convinced me otherwise.
repeat 30 [fd :size / 2 rt 360 / 30 fd :size / 2]
After a good deal of experimenting with distances and sizes, here is the buttons procedure I finally decided on. You will notice that I returned the turtle to her home position at the snowperson's neck after drawing the buttons, in case I wanted to add more features to the drawing later on.
repeat 3 [pu fd 20 pd seth 90 circle 1 seth 180]
My final improvements were to add an ht command as the last instruction of snowperson (so the turtle wouldn't mess up the picture she had drawn with her own image) and a cg st instruction line at the beginning of snowperson (to be sure there was a clean page and so I could watch the turtle draw the picture.)
I have provided this discussion in order to give you the "feel" of how I went about solving the snowperson problem. I hope you were able to see how I combined top down and bottom up programming styles. I don't want you to think that this is the only way to solve this problem. Of course, it is not. I urge you to try your hand at another solution done your own way. I believe, however, that this "middle out" approach to tackling new programming projects is worth your considering.
Some people call this problem solving technique "guided discovery." The top down approach provides the guidance and structure; the bottom up approach provides the fun and excitement that result from making unexpected discoveries along the way.
1. Create a snowperson procedure that draws the head, body, and buttons as above and then adds features to the snowperson's face (or at least a nose!) You might also consider modifying the circle procedure to draw filled-in shapes.
2. Write a program that draws a whole row of snowpeople, side by side.
3. Do you remember the first drawing you did back in Unit #1? You printed HI on the screen. Try a "middle out" approach to this problem, using subprocedures for the vertical and horizontal lines and inputs to determine the height and width of the letters. If you are feeling brave, try changing it to HA.
4. Using a "middle out" approach, write a program that draws a simple house - a square for the walls and a triangle for the roof. If the spirit moves, add a door and windows ... and even a chimney!
5. Building upon the design procedure from Exploration #4, write a program that draws a flower - blossom, stem, and leaves.
6. Add instructions to snowperson that ask the user to choose
a size for the body procedure, thereby enabling you to draw different
sizes of snowpeople. What change will you make in the Title line of body?
What changes will you make in the Title lines of head and buttons?
How will you adjust the spacing of the buttons for different sizes of body?