001package hw0.optional;
002
003/**
004 * Card is a class representing single playing card consisting of a value and a
005 * suit (e.g. [Ace,Spades],[10,Clubs]). Cards are immutable; once a Card has
006 * been created with a given value and suit, that value and suit cannot be
007 * changed.
008 */
009public class Card implements Comparable<Card> {
010
011    // AF(c) = c represents a playing card with value of c.value and a
012    // suit of c.suit (e.g. Ace of Spades, 10 of Clubs)
013
014    // RI(c) = c.value != null && c.suit != null
015
016    //
017    // MEMBER VARIABLES
018    //
019
020    // the member variables are declared to be final because this class
021    // is immutable.
022
023    /**
024     * The value of this card.
025     */
026    private final CardValue value;
027
028    /**
029     * The suit of this card.
030     */
031    private final CardSuit suit;
032
033    //
034    // METHODS
035    //
036
037    // -------------------------------------------
038    /**
039     * Creates a new playing card.
040     *
041     * @param aValue
042     *            the value of this card
043     * @param aSuit
044     *            the suit of this card
045     *
046     * @modifies this
047     * @effects creates a new <code>Card</code> object
048     */
049    public Card(CardValue aValue, CardSuit aSuit) {
050        this.value = aValue;
051        this.suit = aSuit;
052    }
053
054    // -------------------------------------------
055    /**
056     * @effects returns the <code>CardSuit</code> associated with this card
057     */
058    public CardSuit getSuit() {
059        return this.suit;
060    }
061
062    // -------------------------------------------
063    /**
064     * @effects returns the <code>CardValue</code> associated with this card
065     */
066    public CardValue getValue() {
067        return this.value;
068    }
069
070    // -------------------------------------------
071    /**
072     * Compares this card with the specified card for order. The purpose of
073     * being able to compare cards is to be able to sort a hand of cards.
074     * <p>
075     * Cards are ranked primarily by number, secondarily by suit. That means
076     * that this card is ranked lower than another card if one of these
077     * conditions is met:
078     * <ul>
079     * <li>This card's face value is less than the other card's face value; or
080     * <li>Both cards' face values are equal, but this card's suit is ranked
081     * lower than the other card's suit.
082     * </ul>
083     *
084     * EXAMPLE: [Ace,Clubs] is ranked higher than [10,Spades] because face value
085     * is higher, but is ranked lower than [Ace,Spades] because its suit is
086     * ranked lower.
087     *
088     * @param c
089     *            the Card to be compared
090     * @exception ClassCastException
091     *                if the specified object's type is not Card
092     * @exception NullPointerException
093     *                if the specified object is null
094     *
095     * @effects
096     * <ul>
097     * <li>If <code>o</code> is not an instance of Card, throws a
098     * <code>ClassCastException</code></li>
099     * <li>If <code>o</code> is null, throws a
100     * <code>NullPointerException</code></li>
101     * <li>Returns a negative integer, zero, or a positive integer if this
102     * <code>Card</code> is less than, equal to, or greater than the specified
103     * <code>Card</code>, respectively</li>
104     * </ul>
105     */
106    public int compareTo(Card c) {
107        if (c == null) {
108            throw new NullPointerException();
109        }
110        // cast the Object o to a Card now that we've check to make sure it
111        // is one!
112
113        if (this.value.equals(c.value)) {
114            return this.suit.compareTo(c.suit);
115        } else {
116            return this.value.compareTo(c.value);
117        }
118    }
119
120    // -------------------------------------------
121    /**
122     * Returns true if this card is equal to the other card. Two cards are equal
123     * if both their values and suits are identical.
124     *
125     * @param otherCardObject
126     *            the other card
127     *
128     * @effects returns true if both cards are equal; in all other cases,
129     *          returns false
130     */
131    public boolean equals(Object otherCardObject) {
132        if (!(otherCardObject instanceof Card)) {
133            return false;
134        }
135        return hashCode() == ((Card) otherCardObject).hashCode();
136    }
137
138    // -------------------------------------------
139    /**
140     * Returns a hashcode for this object. This hashcode is the same for all
141     * Cards equal to this one (as indicated by the equals method). Note that it
142     * is good practice to override the hashCode method when redefining the
143     * equals method.
144     *
145     * @effects returns a hashcode for this object; invoking this methods on two
146     *          equal Cards results in the same hashcode
147     */
148    public int hashCode() {
149        int suitMultiplier = suit.ordinal();
150        int valueInt = value.ordinal() + 1;
151        return ((suitMultiplier * 13) + valueInt);
152    }
153
154    // -------------------------------------------
155    /**
156     * @effects returns a description of this card
157     */
158    public String toString() {
159        return (value.toString() + " of " + suit.toString());
160    }
161
162}