package common.handeval.stevebrecher;
/**
* An immutable poker card.
* @version 2006Dec11.0
* @author Steve Brecher
*
*/
public class Card implements Comparable<Card> {
/**
* The card ranks, from two (deuce) to ace.
*/
public static enum Rank {
TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE;
/**
* @return the character in {@link #RANK_CHARS} denoting this rank.
*/
public char toChar() {
return RANK_CHARS.charAt(this.ordinal());
}
/**
* @param c a character present in {@link #RANK_CHARS} (case insensitive)
* @return the Rank denoted by character.
* @throws IllegalArgumentException if c not in {@link #RANK_CHARS}
*/
public static Rank fromChar(char c) {
int i = RANK_CHARS.indexOf(Character.toUpperCase(c));
if (i >= 0)
return Rank.values()[i];
throw new IllegalArgumentException("'" + c + "'");
}
/**
* @return the pip value of this Rank, ranging from 2 for
* a <code>TWO</code> (deuce) to 14 for an <code>ACE</code>.
*/
public int pipValue() {
return this.ordinal() + 2;
}
public static final String RANK_CHARS = "23456789TJQKA";
}
/**
* The card suits, from club to spade.
*/
public static enum Suit {
CLUB, DIAMOND, HEART, SPADE;
/**
* @return the character in {@link #SUIT_CHARS} denoting this suit.
*/
public char toChar() {
return SUIT_CHARS.charAt(this.ordinal());
}
/**
* @param c a character present in {@link #SUIT_CHARS} (case insensitive)
* @return the Suit denoted by the character.
* @throws IllegalArgumentException if c not in {@link #SUIT_CHARS}
*/
public static Suit fromChar(char c) {
int i = SUIT_CHARS.indexOf(Character.toLowerCase(c));
if (i >= 0)
return Suit.values()[i];
throw new IllegalArgumentException("'" + c + "'");
}
public static final String SUIT_CHARS = "cdhs";
}
private final Rank rank;
private final Suit suit;
/**
* Constructs a card of the specified rank and suit.
* @param rank a {@link Rank}
* @param suit a {@link Suit}
* @see #getInstance(com.stevebrecher.poker.Card.Rank, com.stevebrecher.poker.Card.Suit)
*/
public Card(Rank rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}
/**
* Constructs a card of the specified rank and suit.
* @param rs a {@link String} of length 2, where the first character is in {@link Card.Rank#RANK_CHARS} and
* the second is in {@link Card.Suit#SUIT_CHARS} (case insensitive).
* @throws IllegalArgumentException on the first character in rs which is not found in the respective string.
* @see #getInstance(String)
*/
public Card(String rs) {
if (rs.length() != 2)
throw new IllegalArgumentException('"' + rs + "\".length != 2");
try {
this.rank = Rank.fromChar(rs.charAt(0));
this.suit = Suit.fromChar(rs.charAt(1));
} catch (IllegalArgumentException e) {
throw e; // indicates the first erroneous character
}
}
private final static Card[] theCards = new Card[52];
static {
int i = 0;
for (Suit s : Suit.values())
for (Rank r : Rank.values())
theCards[i++] = new Card(r, s);
}
/**
* Returns a pre-existing instance of {@link Card} of the specified rank and suit.
* @param rank a {@link Rank}
* @param suit a {@link Suit}
* @return an instance of {@link Card} of the specified rank and suit.
*/
public static Card getInstance(Rank rank, Suit suit) {
return theCards[suit.ordinal() * 13 + rank.ordinal()];
}
/**
* Returns a pre-existing instance of {@link Card} of the specified rank and suit.
* @param rs a {@link String} of length 2, where the first character is in {@link Card.Rank#RANK_CHARS} and
* the second is in {@link Card.Suit#SUIT_CHARS} (case insensitive).
* @return an instance of {@link Card} of the specified rank and suit.
* @throws IllegalArgumentException on the first character in rs which is not found in the respective string.
*/
public static Card getInstance(String rs) {
if (rs.length() != 2)
throw new IllegalArgumentException('"' + rs + "\".length != 2");
try {
Rank rank = Rank.fromChar(rs.charAt(0));
Suit suit = Suit.fromChar(rs.charAt(1));
return theCards[suit.ordinal() * 13 + rank.ordinal()];
} catch (IllegalArgumentException e) {
throw e; // indicates the first erroneous character
}
}
/**
* Returns a {@link String} of length 2 denoting the rank and suit of this card.
* @return a {@link String} of length 2 containing a character in {@link Card.Rank#RANK_CHARS} denoting this
* card's rank followed by a character in {@link Card.Suit#SUIT_CHARS} denoting this
* card's suit.
*/
@Override
public String toString() {
return String.format("%c%c", rank.toChar(), suit.toChar());
}
/**
* Returns the {@link Rank} of this card.
* @return the {@link Rank} of this card.
*/
public Rank rankOf() {
return rank;
}
/**
* Returns the {@link Suit} of this card.
* @return the {@link Suit} of this card.
*/
public Suit suitOf() {
return suit;
}
/**
* Compares the parameter to this card.
* @return <code>true</code> if the parameter is a {@link Card} of the same rank and suit
* as this card; <code>false</code> otherwise.
*/
@Override
public boolean equals(Object that) {
if (!(that instanceof Card))
return false;
Card c = (Card) that;
return this.rank == c.rank && this.suit == c.suit;
}
/* result is a perfect hash code */
@Override
public int hashCode() {
return rank.ordinal() * 4 + suit.ordinal();
}
/**
* Compares the specified Card to this card, first on rank; then, if equal, on suit.<br>
* Note that the suit comparison is not germane to the core game of
* poker but is the one traditionally used to assign stud bring-ins, etc.
* @param that the Card to be compared
* @return a negative integer, zero, or a positive integer as this Card is less than,
* equal to, or greater than the specified Card.
*/
public int compareTo(Card that) {
int result = this.rank.compareTo(that.rank);
if (result != 0)
return result;
return this.suit.compareTo(that.suit);
}
}