3. More Sophisticated Programming

What We Will Cover


Illuminations

Questions from last class or the reading?

  • Remember to bring headphones as we will be introducing sounds on Thursday
  • Reminder: Boss Events

Homework Questions?

3.1: Variables Revisited

Learner Outcomes

At the end of the lesson the student will be able to:

  • Create variable names according to the rules of Java
  • Write code for declaring variables and assigning them values
  • Trace variable assignment operations

3.1.1: Review of Variables

  • Memory is important in a computer program, just like in real life
  • We can do very little without memory in computer programs (or real life)
  • To remember something in Java, we use a variable
  • variable: the name of a place to store data in a computer's memory

Variable Declaration

  • The following statement declares a variable:
    int x;
    
  • When we declare a variable we tell the computer to set aside space to store data in its memory
  • Notice that a variable declaration has two parts:
    dataType variableName;
  • Where:
    • dataType: the type of data the variable will store
    • variableName: the name of the variables
  • In our example
    int x;
    
    • int: the data type telling the computer to store integer values
    • x: a name we made up for the variable

Storing a Value

  • After declaring a variable, we give it a value with an assignment statement
    x = 42;
    
  • The equals (=) sign is how we make an assignment statement
  • An assignment statement sets or resets the value stored in a variable
  • The variable in which to store the data is always on the left-hand side of the equals (=) sign
  • The value to assign is on the right-hand side of the equals (=) sign
  • Notice that we can both declare a variable and assign it a value in one statement:
    int x = 42; // declaration + assignment
    
  • Good programming practice says we should assign a value when we declare a variable

Check Yourself

  1. The name of a location to store data in a computer's memory is known as a(n) ________.
  2. True or false: remembering data is rarely important when processing information.
  3. To specify the type of data stored in a variable, variable declarations include a(n) ________ ________.

3.1.2: Variable Names

  • A variable name is a sequence of letters, digits, underscores ( _ ) and currency symbols like: $, ¢, £, ¥
  • However, the name must start with either a letter, underscore character ("_") or currency symbol
    • Cannot start with a number
    • A currency symbol is allowed but its use is discouraged
  • Also, a variable name cannot be one of the Java reserved words (keywords)
    • For a list of reserved words, see: keywords
    • Keywords have a predefined meaning in the Java language
  • Note that we cannot have spaces in a variable name
    • A space is NOT a letter, digit, underscore character or currency symbol
  • Also, variable names are cAsE sEnSiTiVe
    • id, ID, iD and Id are all valid but different names
  • Always choose variable names that describes the data stored in the variable
    int randomNumber;
    

Program Style

  • In addition to valid code, professional programmers often follow certain style conventions in naming
  • By convention, variable names in Java always start with a lower case letter
  • If the name has multiple words, use capital letters to mark the start of a new word
  • A program will still work without following these style conventions
  • However, the code will look amateurish rather than professional

Group Activity

Which of the following are valid variable names?

  1. int myHello2;
  2. int 2myHello;
  3. int My_HeLlO;
  4. int my hello;
  5. int _a_very_long_variable_name_that_is_hard_to_read;
  6. int hel-lo;

Check Yourself

  1. True or false: a variable is how a program stores data in a computer's main memory.
  2. True or false: a data type like int tells a computer program the kind of data we want to work with.
  3. Write the code to declare an int variable named foo and assign it a value of 10.

    answer

3.1.3: Data Types

  • Like human memory, a computer must encode information before storage
  • The data type tells the computer how to encode the data and how much memory space to set aside
  • Java has many different data types including the following:
Type Bytes Use
boolean 1 A true or false value.
int 4 Integers from -2,147,483,647 to 2,147,483,647.
double 8 Numbers like 12.345 that contain decimal points.
  • In addition, data types can be class types like World, Actor and Bug
  • A class type is a blueprint or template for creating objects
  • We make new class types whenever we subclass World or Actor
Type Bytes Use
Actor 4+ An Actor object or its subclasses like Bug.
Bug 4+ An Bug object.
World 4+ A World or its subclasses like BugWorld.

Data Type Analogy

  • We can think of a data type as a child's game where we match shapes to holes
  • Java does not allow square data pegs in round memory holes

Matching shapes to holes

Integer Data Type Example

  • A commonly used numeric data type is int which is shorthand for integer
  • An int is a whole number with no fractions or decimal points
  • Thus we can store values in variables like:
    int x = getX();
    int y = getY();
    setLocation(x + 2, y);
    
  • However, if we try to store a number with a decimal point, we get an error
    int x = 12.34; // error: incompatible types
    
  • The problem is that we cannot store the decimal part in an int variable
  • The compiler with check and verify we do not make this type of an error
  • Variables can store many other types of data including non-numeric types
  • We simply specify the data type for the variable name

Group Activity: Name that Data Type!

Value Data Type
Bug
-213.555
42
42.0
true
Wombat
false

Solo Activity (2m)

On a piece of paper write a variable declaration for:

  1. A variable to store dollars and cents
  2. A variable to store the count of the number of people in a room
  3. A variable to store whether or not a light bulb is on or off
  4. A variable to store a Bug object

Have your deskmate verify your variable declarations and write their name on your paper as having verified your work.

3.1.4: Variable Assignment

  • After declaring a variable, we give it a value with an assignment statement like:
    x = 42;
    
  • To assign values, we use an assignment operator which is the "equals sign" (=)
  • An assignment statement sets or resets the value stored in a variable
  • The assignment is made in an assignment statement in this form:
    variable = expression;
  • Where:
    • variable: the name of the variable
    • expression: the data we want to store in the variable
  • An assignment statement assigns the value of expression (right side) to the variable (left side)
  • The simplest expression is a literal value:
    length = 25;
    width = 17.5;
    
  • Numbers like 25 and 17.5 are called literals because they represent exactly what they are literally
  • In each statement above, the value on right is assigned to the variable on the left
  • We may assign results of more complex expressions to a variable like:
    total = num1 + num2;
    slope = (y2 - y1) / (x2 - x1);
    
  • The expression on the right is evaluated (computed) before assignment to the variable on the left
  • Assignment causes the value in a variable to change

Assigning Initial Values to Variables

  • Initial values may or may not be assigned when variables are declared:
    // Not initialized when declared and have unknown values
    int sum;
    double amount;
    
    // Initialized when declared with assigned values
    int sum = 0;
    double amount = 42 * 2;
    
  • Good programming practice: initialize variables when declared

Variable Assignment Flow

  • A computer is a machine with a memory that follows a set of instructions
  • For a computer, or anyone, to follow a set of instructions it must know two things
    1. the actions to be taken
    2. the order of the actions
  • A computer always follows a set of instructions in order from first to last
  • When working with variables, we must keeps this property of computers in mind
  • First, a variable must be declared
  • Next a variable must be assigned a value with an assignment statement
  • To change the value of a variable we can reassign a value with another assignment statement
  • The original value is overwritten and replaced by the new value
  • The equals (=) sign does not express equality as it does in math

Solo Activity (2m)

On your paper from the last activity, write a statement to assign a value to each variable you declared. For the Bug object, assume there is a method named getBug() that returns a Bug object.

Check Yourself

  1. True or false: the "equals sign" (=) is the assignment operator.
  2. True or false: in an assignment statement, the value on the left is assigned to the variable on the right.
  3. After executing the following statement, the value of number is ________.
    int number;

Exercise 3.1: Variable Assignment Tracing (16m)

Understanding variables and assignment is critical to being able to program but is an easy thing to be confused about. Get over this hurdle and programming will be far easier.

In this exercise we complete a series of dry run exercises where we step through short fragments of code. This is an important activity to reinforce your understanding of variables. The instructor will step through the first exercise with you.

Specifications

  1. Take out a piece of paper to record your answers, making sure to put the exercise name and your name on the paper.
  2. Open the Variable Assignment Tracing Exercises.
  3. Click the first problem and follow the steps, filling in the boxes to get the final answers.
  4. After completing a problem and before continuing to the next, compare your answers with another student.
  5. If there is a disagreement, ask the instructor for clarification.
  6. After verifying your answer, record the problem number and final values of all variables on your paper.
  7. Repeat for the remaining exercise problems.
  8. After finishing all the exercise problems, answer the Check Understanding questions and record the question number and answer on your paper.

When finished, please help those around you.

3.1.5: Summary

  • Variables are how we can store data in our programs
  • Variables must be declared before use like:
    int x;
    
  • One declared we can assign a value to the variable like:
    x = 42;
    
  • Simple assignment statements have a variable, equals sign and an expression:
    variable = expression;
  • The expression is computed before the assignment
  • Variables can be assigned new values while our program executes

3.2: Creating Random Behavior

Learner Outcomes

At the end of the lesson the student will be able to:

  • Write code that generates random numbers
  • Write code for declaring variables and assigning them values
  • Write code using relational operators
  • Apply random numbers to change actor behavior

3.2.1: Random Behavior and Random Numbers

  • Recall our Bug scenario from lesson 2
  • So you can follow along, open your bug scenario.
  • If you do not have the scenario, download, unzip and open this scenario link.
  • We have looked at the basics of starting to program games and simulations
  • Now we look at how to add more interesting behavior to our actors
  • We will start with adding random behavior

Need for Random Behavior

  • In our current games, our actors walk across our worlds in straight lines
  • However, most animals do not always walk in a straight line
  • Instead they tend to wander around or amble towards a destination
  • We can simulate wandering by having our actors turn a little off course now and then
  • The amount of the turn can be random
  • Also the choice of when to turn off course can be random
  • These two factors simulate the natural actions of many animals and insects
  • To simulate random behavior, we use random numbers

Random Numbers

  • Random numbers are a series of numbers without any apparent pattern
  • This means that we cannot predict the next number in the sequence
  • Greenfoot has a method for generating random numbers:
    Greenfoot.getRandomNumber(limit)
    
  • Where:
    • limit: the upper limit of the random number generated (limit not included)
  • The method returns a random integer between 0 and up to, but not including, limit
  • For example, the following statement returns a random number between 0 and 9:
    Greenfoot.getRandomNumber(10);
    

Dot Notation

  • Let us briefly discuss the notation of the method call:
    Greenfoot.getRandomNumber(10);
    
  • In this example, Greenfoot is the name of a class and getRandomNumber is the name of a method
  • Notice the dot (period) between the class name and the method name
  • This notation is called dot notation
  • When we call methods that are defined in our own class or inherited, just using the method name is enough
  • When we call methods from other classes, we must specify the class or object that has the method
  • The dot is used to separate the class or object name from the method name
  • Since the getRandomNumber() method is from the Greenfoot class, we write Greenfoot in front of the method call
  • We can call the method this way because the getRandomNumber() method is declared with the keyword static
  • There are other times to use dot notation and we will learn about these situations later in the course
  • For now, memorize the syntax for generating random numbers

Check Yourself

  1. One of a series of numbers without any apparent pattern is known as a(n) ________ number.
  2. To call a static method of another class, we place a(n) ________ between the class name and the method name.
  3. What code do you write to get the following result, including the end points?
    1. A random number between 0 and 9. answer
    2. A random number between 0 and 10. answer
    3. A random number between 1 and 10. answer
    4. A random number between -10 and 10. answer
  4. The problem with this random number generator from xkcd is that ________.
    1. dice rolling is not a fair way to get random numbers
    2. it was not selected randomly
    3. you can predict the number ahead of time
    4. nothing is wrong

3.2.2: Applying Random Numbers

  • Let us look at how to apply random numbers to create random behavior
  • The code for the Bug class at the end of lesson 2 is listed below
  • The bug moves in a straight line until it hits the edge of the world

Bug with Straight Line Movement

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import greenfoot.*;

/**
 * A bug that moves around a world.
 *
 * @author Ed Parrish
 * @version 1.1
 */
public class Bug extends Actor
{
    /**
     * Act - do whatever the Bug wants to do. This
     * method is called whenever the 'Act' or 'Run'
     * button gets pressed in the environment.
     */
    public void act()
    {
        move(3);
        int amount = 17;
        if (isAtEdge())
        {
            turn(amount);
        }
    }
}

Randomizing the Turns

  • We can add some randomization by adjusting the amount of the turn by a random number
  • For example, we can change the way the bug turns with:
    int degrees = Greenfoot.getRandomNumber(35);
    // other code omitted
    turn(degrees);
    
  • Now the bug will turn between 0 and 34 degrees when it is at the edge of the world
  • We can get an actor to turn randomly either right or left using code like:
    int degrees = Greenfoot.getRandomNumber(91) - 45;
    // other code omitted
    turn(degrees);
    
  • We can write these commands without a variable by nesting the method calls:
    turn(Greenfoot.getRandomNumber(91) - 45);
    
  • Nested method calls are executed from the innermost parenthesis outwards
  • The sequence of operations is:
    1. Greenfoot.getRandomNumber(91) returns a number between 0 and 90
    2. Our code then subtracts 45 from the returned number
    3. The turn() method executes and turns between -45 and +45 degrees
  • Which approach is easier to understand -- using variables or nesting method calls?

Check Yourself

  1. Write code to assign a random number between 0 and 99 to a variable named randomNumber.

    answer

  2. To cause an actor to make a random right-turn between 0 and 45 degrees inclusive write ________.
    1. turn(random(45));
    2. turn(getRandomNumber(45));
    3. turn(Greenfoot.getRandomNumber(45));
    4. turn(Greenfoot.getRandomNumber(46));
  3. With the following code, an actor will turn between ________ and ________ degrees.
    int randNum = Greenfoot.getRandomNumber(91) - 45;
    turn(randNum);
    

3.2.3: Relational Operators

  • Another interesting behavior we can add is to sometimes turn and sometimes not turn
  • For this behavior, we need to discuss relational operators for if-statements

Reviewing if-statements

  • Remember that to make an if-statement we need to code a test condition
    if (test)
    {
       statement1
       statement2
       ...
    }
    
  • Where:
    • test: the test condition that evaluates to true or false
    • statementX: the statements to execute depending on the test condition
  • The computer uses the test to decide whether or not to execute the statement
  • The test must evaluate to either true or false
  • Last time we discussed a simple test condition:
    if (isAtEdge())
    {
        turn(17);
    }
    
  • Another way to code a test condition is to use a relational expression

Relational Expressions

  • All computers can compare two numbers using a relational operators
  • Expressions that compare numbers are called relational expression
  • The relational operator compares two operands like:

    relational expression

  • The above example is called a relational expression
  • We have used relational operators in algebra and relational operators in Java are similar
  • The following table shows the similarities and differences between algebra and Java

Relational Operators

Math Name Java Examples   Result Notes
= Equal to == 5 == 10
2 == 2
false
true
Do not confuse with = which is assignment.
Not equal to != 5 != 10
2 != 2
true
false
The ! is like the line that "crosses through" the equal sign.
< Less than < 5 < 10
5 < 5
5 < 2
true
false
false
Less than or equal to <= 5 <= 10
5 <= 5
5 <= 2
true
true
false
Be careful not to write =<. Code the symbols in the order people normally say them.
> Greater than > 5 > 10
5 > 5
5 > 2
false
false
true
Greater than or equal to >= 5 >= 10
5 >= 5
5 >= 2
false
true
true
Be careful not to write =>. Code the symbols in the order people normally say them.

Boolean Variables and Relationships

  • Notice that relational expressions always evaluate to true or false
  • Thus we can assign a relational expression to a Boolean variable
    boolean test = 5 != 2;
    System.out.println(test);
    

Activity (2m)

Write a relational expression for the following test conditions in Java, then check your answer by pressing the answer link. Assume that both x and y are random numbers between -10 and +10.

int x = Greenfoot.getRandomNumber(21) - 10;
int y = Greenfoot.getRandomNumber(21) - 10;
answer
answer
answer
answer
answer
answer

3.2.4: Adding a Randomized Walk

  • Operands of a relational expression can be a method call
  • For example:
    Greenfoot.getRandomNumber(100) < 10
    
  • The method call to getRandomNumber() returns an integer between 0 and 99
  • The relational expression lets us test if the random number is less than 10
  • If so, the expression evaluates to true; otherwise the expression evaluates to false
  • We can use random numbers and relational operators to create a random walk for our actors
  • For instance, if we want our actor to turn a little off course 10% of the time, we would code an if-statement like:
    if (Greenfoot.getRandomNumber(100) < 10) {
        turn(5);
    }
    
  • If we want to turn a random amount, we can code something like:
    if (Greenfoot.getRandomNumber(100) < 10) {
        int degrees = Greenfoot.getRandomNumber(45);
        turn(degrees);
    }
    
  • To randomly turn either right or left, we can use:
    if (Greenfoot.getRandomNumber(100) < 10) {
        int degrees = Greenfoot.getRandomNumber(91) - 45;
        turn(degrees);
    }
    

Check Yourself

  1. True or false: one or both of the operands of a relational expression can be a method call.
  2. True or false: to randomly select when to turn we usually write an if-statement with a random number for a test condition.
  3. Write the first line of an if-statement that executes 25% of the time.

    answer

Exercise 3.2: Natural Movement (5m)

In this exercise, we add more natural movement to our bug using random numbers.

Specifications

  1. If you do not already have the bugs scenario, download bugs1.zip to a convenient place like the Desktop and unzip the file.

  2. Double-click the project.greenfoot file in the unzipped folder to start Greenfoot and open the scenario.
  3. Open the source code editor of the Bug class by double-clicking on Bug in the inheritance hierarchy, or by right-clicking on the Bug class and selecting Open editor.

    If you have problems, ask a guild member or the instructor for help.

  4. Just before the call to move() in the act() method, declare a variable and assign it a random number between 0 and 99.
    int percent = Greenfoot.getRandomNumber(100);
    

    For more information see section: 3.2.2: Applying Random Numbers.

  5. Add an if-statement to check if the random number from the variable is less than 10, so that the bug randomly turns 10% of the time.
    if (percent < 10)

    Make certain that the move() method is NOT inside the braces of the if-statement.

  6. Add a randomized turn inside the new if-statement so the bug turns a random amount.

    For more information see section: 3.2.4: Adding a Randomized Walk.

  7. Save your scenario to upload to Canvas later as part of the next lab.

    We will be adding more code to these files in subsequent exercises, so it is not time to submit them to Canvas yet. However, it is a good idea to have a backup copy in case of problems later in development.

When finished, please help those around you.

3.2.5: Summary

  • Most actors in a game or simulation do not walk in straight lines
  • To more closely simulate the behavior of animate objects, we can add randomness to their movement
  • To add random behavior, we start with random numbers
  • We discussed Greenfoot's method for generating random numbers:
    public static int getRandomNumber()(int limit)
    
  • To call the method we write:
    Greenfoot.getRandomNumber(max);
    
  • Where max is one more than the maximum random number wanted
  • The method returns a random integer between 0 and up to, but not including, max
  • Method calls like this are known as dot notation, because there is a dot between the class name and the method name
  • We have to use dot notation whenever the method we want to use is not in the class or its superclasses
  • We can store information, like the call to getRandomNumber(), in a variable
  • To use a variable, you first have to declare it, like:
    int randNum;
    
  • The word int in the above is a data type meaning integer
  • Variables can be assigned values using an assignment operator, which is the equals sign:
    randNum = Greenfoot.getRandomNumber(35);
    
  • We can combine a declaration and assignment into one statement like:
    int randNum = Greenfoot.getRandomNumber(35);
    
  • We discussed various ways to use random numbers for randomizing turns, like:
    int randNum = Greenfoot.getRandomNumber(35);
    turn(randNum);
    
  • For creating a random walk for our actors, we used relational operators
  • The relational operators are tests for equality and inequality of two numbers
  • These tests return a Boolean value, either true or false
  • The relational operators of Java include:
    ==  !=  <   <=  >   >=
    
  • We can use a relational operator for a random walk using code like:
    if (Greenfoot.getRandomNumber(100) < 10) {
        turn(5);
    }
    

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. How do you store information in a computer's main memory? (3.2.1)
  2. What is the code to declare an int variable named foo and assign it a value of 10? (3.2.1)
  3. True or false: most animals always walk in straight lines. (3.2.1)
  4. What is a random number? (3.2.1)
  5. What code do we write to get a random number? (3.2.1)
  6. True or false: you must specify a class name or object name when calling a method outside the class or its superclasses. (3.2.1)
  7. Which of the following causes an actor to make a random right-turn between 0 and 45 degrees? (3.2.2)
    1. turn(random(45));
    2. turn(getRandomNumber(45));
    3. turn(Greenfoot.getRandomNumber(-45));
    4. turn(Greenfoot.getRandomNumber(45));
  8. Which of the following is NOT one of Java's relational operators? (3.2.3)
    1. >
    2. !=
    3. <=
    4. =>
  9. True or false: a relational expression consist of two operands and a relational operator. (3.2.3)
  10. Which of the following is NOT a relational expression? (3.2.3)
    1. Greenfoot.getRandomNumber(100) < 10
    2. 10 >= Greenfoot.getRandomNumber(100)
    3. Greenfoot.getRandomNumber(100) != Greenfoot.getRandomNumber(100)
    4. <= Greenfoot.getRandomNumber(100) 10
  11. What turn does an actor make with the following statement? (3.2.4)
    turn(Greenfoot.getRandomNumber(91) - 45);
    
  12. How often does an actor turn with the following code? (3.2.4)
    if (Greenfoot.getRandomNumber(100) < 10) {
        turn(5);
    }
    

3.3: Simple Actor Interaction

Learner Outcomes

At the end of the lesson the student will be able to:

  • Add multiple actors to a scenario
  • Write code for actor interaction
  • Write code for class literals

3.3.1: Adding Other Actors

  • To make our games and simulations more interesting, we want to add more actors
  • Some bugs like to eat flowers
  • For our simulation, we will assume that our bug eats flowers
    • In reality, ladybugs typically eat aphids or scales
    • We can change the bug image if we prefer a different bug
  • We can add flowers by subclassing Actor

Try It: Add a Flower Class (2m)

  1. Open your Bug scenario if not already open.
  2. Right-click on Actor in the class diagram and select New Subclass...
  3. Type in a name for the new actor that is the name of the class you are inserting (Flower).
  4. Press the Ok button and verify the Flower subclass was added to the class diagram.

Adding Predators

  • To make our bug scenario more interesting, let us add a predator as well
  • A lizard seems like a good choice, since they are often depicted in menacing ways

    Lizard

  • We want a lizard to wander around the screen like our bug
  • To start with, we copy the complete act() method of the Bug class into the Lizard class
    • We will change act() methods later as we add functionality
  • However, the act() method of Lizard needs the isAtEdge() method
  • We could copy the isAtEdge() method into Lizard as well
  • However, having duplicated methods in multiple classes can lead to problems
  • For instance, if we decide to change the isAtEdge() method, we would have to remember to change it in all the classes
  • A better approach is to create a new superclass for common methods

Try It: Add a Predator (3m)

  1. Open your Bug scenario if not already open.
  2. Right-click on Actor in the class diagram and select New Subclass...
  3. Type in a name for the new actor that is the name of the class you are inserting (Lizard).
  4. Press the Ok button and verify the Lizard subclass was added to the class diagram.
  5. For now, copy the act() method of Bug to Lizard

When finished, help those around you.

3.3.2: Interaction Methods

  • Notice that when a bug meets a flower, nothing happens
  • However, in our scenario, we want our bugs to eat the flowers
  • For our bug to eat flowers, we need two capabilities:
    1. A way for a bug to detect flowers within range
    2. A way to delete the eaten flower from the scenario
  • Greenfoot has a method for detecting objects named: isTouching()
  • Also, Greenfoot has a method for removing objects named: removeTouching()
  • Both of these methods are in the Actor class and are shown below

Commonly Used Actor Methods for Interaction

Method Description
isTouching(Class cls) Returns true if this actor is touching another object of the given class; otherwise returns false.
removeTouching(Class cls) Removes one object of the given class that this actor is currently touching, if any exist.

Class Literals

  • To call the isTouching() method, we use something like:
    isTouching(Flower.class)
    
  • Similarly, to call removeTouching() we use something like:
    removeTouching(Flower.class)
    
  • Both method signatures require a Class description
  • To obtain a Class description, we add .class to the name of a class
  • Adding the ".class" evaluates to what is known as a class literal
  • A class literal is simply a description of a class consisting of the name of a class followed by a "." and the word class
  • An English description of the Flower class would be, "Flower class"
  • In the Java programming language, a description of the Flower class is: Flower.class
  • By using a class literal, the isTouching() and removeTouching() methods can look for a specific type of object, rather than all objects

Example Code Calling isTouching() and removeTouching()

if (isTouching(Flower.class)) {
    removeTouching(Flower.class);
}

Check Yourself

  1. The method isTouching() is defined in the class ________.
  2. True or false: the purpose of method isTouching() is to detect if our actor has touched another actor.
  3. A class literal is created by using the name of the class followed by a dot and the word ________.
  4. True or false: the advantage of using a Class parameter is that we can specify a single type of object.
  5. True or false: a class literal is how you can specify a particular class for a method parameter.

Exercise 3.3: Actor Interaction (7m)

In this exercise, we add methods for object interaction.

Specifications

  1. Start Greenfoot and open the Bug scenario from the last exercise and the following Try Its:
    1. Try It: Add a Flower Class
    2. Try It: Add a Predator
  2. Open the editor for the Bug class and add the following code to the act() method:
    if (isTouching(Flower.class)) {
        removeTouching(Flower.class);
    }
    
  3. Press the Compile button and verify there are no errors.

    Resolve any errors you find, getting help from a guild member or the instructor as needed.

  4. Open the source code editor of the Lizard class and copy the following code into the act() method:
    if (isTouching(Flower.class)) {
        removeTouching(Flower.class);
    }
    
  5. Modify the code added to the Lizard class to check for and remove a Bug instead of a Flower.
  6. Compile all the classes and verify there are no errors. Resolve any errors you find, getting help from a guild member or the instructor as needed.

  7. Set up several flowers and one or more bugs and a Lizard to see how the scenario works. Verify that the bug eats flowers and the Lizard eats bugs.
  8. Save a copy of your final scenario with all the changes made to upload to Canvas as part of the next lab.

    We will be adding more code to these files in subsequent exercises, so it is not time to submit them to Canvas yet. However, it is a good idea to have a backup copy in case of problems later in development.

When finished please help those around you.

3.3.3: Summary

  • We add many actors to most scenarios
  • When we add actors, we usually want then to interact in some way
  • We examined two methods for actor interaction:
    • isTouching(): returns true is we can see an object in the same cell
    • removeTouching(): tries to "eat" (remove from the world) the specified object
  • To make use of the methods, you write code like:
    if (isTouching(Flower.class)) {
        removeTouchingFlower.class);
    }
    
  • Adding the .class to the name of a class is known as a class literal
  • A class literal is the description of a class
  • For instance, a description of the Flower class would be, "class Flower"
  • Using the class literal as a parameter allows us to specify a single type of actor rather than all actors

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What is a class literal? (3.3.2)
  2. True or false: in our scenario, when we call removeTouching() we always remove an object from the world. (3.3.2)

3.4: Creating New Methods

Learner Outcomes

At the end of the lesson the student will be able to:

  • Discuss the reason for writing methods
  • Define methods with and without parameters

3.4.1: Writing Methods

  • In the previous sections we added new behavior to the Bug class, like:
    • Turning at the edge of the world
    • Occasional random turns
    • Eating flowers
  • Notice that the act() method is getting longer and longer as we add code
  • If we continue adding code as we have, the method will become really long and hard to understand
  • The biggest problem in developing software is managing the complexity of programs
  • We can improve our code by organizing it into smaller pieces known as methods
  • Methods are a key tool in creating easy-to-understand programs that can be changed easily

What is a Method?

  • As developers, we need to know how to write and call methods

    Method -- a named sequence of statements that can receive input, perform an action, and optionally return a value.

  • We have looked at methods before, such as the lookForWorm() method from the textbook (p.38):
    /**
     * Check whether we have stumbled upon a worm.
     * If we have, eat it. If not, do nothing.
     */
    public void lookForWorm()
    {
        if ( isTouching(Worm.class) )
        {
            removeTouching(Worm.class);
        }
    }
    
  • Methods are like little programs in our larger program
  • We give each little method something we want it to do
  • We call the method and cause it to be executed from anywhere within our class
  • When the method has finished running, program execution returns to the point just after the code that called the method

Check Yourself

  1. True or false: people write methods to organize code into small understandable pieces.
  2. Which of the following are features of a method?
    1. Must have a name
    2. Can receive input
    3. Performs an action
    4. Must return a value
  3. True or false: when a method finishes executing, the program flow returns to the point just after the code that called the method.

3.4.2: Defining Methods

  • In this section we look at method definition syntax and examine a simple example method
  • After we understand the syntax we can write more complicated methods

Method Syntax

  • The general syntax for defining a new method is:
    public returnType methodName(parameter1, ..., parametern) {
        statements
    }
    
  • Where:
    • returnType: the data type of the value returned
    • methodName: the name you make up for the method
    • parameterx: the input values, if any
    • statements: the statements to execute when calling the method
  • The word public is known as an access modifier
  • Methods have public access if we want to make them accessible to other classes
  • There are other access modifiers but we should use public for now
  • Can you identify each of these syntax items in the act() method we have always used?
    public void act()
    {
        // add commands here
    }
    

Example of Writing a New Method

  • As an example of writing a new method, let us make a method out of our code to look for a flower
  • For example:
    /**
     * Checks whether we have stumbled upon a flower.
     * If we have, then eat it. Otherwise, do nothing.
     */
    public void lookForFlower() {
        if (isTouching(Flower.class)) {
            removeTouching(Flower.class);
        }
    }
    
  • The overall code is known as a method definition
  • The above code defines a new method
  • Let us look at each part of the new method

Comments

  • The first four lines are a comment
  • Comments are ... comments -- notes to people reading the code
  • The computer ignores comments entirely
  • We write comments to explain our code to human readers
  • Every method should have a comment block like the example

Method signature

  • The next line after the comment is the method signature:
    public void lookForFlower()
    
  • We technically can use words other than public, but for now always use public
  • The return type is the keyword: void
  • The word void is used when we want to return nothing from a method
  • Following the return type is the method name: lookForFlowers
  • Method names follow rules similar to variable names:
    • A sequence of letters, digits, underscores -- cannot contain spaces
    • Must start with a letter and not a number
    • Names are case sensitive
    • Cannot be a keyword
  • By convention, method names in Java always start with a lower case letter
  • If the name logically has multiple words, then use capital letters to mark the start of a new word
  • Following the method name is a set of parenthesis
  • Inside the parenthesis are the parameters, if any
  • How many parameters are there in this example?

Method Body

  • The last few lines -- the curly braces and anything between them -- is called the method body
  • The method body contains the list of statements executed when the method is invoked (called)

Check Yourself

  1. True or false: The compiler ignores method comments.
  2. True or false: method names are case sensitive.
  3. What is wrong with the following method name? (answer)
    public void 4flowers() { }
  4. What is wrong with the following method name? (answer)
    public void switch() { }
  5. For the following code, match the syntax item with the code
    public void lookForFlower() {
        if (isTouching(Flower.class)) {
            removeTouching(Flower.class);
        }
    }
    
1. Braces a. { }
2. Return type b. lookForFlower
3. method call c. ( )
4. Method name d. if (isTouching(Flower.class)) {...}
5. if statement e. removeTouching(Flower.class);
6. Parameter list f. void

3.4.3: Calling Methods

  • When we define a method, the code does not immediately get executed
  • In fact, defining a method does not guarantee it is ever executed
  • To execute the code in a method, we must code a method call
  • We can call our example method from inside the act() method using the code:
    lookForFlower();
    
  • Notice that the method call has an empty parameter list
  • The number and order of parameters must match the parameters defined in the method
  • In this case, there are no parameters defined and so the method call has an empty parameter list

Organizing with Methods

  • Our method and method call does not change the execution of our program
  • Instead, defining short methods like this makes programs easier to understand
  • As we add more code to a class, methods tend to become longer and longer
  • Longer methods are harder to understand
  • By separating our code into a number of short methods, we make the code easier to read
  • For example, if we were to organize all the code of Bug into short methods, we might end up with an act() method like:
    public void act()
    {
        turnAtEdge();
        randomMove(5);
        lookForFlower();
    }
    
  • Understanding the act() method is now easier because it is short
  • We can clearly see the logic and flow of our act() method

Check Yourself

  1. True or false: defining a method means it will be executed.
  2. True or false: method calls always have parenthesis, even when a method does not define any parameters.
  3. True or false: defining short methods makes it easier to understand the logic of a program.

3.4.4: Parameters

  • When defining a method, it is worth thinking about what helpful action it will perform
  • We can sometimes make a method more useful if we give it parameters
  • Recall from lesson 2.4.3 that every method has a parameter list

    Parts of a method

  • Even methods that accept no parameters have an empty parameter list
  • Thus, we always have parenthesis when we define a method

Adding Parameters

  • For some methods adding a parameter makes the method more useful
  • For example, we add a parameter to randomMove() like:
    public void randomMove(int speed)
    
  • Our randomMove() method now receives the number of pixels to move in the speed parameter
  • We move the number of pixels in speed when the method is called as shown in the following example

Passing Arguments to a Method

Passing arguments in a method call

Arguments and Parameters

  • Depending on our background, we might use the term arguments or parameters for the values passed to methods
  • The terminology is not that important
  • However, the way I will use the terms is:
    • A method definition has parameters
      public void randomMove(int speed) // speed is a parameter
          // ...
      }
      
    • A method call passes arguments
      randomMove(5); // 5 is an argument
      
  • Arguments are values we pass into methods
  • When the argument drops into a method, it lands in a parameter
  • A parameter is just like other variables in the method
    • Except that a parameter gets initialized by an argument
  • The important part is:

    We must pass every method parameter an argument.

  • The arguments must be in the same order as the parameters
  • Also, the argument value must be compatible with the type of the parameter
  • For example, we cannot call randomMove() with: randomMove("Ed Parrish")

Check Yourself

  1. To received input, a method has __________.
  2. Parameters are set on the first line of a function inside a set of __________
    1. Curly braces -- { }
    2. Parenthesis -- ( )
    3. Square brackets -- [ ]
    4. Colons -- : :
  3. True or false: like any other variable, a method parameter has both a type and a name.
  4. If a method has three parameters, a method call must include ________ arguments.
  5. For the following method signature, the parameter names are __________
    int add(int a, int b)
    
    1. a
    2. b
    3. both a and b
    4. cannot tell from the method signature

Exercise 3.4: Writing Methods (10m)

In this exercise, we write new methods for our scenario.

Specifications

  1. Start Greenfoot and open the Bug scenario from the last exercise.

    If you are missing the scenario then download, save and unzip the file: bugs2.zip.

  2. Open the source code editor of the Bug class and add the following method:
        /**
         * Checks whether we have stumbled upon a flower.
         * If we have, then eat it. Otherwise, do nothing.
         */
        public void lookForFlower()
        {
            if (isTouching(Flower.class))
            {
                removeTouching(Flower.class);
            }
        }
    

    For more information see lesson: 3.4.2: Defining Methods.

  3. Change the act() method of Bug to call this new method.

    For more information see lesson: 3.4.3: Calling Methods.

  4. Add two new methods to the Bug class, copying the appropriate code from the act() method:
    • public void turnAtEdge()
    • public void randomMove(int speed)
  5. Change the act() method of Bug as follows:
        public void act()
        {
            turnAtEdge();
            randomMove(5);
            lookForFlower();
        }
    

    When completed, compile the class and verify there are no errors. Resolve any errors you find, getting help from a guild member or the instructor as needed.

  6. Organize the code in the Lizard class in a similar way.

    However, instead of looking for and eating flowers, look for and eat bugs.

  7. Compile and run your scenario to verify all the changes work well.

    If you have problems, ask a guild member or the instructor for help as needed.

  8. Save a copy of your final scenario with all the changes made to upload to Canvas as part of the next lab.

    We will be adding more code to these files in subsequent exercises, so it is not time to submit them to Canvas yet. However, it is a good idea to have a backup copy in case of problems later in development.

As time permits, read the following sections and be prepared to answer the Check Yourself questions in the section: 3.4.4: Summary.

3.4.5: Summary

  • As we add more code to methods, they can become too long to easily understand
  • The solution is to break up the long sequences of code into shorter sections using methods

Defining Methods

  • Methods allow you to organize code within a class
  • To define a method, we use the following syntax:
    public returnType methodName(parameter1, ..., parametern) {
        statements
    }
    
  • Where:
    • returnType: the data type of the value returned
    • methodName: the name you make up for the method
    • parameterx: the input values, if any
    • statements: the statements to execute when the method is called
  • The word public is known as an access modifier
  • Methods have public access if we want to make them accessible to other classes
  • As an example, we wrote the method:
    public void randomMove(int speed) // speed is a parameter
    {
        int randNum = Greenfoot.getRandomNumber(100);
        if (Greenfoot.getRandomNumber(100) < 10)
        {
            turn(Greenfoot.getRandomNumber(100) - 45);
        }
        move(speed);
    }
    
  • If the method does not return a value, we use the return type: void
  • Otherwise, we specify the type of data we want to return
  • A method name follows the same rules as variable names
  • However, the method name is always followed by a set of parenthesis
  • Inside the parenthesis are the parameters, if any
  • We should always provide a comment block before a method
  • The comment helps explain the method to humans reading the code

Calling Methods

  • When we define a method, the code does not execute automatically
  • To execute the code, we must code a method call like:
    randomMove(5);
    
  • When we call a method, we specify its name and provide arguments for each parameter
  • The flow of the program execution stops and jumps to the called method
  • When the called method finishes executing it returns

Parameters and Arguments

  • When we define a method, we want it to be reusable
  • To make a method more reusable, we avoid hard-wiring important values
  • Instead, we pass the key values by defining parameters
  • A parameter is a variable that receives information during a function call
  • To identify their special ability, parameters are declared inside the parenthesis () of a function definition
    public void randomMove(int speed) { /* statements */ }
    
  • When we call a method, we supply an argument for each parameter
    randomMove(5)
    
  • Parameter variables hold the argument values when we call a function

    method parameter flow

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. Why do programmers write methods? (3.4.1)
  2. What is a method? (3.4.1)
  3. How can you tell the difference between a method name and a variable name? (3.4.1)
  4. What are items always present in a method signature? (3.4.1)
  5. What is the purpose of comments? (3.4.2)
  6. True or false: The compiler ignores comments. (3.4.2)
  7. What is wrong with the following method name? (3.4.2)
    public void 4flowers() { }
  8. What is wrong with the following method name? (3.4.2)
    public void switch() { }
  9. Which of the following is a method definition and which is a method call? (3.4.3)
    1. public void lookForFlower() { }
    2. lookForFlower();
  10. True or false: Within reason, shorter methods are easier to understand than longer methods. (3.4.3)
  11. How can you use methods to make your code easier to understand? (3.4.3)

3.5: Bells and Whistles

Learner Outcomes

At the end of the lesson the student will be able to:

  • Write code for keyboard interaction
  • Describe the String data type
  • Write code to produce sound effects
  • Write code to end a scenario
  • Find class and method documentation in the Greenfoot API

3.5.1: Keyboard Interaction and Strings

  • So far the actors in our scenario move on their own
  • What we want to do with our bug is get the player involved
  • We want the player to control the actions of the bug using the keyboard
  • The Greenfoot framework has a method that lets us check whether a key on the keyboard has been pressed
  • The method is in the Greenfoot class and its signature is:
    static boolean isKeyDown(String keyName)
    
  • As we can see, the method is static and the return type is boolean
  • This means that the method returns true or false and we can use it in an if-statement
  • However, notice that the data type of the parameter is new: String
  • In order to use this method, we need to look at the String data type

Strings

  • A string is a sequence of characters (letters, digits, other symbols)
  • To indicate a string in a program we enclose the characters within double quotes
  • For example:
    "This is a string"
    "b"
    "$3.95"
    "My name is Ed"
    
  • We create variables for strings using the String data type
  • For example:
    String firstName;           // declaration
    firstName = "Edward";       // assignment
    String lastName = "Parrish" // declaration + assignment
    
  • When a method parameter expects a String, we must provide either characters in double quotes or a variable of type String

Check Yourself

  1. To check whether a key on the keyboard has been pressed, call the Greenfoot class method ________.
  2. A sequence of character data is known as a(n) ________.
  3. The name of the data type for storing strings in variables is ________.
    1. String
    2. string
    3. str
    4. Text

3.5.2: Using Strings to Specify Key Presses

  • To call the isKeyDown() method, we need a String argument
    static boolean isKeyDown(String keyName)
    
  • So what string do we provide for the method call?

Key Names

  • Every key on the keyboard has a name
  • For keys that produce a visible character, that character is their name
  • For example, the A-key is named "A" (or "a")
  • The number keys are: "0", "1", ..."9"
  • Other keys have names as well
  • The cursor keys are named: "up", "down", "left", "right"
  • Other control characters include: "enter", "space", "backspace"
  • The function keys are: "F1", "F2", .., "F12"
  • For more information, see the Class Greenfoot documentation

Using isKeyDown()

  • If we want to test for the right-cursor key, we write an if-statement like:
    if (Greenfoot.isKeyDown("right"))
    {
        // do something
    }
    
  • For example, to make an actor turn right by 10 degrees we would write:
    if (Greenfoot.isKeyDown("right"))
    {
        turn(10);
    }
    
  • We can add this code to a method and call the method from the act() method
  • For instance:
    /**
      * Check if a control key has been pressed and react.
      */
    public void checkKeyPress() {
        if (Greenfoot.isKeyDown("right"))
        {
            turn(10);
        }
    }
    
  • Then the act() method would look like:
    public void act()
    {
        checkKeyPress();
        move();
    }
    

Check Yourself

  1. When calling isKeyDown() for the B-key, use the parameter ________.
  2. When calling isKeyDown() for the left-cursor key, use the parameter ________.
  3. Write the first line of an if-statement that tests when the left cursor key is pressed.

    answer

  4. The best place to put the above if-statement is in the ________ method.
    1. act()
    2. isAtEdge()
    3. checkKeyPress()
    4. move()

3.5.3: Adding Sound

  • Another "bell and whistle" we can add to our scenario is sound
  • As before, a method in the Greenfoot class can help us
  • By looking through the documentation, we find the playSound() method
  • The method expects a String parameter, which is the name of the sound file
  • The scenario from the book has some sound files and we will use one for our example: slurp.wav
  • We must add the sound file to the "sounds" folder in our scenario
  • To play the sound, we use the command:
    Greenfoot.playSound("slurp.wav");
  • As you can see, the file name is specified as a string
  • A convenient place to add the command in the Bug class is in lookForFlower()

Getting Sounds

  • To play sampled sound, you will need some sound files
  • You can get free sound effects files from the Internet like:
  • You can search for sounds on the web using:
  • However, make sure you verify the licensing
  • Also you can create your own sounds using the microphone on your cell phone or other device
  • Then you can edit the sounds using a sound editing program
  • Some free sound editing programs you might try are:

Sound File Size

  • Sound files can become quite large
  • When developing a game, we need to find or develop sound files that convey the effect we want without becoming overly large
  • As a rule of thumb, we want no sound file larger than one megabyte
  • Also, the sum total of all sound files should be no larger than three megabytes
  • If we find our sound files are too large, we can use a sound editing program to reduce the size
  • For instance, using use mono rather than stereo will cut the sound size in half
  • Another good idea is to use an MP3 format with medium, or higher, compression

Check Yourself

  1. To play sounds, first add the sound files to the ________ folder of your scenario.
  2. To play a sound file, call the Greenfoot class method ________.
  3. True or false: you can use any sound file you can find on the Internet.

3.5.4: Ending the Scenario

  • One last "bell and whistle" we can add to our scenario is to end execution when the bug is caught by a lizard
  • Again, the Greenfoot class has a method to help us
  • We just need to find the method
  • To find out what methods are available, we look in the Greenfoot API

The Greenfoot API

  • The documentation for the Greenfoot classes is known as the Greenfoot API
  • API is an acronym for Application Programming Interface
  • We can find the Greenfoot API in Greenfoot by using the Help menu

    From the Help menu, select Greenfoot Class Documentation

  • This will show us the documentation for all the Greenfoot classes in a Web browser
  • Another way to find the documentation is online at http://www.greenfoot.org/files/javadoc/
  • The API shows all the available classes and we can follow the hyperlinks to find details about each class

Finding the Method

  • The method we are interested in is in the Greenfoot class
  • We click on a hyperlink for the Greenfoot class
  • When we get to the class, scroll down and look through the methods
  • Each method is listed and the one we are interested in has an explanation that says

    Pause the execution.

  • You can follow the hyperlink of the method name and often get more detailed information about the method

Check Yourself

  1. The acronym API stand for A________ P________ I________.
  2. True or false: the name of the documentation for Greenfoot classes is called the Greenfoot API.
  3. To end a scenario, call the Greenfoot class method ________.

Exercise 3.5: Keypresses and Sounds (10m)

In this exercise, we add keyboard controls and sounds to our scenario. In addition, we add a stopping condition.

Specifications

  1. Start Greenfoot and open the Bug scenario from the last exercise.
  2. Open the source code editor of the Bug class and remove the randomTurn() method call and method.
  3. In the Bug class, add code to turn right pressing the right-cursor key and left by pressing the left-cursor key.

    For more information see lesson: 3.5.2: Using Strings to Specify Key Presses.

  4. Compile the class and verify there are no errors. Then test your scenario to verify the bug changes direction under keyboard control.

    Resolve any errors you find, getting help from a guild member or the instructor as needed.

  5. Save the following sound file in the scenario sounds directory: slurp.wav

    For more information see lesson: 3.5.3: Adding Sound.

  6. In the source code of the Bug class and add the following code to the lookForFlower() method after the removeTouching() method call:
    Greenfoot.playSound("slurp.wav");
    

    When completed, compile the class and verify there are no errors. Resolve any errors you find, getting help from a guild member or the instructor as needed.

  7. Compile the class and verify there are no errors. Then test your scenario to verify the lizard eats a bug when they meet.

    Resolve any errors you find, getting help from a guild member or the instructor as needed.

  8. Save the following sound file in the scenario sounds directory: au.wav

    For more information see lesson: 3.5.3: Adding Sound.

  9. Change the code in the Lizard class to play au.wav sound and the stop the scenario after eating the bug.

    For more information see lesson: 3.5.4: Ending the Scenario.

  10. Compile and run your scenario to verify all the changes work well.

    If you have problems, ask a guild member or the instructor for help as needed.

  11. Save a copy of your final scenario with all the changes made to upload to Canvas as part of the next lab (Lab 3).

As time permits, read the following sections and be prepared to answer the Check Yourself questions in the section: 3.5.5: Summary.

3.5.5: Summary

  • In this section we looked at several features that add interest and excitement to a game or simulation
  • First we looked at how to control actors using the keyboard
  • The important method was found in the Greenfoot class:
    static boolean isKeyDown(String keyName)
    
  • The method checks to see if a particular key is pressed
  • The particular key is specified using a String parameter
  • A string is a sequence of characters and you can specify the characters by placing them in double quotes
  • For instance:
    "This is a string"
    "A"
    "left"
    "right"
    
  • Another way to send the parameter information is to use a String variable like:
    String leftKey;
    leftKey = "left";
    String rightKey = "right";
    
  • When a method parameter expects a String, we must provide either characters in double quotes or a variable
  • Every key on the keyboard has a name
  • For keys that produce a visible character, that character is their name
  • For example, the A-key is named "A" (or "a")
  • The number keys are: "0", "1", ..."9"
  • The cursor keys are named: "up", "down", "left", "right"
  • Other control characters are: "enter", "space", "tab", "escape", "backspace"
  • The function keys are: "F1", "F2", .., "F12"
  • Since the isKeyDown() method returns a boolean type, we can use it in an if-statement like:
  • If we want to test for the right-cursor key, we write an if-statement like:
    if (Greenfoot.isKeyDown("right"))
    {
        // do something
    }
    
  • Another "bell and whistle" we can make to our scenario is the addition of sound
  • We must first place the sound file in the sounds folder of our scenario
  • Then to play the sound, we use the command:
    Greenfoot.playSound("filename.wav");
  • Finally we discussed how to look up classes and method in the Greenfoot API
  • You can find the class documentation from within Greenfoot using the help menu
  • Selecting the Greenfoot Class Documentation from the Help menu opens the documentation in a browser
  • Once you have opened the document ion, you follow the hyperlinks to find the information you want

Check Yourself

Answer these questions to check your understanding. You can find more information by following the links after the question.

  1. What method checks whether a key on the keyboard has been pressed? (3.5.1)
  2. What is a string? (3.5.1)
  3. The name of the data type for storing strings in variables is: (3.5.1)
    1. String
    2. string
    3. str
    4. Text
  4. What is the name of the B-key? (3.5.2)
  5. What is the name of the left-cursor key? (3.5.2)
  6. Where do you place sound files that you want to play in a scenario? (3.5.3)
  7. What is the name of the method that plays sounds? (3.5.3)
  8. True or false: the name of the documentation for Greenfoot classes is called the Greenfoot API. (3.5.4)
  9. What is the name of the method that ends a scenario? (3.5.4)

Wrap Up

Due Next:
Q2: First Program (2/9/17)
Lab 3: Finishing the Crab (2/14/17)
Q3: Methodical Improvement (2/16/17)
  • When class is over, please shut down your computer
  • You may complete unfinished lesson exercises at any time before the due date.
Home | Canvas | Schedule | Syllabus | Room Policies
Help | FAQ's | HowTo's | Links
Last Updated: March 24 2017 @19:28:36