Lab
Activity 1
Introduction:
In this activity, you will complete a Card class that will be used to create card objects.
Think about card games you’ve played. What kinds of information do these games require a card object to “know”? What kinds of operations do these games require a card object to provide?
Exploration:
Now think about implementing a class to represent a playing card. What instance variables should it have? What methods should it provide? Discuss your ideas for this Card class with classmates.
Read the partial implementation of the Card class available in the Activity1 Starter Code folder. As you read through this class, you will notice the use of the @Override annotation before the toString method. The Java @Override annotation can be used to indicate that a method is intended to override a method in a superclass.
In this example, the Object class’s toString method is being overridden in the Card class. If the indicated method doesn’t override a method, then the Java compiler will give an error message.
Here’s a situation where this facility comes in handy. Programmers new to Java often encounter problems matching headings of overridden methods to the superclass’s original method heading. For example, in the Weight class below, the tostring method is intended to be invoked when toString is called for a Weight object.
public class Weight {
private int pounds;
private int ounces;
…
public String tostring(String str) {
return this.pounds + ” lb. ” + this.ounces + ” oz.”;
}
…
}
Unfortunately, this doesn’t work; the tostring method given above has a different name and a different signature from the Object class’s toString method. The correct version below has the correct name toString and no parameter:
public String toString() {
return this.pounds + ” lb. ” + this.ounces + ” oz.”;
}
Activity 1: Design and Create a Card Class
The @Override annotation would cause an error message for the first tostring version to alert the programmer of the errors.
Exercises:
1. Complete the implementation of the provided Card class. You will be required to complete:
a. a constructor that takes two String parameters that represent the card’s rank and suit, and an int parameter that represents the point value of the card;
b. accessor methods for the card’s rank, suit, and point value;
c. a method to test equality between two card objects; and
d. the toString method to create a String that contains the rank, suit, and point value of the card object.
The string should be in the following format:
rank of suit (point value = pointValue)
- Once you have completed the Card class, find the CardTester.java file in the Activity1 Starter Code folder. Create three Card objects and test each method for each Card object.
/** Sample Output:
The rank of the first card is: Queen
The suit of the first card is: Hearts
The point value of the first card is: 12
In summary, the first card is the Queen of Hearts (12)
The rank of the second card is: Five
The suit of the second card is: Spades
The point value of the second card is: 5
In summary, the second card is the Five of Spades (5)
The rank of the third card is: Five
The suit of the third card is: Spades
The point value of the third card is: 5
In summary, the third card is the Five of Spades (5)
The first card and the second card are not equivalent.
The second card and the third card are equivalent.
The first card and the third card are not equivalent.
*/
Activity 2: Initial Design of a Deck Class
Introduction:
Think about a deck of cards. How would you describe a deck of cards? When you play card games, what kinds of operations do these games require a deck to provide?
Exploration:
Now consider implementing a class to represent a deck of cards. Describe its instance variables and methods, and discuss your design with a classmate.
Read the partial implementation of the Deck class available in the Activity 2 Starter Code folder. This file contains the instance variables, constructor header, and method headers for a Deck class general enough to be useful for a variety of card games.
Discuss the Deck class with your classmates; in particular, make sure you understand the role of each of the parameters to the Deck constructor, and of each of the private instance variables in the Deck class.
Exercises:
1. Complete the implementation of the Deck class by coding each of the following:
• Deck constructor — This constructor receives three arrays as parameters. The arrays contain the ranks, suits, and point values for each card in the deck. The constructor creates an ArrayList, and then creates the specified cards and adds them to the list.
For example, if ranks = {“A”, “B”, “C”}, suits = {“Giraffes”, “Lions”}, and values = {2,1,6}, the constructor would create the following cards:
[“A”, “Giraffes”, 2], [“B”, “Giraffes”, 1], [“C”, “Giraffes”, 6], [“A”, “Lions”, 2], [“B”, “Lions”, 1], [“C”, “Lions”, 6]
and would add each of them to cards. The parameter size would then be set to the size of cards, which in this example is 6.
Finally, the constructor should shuffle the deck by calling the shuffle method. Note that you will not be implementing the shuffle method until Activity 4.
• isEmpty — This method should return true when the size of the deck is 0; false otherwise.
• size — This method returns the number of cards in the deck that are left to be dealt.
• deal — This method “deals” a card by removing a card from the deck and returning it, if there are any cards in the deck left to be dealt. It returns null if the deck is empty. There are several ways of accomplishing this task. Here are two possible algorithms:
Algorithm 1: Because the cards are being held in an ArrayList, it would be easy to simply call the List method that removes an object at a specified index, and return that object. Removing the object from the end of the list would be more efficient than removing it from the beginning of the list. Note that the use of this algorithm also requires a separate “discard” list to keep track of the dealt cards. This is necessary so that the dealt cards can be reshuffled and dealt again.
Algorithm 2: It would be more efficient to leave the cards in the list. Instead of removing the card, simply decrement the size instance variable and then return the card at size. In this algorithm, the size instance variable does double duty; it determines which card to “deal” and it also represents how many cards in the deck are left to be dealt. This is the algorithm that you should implement.
- Once you have completed the Deck class, find DeckTester.java file in the Activity2 Starter Code folder. Add code in the main method to create three Deck objects and test each method for each Deck object.
Questions:
1. Explain in your own words the relationship between a deck and a card.
- Consider the deck initialized with the statements below. How many cards does the deck contain?
String[] ranks = {“jack”, “queen”, “king”};
String[] suits = {“blue”, “red”};
int[] pointValues = {11, 12, 13};
Deck d = new Deck(ranks, suits, pointValues);
- The game of Twenty-One is played with a deck of 52 cards. Ranks run from ace (highest) down to 2 (lowest). Suits are spades, hearts, diamonds, and clubs as in many other games. A face card has point value 10; an ace has point value 11; point values for 2, …, 10 are 2, …, 10, respectively. Specify the contents of the ranks, suits, and pointValues arrays so that the statement
Deck d = new Deck(ranks, suits, pointValues);
initializes a deck for a Twenty-One game.
- Does the order of elements of the ranks, suits, and pointValues arrays matter?
/** TESTING
Testing deck1
deck1 size: 3
deck1 deal: three of hearts (point value = 3)
deck1 size: 2
Is deck1 empty?: false
Testing deck2
deck2 size: 1
deck2 deal: ten of diamonds (point value = 10)
deck2 size: 0
Is deck2 empty?: true
Testing deck3
deck3 size: 2
deck3 deal: queen of clubs (point value = 12)
deck3 size: 1
Is deck3 empty?: false
*/