[ Home | Sun Java Docs | Greeter | Robot | Keyboard | Documentation ]


Session 1: Basic Java


 

Notes

This session will cover the following topics, using DrJava:


 

Overview

The Java programming language was introduced by Sun Microsystems in 1995. It is an object-oriented, architecture-neutral, distributed, and multithreaded programming language.

A Java program consists of one or more classes. For each class, the compiler generates portable bytecode in a .class file, which will run on any implementation of the Java Virtual Machine (JVM).

Java provides the following:


 

Variables and Expressions

Declaration statement:

type id;
type id = expr;
type id1 = expr1, id2 = expr2, ... ;

Unary and assignment operators associate right to left, all others associate left to right.

Operator Hierarchy

Member access .
Unary !, -, ++, -, (int), new
Arithmetic *, /, %
+, -
Relational <, <=, >, >=, ==, !=, instanceof
Logical &&
||
Assignment =, +=, -=, *=, /=, %=

Some examples:

> int x;
> x
Error: Variable 'x' uninitialized
> int y = 2 + 3 * 4;
> y
14
> int a = 11, b = a % 3;
> b
2
> x = 42;          // assignment
> System.out.println("x = " + x);
x = 42
> x++;             /* equivalent to: x = x + 1; */
> System.out.println("x = " + x);
x = 43
> x++
43
> x
44
> ++x
45
> x
45

Other basic types:

Type Literals for the Type
Primitive int 5, -123, 0, Integer.MAX_VALUE, ...
double 5.0, -1.23, 0.0, Math.PI, ...
char 'a', 'A', '5', '\n', '\", '\\', '\u03af', ...
boolean true, false

Object String null, "", "A", "abc de", "\"hello\"", ...
Robot new Robot()


 

Strings

Strings are immutable. There exists a rich collection of methods that operate on strings.

> String pet = "snake";
> pet.toUpperCase()
"SNAKE"
> pet
"snake"
> pet.length()
5
> pet.charAt(0)
's'
> pet.indexOf('a')
3
> pet.indexOf('x')
-1
> pet == "snake"
false
> pet.equals("snake")            // equals is universal
true
> pet.equalsIgnoreCase("Snake")
true
> pet.compareTo("monkey") < 0
false
> pet.equals("snake")            
> pet.toString()                 // toString is universal
"snake"

The signature of a method is the number of parameters, together with the type of each parameter. (Note: the return value type is not part of a method signature.) Multiple versions of a method, all with the same name, may be defined as long as they have different signatures, in which case we say the method is overloaded. The substring method is overloaded in the String class.

> pet.substring(3)
"ke"
> pet.substring(1, 3)
"na"


 

Building a Class

A class defines the state and behavior of an object. Here's a simple class definition whose objects have just one behavior.

public class Greeter {
  public String welcome() {
    return "Hello";
  }
}

We use the new operator to create objects of a class type. We can create as many objects as we like; they all have the same behavious, but they are all separate and distinct entities.

> Greeter g = new Greeter();
> g.welcome()
"Hello"
> g == g
true
> g.equals(g)
true
> g.equals(new Greeter())
false
> new Greeter().welcome()
"Hello"
> g.toString()          // returns some useless and uninteresting string
???

We can make Greeter a little more interesting by overloading welcome to take a String parameter. We can also override the definition of toString so that it returns the class name.

public class Greeter {
  public String welcome() {
    return "Hello";
  }

  public String welcome(String name) {
    return "Hello " + name;
  }

  public String toString() {
    return "Greeter";
  }
}

Here are some examples using this new definition:

> g = new Greeter();
> g.welcome()
"Hello"
> g.welcome("Alice")
"Hello Alice"
> g.welcome("Bob")
"Hello Bob"
> g
Greeter

Suppose we want to be able to express the greetings in different languages, say either German, French or English. That is, we'd like to do something like this:

> g = new Greeter();
> g.getLanguage()
"English"
> g.setLanguage("German");
> g.welcome()
"Guten Tag"
> g.welcome("Alice")
"Guten Tag Alice"
> g.setLanguage("French");
> g.welcome()
"Bonjour"
> new Greeter().welcome()
"Hello"
> g
Greeter[language=French]

The getLanguage method is called an accessor method because it retrieves (i.e., accesses) some particular property of the object which is the invoking instance. The setLanguage method is called a mutator because it actually makes a change to the state of the invoking instance.

To implement this language feature, we need to give each object its own individual variable. Such variables are called instance variables because they appear in each and every instance of the class that we create using new.

In order to map a language to a welcome we'll need to make use of a branching statement:

if (boolean-expr)
    statement

if (boolean-expr)
    statement
else
    statement

Putting it all together now:

public class Greeter {
  // instance variable
  private String language = "English";

  public String welcome() {
    if (language.equalsIgnoreCase("German"))
      return "Guten Tag";
    if (language.equalsIgnoreCase("French"))
      return "Bonjour";
    return "Hello";
  }

  public String welcome(String name) {
    return welcome() + " " + name;
  }

  public String getLanguage() {
    return language;
  }

  public void setLanguage(String dialect) {
    language = dialect;
  }

  public String toString() {
    return "Greeter[language=" + getLanguage() + "]";
  }
}

Notice how we avoided redundant code by implementing the one welcome method in terms of the other. Also note that we designated the instance variable as private. This is to prevent unauthorized access to the internal state of the object by some client outside the class.

> g = new Greeter();
> g.language = "Swahili";
IllegalAccessException: field is private


 

Constructors

Unlike local variables, instance variables are automatically initialized. Unless otherwise specified in the declaration, variables of type int contain zero, by default, doubles contain 0.0, booleans contain false, andStrings and other object references contain null.

A constructor is a procedure which is called at object creation time (i.e., when the new operator is applied). The sole purpose of the constructor is to initialize the state of the object. A constructor has no return value type and its name must agree with the class name. If a constructor takes arguments, then they are supplied when the object is created by new. For example,

> g = new Greeter("French");
> g.getLanguage()
"French"

If you do not define any constructors in your class (as has been the case for our Greeter class, up to now), then Java automatically provides you with a default constructor, which does (essentially) nothing.

In our Greeter class, we'll need to define two constructors: one that allows us to create Greeter objects from a particular language and another one that is the default constructor. If we do not define the default constructor explicitly, we will not be able to create garden-variety objects like this: new Greeter().

public Greeter() {
}

public Greeter(String language) {
  setLanguage(language);
}


 

Class Constants

It's typical for a class to provide some public constants that aid in the construction of objects.

> Math.PI
3.141592653589793
> java.awt.Color.RED
java.awt.Color[r=255,g=0,b=0]
> Greeter.ENGLISH
"English"
> Greeter.FRENCH
"French"
> g = new Greeter(Greeter.FRENCH);

Note that these class constants are accessed via the class name, not a particular object. Such constants are designated as static. There is only one copy of each constant (they are not duplicated as instance variables in each object), and every object of the class type has access to the static data.


 

Lab Exercises

Getting Started

Your computer should already be logged into the jett account. (Since everybody is using the same account, please act responsibly!) Perform the following tasks. If you have trouble with anything, then please ask one of the lab assistants for help!

You can review the Greeter and Keyboard code, if you like, but we will be concentrating on the Robot class for the rest of this session.

Here are the exercises we'd like for you to complete:

  1. Take a look at the two definitions of step in the Robot class. Notice that the step(int) method uses a while loop to iterate the body of the loop. Here the syntax for a while statement:

    while (boolean-expr)
        statement

    If we wish to repeat more than just a single statement, then we can use the compound statement, which makes multiple statements look like one.

    {
        statement1
        statement2
        ...
        statementn
    }

    Try out some experiments with these statements in the Interactions window. In the following example, we use multiple lines, but when you type a statement/expression in the Interactions window, you have to type it all on a single line. (Note: cut and paste does work, so if you type a multi-line code fragment into the editor and then paste it into the Interactions window, it will be interpreted fine.)

    > n = 5;
    > i = 0;
    > String language = null;
    > while (i < n) {
        if (i % 2 == 0)
           language = "English";
        else
           language = "German";
        System.out.println(new Greeter(language).welcome());
        System.out.println("i = " + i);
        i++;
      }
    ???
    > i
    ???
    

  2. What do you notice about the wallInFront method? Can you fix it so that it works properly. Try to do it without using an if-else statement. (Note: the logical and operator is denoted as && and the logical or operator is denoted by ||.)

  3. Provide constructors that allow the client to create a Robot from nothing, from an initial position, or from an initial position and direction.

    > alice = new Robot();
    > bob = new Robot(3);
    > charlie = new Robot(5, Robot.SOUTH);
    > alice
    I am at position 1 facing north.
    > bob
    I am at position 3 facing north.
    > charlie
    I am at position 5 facing south.
    

  4. Your instructor will explain the concept of an array in Java. Follow the experiments she performs and try some others of your own.

  5. Assume that the robot is a letter-carrier. At creation time he is carrying a bag containing Robot.NUM_INITIAL_LETTERS letters. On a drop, he takes a single letter out of his bag and places it at his feet on the square he's standing on. On a pickup, he retrieves all the letters at his feet and puts them in his bag. The inventory method returns the number of letters in the robot's bag. The look method prints a message indicating what the robot sees at his current position.

    > Robot.NUM_INITIAL_LETTERS
    3
    > charlie = new Robot(5, Robot.SOUTH);
    > charlie
    I am at position 5 facing south and carrying 3 letters.
    > charlie.look();
    I don't see anything here.
    > charlie.inventory()
    3
    > charlie.drop();
    > charlie.look();
    I see a letter here.
    > charlie.drop();
    > charlie.look();
    I see 2 letters here.
    > charlie.drop();
    > charlie.step();
    > charlie.look();
    I don't see anything here.
    > charlie.pickup();
    I don't see anything here.
    > charlie.turnAround();
    > charlie.step();
    > charlie.look();
    I see 3 letters here.
    > charlie.pickup();
    > charlie
    I am at position 5 facing north and carrying 3 letters.
    

  6. If you get done with these exercises before the end of the session, then try out one (or more) of the "Sample Lessons" in the next section. The Procrastinator problem, number 3, is fun!


 

Sample Lessons

Here are some suggested problems that can be assigned to students. A list of the material required by each exercise appears in square brackets.

  1. [String, int, classes w/o constructors, methods w/o parameters, return, toString(), maintaining state, incrementing a counter]

    Define a class named Tree with the following three methods inside the Tree class:

    Here are some examples of the usage of this class:

    > t = new Tree();
    > t.toString()
    "
        *
       / \
      /   \
     /     \
    /-------\
       " "
       " "
       " "
    "
    > t.getHeight()
    8
    > t.getTreeTop()
    "*"
    

    Modify this class so that the symbol used for the tree top can be changed by the user, like this:

    > t.setTreeTop("#")
    > t.getTreeTop()
    "#"
    > t
    
        #
       / \
      /   \
     /     \
    /-------\
       " "
       " "
       " "
    
    

    Finally, include a grow method which increases the height of the tree by adding another row to its trunk.

    > t.getHeight()
    8
    > t.grow()
    > t
    
        #
       / \
      /   \
     /     \
    /-------\
       " "
       " "
       " "
       " "
    
    > t.getHeight()
    9
    

  2. [double, arithmetic, parameters, constructors, setters and getters, void]

    To calculate your weight on another world, you multiply your earthly weight by a certain factor determined by the other planet's gravitational pull. The following table gives the correspondence between weights on Earth and weights on the other planets.

    Planet What one earthly pound weighs on other planet
    Mercury .378
    Venus .906
    Earth 1.0
    Mars .379
    Jupiter 2.533
    Saturn 1.066
    Uranus .905
    Neptune 1.133
    Pluto .067

    Define a Planet class that works like this:

    > mercury = new Planet();
    > mercury.setName("Mercury");
    > mercury.setFactor(.378);
    > mercury
    Planet[name=Mercury,factor=0.378]
    > mercury.getName()
    "Mercury"
    > mercury.getFactor()
    0.378
    > mercury.convert(100.0)
    37.8
    > mercury.convert(1000.0)
    378.0
    > neptune = new Planet();
    > neptune
    Planet[name=null,factor=0.0]
    > neptune.setName("Neptune");
    > neptune.setFactor(1.133);
    > weight = 123.4;
    > p = mercury;
    > p.convert(weight)
    46.6452
    > p = neptune;
    > p.convert(weight)
    139.81220000000002
    

  3. [variables, assignment, sequencing, maintaining state]

    Define a class named Procrastinator as follows. A Procrastinator object is initialized with two Strings representing tasks to be performed, as shown below. It has a method named doTask that takes a String s. When doTask is applied, it returns a message saying that I'll do s right after I do something else. The "something else" is whatever the Procrastinator object was asked to do two steps previously, using the initial strings to get the ball rolling.

    > p = new Procrastinator();
    > p.init("take a nap", "watch TV")
    > p.doTask("wash the dishes")
    "I'll wash the dishes right after I take a nap."
    > p.doTask("do my homework")
    "I'll do my homework right after I watch TV."
    > p.doTask("feed the dog")
    "I'll feed the dog right after I wash the dishes."
    > p.doTask("mow the lawn")
    "I'll mow the lawn right after I do my homework."
    > p.init("floss my teeth", "do laundry")
    > p.doTask("change the lightbulb")
    "I'll change the lightbulb right after I floss my teeth."
    

  4. [local variables (for swap), assignment, sequencing, maintaining state]

    I can easily switch between two television stations using my remote control because it remembers the previous channel before changing to a new channel. Initially, the television is tuned to channel 3.

    Define a class named RemoteControl that models this behavior. Here's how your class should work:

    > rc = new RemoteControl();
    > rc.getChannel()
    3
    > rc.changeChannel(56)
    > rc.getChannel()
    56
    > rc.goBack()
    > rc.getChannel()
    3
    > rc.goBack()
    > rc.getChannel()
    56
    > rc.changeChannel(8)
    > rc.goBack()
    > rc.getChannel()
    56
    > rc.goBack()
    > rc.getChannel()
    8
    > rc = new RemoteControl();
    > rc.goBack()
    > rc.getChannel()
    3
    > rc.goBack()
    > rc.getChannel()
    3 
    

  5. [variables, assignment, sequencing, maintaining state, methods that call methods, constructors]

    Robert Hanssen, a convicted spy, is said to have communicated with his Russian counterpart via a dead drop. They never met, but would leave messages for one another in plastic bags under a bridge. To indicate that a message was waiting to be picked up, they would leave a signal in a public place (in this case, it was a chalk mark on a mailbox).

    This form of anonymous communication has many advantages over a face-to-face meeting, among which are:

    Define a class named DeadDrop to represent a location that can hold at most one message. This class has two constructors and four methods, including the customary toString method.

    The toString method should not reveal the contents of the message, if one exists, in the dead drop. Here's an example of how your class should work. Make sure that it behaves exactly as shown in the following transcript.

    > lamppost = new DeadDrop();
    > lamppost.getDropCount()
    0
    > lamppost
    DeadDrop[there's no message here]
    > lamppost.pickup()
    null
    > lamppost.drop("The blue jay sings at noon.")
    > lamppost
    DeadDrop[there's one message waiting for pickup]
    > lamppost.pickup()
    "The blue jay sings at noon."
    > lamppost.pickup()
    null
    > lamppost.drop("The cat's tail is too short.")
    > lamppost.drop("No, no! The cat's tail is too LONG!")
    > lamppost.pickup()
    "No, no! The cat's tail is too LONG!"
    > lamppost.getDropCount()
    3
    > bushes = new DeadDrop("Just concentrate on the sauerkraut.");
    > bushes.getDropCount()
    1
    > bushes
    DeadDrop[there's one message waiting for pickup]
    > bushes.pickup()
    "Just concentrate on the sauerkraut."
    > bushes
    DeadDrop[there's no message here]
    

    Try to avoid redundant code. For example, if you arrange things properly, then you should only have one statement in your class that modifies your drop counter.

  6. [Math, overloaded methods]

    Define a class named Circle that represents a circle in the (x, y)-plane. A circle is described by its center point and its radius. Use two integers for the point and a double for the radius. Provide the usual getter and setter methods, methods for computing the area and circumference of the circle, as well as some mutators, as shown below, to change the size and location of the circle.

    > c = new Circle(10, 20, 5.67)
    Circle[x=10,y=20,radius=5.67]
    > c.translate(3, -2)
    > c.getX()
    13
    > c.getY()
    18
    > c.getRadius()
    5.67
    > c.area()
    100.9987480609929
    > c.circumference()
    35.625660691708255
    > c.setX(42)
    > c.setY(c.getY())
    > c.circumference()
    35.625660691708255
    > c.addPoint(5, 2)
    > c
    Circle[x=42,y=18,radius=40.311288741492746]
    > c.addPoint()           // adds the origin (0,0) to the circle
    > c.circumference()
    287.1078820894653
    > c
    Circle[x=42,y=18,radius=45.69463863518345]
    > c.setRadius(37.2)
    > c
    Circle[x=42,y=18,radius=37.2]
    > c.addPoint(c.getX(), c.getY())
    > c
    Circle[x=42,y=18,radius=0.0]
    

    If you don't know the formulas for computing the area and/or circumference of a circle, then look them up. The addPoint method takes an (x, y)-coordinate and adjusts the circle so that the given point is on the circle. (Hint: use the Pythagorean Theorem to find the new radius.) The translate method updates the location of the circle by adjusting the coordinates of the center point according to the amounts given as arguments.

    Make use of the following constants and methods from the Math class.

    > Math.PI
    3.141592653589793
    > Math.sqrt(81)        // computes the square root of 81
    9.0
    > Math.pow(2, 10)      // computes 2 raised to the 10 power
    1024.0
    > Math.pow(3, 4)
    81.0
    > Math.pow(78392, 0)
    1.0
    

  7. [coupled classes, objects as parameters, System.err, class constants, predicates]
    1. Define a class named Product that works like this:

      > Product p = new Product("milk", 2);
      > p.getName()
      "milk"
      > p.getWeight()
      2
      > p
      Product[name=milk,weight=2]
      > p = new Product("eggs", -12);
      -12 is an invalid weight, so I'll assume you mean 1.
      > p.getWeight()
      1
      > new Product("feather", 0)
      Product[name=feather,weight=0]
      > p = new Product("", 0);
      > p.getName()
      ""
      

      Notice that when the constructor detects an invalid weight (i.e., a negative number of pounds), it prints a message to System.err. Assume all product weights are ints.

      Right now a Product only encapsulates two pieces of information, a name and a weight, but later we may also want to include other information, such as cost and bar code data.

    2. Define a class named Bag with the following specifications:

      • new Bag() creates a Bag that can hold up to 10 pounds.

      • new Bag(capacity) creates a Bag that can hold up to capacity pounds, where capacity represents the maximum number of pounds the bag can hold. If capacity is negative, then print an error message to System.err and use 10 as the bag's capacity. Assume capacity is an int.

      • b.getCapacity() returns the capacity, in pounds, of the bag b.

      • b.getWeight() returns the combined weight of all items currently in the bag b.

      • b.isEmpty() returns true if the bag b is empty, and false otherwise.

      • b.canFit(p) returns true if the bag b can hold the product p, and false otherwise. This method does not actually change the bag. It just determines whether or not an item weighing p.getWeight() pounds can fit in the bag.

      • b.addItem(p) mutates the bag b by adding the product p to the bag, if it fits. If the addition of this item would cause the bag to exceed its capacity, then the bag is left unchanged and a message is printed to System.out as shown below.

      • b.toString() returns a string representing the contents of the bag. If the bag is empty, then null is returned. Otherwise, a string containing the names of the items that have been added to the bag, separated by commas, is returned.

      Here's an example of how this class works.

      > Bag b = new Bag(12);
      > b
      null
      > b.toString()
      null
      > b.getCapacity()
      12
      > b.isEmpty()
      true
      > b.getWeight()
      0
      > Product staple = new Product("flour", 3);
      > b.addItem(staple);
      > b.isEmpty()
      false
      > staple = new Product("sugar", 5);
      > b.addItem(staple);
      > b
      flour,sugar
      > b.getWeight()
      8
      > b.addItem(new Product("milk", 2))
      > b.addItem(new Product("feather", 0));
      > b
      flour,sugar,milk,feather
      > fat = new Product("butter", 3);
      > b.addItem(fat);
      The butter cannot fit in this bag.
      > b.canFit(fat)
      false
      > fat.getWeight()
      3
      > b.getWeight()
      10
      > b
      flour,sugar,milk,feather
      > b.getCapacity()
      12
      

      Include the following public constant and make use of it in your constructors.

      > Bag.DEFAULT_CAPACITY
      10
      > new Bag().getCapacity()
      10
      > b = new Bag(-4);
      -4 is an invalid capacity, so I'll assume you mean 10.
      > b.getCapacity()
      10
      

      Make sure that your class works properly in the following extreme cases:

      > b = new Bag();
      > b.isEmpty()
      true
      > b
      null
      > b.toString()
      null
      > b.addItem(new Product("", 0));
      > b.isEmpty()
      false
      > b.getWeight()
      0
      > b.toString()
      ""
      > b = new Bag();
      > b.addItem(new Product("null", 0));
      > b
      null
      > b.toString()
      "null"
      > b.isEmpty()
      false
      

  8. [documentation, Math.random(), chaining by returning this, equals]

    Define a Coin class according to these specifications. Here's an example of how this class should behave.

    > Coin c = new Coin();
    > c.isTails()
    true
    > c.turnOver();
    > c.isTails()
    false
    > c.isHeads()
    true
    > c.flip();
    > c.isHeads()
    true
    > c.flip();
    > c.isHeads()
    false
    > int n = 0;
    > while (!c.isHeads()) {
        c.flip();
        n++;
      }
    > System.out.println("I flipped " + n + " times until I got a head.");
    I flipped 4 times until I got a head.
    > n
    4
    > Coin d = new Coin();
    > c.isHeads() == d.isHeads()
    false
    > c.equals(d)
    false
    > c.getValue() == d.getValue() && c.getValue() == 1
    true
    > Coin dime = new Coin(10);
    > dime.getValue()
    10
    > dime
    Coin[value=10,orientation=heads]
    > new Coin(25).flip().flip().flip().flip().turnOver().isHeads()
    true
    

  9. [code reuse, objects as instance variables, char]

    Copy your Coin class and your Product class that you developed earlier into a fresh folder.

    1. Modify the Product class so that it implements the specifications in this documentation. Here's an example of how this class might be used:

      > Product p = new Product("milk", 2, 1.99, 3);
      > p.getName()
      "milk"
      > p.getWeight()
      2
      > p.getUnitCost()
      1.99
      > p.getQuantity()
      3
      > p.inStock()
      true
      > p.purchase();
      > p.getQuantity()
      2
      > p.purchase().purchase().inStock()
      false
      > p.purchase();
      No milk in stock.
      > p
      Product[name=milk,weight=2,unitPrice=1.99,quantity=0]
      > p.equals(new Product("milk", 2, 1.99, 0))
      true
      > p.equals(new Product("coffee", 2, 1.99, 0))
      false
      > p.equals(new Product("milk", 2, 1.99, 4))
      true
      > p.equals(new Product("milk", 3, 1.99, 0))
      false
      > p.equals(new Product("milk", 2, 2.49, 0))
      false
      

      Include error checking in your constructor. Use the same names for your constructor parameters as you do for your instance variables. Hint: use this to distinguish between a parameter and an instance variable with the same name.

    2. Define a class named VendingMachine as described in the documentation. Here's an example of how this class works.

      > VendingMachine vm = new VendingMachine(new Product("Snickers", 1, .65, 2),
                                               new Product("Chips", 1, .75, 3),
                                               new Product("Peanut M&Ms", 1, .85, 5),
                                               new Product("Gum", 1, .40, 1));
      > vm.getCashInBox()
      0
      > vm.printDisplay();
      0 cents has been deposited.
      > vm
      A - Snickers
      B - Chips
      C - Peanut M&Ms
      D - Gum
      > Coin quarter = new Coin(25);
      > Coin dime = new Coin(10);
      > Coin nickel = new Coin(5);
      > vm.insert(quarter).insert(dime).insert(quarter).insert(nickel);
      > vm.printDisplay();
      65 cents has been deposited.
      > vm.getCashInBox()
      0
      > vm.pressButton('D')
      Here's your Gum.
      25
      > vm.getCashInBox()
      40
      > vm
      A - Snickers
      B - Chips
      C - Peanut M&Ms
      D - ***out of stock***
      > vm.pressButton('D')
      We're out of item D. Please make another selection.
      0
      > vm.insert(quarter).insert(quarter).pressButton('D')
      We're out of item D. Please make another selection.
      0
      > vm.printDisplay();
      50 cents has been deposited.
      > vm.pressButton('E')
      No such button as E.
      0
      > vm.pressButton('A')
      Please deposit more money.
      0
      > vm.printDisplay();
      50 cents has been deposited.
      > vm.insert(quarter).pressButton('a')
      Here's your Snickers.
      10
      > vm.getCashInBox()
      105
      > vm.printDisplay();
      0 cents has been deposited.
      > int q = 8;
      > while (q > 0) {
          vm.insert(quarter);
          q--;
        }
      > vm.printDisplay();
      200 cents has been deposited.
      > vm.pressButton('c')
      Here's your Peanut M&Ms.
      115
      > vm.getCashInBox()
      190
      

  10. [user input, objects as return values, string processing]

    In this problem, we implement the child's game of Hangman. You will make use of the Keyboard class to handle user input, so download it to your working directory.

    Consult the documentation for a complete specification of the two classes you are to define, LetterBoard and HangmanGame.

    Here is an example of how LetterBoard should operate:

    > LetterBoard lb = new LetterBoard();
    > lb.contains('a')
    false
    > lb.add('a');
    > lb
    A
    > lb.contains('a')
    true
    > lb.add('e').add('t');
    > lb
    A E T
    > lb.contains('i')
    false
    > lb.add('e');
    > lb
    A E T
    > lb.erase();
    > lb
    
    > lb.add("stuv");
    > lb
    S T U V
    > lb.contains("tv")
    true
    > lb.contains("tvx")
    false
    

    Although the add(String) and contains(String) methods are not required in the implementation of our hangman game, they are just good exercises to gain more practice writing for loops.

    Notice that the HangmanGame constructor selects the secretWord randomly. For now, you can just have it pick from three fixed possibilities. Use whatever words you like. Later we will see how to create a large pool of possible words and choose one at random.

    Here's an example of how this class should work:

    > HangmanGame.NUM_ALLOWED_WRONG_GUESSES
    5
    > HangmanGame g = new HangmanGame();
    > g
    - - - - -
    > g.toString()
    "- - - - -"
    > g.guess('e')
    - - - - E
    > g.guess('x').guess('p')
    - P P - E
    > g.guess('e')
    You've already guessed that letter.
    - P P - E
    > g.getNumWrongGuesses()
    2
    > g.getLetterBoard()
    E X P
    > g.getLetterBoard().contains('e')
    true
    > g.hasWon()
    false
    > g.hasLost()
    false
    > g
    - P P - E
    > g.guess('a')
    A P P - E
    > g.guess('o')
    A P P - E
    > g.guess('l')
    A P P L E
    > g.hasWon()
    true
    > g.hasLost()
    false
    > g.getNumWrongGuesses()
    3
    > g.getLetterBoard()
    E X P A O L
    

    Use for loops whenever you need to iterate some statement a certain number of times. Once you're completely done implementing all the methods shown in the above transcript, implement a play method that enters into an interactive loop with the user. Use Keyboard.readLine() to capture the user input, shown in magenta in the following example:

    > g = new HangmanGame();
    > g.play();
    - - - - - - - -
    Enter your guess: a
    - - - - - - - -         A
    Enter your guess: b
    - - - - - - - -         A B
    Enter your guess: c
    - - - - - - - -         A B C
    Enter your guess: d
    - - - - - - - -         A B C D
    Enter your guess: e
    - - E - E - - -         A B C D E
    Enter your guess: f
    - - E - E - - -         A B C D E F
    Enter your guess: g
    You lost.
    

    Here's another possible play of the same game:

    - - - - - - - -
    Enter your guess: a
    - - - - - - - -         A
    Enter your guess: b
    - - - - - - - -         A B
    Enter your guess: e
    - - E - E - - -         A B E
    Enter your guess: a
    You've already guessed that letter.
    - - E - E - - -         A B E
    Enter your guess: l
    - - E L E - - -         A B E L
    Enter your guess: s
    S - E L E - - -         A B E L S
    Enter your guess: n
    S - E L E - - N         A B E L S N
    Enter your guess: k
    S K E L E - - N         A B E L S N K
    Enter your guess: t
    S K E L E T - N         A B E L S N K T
    Enter your guess: o
    S K E L E T O N         A B E L S N K T O
    You won!
    

    Notice that when you win the game, the entire word is revealed at the last stage.

  11. [arrays as instance variables]

    Define a class named WordPool that allows one to create a pool of words and then select one at random, such that no word in the pool will be repeated until all the words have been used. Here's how this class should work:

    > WordPool wp = new WordPool();
    > wp.add("lions").add("tigers").add("bears");
    > wp
      lions
      tigers
      bears
    > wp.pick()
    "bears"
    > wp
      lions
      tigers
    x bears
    > wp.pick()
    "lions"
    > wp.getNumWords()
    3
    > wp.add("poppies");
    > wp.getNumWords()
    4
    > wp
    x lions
      tigers
    x bears
      poppies
    > wp.pick()
    "poppies"
    > wp.pick()
    "tigers"
    > wp
    x lions
    x tigers
    x bears
    x poppies
    > wp.pick()
    "tigers"
    > wp
      lions
    x tigers
      bears
      poppies
    > WordPool.MAX_WORDS
    4
    > wp.add("and your little dog, too")
    There's no more room in the pool.
    


All materials copyright ©2003 Suzanne Menzel. Last updated December 1, 2003.