Graphic by Keith Ohlfs |
Problem Set 8, Part A
|
[CS111 Home Page] [Syllabus] [Lecture Notes] [Assignments] [Programs] [Documentation] [Software Installation] [FAQ] [CS Dept.] [CWIS]
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.
Your hardcopy submission should include the following
ArrayHand.java
and VectorHand.java
from Task 2BlackjackGame.java
from Task 3For your softcopy submission, upload the CardsAndHands and BlackJack folders to your ps8 drop folder.
IMPORTANT NOTES:
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:
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 intTHREE
;
public final static intFOUR
;
public final static intFIVE
;
public final static intSIX
;
public final static intSEVEN
;
public final static intEIGHT
;
public final static intNINE
;
public final static intTEN
;
public final static intJACK
;
public final static intQUEEN
;
public final static intKING
;
public final static intACE
;
Suits are ordered CLUBS, DIAMONDS, HEARTS, SPADES (lowest to highest).
public final static int
CLUBS
;
public final static intDIAMONDS
;
public final static intHEARTS
;
public final static intSPADES
;
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:
private
ArrayHand (Card[ ]
cards)
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]