In this poker game code, I am trying to create a Card class. But, I wanted to use enum type instead of using constant, because I heard it's better. The only problem is I tried many times to assign the instance value for suit and the faceValue which they are int variables to the enum type variable, but it says incompatible types. What's wrong?
public class Card {
final static int MAX_SUITS = 4;
final static int MAX_FACE_VALUES = 13;
private int suit;
private int faceValue;
enum Suit {HEARTS, DIAMONDS, SPADES, CLUBS}
enum Face {ACE, JACK, QUEEN, KING}
public Card(int suit, int faceValue) {
this.suit = suit;
this.faceValue = faceValue;
}
public int getSuit() {
if (suit == 0) {
return suit = Suit.HEARTS; break;
else if (suit == 1)
return suit = Suit.DIAMONDS; break;
else if (suit == 2)
return suit = Suit.SPADES; break;
else if (suit == 3)
return suit = Suit.CLUBS; break;
}
public int getFaceValue() {
if (faceValue == 1)
return faceValue = Face.ACE; break;
else if (faceValue == 11)
return faceValue = Face.JACK; break;
else if (faceValue == 12)
return faceValue = Face.QUEEN; break;
else if (faceValue == 13)
return faceValue = Face.KING; break;
}
public void setFaceValue(int faceValue) {
this.faceValue = faceValue;
}
public void setSuit(int suit) {
this.suit = suit;
}
#Override
public String toString() {
if (suit > MAX_SUITS || faceValue > MAX_FACE_VALUES)
return "invalid entry";
else if((suit < 0 || faceValue < 0))
return "invalid entry";
else
return faceValue + " of " + suit;
}
}
How to assign enum variable to a numerical variable?
You can't. You'll have to refactor and change all your uses of int (when representing a suit) to Suit.
I hesitated do write this answer, because it defeats the whole purpose of enums, and it does not make sense to create any form of "mapping" between int values and enum constants.
Just don't do it.
Do what others suggested: Replace your int values with the corresponding enum constants. Then you also won't need these ugly workarounds with MAX_SUITS etc.
One (comparatively) clean implementation of the Card class could look as follows:
public class Card {
public static void main(String[] args)
{
Card c0 = new Card(Suit.HEARTS, Face.ACE);
Card c1 = new Card(Suit.DIAMONDS, Face.QUEEN);
System.out.println(c0);
System.out.println(c1);
}
private final Suit suit;
private final Face face;
enum Suit {HEARTS, DIAMONDS, SPADES, CLUBS}
enum Face {ACE, JACK, QUEEN, KING}
public Card(Suit suit, Face face) {
this.suit = suit;
this.face = face;
}
public Suit getSuit() {
return suit;
}
public Face getFace() {
return face;
}
#Override
public String toString() {
return getFace() + " of " + getSuit();
}
}
However, to still answer the question: It is possible to establish a mapping between int and enum values, with the built-in methods. You can use the Enum#ordinal method to obtain an int, and the (implicit) Enum#values method to obtain an array of the constants that can be accessed using an int as the index.
So the NOT recommended way of implementing it could be this:
public class Card {
public static void main(String[] args)
{
Card c0 = new Card(Suit.HEARTS.ordinal(), Face.ACE.ordinal());
Card c1 = new Card(Suit.DIAMONDS.ordinal(), Face.QUEEN.ordinal());
System.out.println(c0);
System.out.println(c1);
}
final static int MAX_SUITS = 4;
final static int MAX_FACE_VALUES = 13;
private int suit;
private int faceValue;
enum Suit {HEARTS, DIAMONDS, SPADES, CLUBS}
enum Face {ACE, JACK, QUEEN, KING}
public Card(int suit, int faceValue) {
this.suit = suit;
this.faceValue = faceValue;
}
public int getSuit() {
return suit;
}
public int getFaceValue() {
return faceValue;
}
public Suit getSuitEnum() {
return Suit.values()[suit];
}
public Face getFaceValueEnum() {
return Face.values()[faceValue];
}
public void setFaceValue(int faceValue) {
this.faceValue = faceValue;
}
public void setSuit(int suit) {
this.suit = suit;
}
#Override
public String toString() {
if (suit > MAX_SUITS || faceValue > MAX_FACE_VALUES)
return "invalid entry";
else if((suit < 0 || faceValue < 0))
return "invalid entry";
else
return getFaceValueEnum() + " of " + getSuitEnum();
}
}
Edit: I guess the confusion comes from the fact that you wanted to store the "face value" as an enum as well, and there are only enum constants for some of the face values (while the others are simply int, from 2 to 10). To put it that way: Storing the face value as an enum is probably not a good idea...
Another not recommended way to do what you want:
(I've just written this code ad-hoc and not run it, so apologies for any typo's):
public enum Suit {
HEARTS( 1 ),
DIAMONDS( 2 ),
SPADES( 3 ),
CLUBS( 4 );
private int id = -1;
public Suit( int id ) {
this.id = id;
}
public int getId() {
return id;
}
public static Suit parse( int suitId ) {
for( Suit s : values() ) {
if( s.getId() == suitId ) {
return s;
}
}
return null;
}
}
public enum Face {
ACE( 11 ),
JACK( 12 ),
QUEEN( 13 ),
KING( 14 );
private int val = -1;
public Face( int val ) {
this.val = val;
}
public int getVal() {
return val;
}
public static Face parse( int faceVal ) {
for( Face f : values() ) {
if( f.getVal() == faceVal ) {
return f;
}
}
return null;
}
}
public class Card {
final static int MAX_SUITS = 4;
final static int MAX_FACE_VALUES = 13;
private Suit suit;
private Face faceValue;
public Card(int suit, int faceValue) {
setSuit( suit );
setFaceValue( faceValue );
}
public int getSuit() {
return suit.getId();
}
public int getFaceValue() {
return face.getVal();
}
public void setFaceValue(int faceValue) {
this.faceValue = Face.parse( faceValue );
}
public void setSuit(int suit) {
this.suit = Suit.parse( suit );
}
...
}
but your basically using the enum as an integer store in this scenario. External actors on Card basically interact with it only in terms of integers, so using the enum is purely internal and a little pointless here.
One other point about your initial implementations of getSuit() and getFaceValue() - I think you probably meant to use a switch there (the break's do not have a huge effect in those if/else's):
Suit returnVal;
switch( suit ) {
case 0: returnVal = Suit.HEARTS;
break;
case 1: returnVal = Suit.DIAMONDS;
break;
case 2: returnVal = Suit.SPADES;
break;
case 3: returnVal = Suit.CLUBS;
break;
default: returnVal = null;
break;
}
return returnVal;
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I have to create 3 class (Card, Deck and Tester) to play a game of card. The rules are easy, just compare two cards randomly from the deck and whichever one is higher is the winner. It runs for the entire deck.
Here's my card class (I exclude my comments)
public class Card {
private int value;
private String suit;
public Card(){
value =1;
suit = "clubs";
}
public Card(int n, String s) {
n = value;
s = suit;
}
public int getValue() {
return value;
}
public void setValue(int n) {
if ((n >0) && (n<14)) {
n = value;
}
else {
return;
}
}
public String getSuit() {
return suit; // return the string
}
public void setSuit(String s) {
if ((s.equals("clubs") || (s.equals("hearts") || (s.equals("diamonds") || (s.equals("spades")))))){
s = suit;
}
else {
return;
}
}
public int rank() {
int rank=0;
int suitVal=0;
if (suit.equals("clubs")) {
suitVal =1;
}
else if(suit.equals("diamonds")) {
suitVal =2;
}
else if(suit.equals("hearts")) {
suitVal =3;
}
else if(suit.equals("spades")) {
suitVal =4;
}
rank= (4*(value-1)) + suitVal;
return rank;
}
}
Deck class:
import java.util.ArrayList;
public class Deck {
int[] value= {1,2,3,4,5,6,7,8,9,10,11,12,13};
String[] suit= {"clubs", "diamonds", "hearts", "spades"};
public ArrayList<Card> card = new ArrayList<Card>();
public Deck() { // make default constructor
for (int a=0; a< value.length; a++) {
for (int b=0; b< suit.length ; b++){
card.add(new Card(value[a], suit[b]));
}
}
}
public Card drawCard() {
int number = (int) Math.random()* (card.size());
Card temp = card.get(number);
card.remove(number);
return temp;
}
Tester:
public class Tester {
public static void main(String[] args) {
Deck deck1 = new Deck();
Card x = deck1.drawCard();
Card y = deck1.drawCard();
int point1=0;
int point2=0;
int player=x.rank();
int comp=y.rank();
for (int i=0; i<52; i++) {
if (player > comp) {
point1++;
}
else {
point2++;
}
}
if (point1 > point2) {
System.out.println("Player is the winner");
}
if (point1 < point2) {
System.out.println("Computer is the winner");
}
}
When I run it it says "Null pointer Exception" and point at line 42 of Card class and line 14 of Tester class. Please help
In the card class,the assignment in parmeterized constructor is wrong, you have the parameters as n and s and this value you should assign to value and suit. But you are doing other way,
public Card(int n, String s) {
n = value;
s = suit;
}
Instead of that, you should assign the values of the parameter to value and suit, something like this.
public Card(int n, String s) {
value = n;
suit = s;
}
This is the reason the value and suit is default all the time, you never changed it.
hello and welcome to SO #Elvin.
As mentioned in the comments the NPE is telling you where the problem occurs.
Your "suits" in if (suit.equals("clubs")) is null.
The problem is in your card constructor method:
public Card(int n, String s) {
n = value;
s = suit;
}
you have it the oposite way, it should be because your attributes are value and suit, so you should "store" the new values in them:
public Card(int n, String s) {
value = n;
suit = s;
}
You seem to be new, try to understand always the message of the error and of course, debug ;)
In a Java program I am trying to return the largest value card in a deck.
Diamonds are the lowest valued suit. Then clubs, then hearts and finally spades have the largest value. As you can see I have a section of code that simply says largest = in the findLargest methods. I am not sure where to go with the rest of this method.
public class Card {
private int number;
private String suit;
/*
* Randomly creates a card numbered 1 to 13 (ace = 1!) and labelled "Hearts","Clubs","Diamonds" or "Spades".
*/
public Card() {
double randomNum = Math.random() * 4.0;
if (randomNum < 1.0)
suit = "Hearts";
else if (randomNum < 2.0)
suit = "Clubs";
else if (randomNum < 3.0)
suit = "Diamonds";
else
suit = "Spades";
randomNum = Math.random() * 13.0;
number = (int) randomNum + 1;
}
/*
* Creates a card with specified number and suit
*/
public Card (int n, String s) {
number = n;
suit = s;
}
public int getNumber() {
return number;
}
public String getSuit () {
return suit;
}
public String cardString() {
// System.out.println(number + " " + suit);
String stringNum = "";
switch (number) {
case 1:
stringNum = "Ace";
break;
case 2:
stringNum = "Two";
break;
case 3:
stringNum = "Three";
break;
case 4:
stringNum = "Four";
break;
case 5:
stringNum = "Five";
break;
case 6:
stringNum = "Six";
break;
case 7:
stringNum = "Seven";
break;
case 8:
stringNum = "Eight";
break;
case 9:
stringNum = "Nine";
break;
case 10:
stringNum = "Ten";
break;
case 11:
stringNum = "Jack";
break;
case 12:
stringNum = "Queen";
break;
case 13:
stringNum = "King";
break;
default:
System.out.println("Error in Card - illegal number");
}
return stringNum + " of " + suit;
}
}
public class PackCards {
private ArrayList<Card> pack;
/*
* Create a random pack of size n
*/
public PackCards(int n) {
Card c;
pack = new ArrayList<Card>();
for (int i = 1; i <= n; i++) {
c = new Card();
pack.add(c);
}
}
public void printPack() {
for (Card c : pack) {
System.out.println(c.cardString());
}
}
public Card findLargest() {
if ( c.getNumber() > largest.getNumber() )
largest =
else if (c.getNumber() == largest.getNumber() ) {
if (largest.getSuit().equals("Diamonds"))
largest = largest.getNumber;
}
else if (c.getNumber() == largest.getNumber() ) {
if (largest.getSuit().equals("Clubs"))
largest = largest.getNumber;
}
else if (c.getNumber() == largest.getNumber() ) {
if (largest.getSuit().equals("Hearts"))
largest = largest.getNumber;
}
else return;
}
I would simplify the code to make it easier to see what you are trying to achieve. In Java 8 you can do.
import java.util.Random;
public class Card {
enum Suit {
// must be in increasing order.
Spades, Diamonds, Clubs, Hearts
}
static final Suit[] SUITS = Suit.values();
private final int number;
private final Suit suit;
/*
* Randomly creates a card numbered 1 to 13 (ace = 1!) and labelled "Hearts","Clubs","Diamonds" or "Spades".
*/
public Card() {
Random rand = new Random();
suit = SUITS[rand.nextInt(SUITS.length)];
number = rand.nextInt(13) + 1;
}
public int getNumber() {
return number;
}
public Suit getSuit() {
return suit;
}
static final String[] NAMES = ",Ace,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King".split(",");
public String cardString() {
assert number > 1 && number < NAMES.length;
return NAMES[number] + " of " + suit;
}
}
This simplifies your pack as well
public class PackOfCards {
private final List<Card> cards;
public PackOfCards(int size) {
// note duplicates are possible, i.e. ever card could be the same.
cards = IntStream.range(0, size)
.mapToObj(n -> new Card())
.collect(Collectors.toList());
}
public Card findLargest() {
return cards.stream().max(Comparator.comparing(Card::getNumber)
.thenComparing(Card::getSuit)).get();
}
}
You can change the Card class to implements the Comparable interface. For example:
public class Card implements Comparable<Card> {
....// your current implementation for the Card class
public int compareTo(Card another) {
if (this.suit.compareTo(another.suit) == 0) {
if (this.number < another.number) {
return -1;
} else if (this.number > another.number) {
return 1;
} else {
return 0;
}
} else if (this.suit.compareTo("Diamonds") == 0) {
// Diamonds being the lowest valued suit ...
return -1;
} else if (this.suit.compareTo("Clubs") == 0) {
// ... then Clubs ...
if (another.suit.compareTo("Diamonds") == 0) {
return 1;
} else {
return -1;
}
} else if (this.suit.compareTo("Hearts") == 0) {
// ... Hearts ...
if (another.suit.compareTo("Spades") == 0) {
return -1;
} else {
return 1;
}
} else {
// ... and largest values, Spades
return 1;
}
}
}
Then, you can modify the PackCards to store the cards in an ordered collection. For example:
pack = new TreeSet<Card>();
That way, the cards in the pack are ordered, and the last one is the largest.
If you want to mantain the order in wich the cards was added to the list, you can obtain the largest one in this way:
largest = Collections.max(pack);
For this sort of work, you want to leverage the object-oriented nature of Java and utilize Enums for both the FaceValue and the Suit. Enums are 'naturally ordered' in the order you list them, making your construction and string output a LOT easier:
public class Card implements Comparable<Card> {
private FaceValue faceValue;
private Suit suit;
/*
* Randomly creates a card numbered 1 to 13 (ace = 1!)
* labelled "Hearts","Clubs","Diamonds" or "Spades".
*/
public Card() {
int randomSuit = (int)Math.floor(Math.random() * 4.0); //Number between 0 and 3, inclusive.
int randomFace = (int)Math.floor(Math.random() * 13.0);
this.faceValue = FaceValue.values()[randomFace];
this.suit = Suit.values()[randomSuit];
}
public Card(FaceValue value, Suit suit) {
this.faceValue = value;
this.suit = suit;
}
// TODO Constructor that convert ints and strings to proper enums and call previous constructor
public int compareTo(Card that) {
int comparison = this.suit.compareTo(that.suit);
return (comparison != 0) ? comparison : this.faceValue.compareTo(that.faceValue);
}
public String cardString() {
return this.faceValue + " of " + this.suit;
}
public enum Suit{
DIAMOND, CLUB, HEART, SPADE;
}
public enum FaceValue {
ACE, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING;
} // You can modify this enum if you need to give back something more specific as the string value.
}
Then for your Deck you can simplify things as well by choosing a good data structure, in this case a TreeSet, which will automatically use the compareTo function you've provided for cards to sort the cards.:
public class Deck {
//By using a Set we eliminate duplicates
private final TreeSet<Card> cards;
public Deck(int size) {
cards = Sets.newTreeSet(IntStream.range(0, size)
.mapToObj(n -> new Card())
.collect(Collectors.toList());
}
//Because this is a TreeSet, finding the largest value is trivial.
public Card findLargest() {
return this.cards.last();
}
}
If you need special strings for the cards in your deck, you would do the following modification to FaceValue:
public enum FaceValue {
ACE {
public String toString() { return "Ace"; }
},
ONE {
public String toString() { return "One"; }
},
... // Fill out the rest in the same manner.
KING {
public String toString() { return "King"; }
}
}
Remember that in Object-Oriented programming, the number one rule is that an object should know how behave. Thus, if you find yourself writing a switch statement, chances are you can defer the behavior to the objects themselves. In this case, you need to create sub-objects (the FaceValue and Suit enums) that you assign to a given card. The card asks those sub parts how they are ordered, and how they should respond to a toString request.
I'm trying to finish this homework but it has been a little bit challenging so far, I'm quite new at java:
1). I have to create enums to replace the named constants for rank and suit in Card.java.
2).Make the changes necessary in Deck.java and DisplayDeck.java so they will work with the new Card.java.
This is my code so far for my three classes: Card.java, Deck.java and DisplayDeck.java
Original Card.java
public class Card {
private final int rank;
private final int suit;
// Kinds of suits
public final static int DIAMONDS = 1;
public final static int CLUBS = 2;
public final static int HEARTS = 3;
public final static int SPADES = 4;
// Kinds of ranks
public final static int ACE = 1;
public final static int DEUCE = 2;
public final static int THREE = 3;
public final static int FOUR = 4;
public final static int FIVE = 5;
public final static int SIX = 6;
public final static int SEVEN = 7;
public final static int EIGHT = 8;
public final static int NINE = 9;
public final static int TEN = 10;
public final static int JACK = 11;
public final static int QUEEN = 12;
public final static int KING = 13;
public Card(int rank, int suit) {
assert isValidRank(rank);
assert isValidSuit(suit);
this.rank = rank;
this.suit = suit;
}
public int getSuit() {
return suit;
}
public int getRank() {
return rank;
}
public static boolean isValidRank(int rank) {
return ACE <= rank && rank <= KING;
}
public static boolean isValidSuit(int suit) {
return DIAMONDS <= suit && suit <= SPADES;
}
public static String rankToString(int rank) {
switch (rank) {
case ACE:
return "Ace";
case DEUCE:
return "Deuce";
case THREE:
return "Three";
case FOUR:
return "Four";
case FIVE:
return "Five";
case SIX:
return "Six";
case SEVEN:
return "Seven";
case EIGHT:
return "Eight";
case NINE:
return "Nine";
case TEN:
return "Ten";
case JACK:
return "Jack";
case QUEEN:
return "Queen";
case KING:
return "King";
default:
//Handle an illegal argument. There are generally two
//ways to handle invalid arguments, throwing an exception
//(see the section on Handling Exceptions) or return null
return null;
}
}
public static String suitToString(int suit) {
switch (suit) {
case DIAMONDS:
return "Diamonds";
case CLUBS:
return "Clubs";
case HEARTS:
return "Hearts";
case SPADES:
return "Spades";
default:
return null;
}
}
public static void main(String[] args) {
// must run program with -ea flag (java -ea ..) to
// use assert statements
assert rankToString(ACE) == "Ace";
assert rankToString(DEUCE) == "Deuce";
assert rankToString(THREE) == "Three";
assert rankToString(FOUR) == "Four";
assert rankToString(FIVE) == "Five";
assert rankToString(SIX) == "Six";
assert rankToString(SEVEN) == "Seven";
assert rankToString(EIGHT) == "Eight";
assert rankToString(NINE) == "Nine";
assert rankToString(TEN) == "Ten";
assert rankToString(JACK) == "Jack";
assert rankToString(QUEEN) == "Queen";
assert rankToString(KING) == "King";
assert suitToString(DIAMONDS) == "Diamonds";
assert suitToString(CLUBS) == "Clubs";
assert suitToString(HEARTS) == "Hearts";
assert suitToString(SPADES) == "Spades";
}
}
My modified Card.java so far:
public class Card {
public enum Suit
{
DIAMONDS(1),
CLUBS(2),
HEARTS(3),
SPADES(4);
private final int suit;
private Suit(int suit)
{
this.suit = suit;
}
public int getSuit()
{
return suit;
}
} //end enum suit
public enum Rank
{
ACE(1),
DEUCE(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),
JACK(11),
QUEEN(12),
KING(13);
private final int rank;
private Rank(int rank)
{
this.rank = rank;
}
public int getRank()
{
return rank;
}
}//end enum rank
public static String rankToString(Rank rank) {
switch (rank) {
case ACE:
return "Ace";
case DEUCE:
return "Deuce";
case THREE:
return "Three";
case FOUR:
return "Four";
case FIVE:
return "Five";
case SIX:
return "Six";
case SEVEN:
return "Seven";
case EIGHT:
return "Eight";
case NINE:
return "Nine";
case TEN:
return "Ten";
case JACK:
return "Jack";
case QUEEN:
return "Queen";
case KING:
return "King";
default:
//Handle an illegal argument. There are generally two
//ways to handle invalid arguments, throwing an exception
//(see the section on Handling Exceptions) or return null
return null;
}
}
public static String suitToString(Suit suit) {
switch (suit) {
case DIAMONDS:
return "Diamonds";
case CLUBS:
return "Clubs";
case HEARTS:
return "Hearts";
case SPADES:
return "Spades";
default:
return null;
}
}
}//end class
And this are the original Deck.java and DisplayDeck.java:
Original Deck.java
import java.util.*;
public class Deck {
public static int numSuits = 4;
public static int numRanks = 13;
public static int numCards = numSuits * numRanks;
private Card[][] cards;
public Deck() {
cards = new Card[numSuits][numRanks];
for (int suit = Card.DIAMONDS; suit <= Card.SPADES; suit++) {
for (int rank = Card.ACE; rank <= Card.KING; rank++) {
cards[suit-1][rank-1] = new Card(rank, suit);
}
}
}
public Card getCard(int suit, int rank) {
return cards[suit-1][rank-1];
}
}
Modified Deck.java:
import java.util.*;
public class Deck {
public static int numSuits = 4;
public static int numRanks = 13;
public static int numCards = numSuits * numRanks;
private Card[][] cards;
public Deck() {
cards = new Card[numSuits][numRanks];
for (Card.Suit suit : Card.Suit.values()) {
for (Card.Rank rank : Card.Rank.values()) {
// I dont know how to change this to work with Card.java
cards[suit-1][rank-1] = new Card(rank, suit);
}
}
}
public Card getCard(int suit, int rank) {
return cards[suit-1][rank-1];
}
}
and DisplayDeck.java
import java.util.*;
public class DisplayDeck {
public static void main(String[] args) {
Deck deck = new Deck();
/// how can i modify this code to work with both Card.java and Deck.java?
for (int suit = Card.DIAMONDS; suit <= Card.SPADES; suit++) {
for (int rank = Card.ACE; rank <= Card.KING; rank++) {
Card card = deck.getCard(suit, rank);
System.out.format("%s of %s%n",
card.rankToString(card.getRank()),
card.suitToString(card.getSuit()));
}
}
}
}
I update my code on what I got so far.
Get rid of all your int representations for rank and suit. You can replace loops like this:
for (int suit = Card.DIAMONDS; suit <= Card.SPADES; suit++) { ...
with an enhanced for loop:
for (Suit suit : Card.Suit.values()) { ...
Replace mappings from int to String with EnumMap<Suit,String> or EnumMap<Rank,String> as appropriate. Methods for checking whether an int value is valid can be disposed of, as a non-null enum is guaranteed to be a legal value.
EDIT (in response to comment): You can define your deck as simply an array of Card objects:
public class Deck {
private List<Card> cards;
public Deck() {
cards = new ArrayList<>();
for (Card.Suit suit : Card.Suit.values()) {
for (Card.Rank rank : Card.Rank.values()) {
cards.add(new Card(suit, rank));
}
}
}
}
With this, you can use the Collections utility class to trivially implement shuffling:
public class Deck {
. . . // as above
public void shuffle() {
Collections.shuffle(cards);
}
}
Since every enum type comes with a built-in compareTo() method that tells you the relative order of two enum values (of the same type). You can build on this to make the Card class implement Comparable<Card>. (This is left as an exercise for the reader :-)). Then you can trivially sort the deck back into its "brand new" order or even sort hands drawn randomly from the deck.
I see that you are currently retrieving a card by suit and rank. That's a weird way to access cards in a deck, especially since you just turn around and use the Card object to retrieve its suit and rank. But if you really need that kind of retrieval, you can expand the Deck definition to include internally an EnumMap<Suit, EnumMap<Rank, Card>> to allow you to quickly retrieve a card that way. (Yes, each card would then be stored in two distinct data structures inside the Deck object.) A better approach, in my view, is to add a method to retrieve a card by offset into the deck (and another method to tell you the deck size):
public class Deck {
. . .
public Card getCard(int index) {
return cards.get(index);
}
public int cardCount() {
return cards.size();
}
}
To be fancier, you can define a method that returns an iterator over all the cards:
public class Deck {
. . .
public Iterator<Card> iterator() {
return cards.iterator();
}
}
Even fancier yet, you could declare Deck to implement Iterable<Card>. Then you can print the deck contents very simply:
Deck deck = new Deck();
for (Card card : deck) {
// print the card
}
Okay in the code below I want to declare that "Diamonds" and "Hearts" are red.
Code Here
if (card.getCardFace() == || card.getCardFace() == )
g.setColor(Color.red);
else
g.setColor(Color.black);
I was wondering on how I could do that if I declared them as chars in my Card class. Do I have to change that ?
Card Class
// Instance Data - all things common to all cards
private String cardFace; // king, q, j, 10 - 2, A
private int faceValue; // numberic value of the card
private char cardSuit; // hold suit of the card
private char suits[] = {(char)(003), (char)(004), (char)(005), (char)(006)};
// Constructor
public PlayingCard(int value, int suit)
{
faceValue = value;
setFace();
setSuit(suit);
}
// helper setFace()
public void setFace()
{
switch(faceValue)
{
case 1:
cardFace = "A";
faceValue = 14;
break;
case 11:
cardFace = "J";
break;
case 12:
cardFace = "Q";
break;
case 0:
cardFace = "K";
faceValue = 13;
break;
default:
cardFace = ("" + faceValue);
}
}
public void setSuit(int suit) // suit num between 0 and 3
{
cardSuit = suits[suit];
}
// other helpers
public int getFaceValue()
{
return faceValue;
}
public String getCardFace()
{
return cardFace;
}
public String toString()
{
return (cardFace + cardSuit);
}
}
(Also let me know if you need more code)
You should use Enums to define types for ranks and suits, something like:
public static enum Suit {
CLUB, DIAMOND, SPADE, HEART
}
public static enum Rank {
TWO("2"), THREE("3"), FOUR("4"), FIVE("5"), SIX("6"), SEVEN("7"),
EIGHT("8"), NINE("9"), TEN("10"), JACK("J"), QUEEN("Q"), KING("K"),
ACE("A");
private final String symbol;
Rank(String symbol) {
this.symbol = symbol;
}
public String getSymbol() {
return symbol;
}
}
---
class Card {
Suit suit;
Rank rank;
}
Then just compare the values:
if (card.suit == Suit.DIAMONDS || card.suit == Suit.HEARTH) {
color = Color.RED;
} else {
color = Color.BLACK;
}
Or define a color as a property of Suit and then just use:
color = card.suit.getColor();
I'm struggling to add together values that I've declared within ENUMS. I basically need to add together values of each card within a hand of cards based on rank.
I've tried a few things but not actually got anywhere. I can display the ENUM's but they have no value.
Here is my code:
Card Class
public class Card {
private Suit suit;
private Rank rank;
int totalValue;
public Card (Suit suit, Rank rank) {
this.suit = suit;
this.rank = rank;
}
public Suit getSuit(){
return suit;
}
public void setSuit(Suit suit)
{
this.suit = suit;
}
public Rank getRank()
{
return rank;
}
public void setRank(Rank rank)
{
this.rank = rank;
}
#Override
public String toString ( ) { return ( rank + " of " + suit); }
}
Suit Class
public enum Suit {
HEARTS , SPADES , CLUBS , DIAMONDS
}
Rank Class
public enum Rank {
ACE(1),
TWO(2),
THREE(3),
FOUR(4),
FIVE(5),
SIX(6),
SEVEN(7),
EIGHT(8),
NINE(9),
TEN(10),
JACK(10),
QUEEN(10),
KING(10);
private int RankValue;
private Rank (int rValue)
{
RankValue = rValue;
}
public int getRankValue()
{
return RankValue;
}
}
Hand Class
public class Hand {
private Card theCards[ ];
private int numCards;
private int totalValue;
private static final int max = 5;
private Rank rank;
private Suit suit;
public Hand ( )
{
theCards = new Card [max];
numCards = 0;
}
public void addCard( Card aCard )
{
if (numCards < max) theCards[numCards++] = aCard;
}
public void setRank(Rank rank){
this.rank = rank;
}
public void setSuit(Suit suit){
this.suit = suit;
}
public int totalValue() {
int totalValue = 0;
for (Card card : theCards) {
totalValue += card.getRank().getRankValue();
}
return totalValue;
}
#Override
public String toString ( )
{
String s = "Rank: " + rank + "Suit: " + suit;
for (int i = 0; i < numCards; ++i) {
s += "\n" + theCards[i] + "\n" + totalValue;
}
return s;
}
}
Finally my Hand Driver with the main method
public class HandDriver {
public static void main( String[] args ){
Hand h1 = new Hand();
Card c1 = new Card(Suit.valueOf("HEARTS"),Rank.valueOf("TEN"));
Card c2 = new Card(Suit.valueOf("SPADES"),Rank.valueOf("ACE"));
Card c3 = new Card(Suit.valueOf("DIAMONDS"),Rank.valueOf("SEVEN"));
Card c4 = new Card(Suit.valueOf("HEARTS"),Rank.valueOf("NINE"));
Card c5 = new Card(Suit.valueOf("HEARTS"),Rank.valueOf("THREE"));
h1.addCard(c1);
h1.addCard(c2);
h1.addCard(c3);
h1.addCard(c4);
h1.addCard(c5);
System.out.print (h1.toString());
;
}
}
I'm basically looking for someone who is able to point me in the right direction to display the total value of all cards
In your Hand class, you are using int totalValue, which is then "shadowed" in your function totalValue(), so totalValue will be zero. Then, in toString() you are using totalValue, which is never calculated. First, remove "int" here:
public int totalValue() {
//removed "int", so you are not declaring local totalValue variable
//but using your class variable
totalValue = 0;
for (Card card : theCards) {
totalValue += card.getRank().getRankValue();
}
return totalValue;
}
Then, in your toString(), call the above function, so that totalValue is calculated, and then you can use it in your loop:
#Override
public String toString ( )
{
String s = "Rank: " + rank + "Suit: " + suit;
//call totalValue() to calculate totalValue
totalValue();
for (int i = 0; i < numCards; ++i) {
//now you can use totalValue, because it's been calculated in totalValue()
s += "\n" + theCards[i] + "\n" + totalValue;
}
return s;
}
As noticed by Holger, you can also use Suit.HEARTS instead of Suit.valueOf("HEARTS").
EDIT: As noticed by Grove, totalValue() doesn't have to be called for every card. Call it before you build your string, and then you can use totalValue variable in your for loop.
There are a few problems with your code.
I agree with "Holger" you should not be using
Suit.valueOf("HEARTS") and
Rank.valueOf("TEN")
Instead it should be
Suit.HEARTS
Rank.TEN
Then in the Card and Hand classes you should probably be calculating the value of that Card or value of that Hand as the suit and rank is added to the Card and as a Card is added to the Hand, that way when you get the total value of the Hand or want to do toString() you only need to read the value rather than calculate it every time.
In the Hand class the way you are adding a Card to the "theCards" array should be like so:
if (numCards < max) {
theCards[numCards] = aCard;
numCards++;
}
Then as I mentioned before you should probably in this if block also call another method which you will need to create to update the total value.
Finally, to calculate the total of a Card you may want to do something like,
int suitVal = suit.ordinal(); // This returns a number which is the position of the enum value
int rankVal = rank.getRankValue();
totalValue = suitVal + rankVal;
I could have just changed all your code and pasted it in here for you but that I think would not be good for learning.
Hope this helps.