Graphic by Keith Ohlfs
CS111, Wellesley College, Spring 2000

Problem Set 8, Part A

Due: Friday, April 28 at 4:00 p.m.

[CS111 Home Page] [Syllabus] [Lecture Notes] [Assignments] [Programs] [Documentation] [Software Installation] [FAQ] [CS Dept.] [CWIS]

Reading

About this Problem Set

This problem set is being distributed in two parts, both of which will be due at the same time on Friday, April 28. Part A covers arrays and vectors, object diagrams, and data abstraction. Part B covers implementing objects, inheritance, and graphics.

Link to Part B

Link to Extra Credit Problems

How to turn in this Problem Set

Your hardcopy submission should include the following

For your softcopy submission, upload the CardsAndHands and BlackJack folders to your ps8 drop folder.

IMPORTANT NOTES:

  1. Pay careful attention to upper and lower case letters in the filenames.
  2. Once you have used Fetch to upload a file to the cs111 server, you should be sure to doublecheck that the file was actually uploaded. You can do this in Fetch by verifying that the file is now listed in your directory. Not only should you check that the file is listed, but you should check that it does not have a size of 0K. If the file isn't listed or if the size for the document is 0K, this means that there was an error in transferring it via Fetch and you must re-upload the document. When transferring a folder, you should check that its contents have been uploaded correctly. That is, you should be sure to check that every single file that you wish to submit has been uploaded correctly. Often times, although not always, you will see a message "Connection Failed" when there is an error in transferring your files.
  3. If you have trouble uploading files, it may be because you have reached the limits of your Nike file system quota. You will get an error message informing you that this is the problem. In this case, you need to delete some of your old files, either from your home directory or your drop folders (which are also counted toward your quota). To delete a file in Fetch, just drag it to the Trash.
  4. It is your responsibility to keep a personal back-up of every file that you submit electronically until you have received a grade for the assignment.


Task 1: Tree Node Diagram [2 pts]

The purpose of this problem is to give you some practice drawing object diagrams. Recall that an object diagram shows a collection of interconnected class instances. Each instance is drawn as a large box that is labelled by the class name and contains the labelled instance variables of the class. Each variable is a small box that contains either a primitive data type (e.g., int, double, boolean, char) or a pointer to another object. These are in the style of Object Land from earlier in the semester.

Please note that these are not the same as the Box-and-Pointer diagrams we have been using lately.

Consider the following Java class declaration:


class Node { public int value; public Node left; public Node right; public Node (int v, Node l, Node r) { this.value = v; this.left = l; this.right = r; } }

The Node class specifies that instances of the node class have three instance variables: a value variable that holds an integer, and variables left and right that hold pointers to other Node instances. The Node constructor takes an integer and two Node instances and intializes the instance variables with these values.

Here is a sequence of statements that creates and manipulates Node instances:

		
Node a = new Node(1, new Node(2, null, null), new Node(3, new Node(4, null, null), null)); a.left.right = a.right.left; a.left.left = a; Node b = a.left; b.left.value = a.left.value + b.right.value;

Recall that null denotes the null pointer, a special value that can fill any variable of object type in place of a pointer to an object of that type.

In this problem, you are to draw a single object diagram that depicts the variables and objects created by executing the above five statements. Your diagram should include the local variables a and b as well as all of the Node instances that are created. It should show the state of all variables and objects at the end of the execution of the five statements.

Follow these conventions:


Task 2: Cards and Hands [4 pts]

Now that we know how to create our own objects, we can start to write complete programs on our own. Writing a program in an object-oriented language involves figuring out how to model the problem using objects. To start, we will pick a problem domain which is simple, but contains infinite possibilities -- card games. Card games are very easy to implement as computer games. In this problem and the next one, we will explore two aspects of implementing card games. By the end of CS111, we will have covered everything we need to know in order to implement an entire card game (graphical user interfaces will be covered later in CS111).

Although the basic concepts behind cards are simple (there are 52 cards, 13 values and 4 suits), many people may choose to represent them in different ways (for example, think of how many different designs for decks of cards you have seen). However, there is a contract that the cards follow which makes it possible to use cards from different decks in the same card game (generally) and identifies these cards as normal playing cards as opposed to other types of cards (such as baseball cards or business cards). The following is the Card Contract that we will be working with in this problem set. There are many alternative contracts that can be written just for cards.


Card Contract

Constants

Values are ordered 2-10, JACK, QUEEN, KING, ACE (lowest to hightest).
public final static int TWO;
public final static int
THREE;
public final static int
FOUR;
public final static int
FIVE;
public final static int
SIX;
public final static int
SEVEN;
public final static int
EIGHT;
public final static int
NINE;
public final static int
TEN;
public final static int
JACK;
public final static int
QUEEN;
public final static int
KING;
public final static int
ACE;

Suits are ordered CLUBS, DIAMONDS, HEARTS, SPADES (lowest to highest).
public final static int CLUBS;
public final static int
DIAMONDS;
public final static int
HEARTS;
public final static int
SPADES;

Public Constructors

public Card (int value, int suit);
Creates a card with the specified value and suit.

Public Instance Methods

public int getValue ();
Returns the value of the card.

public int getSuit ();
Returns the suit of the card.

public int compareTo (Card otherCard);
Returns 0 if cards have the same value and suit. Returns a number less than zero if this card is less than the other card. Returns a number greater than zero if this card is greater than the other card. Cards are ordered by value first, and then by suit.

public boolean equals (Card otherCard);
Returns true if cards have the same value and suit. Otherwise, returns false.

public String valueString ();
Returns a String representation of the value of the card. 2-9 for card values TWO through NINE, "T" for TEN, "J" for JACK, "Q" for QUEEN, "K" for KING, "A" for ACE " " for a card with an unknown (or nonstandard) value.

public String suitString ();
Returns a String representation of the suit of the card. "C" for CLUBS, "D" for DIAMONDS, "H" for HEARTS, "S" for SPADES " " for a card with an unknown (or nonstandard) suit.

public String toString ();
Returns a String representation of the card. This is the String representation of the value of the card followed by the String representation of the suit of the card. For example, the ACE of SPADES would be "AS".


The Card class is implemented in the file Card.java. You do not need to understand the Card implementation to do these problems. The point of having a contract is so that programmers may use objects that other programmers have written without having to know the details of how those objects were implemented. However, the Card implementation is certainly within your reach, so you may study it if you are curious.

Now that we have cards, we need to be able to possess a collection of cards (commonly called a hand of cards). It turns out that there are numerous ways to implement collections of items. The idea behind data abstraction is that users should be able to use a data structure regardless of how it is implemented. This is only possible if the multiple implementations of the data structure follow the same contract. In other words, the user interfaces to the multiple implementations must be the same. Java allows us to define interfaces with the interface keyword. An interface in Java is a contract specification without an implementation. The Hand interface is shown below. It is in the file Hand.java. We do not modify this file.

 

// A Hand is an ordered collection of cards. The cards are indexed starting at zero. public interface Hand { // Public Constructors // Default constructor // Returns an empty hand (i.e. a hand with no cards). // Public Instance Methods // Returns the number of cards in the hand. public int size (); // Adds a card c to the hand so it is at the last index. public void add (Card c); // Returns the card at index i in the hand. // The behavior is unspecified for indices out of range. public Card get (int i); // Inserts the card at index i to the hand. // The indices of all cards whose index was initially // greater than or equal to i are incremented by 1. // The behavior is unspecified for indices out of range. public void insert (int i, Card c); // Removes the card at index i from the hand and returns it. // The indices of all cards whose index was initially // greater than i are decremented by 1. // The behavior is unspecified for indices out of range. public Card remove (int i); // Replaces the card at index i with c and returns the card replaced. // The behavior is unspecified for indices out of range. public Card set (int i, Card c); // Rearranges the cards in the hand to be in card sorted order by index, // from low value to high value. public void sort (); // Returns a new Hand that has the same cards as this Hand. public Hand copy (); // Returns the name of this class. public String className (); // Returns a String representation of this Hand. public String toString (); }


So far, we have studied three ways to represent collections of items: lists, arrays, and vectors. We should be able to use any of them for implementing the Hand contract above. Why would we choose one over the other? It turns out that there are differences in performance with using different data structures to represent things. An implementation of the Hand contract using ObjectLists is available in the file ObjectListHand.java. You should study this implementation to understand how it works. Notice that using an ObjectList is bad because ObjectLists can not be changed. Every time we want to add, remove, or arrange cards, we need to create a new ObjectList.

For this problem, we want to implement the Hand contract using arrays and vectors, and think about which implementation is better and why. The code for this problem is in the folder CardsAndHands. Using AppletViewer to run the file HandTest.html, we can see the correct results of all the test cases using an ObjectList implementation. The test cases should yield the exact same results for the array and vector implementations. The className and toString methods for the array and vector implementations have already been done. Our task will be to flesh out the rest of the Hand contract. Follow the guidelines below for doing the implementation:

Part a -- array implementation
The skeleton for the array implementation is in the file ArrayHand.java. Below are some array-specific implementation details to follow:

Part b -- Vector implementation
The skeleton for the Vector implementation is in the file VectorHand.java. copy is the only method which involves creating a new Vector. No other method in the Vector implementation of Hand should create new Vectors!

The correct output for the Test Cases is shown below.


*********************************************************** Creating a new hand size:0; cards: ObjectListHand[] Add one card: 2D size:1; cards: ObjectListHand[2D] Add many cards: QC, KH, 6C, 7D, TS size:6; cards: ObjectListHand[2D,QC,KH,6C,7D,TS] ----------------------------------------------------------- Get card from 0: 2D Get card from 3: 6C Get card from 5: TS ----------------------------------------------------------- Insert card at 5: AH size:7; cards: ObjectListHand[2D,QC,KH,6C,7D,AH,TS] Insert card at 0: AS size:8; cards: ObjectListHand[AS,2D,QC,KH,6C,7D,AH,TS] Insert card at 8: JC size:9; cards: ObjectListHand[AS,2D,QC,KH,6C,7D,AH,TS,JC] ----------------------------------------------------------- Remove card from 3; Removed card: KH size:8; cards: ObjectListHand[AS,2D,QC,6C,7D,AH,TS,JC] Remove card from 0; Removed card: AS size:7; cards: ObjectListHand[2D,QC,6C,7D,AH,TS,JC] Remove card from 6; Removed card: JC size:6; cards: ObjectListHand[2D,QC,6C,7D,AH,TS] ----------------------------------------------------------- Add cards: JS, AC size:8; cards: ObjectListHand[2D,QC,6C,7D,AH,TS,JS,AC] Set card 7H at 5; Replaced card: TS size:8; cards: ObjectListHand[2D,QC,6C,7D,AH,7H,JS,AC] Set card KS at 0; Replaced card: 2D size:8; cards: ObjectListHand[KS,QC,6C,7D,AH,7H,JS,AC] Set card QC at 7; Replaced card: AC size:8; cards: ObjectListHand[KS,QC,6C,7D,AH,7H,JS,QC] ----------------------------------------------------------- Copy hand: hand: size:8; cards: ObjectListHand[KS,QC,6C,7D,AH,7H,JS,QC] copy: size:8; cards: ObjectListHand[KS,QC,6C,7D,AH,7H,JS,QC] Remove card 4 from copy; Removed card: AH hand: size:8; cards: ObjectListHand[KS,QC,6C,7D,AH,7H,JS,QC] copy: size:7; cards: ObjectListHand[KS,QC,6C,7D,7H,JS,QC] Remove card 7 from hand; Removed card: QC hand: size:7; cards: ObjectListHand[KS,QC,6C,7D,AH,7H,JS] copy: size:7; cards: ObjectListHand[KS,QC,6C,7D,7H,JS,QC] Add cards to hand: 3D, AH hand: size:9; cards: ObjectListHand[KS,QC,6C,7D,AH,7H,JS,3D,AH] copy: size:7; cards: ObjectListHand[KS,QC,6C,7D,7H,JS,QC] ----------------------------------------------------------- Sort hand: hand: size:9; cards: ObjectListHand[3D,6C,7D,7H,JS,QC,KS,AH,AH] ----------------------------------------------------------- Test Hand Sort initial hand: ObjectListHand[AS,QS,TS,8S,6S,4S,2S,AH,QH,TH,8H,6H,4H,2H,AD,QD,TD,8D,6D,4D,2D,AC,QC,TC,8C,6C,4C,2C] sorted hand: ObjectListHand[2C,2D,2H,2S,4C,4D,4H,4S,6C,6D,6H,6S,8C,8D,8H,8S,TC,TD,TH,TS,QC,QD,QH,QS,AC,AD,AH,AS]