University of Washington, CSE 142

Lab 9: Critters Practice

Except where otherwise noted, the contents of this document are Copyright 2013 Stuart Reges and Marty Stepp.

lab document created by Marty Stepp, Stuart Reges and Whitaker Brand

Basic lab instructions

Today's lab

Goals for today:

Exercise : Critters Setup

To work on the critters assignment, you must first download the classes that are used by the simulator. To begin:

What are Critters?

Critters are a type of Object that live inside of CritterMain. There many types of Critters, and CritterMain will initially populate the Critter world with 30 of each type of Critter that has been added to CritterMain. With every tick, CritterMain asks every individual Critter (that is still alive) a few questions, such as:

The individual Critter's answers dictate how it looks and behaves for the next turn.

Inheritance

Every type of Critter you write will be able to interact with CritterMain because they will all inherit from/extend the Critter class. This means that they will initially:

This is how we can guarantee that CritterMain can ask our Critter all of its questions, and that we'll have an answer.

Of course, it's not incredibly useful to just make Critters that act identically to Critter.java. But we are able to override inherited methods the same way we re-wrote toString() in the last lab/in GeoLocation: by implementing a method with the same method signature as the method we're trying to override.

Exercise : LabTA Version 1

Exercise : LabTA Version 2

As we just saw, a default LabTA is black, represented by a ?, and doesn't move over time. This is because LabTA inherits from Critter, and Critter.java tells us that we, by default:

   // make my color black in Critter world
   public Color getColor() {
      return Color.BLACK;
   }

   // don't move when getMove() is called
   public Direction getMove() {
      return Direction.CENTER;
   }

   // represent me as a ? in Critter world
   public String toString() {
      return "?";
   }

Exercise : LabTA Version 2

To change our look/behavior, we need to override the default methods of our LabTA class.

Exercise : LabTA Version 2

Exercise : LabTA Version 3

You might have noticed that LabTAs aren't particularly good Critters, scorewise. We get points for making more LabTAs, killing other Critters, and eating food. But if you let CritterMain run for a while, you can see Stones take out a ton of LabTAs, whilst LabTAs fail to pick up many points! This is because by default, LabTAs have the behavior of a Critter:

   public boolean eat() {
      return false;
   }

   public Attack fight(String opponent) {
      return Attack.FORFEIT;
   }

Exercise : LabTA Version 3

Note that right now, the only Critters in CritterMain are Stones and LabTAs.

Exercise : Solution

public class LabTA {

   public boolean eat() {
      return true;
   }

   public Attack fight(String opponent) {
      return Attack.POUNCE;
   }
   
   // earlier implemented methods ommitted
   ...
}

Exercise : LabTA Version 4

Our LabTA critters currently have very simple behaviors that don't change. They are always magenta, displayed as :-), moving NORTH, attacking using POUNCE, and eating when finding food.

Now we're going to alter the LabTA to change over time. Specifically, we want to alternate colors between magenta and white, switching every time the LabTA moves (getMove() is called), with the initial color (before any moves are made) being magenta.

Developing this kind of behavior is a central part of the critters homework, so reasoning through how to implement this behavior is really important. Think about what kind of information you need to change behavior over time, and recall from the last lab how to encode information into an Object.

Hint: Remember that in defining critters, you get to decide what fields to introduce!

Another hint: Think about what kind of field is suitable. What type of variable captures that we'll either want to be magenta or white?

Exercise : LabTA Version 4

To allow your LabTA critters to change colors on alternate moves, they need to keep track of where they are in the cycle. For example, you could introduce a boolean field that keeps track of whether a LabTA should be displaying itself as magenta or as white. You can then switch the boolean value each time the LabTA makes a move.

  • Add a field to your class called isWhite to keep track of whether the LabTA should be white, or not (in which case it should be magenta). Remember that fields should be declared to be private. Also recall that the default value of a boolean is false.
  • Modify the getMove method to flip this boolean value each time getMove() is called.
    Important: Can the boolean switch be flipped in a different method? Why/why not?
  • Rewrite the getColor method using the isWhite boolean to change colors as expected.
  • Test your new version by recompiling the LabTA class and running CritterMain.

Expression : Solution

import java.awt.*;
public class LabTA extends Critter {
    
    // default value = false
    private boolean isWhite;
    
    public Direction getMove() {
        isWhite = !isWhite;
        return Direction.NORTH;
    }
    
    public Color getColor() {
        if (isWhite) {
            return Color.WHITE;
        } else {
            return Color.MAGENTA;
        }
    }
    
    // methods implemented earlier ommitted
}

Exercise : Important: another solution

import java.awt.*;
public class LabTA extends Critter {
    
    // default value = 0
    private int moves;
    
    public Direction getMove() {
        moves++;
        return Direction.NORTH;
    }
    
    public Color getColor() {
        if (moves % 2 == 1) {
            return Color.WHITE;
        } else {
            return Color.MAGENTA;
        }
    }
    
    // methods implemented earlier ommitted
}


There are many ways of storing information about the state of the Critter. On the last slide, we used a boolean (isWhite). When there are only two possible outcomes, booleans are better style.


Some tasks will require knowing more information about the Critter's history/state. Using an integer to solve this problem is not the best style. However, you might run into other Critters who will need something like an integer move counter to remember how many moves its made.

Exercise : LabTA Version 5

Now we're going to include a bit of randomness. The current version of the LabTA class always moves NORTH. We are going to change it so that it instead randomly chooses between going EAST and WEST.

To solve this problem, we will need access to a Random object. We don't want to construct one every time we call getMove, so we will instead store it as a field. Remember to import java.util.*; to use Random.

  • Declare a field called rand of type Random. Do not initialize the field where it is declared.
  • Constructors exist to set the initial state of our Objects (initializing fields!) So far, we've been using an implicit constructor that takes no parameters and does nothing when it constructs LabTAs. Now add a constructor that takes no parameters, and in the constructor, initialize the Random object.
  • Modify the getMove method so that it uses the Random object to randomly pick between going WEST and going EAST.
  • Test your new version by recompiling LabTA, and running CritterMain again.

Exercise : Solution

import java.awt.*;
import java.util.*;
public class LabTA extends Critter {

    private boolean isWhite; 
    private Random rand;
    
    public LabTA() {
        rand = new Random();
        isWhite = false;      // this line is not necessary, boolean default value is false
    }
    
    public Direction getMove() {
        isWhite = !isWhite;
        boolean goEast = rand.nextBoolean();
        if (goEast) {
            return Direction.EAST;
        } else {
            return Direction.WEST;
        }
    }    
    // methods implemented earlier ommitted
}

Checkpoint: Congratulations!

Nice job making it this far--labs are tough! Feel free to work with the person next to you for the remaining slides. Labs are a unique opportunity (unlike homework) to collaborate directly on ideas, and practice peer programming.

These next problems get a little more challenging as we explore earlier concepts further.

We put a lot of problems in here so that you have plenty to refer back to later when working on homework. Don't feel bad if you don't finish all of them--Brett can't finish them all in a 50 minute lab, either! :)

Forest the cat says good job!

Exercise : Butterfly practice-it

Define a Critter class named Butterfly with the following behavior:
constructor public Butterfly()
color yellow (Color.YELLOW)
eating behavior never eats (this is the default behavior)
fighting behavior always forfeits (this is the default behavior)
movement behavior moves N, W, N, E, then repeats
toString alternates between "x" and "-" on each move
Hint: recall that we can use an integer to keep track of our moves too!
Another hint: in the past, how did we use an integer to handle 2 distinct cases (even and odd)? Can we generalize that strategy to handle 4 distinct cases?

Exercise : Hyena practice-it

Define a Critter class named Hyena with the following behavior (all unspecified behavior should be default behavior):
  • Move in a rectangular pattern, looking for food, walking NORTH then EAST then SOUTH then WEST. Each time the Hyena walks an entire rectangle or eats food, it starts the rectangle pattern over again but with a rectangle 1 step wider than before. The general pattern is as follows, if the Hyena doesn't find any food:

    N, E, S, W, N, E, E, S, W, W, N, E, E, E, S, W, W, W...
  • If the Hyena encounters food at any point during its movement pattern, it eats the food and starts the pattern over (widened by 1). Ex.

    N, E, S, W, N, E, E (eats food), N, E, E, E, S, W, W (eats food), N, E, E, E, E, S, W, W, W, W, N, E, E, E, E, E...

If you finish them all...

If you finish all the exercises, try out our Practice-It web tool. It lets you solve Java problems from our Building Java Programs textbook.

You can view an exercise, type a solution, and submit it to see if you have solved it correctly.

Choose some problems from the book and try to solve them!