001 package ps0.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 */
009 public 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 }