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

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.

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);
// ^^^^^^^^^^ ^^^^^^^^^^

Deck of Cards java project with confusion on intertwining a for loop and toString method

//** The code below is broken up into 2 classes and 2 Enums respectively: Card, Deck, Suit and Rank.
I'm having confusion on intertwining a for loop and toString method as asked in the instructions:
Create a toString() method in the Deck class, using another for loop to print all the Cards in the array by calling the toString() method on each card. This method “asks” the Card to print its rank and suit by only calling toString() on the Card object. There should be no reference to Rank or Suit anywhere in this method. Let Card's toString() method do the work (Delegation).
public class Card {
public static void main(String[] args) {
Card myCard = new Card();
System.out.println(myCard.toString());
System.out.println(new Card(Rank.KING, Suit.CLUBS));
}
public Rank rank;
public Suit suit;
public Rank getRank() {
return rank;
}
private void setRank(Rank rank) {
this.rank = rank;
}
public Suit getSuit() {
return suit;
}
private void setSuit(Suit suit) {
this.suit = suit;
}
// Constructor assigning attributes to rank and suit
public Card(Rank rank, Suit suit) {
setRank(rank);
setSuit(suit);
}
public Card() {
this(Rank.ACE, Suit.SPADES);
}
#Override
public String toString() {
// TODO Auto-generated method stub
String result= rank.toString() + " of " + suit.toString();
return result; }
}
public enum Suit {
NONE, CLUBS, HEARTS, SPADES, DIAMONDS
}
public enum Rank {
JOKER, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN,
KING, ACE
}
public class Deck {
public void main(String[] args) {
int[] DeckArray = new int[54];
int count = 2;
System.out.println(count);
for (count = 0; count <= 54; count++)
{
System.out.println(DeckArray);
}
}
public Card cards[];
public void DeckOfCards() {
this.cards = new Card[52];
Card myCard = new Card();
for (int i = 0; i < 0; i++) {
Card card = new Card(Rank.ACE, Suit.CLUBS);
if (Rank.JOKER != null) {
System.out.println("JOKER");
} else {
System.out.println(myCard);
}
}
for (int i = 0; i < 52; i++) {
String Deck = Arrays.toString(DeckArray)
}
}
}
Let me answer this is Psudo-code so that I won't do your homework for you :)
class Deck {
...
public String toString() {
for every item in this.cards {
currentItem.toString() // prints
}
}
}
Best of luck! Once you get the hang of it programming can be really fun.
Since the original code shows some confusion over how to define the condition that ends the for-loop, you may prefer to use this idiom instead:
for ( Card c : cards ) {
// do your work here
}
You can use the Java 8 Streams API, too, although in this case it feels unnecessarily complex:for-
Arrays.asList(cards).stream().forEach(c -> System.out.println(c.toString()));

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.

My program is not finding a defined method within another class

My card class where the method is defined.
package blackjackgamemodel;
public class Card {
protected Rank rank;
protected Suit suit;
public Card(Card.Rank rank, Card.Suit suit) {
this.rank = rank;
this.suit = suit;
}
public String toString() {
return "" + rank + " of " + suit;
}
public Card.Rank rank() {
return rank;
}
public Card.Suit suit() {
return suit;
}
public enum Rank {
ACE (1), TWO (2), THREE (3), FOUR (4), FIVE (5), SIX (6), SEVEN (7),
EIGHT (8), NINE (9), TEN (10), JACK (11), QUEEN (12), KING (13);
private int value;
Rank(int value) {
this.value = value;
}
public int value() {
return value;
}
}
public enum Suit {
SPADES, HEARTS, CLUBS, DIAMONDS
}
}
The game class where the error is
package blackjackgamemodel;
import blackjackgamemodel.Card;
import blackjackgamemodel.Deck;
public class Game {
protected Deck deck;
protected int sum;
protected int aces;
public Game() {
// Initialize deck, sum and aces.
deck = new Deck();
sum = 0;
aces = 0;
}
public Card draw() {
// Draw a card from the deck
Card drawn_card = deck.draw();
// Calculate the value to add to sum
int v = drawn_card.value();
if (v == 1) {
v = 11;
// If the card is an ace, increase the count of aces.
aces++;
}
else if (v > 10) {
v = 10;
}
// Now v is the Blackjack value of the card.
// If the sum is greater than 21 and there are aces,
// Then decrease the sum by 10 and the aces by 1.
if (aces > 0 && sum > 21) {
sum = sum - 10;
aces = aces - 1;
}
// Return the card that was drawn.
return drawn_card;
}
public int sum() {
// Getter for sum.
return sum;
}
}
ERROR
Description Resource Path Location Type
The method value() is undefined for the type Card Game.java /BlackJack/src/blackjackgamemodel line 25 Java Problem
It's the Card.Rank enum that has the value() method, not the Card class.
Try:
int v = drawn_card.rank().value()
Indeed Card has no value method: It has a rank method and Card.Rank has a value method.
value() isn't a method on Card it is on Card.Rank in your included code.
The message is correct, Card does not have a value() method. Did you mean to get the card's rank and then get that value? That's looks like the intent.
Does your Card have a value method? It looks like Card's rank has a value method.
Try:
int v = drawn_card.rank().value();

Categories

Resources