Appendix    B

Four of a Kind

Application development isn’t an easy task. If you don’t plan carefully before you develop an application, you’ll probably waste your time and money as you endeavor to create it, and waste your users’ time and money when it doesn’t meet their needs.

Caution   It’s extremely important to test your software carefully. You could face a lawsuit if malfunctioning software causes financial harm to its users.

In this appendix, I present one technique for developing applications efficiently. I present this technique in the context of a Java application that lets you play a simple card game called Four of a Kind against the computer.

Understanding Four of a Kind

Before sitting down at the computer and writing code, you need to fully understand the problem domain that you are trying to model via that code. In this case, the problem domain is Four of a Kind, and you want to understand how this card game works.

Two to four players play Four of a Kind with a standard 52-card deck. The object of the game is to be the first player to put down four cards that have the same rank (four aces, for example), which wins the game.

The game begins by shuffling the deck and placing it face down. Each player takes a card from the top of the deck. The player with the highest ranked card (king is highest) deals four cards to each player, starting with the player to the dealer’s left. The dealer then starts its turn.

The player examines its cards to determine which cards are optimal for achieving four of a kind. The player then throws away the least helpful card on a discard pile and picks up another card from the top of the deck. (If each card has a different rank, the player randomly selects a card to throw away.) If the player has four of a kind, the player puts down these cards (face up) and wins the game.

Modeling Four of a Kind in Pseudocode

Now that you understand how Four of a Kind works, you can begin to model this game. You will not model the game in Java source code because you would get bogged down in too many details. Instead, you will use pseudocode for this task.

Pseudocode is a compact and informal high-level description of the problem domain. Unlike the previous description of Four of a Kind, the pseudocode equivalent is a step-by-step recipe for solving the problem. Check out Listing B-1.

Listing B-1.  Four of a Kind Pseudocode for Two Players (Human and Computer)

 1. Create a deck of cards and shuffle the deck.
 2. Create empty discard pile.
 3. Have each of the human and computer players take a card from the top of the deck.
 4. Designate the player with the highest ranked card as the current player.
 5. Return both cards to the bottom of the deck.
 6. The current player deals four cards to each of the two players in alternating fashion, with the first card being dealt to the other player.
 7. The current player examines its current cards to see which cards are optimal for achieving four of a kind. The current player
 throws the least helpful card onto the top of the discard pile.

 8. The current player picks up the deck's top card. If the current player has four of a kind, it puts down its cards and wins the game.
 9. Designate the other player as the current player.
 10. If the deck has no more cards, empty the discard pile to the deck and shuffle the deck.
 11. Repeat at step 7.

Deriving Listing B-1’s pseudocode from the previous description is the first step in achieving an application that implements Four of a Kind. This pseudocode performs various tasks including decision making and repetition.

Despite being a more useful guide to understanding how Four of a Kind works, Listing B-1 is too high level for translation to Java. Therefore, you must refine this pseudocode to facilitate the translation process. Listing B-2 presents this refinement.

Listing B-2.  Refined Four of a Kind Pseudocode for Two Players (Human and Computer)

 1. deck = new Deck()
 2. deck.shuffle()
 3. discardPile = new DiscardPile()
 4. hCard = deck.deal()
 5. cCard = deck.deal()
 6. if hCard.rank() == cCard.rank()
    6.1. deck.putBack(hCard)
    6.2. deck.putBack(cCard)
    6.3. deck.shuffle()
    6.4. Repeat at step 4
 7. curPlayer = HUMAN
    7.1. if cCard.rank() > hCard.rank()
         7.1.1. curPlayer = COMPUTER
 8. deck.putBack(hCard)
 9. deck.putBack(cCard)
10. if curPlayer == HUMAN
    10.1. for i = 0 to 3
          10.1.1. cCards[i] = deck.deal()
          10.1.2. hCards[i] = deck.deal()
    else
    10.2. for i = 0 to 3
          10.2.1. hCards[i] = deck.deal()
          10.2.2. cCards[i] = deck.deal()
11. if curPlayer == HUMAN
    11.01. output(hCards)
    11.02. choice = prompt("Identify card to throw away")
    11.03. discardPile.setTopCard(hCards[choice])
    11.04. hCards[choice] = deck.deal()
    11.05. if isFourOfAKind(hCards)
           11.05.1. output("Human wins!")
           11.05.2. putDown(hCards)
           11.05.3. output("Computer's cards:")
           11.05.4. putDown(cCards)
           11.05.5. End game
    11.06. curPlayer = COMPUTER
    else
    11.07. choice = leastDesirableCard(cCards)
    11.08. discardPile.setTopCard(cCards[choice])
    11.09. cCards[choice] = deck.deal()
    11.10. if isFourOfAKind(cCards)
           11.10.1. output("Computer wins!")
           11.10.2. putDown(cCards)
           11.10.3. End game
    11.11. curPlayer = HUMAN
12. if deck.isEmpty()
    12.1. if discardPile.topCard() != null
          12.1.1. deck.putBack(discardPile.getTopCard())
          12.1.2. Repeat at step 12.1.
    12.2. deck.shuffle()
13. Repeat at step 11.

In addition to being longer than Listing B-1, Listing B-2 shows the refined pseudocode becoming more like Java. For example, Listing B-2 reveals Java expressions (such as new Deck(), to create a Deck object), operators (such as ==, to compare two values for equality), and method calls (such as deck.isEmpty(), to call deck’s isEmpty() method to return a Boolean value indicating whether [true] or not [false] the deck identified by deck is empty of cards).

Converting Pseudocode to Java Code

Now that you’ve had a chance to absorb Listing B-2’s Java-like pseudocode, you’re ready to examine the process of converting that pseudocode to Java source code. This process consists of a couple of steps.

The first step in converting Listing B-2’s pseudocode to Java involves identifying important components of the game’s structure and implementing these components as classes, which I formally introduced in Chapter 3.

Apart from the computer player (which is implemented via game logic), the important components are card, deck, and discard pile. I represent these components via Card, Deck, and DiscardPile classes. Listing B-3 presents Card.

Listing B-3.   Merging Suits and Ranks into Cards

/**
 *  Simulating a playing card.
 *
 *  @author Jeff Friesen
 */

public enum Card
{
   ACE_OF_CLUBS(Suit.CLUBS, Rank.ACE),
   TWO_OF_CLUBS(Suit.CLUBS, Rank.TWO),
   THREE_OF_CLUBS(Suit.CLUBS, Rank.THREE),
   FOUR_OF_CLUBS(Suit.CLUBS, Rank.FOUR),
   FIVE_OF_CLUBS(Suit.CLUBS, Rank.FIVE),
   SIX_OF_CLUBS(Suit.CLUBS, Rank.SIX),
   SEVEN_OF_CLUBS(Suit.CLUBS, Rank.SEVEN),
   EIGHT_OF_CLUBS(Suit.CLUBS, Rank.EIGHT),
   NINE_OF_CLUBS(Suit.CLUBS, Rank.NINE),
   TEN_OF_CLUBS(Suit.CLUBS, Rank.TEN),
   JACK_OF_CLUBS(Suit.CLUBS, Rank.JACK),
   QUEEN_OF_CLUBS(Suit.CLUBS, Rank.QUEEN),
   KING_OF_CLUBS(Suit.CLUBS, Rank.KING),
   ACE_OF_DIAMONDS(Suit.DIAMONDS, Rank.ACE),
   TWO_OF_DIAMONDS(Suit.DIAMONDS, Rank.TWO),
   THREE_OF_DIAMONDS(Suit.DIAMONDS, Rank.THREE),
   FOUR_OF_DIAMONDS(Suit.DIAMONDS, Rank.FOUR),
   FIVE_OF_DIAMONDS(Suit.DIAMONDS, Rank.FIVE),
   SIX_OF_DIAMONDS(Suit.DIAMONDS, Rank.SIX),
   SEVEN_OF_DIAMONDS(Suit.DIAMONDS, Rank.SEVEN),
   EIGHT_OF_DIAMONDS(Suit.DIAMONDS, Rank.EIGHT),
   NINE_OF_DIAMONDS(Suit.DIAMONDS, Rank.NINE),
   TEN_OF_DIAMONDS(Suit.DIAMONDS, Rank.TEN),
   JACK_OF_DIAMONDS(Suit.DIAMONDS, Rank.JACK),
   QUEEN_OF_DIAMONDS(Suit.DIAMONDS, Rank.QUEEN),
   KING_OF_DIAMONDS(Suit.DIAMONDS, Rank.KING),
   ACE_OF_HEARTS(Suit.HEARTS, Rank.ACE),
   TWO_OF_HEARTS(Suit.HEARTS, Rank.TWO),
   THREE_OF_HEARTS(Suit.HEARTS, Rank.THREE),
   FOUR_OF_HEARTS(Suit.HEARTS, Rank.FOUR),
   FIVE_OF_HEARTS(Suit.HEARTS, Rank.FIVE),
   SIX_OF_HEARTS(Suit.HEARTS, Rank.SIX),
   SEVEN_OF_HEARTS(Suit.HEARTS, Rank.SEVEN),
   EIGHT_OF_HEARTS(Suit.HEARTS, Rank.EIGHT),
   NINE_OF_HEARTS(Suit.HEARTS, Rank.NINE),
   TEN_OF_HEARTS(Suit.HEARTS, Rank.TEN),
   JACK_OF_HEARTS(Suit.HEARTS, Rank.JACK),
   QUEEN_OF_HEARTS(Suit.HEARTS, Rank.QUEEN),
   KING_OF_HEARTS(Suit.HEARTS, Rank.KING),
   ACE_OF_SPADES(Suit.SPADES, Rank.ACE),
   TWO_OF_SPADES(Suit.SPADES, Rank.TWO),
   THREE_OF_SPADES(Suit.SPADES, Rank.THREE),
   FOUR_OF_SPADES(Suit.SPADES, Rank.FOUR),
   FIVE_OF_SPADES(Suit.SPADES, Rank.FIVE),
   SIX_OF_SPADES(Suit.SPADES, Rank.SIX),
   SEVEN_OF_SPADES(Suit.SPADES, Rank.SEVEN),
   EIGHT_OF_SPADES(Suit.SPADES, Rank.EIGHT),
   NINE_OF_SPADES(Suit.SPADES, Rank.NINE),
   TEN_OF_SPADES(Suit.SPADES, Rank.TEN),
   JACK_OF_SPADES(Suit.SPADES, Rank.JACK),
   QUEEN_OF_SPADES(Suit.SPADES, Rank.QUEEN),
   KING_OF_SPADES(Suit.SPADES, Rank.KING);

   private Suit suit;

   /**
    *  Return <code>Card</code>'s suit.
    *
    *  @return <code>CLUBS</code>, <code>DIAMONDS</code>, <code>HEARTS</code>,
    *  or <code>SPADES</code>
    */

   public Suit suit()
   {
      return suit;
   }

   private Rank rank;

   /**
    *  Return <code>Card</code>'s rank.
    *
    *  @return <code>ACE</code>, <code>TWO</code>, <code>THREE</code>,
    *  <code>FOUR</code>, <code>FIVE</code>, <code>SIX</code>,
    *  <code>SEVEN</code>, <code>EIGHT</code>, <code>NINE</code>,
    *  <code>TEN</code>, <code>JACK</code>, <code>QUEEN</code>,
    *  <code>KING</code>.
    */

   public Rank rank()
   {
      return rank;
   }

   Card(Suit suit, Rank rank)
   {
      this.suit = suit;
      this.rank = rank;
   }

   /**
    *  A card's suit is its membership.
    *
    *  @author Jeff Friesen
    */

   public enum Suit
   {
      CLUBS, DIAMONDS, HEARTS, SPADES
   }

   /**
    *  A card's rank is its integer value.
    *
    *  @author Jeff Friesen
    */

   public enum Rank
   {
      ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN,
      KING
   }
}

Listing B-3 begins with a Javadoc comment that’s used to briefly describe the subsequently declared Card class and identify this class’s author. (I briefly introduced Javadoc comments in Chapter 2.)

Note   One feature of Javadoc comments is the ability to embed HTML tags. These tags specify different kinds of formatting for sections of text within these comments. For example, <code> and </code> specify that their enclosed text is to be formatted as a code listing. Later in this appendix, you’ll learn how to convert these comments into HTML documentation.

Card is an example of an enum, which is a special kind of class that I discussed in Chapter 6. If you haven’t read that chapter, think of Card as a place to create and store Card objects that identify all 52 cards that make up a standard deck.

Card declares a nested Suit enum. (I discussed nesting in Chapter 5.) A card’s suit denotes its membership. The only legal Suit values are CLUBS, DIAMONDS, HEARTS, and SPADES.

Card also declares a nested Rank enum. A card’s rank denotes its value: ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, and KING are the only legal Rank values.

A Card object is created when Suit and Rank objects are passed to its constructor. (I discussed constructors in Chapter 3.) For example, KING_OF_HEARTS(Suit.HEARTS, Rank.KING) combines Suit.HEARTS and Rank.KING into KING_OF_HEARTS.

Card provides a rank() method for returning a Card’s Rank object. Similarly, Card provides a suit() method for returning a Card’s Suit object. For example, KING_OF_HEARTS.rank() returns Rank.KING, and KING_OF_HEARTS.suit() returns Suit.HEARTS.

Listing B-4. presents the Java source code to the Deck class, which implements a deck of 52 cards.

Listing B-4.   Pick a Card, Any Card

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 *  Simulate a deck of cards.
 *
 *  @author Jeff Friesen
 */

public class Deck
{
   private Card[] cards = new Card[]
   {
      Card.ACE_OF_CLUBS,
      Card.TWO_OF_CLUBS,
      Card.THREE_OF_CLUBS,
      Card.FOUR_OF_CLUBS,
      Card.FIVE_OF_CLUBS,
      Card.SIX_OF_CLUBS,
      Card.SEVEN_OF_CLUBS,
      Card.EIGHT_OF_CLUBS,
      Card.NINE_OF_CLUBS,
      Card.TEN_OF_CLUBS,
      Card.JACK_OF_CLUBS,
      Card.QUEEN_OF_CLUBS,
      Card.KING_OF_CLUBS,
      Card.ACE_OF_DIAMONDS,
      Card.TWO_OF_DIAMONDS,
      Card.THREE_OF_DIAMONDS,
      Card.FOUR_OF_DIAMONDS,
      Card.FIVE_OF_DIAMONDS,
      Card.SIX_OF_DIAMONDS,
      Card.SEVEN_OF_DIAMONDS,
      Card.EIGHT_OF_DIAMONDS,
      Card.NINE_OF_DIAMONDS,
      Card.TEN_OF_DIAMONDS,
      Card.JACK_OF_DIAMONDS,
      Card.QUEEN_OF_DIAMONDS,
      Card.KING_OF_DIAMONDS,
      Card.ACE_OF_HEARTS,
      Card.TWO_OF_HEARTS,
      Card.THREE_OF_HEARTS,
      Card.FOUR_OF_HEARTS,
      Card.FIVE_OF_HEARTS,
      Card.SIX_OF_HEARTS,
      Card.SEVEN_OF_HEARTS,
      Card.EIGHT_OF_HEARTS,
      Card.NINE_OF_HEARTS,
      Card.TEN_OF_HEARTS,
      Card.JACK_OF_HEARTS,
      Card.QUEEN_OF_HEARTS,
      Card.KING_OF_HEARTS,
      Card.ACE_OF_SPADES,
      Card.TWO_OF_SPADES,
      Card.THREE_OF_SPADES,
      Card.FOUR_OF_SPADES,
      Card.FIVE_OF_SPADES,
      Card.SIX_OF_SPADES,
      Card.SEVEN_OF_SPADES,
      Card.EIGHT_OF_SPADES,
      Card.NINE_OF_SPADES,
      Card.TEN_OF_SPADES,
      Card.JACK_OF_SPADES,
      Card.QUEEN_OF_SPADES,
      Card.KING_OF_SPADES
   };

   private List<Card> deck;

   /**
    *  Create a <code>Deck</code> of 52 <code>Card</code> objects. Shuffle
    *  these objects.
    */

   public Deck()
   {
      deck = new ArrayList<Card>();
      for (int i = 0; i < cards.length; i++)
      {
         deck.add(cards[i]);
         cards[i] = null;
      }
      Collections.shuffle(deck);
   }

   /**
    *  Deal the <code>Deck</code>'s top <code>Card</code> object.
    *
    *  @return the <code>Card</code> object at the top of the
    *  <code>Deck</code>
    */

   public Card deal()
   {
      return deck.remove(0);
   }

   /**
    *  Return an indicator of whether or not the <code>Deck</code> is empty.
    *
    *  @return true if the <code>Deck</code> contains no <code>Card</code>
    *  objects; otherwise, false
    */

   public boolean isEmpty()
   {
      return deck.isEmpty();
   }

   /**
    *  Put back a <code>Card</code> at the bottom of the <code>Deck</code>.
    *
    *  @param card <code>Card</code> object being put back
    */

   public void putBack(Card card)
   {
      deck.add(card);
   }

   /**
    *  Shuffle the <code>Deck</code>.
    */

   public void shuffle()
   {
      Collections.shuffle(deck);
   }
}

Deck initializes a private cards array to all 52 Card objects. Because it’s easier to implement Deck via a list that stores these objects, Deck’s constructor creates this list and adds each Card object to the list. (I discussed List and ArrayList in Chapter 9.)

Deck also provides deal(), isEmpty(), putBack(), and shuffle() methods to deal a single Card from the Deck (the Card is physically removed from the Deck), determine whether or not the Deck is empty, put a Card back into the Deck, and shuffle the Deck’s Cards.

Listing B-5. presents the source code to the DiscardPile class, which implements a discard pile on which players can throw away a maximum of 52 cards.

Listing B-5.   A Garbage Dump for Cards

import java.util.ArrayList;
import java.util.List;

/**
 *  Simulate a pile of discarded cards.
 *
 *  @author Jeff Friesen
 */

public class DiscardPile
{
   private Card[] cards;
   private int top;

   /**
    *  Create a <code>DiscardPile</code> that can accommodate a maximum of 52
    *  <code>Card</code>s. The <code>DiscardPile</code> is initially empty.
    */

   public DiscardPile()
   {
      cards = new Card[52]; // Room for entire deck on discard pile (should
                            // never happen).
      top = -1;
   }

   /**
    *  Return the <code>Card</code> at the top of the <code>DiscardPile</code>.
    *
    *  @return <code>Card</code> object at top of <code>DiscardPile</code> or
    *  null if <code>DiscardPile</code> is empty
    */

   public Card getTopCard()
   {
      if (top == -1)
         return null;
      Card card = cards[top];
      cards[top--] = null;
      return card;
   }

   /**
    *  Set the <code>DiscardPile</code>'s top card to the specified
    *  <code>Card</code> object.
    *
    *  @param card <code>Card</code> object being thrown on top of the
    *  <code>DiscardPile</code>
    */

   public void setTopCard(Card card)
   {
      cards[++top] = card;
   }

   /**
    *  Identify the top <code>Card</code> on the <code>DiscardPile</code>
    *  without removing this <code>Card</code>.
    *
    *  @return top <code>Card</code>, or null if <code>DiscardPile</code> is
    *  empty
    */

   public Card topCard()
   {
      return (top == -1) ? null : cards[top];
   }
}

DiscardPile implements a discard pile on which to throw Card objects. It implements the discard pile via a stack metaphor: the last Card object thrown on the pile sits at the top of the pile and is the first Card object to be removed from the pile.

This class stores its stack of Card objects in a private cards array. I found it convenient to specify 52 as this array’s storage limit because the maximum number of Cards is 52. (Game play will never result in all Cards being stored in the array.)

Along with its constructor, DiscardPile provides getTopCard(), setTopCard(), and topCard() methods to remove and return the stack’s top Card, store a new Card object on the stack as its top Card, and return the top Card without removing it from the stack.

The constructor demonstrates a single-line comment, which starts with the // character sequence. This comment documents that the cards array has room to store the entire Deck of Cards. I formally introduced single-line comments in Chapter 2.

The second step in converting Listing B-2’s pseudocode to Java involves introducing a FourOfAKind class whose main() method contains the Java code equivalent of this pseudocode. Listing B-6 presents FourOfAKind.

Listing B-6.   FourOfAKind Application Source Code

/**
 *  <code>FourOfAKind</code> implements a card game that is played between two
 *  players: one human player and the computer. You play this game with a
 *  standard 52-card deck and attempt to beat the computer by being the first
 *  player to put down four cards that have the same rank (four aces, for
 *  example), and win.
 *
 *  <p>
 *  The game begins by shuffling the deck and placing it face down. Each
 *  player takes a card from the top of the deck. The player with the highest
 *  ranked card (king is highest) deals four cards to each player starting
 *  with the other player. The dealer then starts its turn.
 *
 *  <p>
 *  The player examines its cards to determine which cards are optimal for
 *  achieving four of a kind. The player then throws away one card on a
 *  discard pile and picks up another card from the top of the deck. If the
 *  player has four of a kind, the player puts down these cards (face up) and
 *  wins the game.
 *
 *  @author Jeff Friesen
 *  @version 1.0
 */

public class FourOfAKind
{
   /**
    *  Human player
    */

   final static int HUMAN = 0;

   /**
    *  Computer player
    */

   final static int COMPUTER = 1;

   /**
    *  Application entry point.
    *
    *  @param args array of command-line arguments passed to this method
    */

   public static void main(String[] args)
   {
      System.out.println("Welcome to Four of a Kind!");
      Deck deck = new Deck(); // Deck automatically shuffled
      DiscardPile discardPile = new DiscardPile();
      Card hCard;
      Card cCard;
      while (true)
      {
         hCard = deck.deal();
         cCard = deck.deal();
         if (hCard.rank() != cCard.rank())
            break;
         deck.putBack(hCard);
         deck.putBack(cCard);
         deck.shuffle(); // prevent pathological case where every successive
      }                  // pair of cards have the same rank
      int curPlayer = HUMAN;
      if (cCard.rank().ordinal() > hCard.rank().ordinal())
         curPlayer = COMPUTER;
      deck.putBack(hCard);
      hCard = null;
      deck.putBack(cCard);
      cCard = null;
      Card[] hCards = new Card[4];
      Card[] cCards = new Card[4];
      if (curPlayer == HUMAN)
         for (int i = 0; i < 4; i++)
         {
            cCards[i] = deck.deal();
            hCards[i] = deck.deal();
         }
      else
         for (int i = 0; i < 4; i++)
         {
            hCards[i] = deck.deal();
            cCards[i] = deck.deal();
         }
      while (true)
      {
         if (curPlayer == HUMAN)
         {
            showHeldCards(hCards);
            int choice = 0;
            while (choice < 'A' || choice > 'D')
            {
               choice = prompt("Which card do you want to throw away (A, B, " +
                               "C, D)? ");
               switch (choice)
               {
                  case 'a': choice = 'A'; break;
                  case 'b': choice = 'B'; break;
                  case 'c': choice = 'C'; break;
                  case 'd': choice = 'D';
               }
            }
            discardPile.setTopCard(hCards[choice - 'A']);
            hCards[choice - 'A'] = deck.deal();
            if (isFourOfAKind(hCards))
            {
               System.out.println();
               System.out.println("Human wins!");
               System.out.println();
               putDown("Human's cards:", hCards);
               System.out.println();
               putDown("Computer's cards:", cCards);
               return; // Exit application by returning from main()
            }
            curPlayer = COMPUTER;
         }
         else
         {
            int choice = leastDesirableCard(cCards);
            discardPile.setTopCard(cCards[choice]);
            cCards[choice] = deck.deal();
            if (isFourOfAKind(cCards))
            {
               System.out.println();
               System.out.println("Computer wins!");
               System.out.println();
               putDown("Computer's cards:", cCards);
               return; // Exit application by returning from main()
            }
            curPlayer = HUMAN;
         }
         if (deck.isEmpty())
         {
            while (discardPile.topCard() != null)
               deck.putBack(discardPile.getTopCard());
            deck.shuffle();
         }
      }
   }

   /**
    *  Determine if the <code>Card</code> objects passed to this method all
    *  have the same rank.
    *
    *  @param cards array of <code>Card</code> objects passed to this method
    *
    *  @return true if all <code>Card</code> objects have the same rank;
    *  otherwise, false
    */

   static boolean isFourOfAKind(Card[] cards)
   {
      for (int i = 1; i < cards.length; i++)
         if (cards[i].rank() != cards[0].rank())
            return false;
      return true;
   }

   /**
    *  Identify one of the <code>Card</code> objects that is passed to this
    *  method as the least desirable <code>Card</code> object to hold onto.
    *
    *  @param cards array of <code>Card</code> objects passed to this method
    *
    *  @return 0-based rank (ace is 0, king is 13) of least desirable card
    */

   static int leastDesirableCard(Card[] cards)
   {
      int[] rankCounts = new int[13];
      for (int i = 0; i < cards.length; i++)
         rankCounts[cards[i].rank().ordinal()]++;
      int minCount = Integer.MAX_VALUE;
      int minIndex = -1;
      for (int i = 0; i < rankCounts.length; i++)
         if (rankCounts[i] < minCount && rankCounts[i] != 0)
         {
            minCount = rankCounts[i];
            minIndex = i;
         }
      for (int i = 0; i < cards.length; i++)
         if (cards[i].rank().ordinal() == minIndex)
            return i;
      return 0; // Needed to satisfy compiler (should never be executed)
   }

   /**
    *  Prompt the human player to enter a character.
    *
    *  @param msg message to be displayed to human player
    *
    *  @return integer value of character entered by user.
    */

   static int prompt(String msg)
   {
      System.out.print(msg);
      try
      {
         int ch = System.in.read();
         // Erase all subsequent characters including terminating newline
         // so that they do not affect a subsequent call to prompt().
         while (System.in.read() != ' '),
         return ch;
      }
      catch (java.io.IOException ioe)
      {
      }
      return 0;
   }

   /**
    *  Display a message followed by all cards held by player. This output
    *  simulates putting down held cards.
    *
    *  @param msg message to be displayed to human player
    *  @param cards array of <code>Card</code> objects to be identified
    */

   static void putDown(String msg, Card[] cards)
   {
      System.out.println(msg);
      for (int i = 0; i < cards.length; i++)
         System.out.println(cards[i]);
   }

   /**
    *  Identify the cards being held via their <code>Card</code> objects on
    *  separate lines. Prefix each line with an uppercase letter starting with
    *  <code>A</code>.
    *
    *  @param cards array of <code>Card</code> objects to be identified
    */

   static void showHeldCards(Card[] cards)
   {
      System.out.println();
      System.out.println("Held cards:");
      for (int i = 0; i < cards.length; i++)
         if (cards[i] != null)
            System.out.println((char) ('A' + i) + ". " + cards[i]);
      System.out.println();
   }
}

Listing B-6. follows the steps outlined by and expands on Listing B-2’s pseudocode. Because of the various comments, I don’t have much to say about this listing. However, there are a couple of items that deserve mention:

  • Card’s nested Rank enum stores a sequence of 13 Rank objects beginning with ACE and ending with KING. These objects cannot be compared directly via > to determine which object has the greater rank. However, their integer-based ordinal (positional) values can be compared by calling the Rank object’s ordinal() method. For example, Card.ACE_OF_SPADES.rank().ordinal() returns 0 because ACE is located at position 0 within Rank’s list of Rank objects, and Card.KING_OF_CLUBS.rank().ordinal() returns 12 because KING is located at the last position in this list.
  • The leastDesirableCard() method counts the ranks of the Cards in the array of four Card objects passed to this method and stores these counts in a rankCounts array. For example, given two of clubs, ace of spades, three of clubs, and ace of diamonds in the array passed to this method, rankCounts identifies one two, two aces, and one three. This method then searches rankCounts from smallest index (representing ace) to largest index (representing king) for the first smallest nonzero count (there might be a tie, as in one two and one three)—a zero count represents no Cards having that rank in the array of Card objects. Finally, the method searches the array of Card objects to identify the object whose rank ordinal matches the index of the smallest nonzero count and returns the index of this Card object.This behavior implies that the least desirable card is always the smallest ranked card. For example, given two of spades, three of diamonds, five of spades, and nine of clubs, two of spades is least desirable because it has the smallest rank.

    Also, when there are multiple cards of the same rank, and when this rank is smaller than the rank of any other card in the array, this method will choose the first (in a left-to-right manner) of the multiple cards having the same rank as the least desirable card. For example, given (in this order) two of spades, two of hearts, three of diamonds, and jack of hearts, two of spades is least desirable because it’s the first card with the smallest rank. However, when the rank of the multiple cards isn’t the smallest, another card with the smallest rank is chosen as least desirable.

The JDK provides a javadoc tool that extracts all Javadoc comments from one or more source files and generates a set of HTML files containing this documentation in an easy-to-read format. These files serve as the program’s documentation.

For example, suppose that the current directory contains Card.java, Deck.java, DiscardPile.java, and FourOfAKind.java. To extract all of the Javadoc comments that appear in these files, specify the following command:

javadoc *.java

The javadoc tool responds by outputting the following messages:

Loading source file Card.java...
Loading source file Deck.java...
Loading source file DiscardPile.java...
Loading source file FourOfAKind.java...
Constructing Javadoc information...
Standard Doclet version 1.7.0_06
Building tree for all the packages and classes...
Generating Card.html...
Generating Card.Rank.html...
Generating Card.Suit.html...
Generating Deck.html...
Generating DiscardPile.html...
Generating FourOfAKind.html...
Generating package-frame.html...
Generating package-summary.html...
Generating package-tree.html...
Generating constant-values.html...
Building index for all the packages and classes...
Generating overview-tree.html...
Generating index-all.html...
Generating deprecated-list.html...
Building index for all classes...
Generating allclasses-frame.html...
Generating allclasses-noframe.html...
Generating index.html...
Generating help-doc.html...

Furthermore, it generates a series of files, including the index.html entry-point file. If you point your web browser to this file, you should see a page that is similar to the page shown in Figure B-1.

9781430257226_AppB-01.jpg

Figure B-1 .  Viewing the entry-point page in the generated Javadoc for FourOfAKind and supporting classes

javadoc defaults to generating HTML-based documentation for public classes and public/protected members of classes. You learned about public classes and public/protected members of classes in Chapter 3.

For this reason, FourOfAKind’s documentation reveals only the public main() method. It doesn’t reveal isFourOfAKind() and the other package-private methods. If you want to include these methods in the documentation, you must specify -package with javadoc:

javadoc -package *.java

Note   The standard class library’s documentation from Oracle was also generated by javadoc and adheres to the same format.

Compiling, Running, and Distributing FourOfAKind

Unlike Chapter 1’s DumpArgs and EchoText applications, which each consist of one source file, FourOfAKind consists of Card.java, Deck.java, DiscardPile.java, and FourOfAKind.java. You can compile all four source files via the following command line:

javac FourOfAKind.java

The javac tool launches the Java compiler, which recursively compiles the source files of the various classes it encounters during compilation. Assuming successful compilation, you should end up with six classfiles in the current directory.

Tip   You can compile all Java source files in the current directory by specifying javac *.java.

After successfully compiling FourOfAKind.java and the other three source files, specify the following command line to run this application:

java FourOfAKind

In response, you see an introductory message and the four cards that you are holding. The following output reveals a single session:

Welcome to Four of a Kind!

Held cards:
A. SIX_OF_CLUBS
B. QUEEN_OF_DIAMONDS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. NINE_OF_HEARTS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. FOUR_OF_DIAMONDS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. KING_OF_HEARTS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. QUEEN_OF_CLUBS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. KING_OF_DIAMONDS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. TWO_OF_HEARTS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. FIVE_OF_DIAMONDS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. JACK_OF_CLUBS
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Held cards:
A. SIX_OF_CLUBS
B. TWO_OF_SPADES
C. SIX_OF_HEARTS
D. SIX_OF_SPADES

Which card do you want to throw away (A, B, C, D)? B

Human wins!

Human's cards:
SIX_OF_CLUBS
SIX_OF_DIAMONDS
SIX_OF_HEARTS
SIX_OF_SPADES

Computer's cards:
SEVEN_OF_HEARTS
TEN_OF_HEARTS
SEVEN_OF_CLUBS
SEVEN_OF_DIAMONDS

Although Four of a Kind isn’t much of a card game, you might decide to share the FourOfAKind application with a friend. However, if you forget to include even one of the application’s five supporting classfiles, your friend will not be able to run the application.

You can overcome this problem by bundling FourOfAKind’s six classfiles into a single JAR (Java ARchive) file, which is a ZIP file that contains a special directory and the .jar file extension. You can then distribute this single JAR file to your friend.

The JDK provides the jar tool for working with JAR files. To bundle all six classfiles into a JAR file named FourOfAKind.jar, you could specify the following command line, where c tells jar to create a JAR file and f identifies the JAR file’s name:

jar cf FourOfAKind.jar *.class

After creating the JAR file, try to run the application via the following command line:

java -jar FourOfAKind.jar

Instead of the application running, you’ll receive an error message having to do with the java application launcher tool not knowing which of the JAR file’s six classfiles is the main classfile (the file whose class’s main() method executes first).

You can provide this knowledge via a text file that’s merged into the JAR file’s manifest, a special file named MANIFEST.MF that stores information about the contents of a JAR file and is stored in the JAR file’s META-INF directory. Consider Listing B-7.

Listing B-7.   Identifying the Application’s Main Class

Main-Class: FourOfAKind

Listing B-7. tells java which of the JAR’s classfiles is the main classfile. (You must leave a blank line after Main-Class: FourOfAKind.)

The following command line, which creates FourOfAKind.jar, includes m and the name of the text field providing manifest content:

jar cfm FourOfAKind.jar manifest *.class

This time, java -jar FourOfAKind.jar succeeds and the application runs because java is able to identify FourOfAKind as the main classfile.

Note   Now that you’ve finished this book, you’re ready to dig into Android app development. Check out Apress’s Beginning Android and Android Recipes books for guidance. After you’ve learned some app development basics, perhaps you might consider transforming Four of a Kind into an Android app.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.253.62