difference method java using enum types - java

I wish to write a method that can return the difference in value of 2 cards.
Im confused as I'm learning enums and not sure of the most efficient way to implement it.
public class Card implements Comparable<Card> {
public enum Rank {TWO, THREE, FOUR, FIVE, SIX,SEVEN, EIGHT, NINE, TEN,
JACK, QUEEN, KING, ACE}
public enum Suit {CLUBS, DIAMONDS, HEARTS, SPADES}
public static int difference(Card c){
}
Any help or guidance would be appreciated.

public enum Rank {ACE(1), TWO(2); /* obviously add the other values*/
private int value ;
Rank(int value){
this.value = value;
};
public int getValue(){
return this.value;
}
public int calcDifference(Rank rank){
return getValue() - rank.getValue();
}
};
which can then be called like so :
Rank rankAce = Rank.ACE;
System.out.println(rankAce.calcDifference(Rank.TWO));
You could remove the int value and just use ordinal, but this way gives you a bit of flexibility.

The simplest way to define a value of a card is to add thirteen times the suit to the rank, or to add four times the rank to the suit:
public int faceValue(Card c) {
return 13*c.getSuit().ordinal()+c.getRank().ordinal();
}
or
public int faceValue(Card c) {
return 4*c.getRank().ordinal()+c.getSuit().ordinal();
}
Both ways produce numbers from 0 to 51, inclusive.
With faceValue in hand, you can define the difference function as follows:
public static int faceValueDifference(Card left, Card right){
return left.faceValue()-right.faceValue();
}

Related

Incompatible types error when iterating through enum elements to create new object

I am trying to use two enums to create a deck of cards via a 2d array, then print all of the created cards.
public class Deck {
private Card[][] cards;
public Deck() {
cards = new Card[4][13];
for (Card.Suit suit : Card.Suit.values()) {
for (Card.Rank rank : Card.Rank.values()) {
//This is where my problem begins
cards[suit][rank] = new Card(suit, rank);
}
}
}
public Card getCard(Card.Suit s, Card.Rank r) {
//The error appears here as well.
return cards[suit][rank];
}
Here are the enums I'm trying to use.
public class Card {
private Rank rank;
private Suit suit;
// Kinds of suits
public enum Suit {
CLUBS,
DIAMONDS,
HEARTS,
SPADES;
}
// Kinds of ranks
public enum Rank {
ACE,
DEUCE,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
TEN,
JACK,
QUEEN,
KING;
}
public Card(Suit s, Rank r) {
rank = r;
suit = s;
}
...}
What I think should be happening is that the for loop is going through each element via Card.Suit.values() and then Card.Rank.values() and creating a new Card(Suit suit, Rank rank), according to it's index in the array cards[s][r].
When I compile my code it gives the error.
"Deck.java:42: error: incompatible types: Suit cannot be converted to int
cards[suit][rank] = new Card(suit, rank);"
Indexes in arrays need to be integers, but at line cards[suit][rank] = ... you are passing enum constant held by suit (like CLUBS) and rank. You can get int representing position of current enum constant with Enum#ordinal() method.
Change your
cards[suit][rank] = new Card(suit, rank);
to
cards[suit.ordinal()][rank.ordinal()] = new Card(suit, rank);
// ^^^^^^^^^^ ^^^^^^^^^^

How do I add an Object to a enum defined class?

I am trying to follow this code from Oracle docs that show you how to use Java ENUMS. However, I am trying to add a "Clown" in the final protoDeck since each deck of 52 cards can contain an additional "Clown" or "Joker" card. I cannot add the CLOWN to a SUIT or a RANK because its none of them.
I tried creating a new enum as
public enum Clown {Clown}
and tried to put this inside the protoDeck but it does not work
public class Card {
public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES }
private final Rank rank;
private final Suit suit;
private Card(Rank rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Rank rank() { return rank; }
public Suit suit() { return suit; }
public String toString() { return rank + " of " + suit; }
private static final List<Card> protoDeck = new ArrayList<Card>();
// Initialize prototype deck
static {
for (Suit suit : Suit.values())
for (Rank rank : Rank.values())
protoDeck.add(new Card(rank, suit));
}
public static ArrayList<Card> newDeck() {
return new ArrayList<Card>(protoDeck); // Return copy of prototype deck
}
}
Make Card into an interface.
You can link Clown together in the same group as the other cards, just make it behave appropriately in these situations too. So you'd have something like:
public interface Card {
Rank getRank();
Suit getSuit();
}
public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE, OTHER }
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES, NONE }
public class RegularCard implements Card {
private RegularCard(Rank rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Rank getRank() { return rank; }
public Suit getSuit() { return suit; }
}
public enum MiscellaneousCards implements Card {
CLOWN, JOKER;
// etc.
}
I cannot add the CLOWN to a SUIT or a RANK because its none of them.
I am not good at card games but I just want to suggest one thing that Clown or Joker is also part of Suite in many games it is actively take part in game.
So my suggestion is you should not create any other enum but just add Rank or Suite for Clown.
Joker does have specific rank 500 or 50 in many games which mean Joker does have rank which you can represent by UNDEFINED OR CUSTOM.
public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,
SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE, CUSTOM }
public enum Suit { CLOWN, CLUBS, DIAMONDS, HEARTS, SPADES }
In most card games, the CLOWN matches ANY suite and ANY Rank. So you may just add ANY to both the Suite and Rank. Now the problem comes when you are creating protoDeck. You can add a method isValid to either Rank or Suit that returns true only when (Suite == ANY && Rank == ANY) || (Suite != ANY && Rank != ANY).
Thanks to #KDM and #TAsk
I ended up making it work like this:
public class CardSet {
// Create ENUM for both Suites and Ranks
public enum Ranks {TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE, CLOWN}
public enum Suits {SPADES, HEARTS, CLUBS, DIAMONDS, CLOWN}
private final Ranks rank;
private final Suits suit;
private int numOfDecks;
public CardSet(Suits suit, Ranks rank) {
this.rank = rank;
this.suit = suit;
}
private static final List<CardSet> deck = new ArrayList<CardSet>();
static {
for (Suits suit : Suits.values()) {
for (Ranks rank : Ranks.values()) {
if ((suit != Suits.CLOWN && rank != Ranks.CLOWN) || (suit == Suits.CLOWN && rank == Ranks.CLOWN)) {
deck.add(new CardSet(suit, rank));
}
}
}
}
public int getNumOfDecks(){
return this.numOfDecks;
}
public List<CardSet> getNewDeck(){
return new ArrayList<>(deck);
}
And the output is something like this with CLOWN-CLOWN at the end:
SPADES-TWO
SPADES-THREE
SPADES-FOUR
SPADES-FIVE
SPADES-SIX
SPADES-SEVEN
SPADES-EIGHT
SPADES-NINE
SPADES-TEN
SPADES-JACK
SPADES-QUEEN
SPADES-KING
SPADES-ACE
HEARTS-TWO
HEARTS-THREE
HEARTS-FOUR
HEARTS-FIVE
HEARTS-SIX
HEARTS-SEVEN
HEARTS-EIGHT
HEARTS-NINE
HEARTS-TEN
HEARTS-JACK
HEARTS-QUEEN
HEARTS-KING
HEARTS-ACE
CLUBS-TWO
CLUBS-THREE
CLUBS-FOUR
CLUBS-FIVE
CLUBS-SIX
CLUBS-SEVEN
CLUBS-EIGHT
CLUBS-NINE
CLUBS-TEN
CLUBS-JACK
CLUBS-QUEEN
CLUBS-KING
CLUBS-ACE
DIAMONDS-TWO
DIAMONDS-THREE
DIAMONDS-FOUR
DIAMONDS-FIVE
DIAMONDS-SIX
DIAMONDS-SEVEN
DIAMONDS-EIGHT
DIAMONDS-NINE
DIAMONDS-TEN
DIAMONDS-JACK
DIAMONDS-QUEEN
DIAMONDS-KING
DIAMONDS-ACE
CLOWN-CLOWN

Order a list of objects

I am making a program that simulates a card game. I have a class Card that represents a playing card:
//suit types
public enum Suits{
SPADES,
CLUBS,
HEARTS,
DIAMONDS
}
//value types
public enum Values{
TWO,
THREE,
FOUR,
FIVE,
SIX,
SEVEN,
EIGHT,
NINE,
TEN,
JACK,
QUEEN,
KING,
ACE,
}
private Suits suit;
private Values value;
//Card constructor
public Card(Values value, Suits suit){
this.value = value;
this.suit = suit;
}
In my game class I have a players hand represented by a List of Cards:
public List<Card> playerHand = new ArrayList<Card>();
Is there a way that I can sort the players hand by my enum Values? Meaning if a players hand is:
TEN, ACE, TWO, FIVE
After ordering it would be:
TWO, FIVE, TEN, ACE
My conditions would be Ace is always high, and Suit doesn't matter. I know ordering Lists are trivial I just don't know how to do it for an Object based on an enum
Enums have a default ordering, i.e. they implement Comparable and thus you can just sort a list of enums or call ACE.compareTo( TEN ) in some Comparator. Note that the order of the enum values is the order of definition in the enum class (based on ordinal, see next paragraph), i.e. in your case TWO < THREE < FOUR etc.
Additionally enums have an ordinal, i.e. the index of the enum value inside the definition. In your case TWO would have the ordinal 0, THREE the ordinal 1 etc.
In order to sort your cards, you could use a Comparator (or implement Comparable<Card>) like this:
class CardComparator implements Comparator<Card> {
public int compare( Card lhs, Card rhs) {
//suit would be relevant otherwise you'd end up with spades 10, hearts 10, spades jack etc.
//thus sort by suit first to keep the cards of a suit together
int r = lhs.suit.compareTo( rhs.suit );
if( r == 0) { //same suit
r = lhs.value.compareTo( rhs.value );
}
return r;
}
}
Use
Collections.sort(list, comparator);
for sorting. As for comparator:
new Comparator<Card>() {
#Override
public int compare(Card x, Card y) {
return x.getValue().compareTo(y.getValue());
}
}
I would set a value for each of the Suits and Values, so that I can compare them to one another. For example:
public enum Suits{
SPADES(1),
CLUBS(2),
HEARTS(3),
DIAMONDS(4);
private int value;
private Suits(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
and the Values enum:
public enum Values{
TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),
JACK(11),
QUEEN(12),
KING(13),
ACE(14);
private int value;
private Values(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
Then, you can implement a Comparator for the Cards:
public class CardsComparator implements Comparator<Card> {
public int compare(Card c1, Card c2) {
//implementation based on the values of Suits and Values.
if (c1.getSuits().getValue() == c2.getSuits.getValue()) {
return c1.getValue().compareTo(c2.getValue());
} else {
return c1.getSuits().compareTo(c2.getSuits());
}
}
}
and apply an instance of the Comparator to sort your List<Card>:
Collections.sort(listOfCards, new CardsComparator());
You can implement the interface Comparable. You would have to redefine the compareTo method for your Card class and it would then allow you to do something like :
Card a = ...;
Card b = ...;
if(a.compareTo(b) <= 0) {
...
}
Or even :
Collections.sort(list);
See http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

How to loop using enum just for certain portions(face cards) in a deck of cards

I am creating a deck of poker cards (52 cards). I want to be able to print it out for example:
2 of Club, 3 of Club......
2 of Diamond, 3 of Diamond....
Queen of Diamond, King of Diamond
and so on for the 52 cards.
I am able to do this now but having problem when it comes to the face cards which are the Jack, Queen, King and Ace. Currently I am using numbers to represent them. so instead of printing Jack of Clubs, it shows as 11 of Clubs which is wrong. I tried to store the face cards in an enum and tried to loop them but can't really get around to do it.
Can I get some advice on how I could get my face cards in instead of representing them as numbers. I have attached my main method and the class below. Thanks for help.
//Card Class
import java.util.Objects;
public class Card {
public enum Suits{
CLUBS, DIAMONDS, HEARTS, SPADES;
}
public enum Faces{
JACK, QUEEN, KING, ACE;
}
private int rank;
private String suit;
public Card(int rank, String suit){
this.rank = rank;
this.suit = suit;
}
public int getRank(){
return rank;
}
public String getSuit(){
return suit;
}
public String format(){
return String.format("%d of %s, ", getRank(), getSuit());
}
}
//Main method
public class CardTester {
public static void main(String[] args) {
Card[] cards = new Card[52];
int i = 0;
for (Card.Suits suit : Card.Suits.values()) {
for (int y = 2; y < 15; y++) {
cards[i] = new Card(y, suit.name());
i++;
}
}
for(Card p : cards){
System.out.print(p.format() + " ");
}
}
}
Change your format() method to:
public String format(){
if (getRank() < 11) {
return String.format("%d of %s, ", getRank(), getSuit());
}
else {
Faces face = Faces.values()[getRank() - 11];
return String.format("%s of %s, ", face, getSuit());
}
}
Alternatively, here's a better implementation for Card:
import java.util.Objects;
public class Card {
public enum Suit {
CLUBS, DIAMONDS, HEARTS, SPADES;
}
public enum Rank {
TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN,
JACK, QUEEN, KING, ACE;
}
private final Suit suit;
private final Rank rank;
public Card(Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
public Suit getSuit(){
return suit;
}
public Rank getRank(){
return rank;
}
#Override
public String toString() {
return rank + " of " + suit;
}
#Override
public int hashCode() {
int hash = 5;
hash = 97 * hash + Objects.hashCode(this.suit);
hash = 97 * hash + Objects.hashCode(this.rank);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Card other = (Card) obj;
if (this.suit != other.suit) {
return false;
}
if (this.rank != other.rank) {
return false;
}
return true;
}
}
You can use it like this:
import java.util.ArrayList;
import java.util.List;
public class CardTester {
public static void main(String[] args) {
List<Card> cardList = new ArrayList<>();
Card lastCard = new Card(Card.Suit.SPADES, Card.Rank.ACE);
for (Card.Suit suit : Card.Suit.values()) {
for (Card.Rank rank : Card.Rank.values()) {
Card card = new Card(suit, rank);
cardList.add(card);
if (!card.equals(lastCard)) {
System.out.print(card + ", ");
}
else {
System.out.print(card);
}
}
}
// use cardList
}
}
Your modelling of cards is flawed, and your problem highlights this. Rank is not numeric and should not be an 'int'. You might want to use an enum for the rank.
You might be tempted to give your rank an integer value, but this is probably not a good idea. The value is generally defined by the game you are playing, and not by the deck of cards. For example in poker a king is ranked higher than a jack, but in blackjack they are ranked the same.
May be source code shown below will help you:
public enum Faces
{
JACK( 1, "Jack" ), QUEEN( 2, "Queen" ), KING( 3, "King" ), ACE( 4, "Ace" );
public int GetNumber()
{
return m_number;
}
public String GetName()
{
return m_name;
}
private Faces( int number_, String name_ )
{
m_number = number_;
m_name = name_;
}
private int m_number;
private String m_name;
}
you may delete the enum Faces you already have and add the following method to class Card:
public String getFace(int rank){
String result = "";
switch (rank){
case 11: result = "Jack"; break;
case 12: result = "QUEEN"; break;
case 13: result = "KING"; break;
case 14: result = "ACE"; break;
default:{
result = Integer.toString(rank);
break;
}
}
return result;
}
and modify your format() method to look like this:
public String format(){
return String.format("%s of %s, ", getFace(getRank()), getSuit());
}
This will do the job ;-)
A card consists of RANK and SUIT. Common poker software convention is to represent cards as SUIT+RANK Strings, as in 3c for 3 of clubs and Kd for king of diamonds. (see pokerstove or most hand history producers and consumers)
You need to expand the concept of RANK beyond faces. I've been using the Steve Brecher poker eval library, and his RANK class looks like this:
A simple lookup of the string "23456789TJQKA" converts between the enum and the RANK. There is a similar SUIT enum and a pretty reasonable Comparable class that combines the two.
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";
}
You can find his old but still perfectly serviceable libraries here: http://www.brecware.com/Software/software.html or http://pokersource.sourceforge.net/
U can try this solution which uses enum. First of all you need to create two enums. One for suits and the other for cards.
The enum for suits is:
public enum suits
{
club, diamond,heart,spades
}
The enum for cards is:
public enum cards
{
two(2), three(3), four(4), five(5), six(6), seven(7), eight(8),nine(9),
ten(10), jack(11), queen(12), king(13),ace(14);
int number;
private cards(int number)
{
this.number=number;
}
public int getNumber()
{
return this.number;
}
}
THen in your main class you can loop through both the enums to get your result as follows:
public class Javaclass
{
public static void main(String[] args)
{
int count=2;
for(suits suit:suits.values())
{
for(cards card: cards.values())
{
if(count<=10)
System.out.println(card.getNumber()+" of "+suit);
else
System.out.println(card+" of "+suit);
count++;
}
count=2;
System.out.println("");
}
}
}
Hope this helps.

Comparing two objects in Java .. each object has two fields

I want to compare between two cards in poker hand .. each of them has a suit and a rank and I want to check if there are duplicates to create an exception .. need help with this piece of code please ! is it ok to use the equals method or it is wrong ?!
import java.util.ArrayList;
public class Pokerhand {
public final int CARDS_NUMBER = 5;
ArrayList<Card> cards = new ArrayList<Card>();
public Pokerhand (Card card1 , Card card2, Card card3, Card card4, Card card5)
{
cards.add(card1);
cards.add(card2);
cards.add(card3);
cards.add(card4);
cards.add(card5);
}
private boolean check(ArrayList<Card> cards)
{
if (cards.size() != CARDS_NUMBER)
throw new IllegalArgumentException("Incorrect number of cards!! ");
for ( int i=0 ; i<= cards.size(); i++)
{
if (cards.get(i).equals(cards.get(i+1)))
throw new IllegalArgumentException("Duplicat card");
}
}
}
You should consider implementing Comparable in your Card class. Say each card has rank (1-king) and suit (hearts, diamonds, etc.) The method compareTo would look like:
public int compareTo(Card anotherCard) {
if (this.suit.equals(anotherCard.suit) && this.rank.equals(anotherCard.rank)) {
return 0;
}
else if (this.suit.equals(anotherCard.suit)) {
return this.rank.compareTo(anotherCard.rank);
}
else {
return this.suit.compareTo(anotherCard.suit);
}
}
Then you should just use card1.compareTo(card2) == 0 instead of card1.equals(card2)
You should override the equals method, or it just compare the reference of two objects, rather than the value of the cards.
Here is a example:
public class Card {
private int rank;
private int suit;
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Card)) {
return false;
}
Card c = (Card) obj;
return this.rank == c.rank && this.suit == c.suit;
}
}
Instead of
if (cards.get(i).equals(cards.get(i+1)))
throw new IllegalArgumentException("Duplicat card");
Try:
if(cards.get(i).getSuit() == cards.get(i+1).getSuit()
&& cards.get(i).getRank() == cards.get(i+1).getRank())
throw new IllegalArgumentException("Duplicat card");
This way you are comparing the values within the objects as opposed to comparing the object references are the same.
You could maybe model this better using enums. For example:
import java.util.EnumSet;
public class PokerGame {
public enum Suit {
SPADES, HEARTS, DIAMONDS, CLUBS
}
public enum Rank {
ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGH, NINE, TEN, JACK, QUEEN, KING
}
public enum Card {
ACE_OF_SPADES(Rank.ACE, Suit.SPADES),
TWO_OF_SPADES(Rank.TWO, Suit.SPADES),
THREE_OF_SPADES(Rank.THREE, Suit.SPADES),
FOUR_OF_SPADES(Rank.FOUR, Suit.SPADES),
FIVE_OF_SPADES(Rank.FIVE, Suit.SPADES);
// the other cards left as an exercise for the reader (-;
private Rank rank;
private Suit suit;
Card(Rank rank, Suit suit) {
this.rank = rank;
this.suit = suit;
}
public Rank rank() {
return rank;
}
public Suit suit() {
return suit;
}
}
public static void main(String[] args) {
EnumSet<Card> deck = EnumSet.allOf(Card.class);
System.out.println(deck.size());
}
}
You can then use EnumSet to create decks or hands of cards, always guaranteed to be unique.
Additional remark, the following logic is flawed:
for ( int i=0 ; i<= cards.size(); i++)
{
if (cards.get(i).equals(cards.get(i+1)))
throw new IllegalArgumentException("Duplicat card");
}
This will throw an IndexOutOfBoundsException because you are iterating up to cards.size() and acccessing cards.get(i + 1). Furthermore this will not detect non-adjacent duplicates.

Categories

Resources