CS 161 Lab F - Turtle Loops

Due Fri Mar 6 at the start of class

Overview

In this lab, we'll be revisiting the Turtle class from Lab B and making more sophisticated drawings, all requiring loops!

This lab should be completed in pairs. You will need to find a different partner than you had for the last lab. Be sure to review the pair programming guidelines before you begin; remember to switch off who is driving and who is navigating!

Objectives

Necessary Files

You will need to download and extract the TurtleLoop BlueJ project from the TurtleLoop.zip file. This project includes Turtle class that you worked with before. You will need to create a pair of new classes as well.

You may want to refamiliarize yourself with the Turtle class described in Lab B. You can instantiate a Turtle on the workbench and call it's methods to play with it. You can also view the JavaDoc for the turtle by double-clicking on the class in BlueJ, or by looking at the bottom of the page.

Part 0: Drawer and Tester

For this lab, you'll be making two new Java classes: a TurtleDrawer that tells the Turtle how to draw, and a TurtleTester that you can use to call methods on the drawer. The first step (which you should not skip over) is to make these new classes

  1. Start by creating a new TurtleDrawer class with the following requirements:
    1. It has one attribute: a Turtle object that will do the drawing
    2. It has one constructor that takes in a single parameter: a Color object specifying the default color for the turtle's pen.
      • You will need to
        import java.awt.Color;
        so that you can use the Color class here. Put the import at the very top of the file (above the class comment).
      • The constructor should instantiate the Turtle attribute, assign the given color to the pen (check the JavaDoc for what method to use!), and lower the pen for drawing.
      • You should also use the setSpeed() method to set the turtle's speed to 0.9. This will help your drawings appear at a reasonable rate, so you don't spend too much time waiting! If that still isn't fast enough for you, you can try the max speed of 1.0.
  2. You could test that your constructor works by instantiating a new TurtleDrawer in BlueJ, but let's use the opportunity to get our tester setup instead. Create another new class TurtleTester that contains a single static method:
    public static void test()
  3. Inside this test() method, add code that instantiates a new TurtleDrawer object (not a Turtle, but a TurtleDrawer!). Hint: remember to use the new keyword to call the constructor that you just wrote!
    • You will need to pass your constructor a Color object. I recommend you use one of the constant colors defined in the Color class. Color.BLACK is a good default, but you can pick whatever color you want. Don't spend a lot of time making a custom color here!
    • Once again, you'll need to import the Color class.
  4. Now test that your program works by right-clicking on the TurtleTester class and selecting the test() method. Your Turtle progam should start!
    • Your "workflow" should involve writing a method in your TurtleDrawing class, and then adding code to your test() method that calls that method (using dot notation).
    • You can comment out old method calls when you start working on a new method, but don't delete the code (in case you want to test it again later!)

Part 1: Triangles

To practice with the testing workflow, let's add a quick and dirty method to the TurtleDrawing class.

  1. Add a method called drawTriangle. It takes in a sideLength (in int precision) as a parameter, and doesn't return anything.
  2. Make sure to add a method comment (preferably in JavaDoc format) for this method!
  3. This method should instruct the Turtle to to draw an equilateral triangle (i.e., one where all the sides are the same length):

    There are a couple of things to consider before you plunge into writing the code:

    • Notice that when the Turtle is first instantiated, it initially faces east.
    • Observe how the angles are all 60 degrees within an equilateral triangle. Once a side is drawn, you then want to turn your turtle left to prepare drawing the next side. But how many degrees do you need to turn?
    • Even better: Is there a relationship between the degrees-turn you always need to make and the number of sides in this shape (three)? Answering this now will makes your life easier later. (Hint: The turtle always faces the same direction before and after the polygon is drawn. How many degrees must it have turned during its traversal?)
    • Because a triangle is easy to draw, it may be tempting to write this method directly, like the code that's given below:
      public void drawTriangle(int sideLength)
      {
        intd turnDegrees = 120; //how much to turn left by at each corner
      
        //first edge
        turtle.forward(sideLength);
        turtle.left(turnDegrees);
      
        //second edge
        turtle.forward(sideLength);
        turtle.left(turnDegrees);
      
        //third edge
        turtle.forward(sideLength);
        turtle.left(turnDegrees);
      }
      This isn't very fun, but it does reveal the code's repetitive structure. The code segments for each of the edges are exactly the same. So instead of writing the same thing 3 times, put them in a loop that iterates exactly 3 times (hey, that's the number of sides for a this particular shape...).
  4. Your task is to write this method using a loop to replace the redundant, repetitve code segments. You can either use a while loop or a for loop (though since this is definite iteration, a for loop would be appropriate...). The following code gives examples of how to iterate n times (for a positive n):
    int i = 0;
    while (i < n)
    {
      //statements to repeat
      i++;
    }
    for (int i = 0; i < n; i++)
    {
      //statements to repeat
    }        
  5. Make sure and test your method by calling it from the TurtleTester. You can also check in with us when you're done to make sure everything looks right.
  6. If you haven't yet, this is a good time to switch drivers!

Part 2: Polygons and Refactoring

Triangles are cool and all, but your TurtleDrawer class should be made general. What we mean by general is that writing a method just to draw a single shape doesn't make a whole lot of sense. If we wrote new methods to draw 4-sided square, a 5-sided pentagon, a 6-sided hexagon, etc., then when would we ever stop writing methods?!

Being the good computer scientists that you are, you recall the concept of abstraction. This time our old pal abstraction is used in the context of method design. A much better alternative would be to write a single method that takes in, along with the sideLength, the number of sides of the shape and draws it with however many sides we say!

  1. Add a new method drawPolygon to your TurtleDrawer class. This method should take in the sideLength, the number of sides (think: int or double?) AND a a pen Color for the polygon you wish to draw.
    • If sides is less than three, then this method should do nothing.
  2. Make sure to add a method comment (preferably in JavaDoc format) for this method!
  3. Before you dive into the code, think about what needs to be done to generalize the drawTriangle method you previously wrote to draw any polygon with an arbitrary number of sides.
  4. If you didn't answer the question in Part 1 about how much to turn after each side is drawn, you need to do so now. To help you through this process, draw several polygons on a piece of paper. Start with triangle (3-sides) again, then try a square (4-sides), pentagon (5-sides), and so on, until it becomes obvious what the relationship between the number of sides vs. how much to turn by. (Hint: consider that the turtle needs to go 360 degrees (a full circle), but we need to break all of that up into n turns...).

    Once you figure out the formula to find the turn-degrees given the number of sides, You should calculate this value and store it as a local variable (don't repeat calculations if you don't have to!)

  5. Now you're ready to write your method. Remember to write-a-little, test, write-a-little, test. Call the method from your tester to avoid needing to repeatedly type in things like the number of sides or the Color. When you're done, make sure it works on multiple inputs. For instance, here's what the following method calls should draw:
    drawPolygon(150, 4, Color.BLACK); drawPolygon(150, 5, Color.BLACK); drawPolygon(150, 6, Color.BLACK);

    It is not an illusion that the shapes get larger with these calls, because we're not changing the sideLength, but we're increasing the number of sides. (Figuring out how much to change the sideLength so the polygon stays the same radius is a fun math problem we don't have time for).

  6. Refactoring (important! read this!): The correct implementation of drawPolygon() renders drawTriangle() a bit too specialized, doesn't it? Indeed, you should now replace the entire body of the drawTriangle() method with a single line of code calling the drawPolygon() method (with appropriate parameters). Make sure you understand why this works--and if not, ask!

    What you just did is called refactoring: taking the existing code-base, and improving its design.

    You might wonder why we even kept drawTriangle() around, instead of removing it altogether. Consider this real-world scenario: Suppose thousands of users are currently using the old version of the TurtleDrawer class. Today, we decide to refactor the code and release a new and improved version to the public. If we removed drawTriangle() completely, and insisted that everyone switch to using drawPolygon(), then everyone's code which made calls to drawTriangle() would now broken and require fixing. Not a very effective upgrade, is it?

    So by keeping drawTriangle() around, we ensure that our new upgrade is backward-compatible. We might warn the user the drawTriangle() method is now deprecated, and might be removed in future versions of our code. This makes for a much smoother upgrade.

  7. If you haven't recently, now is a good time to switch drivers!

Part 3: Zigzags

Next, you'll make a method that has the turtle draw zigzags.

  1. Zigzags: It turns out that these cool lines don't just make for great sweatpants and haircut patterns. Zigzags are also great ways for us to practice! loops. Make a new method, called drawZigzag(), that takes as input two int arguments. The first argument specifies the length of the zigzag line to be drawn. The second argument is the width, and is both the width and the zigzagging interval (see below for illustration). You method will also need to take in two Colors as parameters: a zigColor and a zagColor. (Yes, this may seem like a lot of parameters, but 4 isn't actually that many).
  2. Make sure to add a method comment (preferably in JavaDoc format) for this method!
  3. Things to consider when implementing this method:
    1. For convenience, let's call the lines that move vertically along the width a "zig line", and the longer lines that sweep back across a "zag line".
    2. In the picture above, the turtle was initially facing east. Therefore, when I called the method, I expected that the zigzag will be drawn horizontally, and to the east. But notice how the first zig-line is actually vertical! You should not assume that the turtle will always be facing east, but you'll still need to change the turtle's angle before you do any drawing at all. (The "zig-zagging" should take the turtle in the same direction it was facing when the method was first called).
    3. Next, you need to determine the length of the zag-lines, as well as the angle of your turns. (Hint: These sawtooth shapes sure remind me of right triangles...
      • Watch out for rounding errors when calculating ratios in int precision. Remember you can cast from a double to an int using:
        int x = (int)3.0;
    4. Think about the loop condition, which is related to how much you should draw per iteration. What appears to be the "minimally repeated pattern"? Perhaps a single zig-line plus zag-line combination (looks like a tooth)?
    5. Don't forget to make sure your ziglines and zaglines alternate colors.
  4. Again, test this method using your tester (this will make it easy to give different colors!). Make sure to test out your drawing when the turtle faces different directions (you can do this by temporarily having the constructor change the starting direction of the turtle. Just remember to remove this code later!)
  5. If you haven't recently, now is a good time to switch drivers!

Part 4: Your Own Pattern

It's amazing how many cool patterns we can now draw with just the drawPolygon() and drawZigzag() methods implemented. Your last task is to create your very own pattern by combining (you guessed it) loops and those previous methods you wrote.

You are not required to draw the above pattern, but can use it as inspiration. If you're wondering, the algorithm for this one is surprisingly simple: first draw a polygon with sideLength-long edges. After the first one is complete, shrink the sideLength by 20%. Repeat this process five times. Each time through the loop, check if you're in an odd iteration, or an even iteration. Depending on this check, set the pen's color to either Color.BLUE or Color.RED.

  1. In the TurtleDrawer class, add another method called drawPattern(). This method should take no parameters and return nothing. The method should draw a new pattern of your own design by repeatedly calling the previous methods you've written. Your pattern should meet the following criteria:
    1. You must use at least one loop.
    2. You must use at least two colors.
  2. Make sure to add a method comment (preferably in JavaDoc format) for this method!
  3. You should get creative with this, but to give you some ideas on expectations, here are some patterns of sufficient difficulty that you can make:
    • Nested polygons like the ones found about, but with each polygon "centered" in the other.
    • A wall (several rows or columns) of zigzags, changing colors every row or column
    • A "grid" of polygons--can you make a honeycomb? (Hint: you will probably need a nested loop for this one, as well as have the turtle turn around to move back across a row).
  4. The fancier your design, the better!

Extensions

This is not required and will not give extra credit, but its good for your health and is excellent practice

  1. Dashed lines: All of the drawings so far have used solid lines. Make a new method called drawDashedLined that draws a dashed line, like the one shown below.

    This method should take in two int parameters (the dashLength and the length), as well as a Color.

  2. To build intution, try coding this up sequentially (without loops) to figure out the repetitive structure.
  3. Things to note:
    • You'll need to lift and lower the pen repeatedly to implement this algorithm.
    • Think about the loop condition. When do you stop the pen-up/pen-down/move cycle?
    • If the dashLength is zero or negative number, you should draw a solid line.

Submission

  1. Make sure both of your names are in a JavaDoc comment on both of your class (TurtleDrawer and TurtleTester). If your names aren't on your assignment, we can't give you credit!
  2. Right-click on the project folder you downloaded, then:
    • If using Linux, select Compress...
    • If using Windows, select Send to and then Zip file
    • If using Mac, select Compress ... items

    This will let you take the selected folder (or files) and generate a new compressed .zip file.

  3. Navigate to the course on Moodle (Lecture Section A), (Lecture Section B). Upload your .zip file to the Lab F Submission page. Remember to click "Save Changes"! You may submit as often as you'd like before the deadline; we will grade the most recent copy.
  4. While you're on Moodle, remember to fill out the Lab F Partner Evaluation. Both partners need to submit evaluations.

Grading

This assignment will be graded out of 26 points.

Documentation

Below is the JavaDoc for the Turtle class, for your reference.



Class Turtle


public class Turtle

A class representing a Papert-style Turtle that can be moved about a canvas. This class acts as an initializer and wrapper for the JTF Turtle, so that it can be controlled through the BlueJ interface Note that this class uses a singleton canvas (run as an applet)

Version:
Aug 2013
Author:
Joel

Constructor Summary
Turtle()
          Constructor for objects of class Turtle
 
Method Summary
 void forward()
          Moves the turtle forward by one "step" (the size of the turtle; 30 pixels).
 void forward(int distance)
          Moves the turtle forward the specified distance (in pixels)
 double getDirection()
          Gets the turtle's current facing (in degrees counterclockwise from the x axis)
 Color getPenColor()
          Returns the color of the turtle's pen.
 String getPenColorName()
          Returns the name of the color of the turtle's pen.
 double getSpeed()
          Gets the turtle's current speed.
 boolean isPenDown()
          Gets whether the turtle's pen is down or not.
 void left(int angle)
          Turns the turtle to the left the specified number of degrees
 void penDown()
          Puts the turtle's pen down.
 void penUp()
          Lifts the turtle's pen up.
 void printText(String message)
          Prints the given message on the screen.
 void right(int angle)
          Turns the turtle to the right the specified number of degrees
 void setPenColor(Color color)
          Sets the color of the turtle's pen.
 void setPenColorByName(String color)
          Sets the color of the turtle's pen, using the name of the color.
 void setSpeed(double speed)
          Sets the turtle's speed.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

Turtle

public Turtle()
Constructor for objects of class Turtle

Method Detail

forward

public void forward()
Moves the turtle forward by one "step" (the size of the turtle; 30 pixels).


forward

public void forward(int distance)
Moves the turtle forward the specified distance (in pixels)


getDirection

public double getDirection()
Gets the turtle's current facing (in degrees counterclockwise from the x axis)


getPenColor

public Color getPenColor()
Returns the color of the turtle's pen. Note that this will look like jibberish in BlueJ.


getPenColorName

public String getPenColorName()
Returns the name of the color of the turtle's pen.


getSpeed

public double getSpeed()
Gets the turtle's current speed. 0.5 is default, 1 is fastest, 0 is slowest.


isPenDown

public boolean isPenDown()
Gets whether the turtle's pen is down or not.


left

public void left(int angle)
Turns the turtle to the left the specified number of degrees


penDown

public void penDown()
Puts the turtle's pen down.


penUp

public void penUp()
Lifts the turtle's pen up.


printText

public void printText(String message)
Prints the given message on the screen. Note that this will not move the turtle.


right

public void right(int angle)
Turns the turtle to the right the specified number of degrees


setPenColor

public void setPenColor(Color color)
Sets the color of the turtle's pen. Note that if called through BlueJ, you will need to specify the full path to the color (i.e., java.awt.Color.RED or java.awt.Color.BLUE).


setPenColorByName

public void setPenColorByName(String color)
Sets the color of the turtle's pen, using the name of the color. Can either be: "red", "green", "blue", "cyan", "magenta", "yellow", "pink", "gray", "black", "white"


setSpeed

public void setSpeed(double speed)
Sets the turtle's speed. 0.5 is default, 1 is fastest, 0 is slowest.