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.
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 ;)
This question already has answers here:
How to make toString method within object?
(4 answers)
Closed 7 years ago.
import java.util.ArrayList;
public class Card {
int number;
String suit;
public Card(int number, String suit) {
this.number = number;
this.suit = suit;
}
public static void main(String[] args) {
String[] suit = {
"Clubs",
"Diamonds",
"Spades",
"Hearts"
};
String[] high = {
"Jack",
"Queen",
"King"
};
ArrayList<Card> deckOfCards = new ArrayList<Card>(52);
for (int j = 0; j < 4; j++) {
for (int i = 0; i < 13; i++) {
deckOfCards.add(new Card (i+1, suit[j]));
}
}
#Override
public String toString(Card card) {
this.suit = suit;
this.number = number;
String type;
if (number < 10) {
type = Integer.toString(number);
}
else {
type = high[i-number];
}
return suit + " of " + type;
}
}
}
So I have the object called card and I want to print the suit (the string) and the number on it (the int) with the method at the bottom but I'm not 100% sure how to do it. Needless to say, the part at the bottom doesn't compile or work
Thanks
This should go inside your Card class:
#Override
public String toString() {
return String.valueOf(this.number) + " of " + this.suit;
}
Call the function like this:
currentCard.toString();
or print it out to the console like this:
System.out.println(currentCard.toString());
toString method doesn't take any arguments and should be inside your card object. It's a string representation of the object. The values are set by the constructor.
Place the suit and high array in your card class at the top with the other variables, so your code looks like this:
int number;
String cardSuit; //renamed this variable because you have an array with the same name
String[] suit = {
"Clubs",
"Diamonds",
"Spades",
"Hearts"
};
String[] high = {
"Jack",
"Queen",
"King"
};
#Override
public String toString()
{
String type;
if (number < 10) {
type = Integer.toString(number);
}
else {
type = high[i-number];
}
return "Suit " + this.suit + " and Number " + this.type;
}
Side Note: It's a good idea to make your variables private and use getters/setters to set and access them. Also, override equals as well. If you're using eclipse it can generate it for you automatically.
I am trying to create a poker game in which I create the deck in the Card class, and use a comparator to sort the deck in alphabetical order. I'm having trouble with what to put in the comparator, and in my dealer class, (this is where I create the deck, shuffle, as well as calling the comparator). When my CompareCards does compile, my Dealer class will give me the error of:
Dealer.java:24: error: incompatible types: void cannot be converted to String
String s = Collections.sort(deck);
^
Note: Dealer.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
I know that when doing the sort, you have to include the Comparator name, but in this case it doesn't work either way. Here is my card class:
import java.util.*;
public class Card{
String suit = null;
String value = null;
String rank = null;
public static final String[] SUIT = {"C", "D", "H", "S" };
public static final String[] RANK = {"A","2","3","4","5","6","7","8","9","T","J","Q","K"};
public Card(int i, int j){
suit = RANK [i];
rank = SUIT [j];
value = rank + suit;
}
public String getSuit(){
return suit;
}
public String getRank(){
return rank;
}
public String toString(){
return(value);
}
}
Here is my Comparator and CompareCards class:
public interface Comparator <Card>{
public int compare(Card o1, Card o2);
}
public class CompareCards implements Comparator<Card>{
public int compare(Card c1, Card c2){
int x = 0;
int y = 0;
int dx = c1.getRank() - c2.getRank();
if(dx == 0){
x = c1.getRank()-c2.getRank();
}
else{
y = c1.getSuit() - c2.getSuit();
}
return x;
}
And here is the dealer class:
import java.util.*;
public class Dealer{
public static void main(String[]args){
// creating deck
List<Card> deck= new ArrayList<Card>();
// calling Card
for(int i = 0; i < 13 ; i++){
for(int j = 0; j < 4 ; j++){
// String s = RANK[i] +SUIT[j];
deck.add(new Card(i, j));
}
}
finding21(deck);
}
public static void finding21 (List deck){
String s = Collections.sort(deck);
System.out.println("Sorted deck: " + s);
// After I sort the deck I am supposed to do a binary search
// for the queen of hearts
/* Collections.shuffle(deck);
System.out.println("Shuffled deck: " + deck);
String HQ = Collections.binarySearch(deck, "HQ");
System.out.print(HQ);
System.out.println(queenH);*/
}
}
Collections.sort does an in-place sort and does not return a value.
That's why the compiler says you can't convert a void to a String.
The void type is used for functions with no return value.
Just use:
Collections.sort(deck);
If you want to print the sorted deck after, you can use:
System.out.println("Sorted deck: " + deck);
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;
I am currently working on a hand of cards class that uses enums that requires me to add methods that:
Add cards into the hand
Calculate the total value of all the cards currently in the hand (so if there were 3 10's in the hand then the total value would be 30)
The problem however is that I can't find out how to add up all the total while still implimenting the method within the hand class (as the task asks us to).
Any help will be greatly appreciated
Heres the code for my Suit enum
public enum Suit
{ HEARTS, CLUBS, DIAMONDS, SPADES; }
Here is the code for my Rank enum.This one has a few added methods including a getValue method
public enum Rank {
ONE(1),TWO(2),THREE(3),FOUR(4),FIVE(5), SIX (6), SEVEN(7), EIGHT(8), NINE(9), TEN(10), KING(10), QUEEN(10),
JACK(10);
private final int cardValue;
private Rank ( int nDays) {
cardValue = nDays;
}
public int getValue() {
return cardValue;
}
}
This is the Card class that uses the Rank and Suit enums to print off the details (excuse the mess)
public class Card {
private Rank rank;
private Suit suit;
public Card (Rank theRank) {
this(theRank,Suit.HEARTS);
}
public Card (Rank theRank, Suit theSuit) {
rank = theRank;
suit = theSuit;
}
public Rank getRank( ) { return rank; }
public Suit getSuit ( ) { return suit; }
public String toString ( ) { return ( rank + " of " + suit +"\n Value of card = " + rank.getValue() ); }
}
And this is the Hand class that requires the addCard method and the totalValue method. I have done the addCard method and now need to do totalValue method)
public class Hand {
private Card theCards[ ];
private Rank rank;
private int numCards; private int totalValue;
private static final int max = 5;
public Hand ( )
{
theCards = new Card [max];
numCards = 0;
}
public void addCard( Card aCard )
{
if (numCards < max)
theCards[numCards++] = aCard;
else
{
System.out.println("Cannot add any more cards as hand is full");
}
}
public void totalValue ()
{
int handValue = 0;
for(Card C: theCards)
{
//get the rank values to appear then print them off
//Add up all values of cards and display the total
totalValue = handValue + C.getValue(); //This was just a test to see if calling up the value of card C would work
}
System.out.println("The total value of all the cards is: " + totalValue);
}
public String toString ( )
{
String s = "";
for (int i = 0; i < numCards; ++i) { s += "\n" + theCards[i];
}
return s;
}
As far as implimentation goes its just a case of creating card objects and adding them to the Hand object so I don't think I'll need to post that here. Thank you to anyone who can help me with my problem.
Card doesn't have a getValue() method but Rank does. So get the card's Rank via its getRank() method and then call getValue() on the rank returned.
The value of a Card is available through its rank field. Right now you are trying to call getValue() directly on the Card, but there's no such method (yet).
Also, you'd normally return the total value of the hand from the totalValue() method, rather than simply printing it; this allows other code to actually use the value.
I managed to figure out how to make it print without returning any nullexception errors. Basicly I simply converted the array into an arraylist as it was much more practical. Here is the final version of the Hand class.
import java.util.*;
public class Hand {
private ArrayList<Card> theCards = new ArrayList<Card >() ;
private static final int max = 5;
public void addCard( Card aCard )
{
if (theCards.size() < max)
theCards.add(aCard);
else
{
System.out.println("Cannot add any more cards as hand is ull");
}
}
public void totalValue() {
int totalValue = 0;
for (Card card : theCards) {
totalValue += card.getRank().getValue();
}
System.out
.println("The total value of all the cards is: " + totalValue);
}
public void outputAllCards ( )
{
System.out.println("Outputting all card etails\n========================");
for (Card card : theCards)
{
System.out.println(card.toString());
}
System.out.println("========================");
} }
I put in a println in order to print a message out when the totalValue method was called. I tried returning by turning the method into a string or int but this didn't work
The value is inside the rank. Does the rank object inside hand play any role (such as doubling value of the corresponding cards in the hand, you have to specify the game rules)? You just have to add up the rank values. I rewrote your code to leave out some unneccessary counters/vars. On the other side it is better to keep a list instead of an array if it can grow.
import java.util.ArrayList;
import java.util.List;
public class Hand {
private final List<Card> cards = new ArrayList<Card>();
private Rank rank;
private static final int MAX = 5;
public void addCard(Card aCard) {
if (cards.size() < MAX) {
cards.add(aCard);
} else {
System.out.println("Cannot add any more cards as hand is full");
}
}
public void totalValue() {
int totalValue = 0;
for (Card card : cards) {
totalValue += card.getRank().getValue();
}
System.out
.println("The total value of all the cards is: " + totalValue);
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (Card card : cards) {
sb.append('\n').append(card.toString());
}
return sb.toString();
}
}