Back to 111 Main Page

Mobius strip

Assignment 16

Task

Model a deck of playing cards to practice writing classes and using arrays.

Concepts: Arrays; method overloading; throwing exceptions
Textbook: 7.1 - 7.3; 3.8; 10.5

Steps

Write a program that allows you to draw cards from a deck of playing cards.

Deck.java

Your Deck class must have at least the following methods:

  /**
   * Constructs a new, ordered deck of 52 playing cards.
   * [The order is up to you, but document what it is here.]
   */
  public Deck() {
  }

  /**
   * Draws the top card from this deck and returns it.
   *
   * @exception IllegalStateException  if this deck is currently empty
   *                                  (that is, if getSize() == 0).
   */
  public PlayingCard draw() throws IllegalStateException {
  }

  /**
   * Draws the given number of cards from this deck and returns
   * them in a new array.
   *
   * @exception IllegalArgumentException  if more cards are requested than are
   *              currently in the deck, or if less than 0 cards are requested
   *              (that is, if cards < 0 || cards > this.getSize()).
   */
  public PlayingCard[] draw(int cards) throws IllegalArgumentException {
  }

  /**
   * Returns the number of cards still in this deck.
   */
  public int getSize() {
  }

  /**
   * Shuffles the cards in this deck.
   */
  public void shuffle() {
  }

Your Deck must internally use an array (not an ArrayList!) to manage your cards. If you create a PlayingCard class, it must have a working toString() method. If you'd rather not write a PlayingCard class, you may instead change the draw methods above to return a String and a String[] instead.

However your returned cards are turned into Strings, they should have the following format: Aces, Jacks, Queens, and Kings should be either be spelled out or indicated with an A, J, Q, or K. 2 through 10 should be represented as numbers. Suits may be spelled out or indicated with a D, H, C, or S. The suit should be listed after the card's value. Thus, you may use a form similar to the sample output below, or an abbreviated form, such as 4H, 3C, AS.

Note that the draw methods are an example of method overloading. You will also have to create and throw exceptions from within these methods. However, we are using exceptions that have already been defined in Java. They are runtime exceptions (which means the compiler will not force you to catch them) because they can be avoided if the programmer that uses your Deck class is just careful to check the current size of the deck.

Shuffling. If you need a good shuffling algorithm, check out Fisher-Yates. This page includes a sample Java method, which you are allowed to borrow/modify as long as you cite where it came from. A brief /* comment */ in your code is sufficient. For example:

/* This method uses the Fisher-Yates shuffle algorithm.
   Code copied/modified from: URL */

where URL is the URL of the page the code came from. Note that the shuffle method on the page does not match the signature required of your Deck, so some additional work will still be required.

UsernameA16.java

Your Deck should work correctly as described above. However, to test some of its functionality, also write a program that allows the user to draw as many cards as she'd like from a deck. If they draw 0 cards, your program should quit. Each card drawn should be displayed one per line.

After each draw, your program should state how many cards remain in the deck.

If the last card in the deck is drawn, a new shuffled deck should be created so that drawing may continue until the total number of requested cards have been drawn. The program should indicate when a new deck has been "opened"/created.

Sample Output

This is your digital deck of playing cards!
A new deck has already been opened and shuffled for you.

[52 cards left in deck] How many cards to draw (0 to quit)? 1

10 of Spades

[51 cards left in deck] How many cards to draw (0 to quit)? 7

Ace of Spades
Queen of Diamonds
8 of Clubs
Queen of Clubs
2 of Clubs
3 of Diamonds
3 of Clubs

[44 cards left in deck] How many cards to draw (0 to quit)? 2

10 of Diamonds
King of Spades

[42 cards left in deck] How many cards to draw (0 to quit)? 45

King of Clubs
6 of Hearts
3 of Hearts
Ace of Hearts
5 of Diamonds
6 of Diamonds
King of Diamonds
4 of Clubs
10 of Clubs
6 of Spades
9 of Spades
2 of Spades
2 of Hearts
5 of Spades
8 of Spades
6 of Clubs
4 of Spades
7 of Clubs
King of Hearts
9 of Diamonds
7 of Spades
3 of Spades
7 of Hearts
7 of Diamonds
Queen of Hearts
Jack of Diamonds
Jack of Spades
9 of Hearts
4 of Diamonds
Queen of Spades
Jack of Clubs
Jack of Hearts
9 of Clubs
8 of Diamonds
4 of Hearts
10 of Hearts
5 of Clubs
Ace of Diamonds
8 of Hearts
5 of Hearts
2 of Diamonds
Ace of Clubs
[--Opened a new deck--]
3 of Diamonds
6 of Diamonds
3 of Spades

[49 cards left in deck] How many cards to draw (0 to quit)? 0

What to submit

Upload your UsernameA16.java file to Tamarin. This single file should also contain all the additional classes needed to run your program.

Grading

Out of 9 points:

1 - Compiles
Your program compiles successfully (no errors)
5.5 - Deck
Uses an array (0.5). Contains the specified constructor (producing a normal, ordered deck of 52 playing cards) (1.0). Each returned cards has the output format described above (1.0). Contains the specified methods (3.0).
2.5 - UsernameA16
Always draws the specified number of cards from a shuffled deck, displaying each 1 per line (1.0). Indicates when a new deck has been opened (0.5). Quits on 0, and catches bad input, such as negative numbers (0.5). Indicates how many cards remain in the deck after each draw (0.5)

FAQs

Demo code?
This modified version of SimpleToDoList.java uses an array, rather than an ArrayList, to store the items. (Because this is only an implementation change of encapsulated details, this class will still run the same with the SimpleToDoListUI and other demo files from A15.)

If you want to learn more about exceptions, check out this Java Tutorial section. See, in particular, this discussion of when to throw unchecked (ie, Runtime) rather than checked exceptions.
I understand how to use two for loops to generate the cards. But how do we then translate certain values to Strings? For example, 1 to "Ace", 13 to "King", 2 to "Hearts".
You can use a series of conditionals (or a switch) to determine how to translate your int values to a String. Consider the following:
	String card = "";
	//translate card value
	if (value == 1) {
	  card += "Ace";
	} else if (...) {
	  ...
	}else {
	  card += value;  //for 2 - 10
	}

	//translate suit
	if (suit == 1) {
	  card += " of Diamonds";
	}else if (suit == 2) {
	  card += " of Hearts";
	}else ...

Where you do this is up to you, however. If you're using a PlayingCard class, you could store the suit and value as ints, and then do this translation in the toString() method. Otherwise, in the constructor, you could translate from int parameters to String instance variables.

If you're not using a PlayingCard class, you could just form the String directly in the nested for loops that generate the 52 cards.

My program crashes if I try to draw a lot of cards.
I'd recommend you use the draw method takes no parameters and draws only one card at a time. Then, in the UI, you'll be able to check the deck size before drawing. If there are no cards left, you can replace the empty deck with a new deck before drawing the next card.
Java supports Unicode, which contains card suit characters, as in: ♦ ♥ ♠ ♣. Couldn't we use those?
Theoretically, yes. They do show up correctly in a Java GUI pane. However, they do not appear on the command line (as that rarely uses a font that can actually represent them), so please don't use them for this assignment.
According to that Wikipedia page, Java is probably only going to be able to provide a subset of all possible deck permutations. Is this okay?
Yeah, that's fine. If you're really worried, I suppose you could have your shuffle method actually shuffle the deck multiple times, but it's not required.
Can I see an example of throwing an exception?
Have a look in 10.5 of your textbook and at the Java Tutorial section on exceptions (link in a FAQ above). But admittedly, these examples are rather brief. Basically, you need to test whether something is wrong, and, if so, throw an exception. Here's what you might have in your draw() method:
  if (this.getSize() == 0) {
    throw new IllegalStateException("The deck is empty.");
  }
You don't need to put the message in there; you can just: throw new IllegalStateException();

This ensures that your Deck does not crash, even if the list is empty. In your UI, you can either make sure you never draw from an empty deck (probably by checking its size first as part of an if or loop); in that case, you don't need to worry about catching this runtime exception (since it'll never happen). However, if you'd rather, you can instead just keep drawing from a deck until it throws an IllegalStateException, and then catch that using a try/catch block.
Should the Deck constructor call shuffle()?
No. A Deck should be ordered when you first construct it.

However, the deck used by the UI program should be shuffled. So, every time you create/"open" a new Deck in the UI, call the shuffle() method before letting the user draw from it.

Or, another option would be to overload the constructor:
  public Deck(boolean shuffled) {
    this();
    if (shuffled) {
      this.shuffle();
    }
  }
This way, your other constructor and methods still meet the requirements of the assignment, but it's easier to create a shuffled deck from your UI: new Deck(true);
How do the draw methods work? How do I remove a card from the deck so that it is never drawn again?
You construct all the cards when you make a new deck and store them internally in an array. You do this in some sort of order so that you know you have 1 of each of the 52 cards. (The class using your Deck might then shuffle them by calling your shuffle() method.)

When the draw() method is called, you just "remove" one or more of those cards from the array. You do this by changing some variable that indicates the index of the "top card" in the array. (You'll need to initialize this variable in your constructor. This is a little bit like the size variable in the sample SimpleToDoList code above.) For example, if you remove one card from the deck, this topCard variable would be incremented by one so that it now holds the index of the card after the one you just removed. Since nothing can ever decrement the private topCard index, there's no way to ever draw that "removed" card from the array again.

Besides this, your draw() method will have to detect if there's no cards to be drawn. (See above FAQ on exceptions.) The draw(int) method works a little differently in that it creates another array of the given size and fills it with cards drawn from the deck. (Think of this of drawing a hand of a certain number of cards.) It then returns this new "hand" array it created.
How do I convert an int to a String?
  int n = 4;
  String s = "" + n;
OR:
  String s = new Integer(n).toString();
Which draw method should I use from the UI?
Your Deck is supposed to have two draw methods. But that doesn't mean you need to use both! Though at first it seems the draw(int) method would be easier to use from your UI, this is probably not true. First of all, it returns an array, which you'll then need to loop through in order to print the cards one-per-line. Secondly, if the user requests more cards than currently in the deck, this is going to take some math and clever looping in order to draw the remaining cards of the current deck and then draw the additional cards needed from one (or more!) new decks.

Instead, as mentioned in an earlier FAQ, just use the draw() method in a loop. Loop once for each card the user asked for and print out each card as you draw it. Before you draw a card each time, just check if the deck is empty. If it is, replace it with a new deck and carry on drawing. Simple.


~ztomasze Index : TA Details: ICS111: Assignment 16
http://www2.hawaii.edu/~ztomasze
Last Edited: 12 Nov 2008
©2008 by Z. Tomaszewski.