Modify a .java file to change constants to enums - java

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
}

Related

Shuffling Deck of Cards Using Card object

Have been attempting to create a class called CardDeck to shuffle card objects created in a different class (called DeckOfCard, sorry for the confusion, not well named) but have run out of ideas of how to accomplish this.
here is what I have come up with, I've included the original class DeckOfCards as well, any help/ advice is welcomed and appreciated!
//CODE FOR CARD OBJECT//
public final static int 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;
public final static int diamonds= 1, clubs= 2, spades= 3, hearts=4;
private final static int numberOfFaces = 13;
private final static int numberOfSuits = 4;
private int face, suit;
private String faceValue, suitName;
//create a random card
public DeckOfCards()
{
face= (int)(Math.random() * numberOfFaces);
setFaceValue();
suit= (int) (Math.random() * numberOfSuits);
setSuitName();
}
//sets the string representation of each face value to its coorspdoing numeric value
private void setFaceValue()
{
switch(face)
{
case ace:
faceValue= "Ace";
break;
case two:
faceValue= "Two";
break;
case three:
faceValue= "Three";
break;
case four:
faceValue= "Four";
break;
case five:
faceValue = "Five";
break;
case six:
faceValue = "Six";
break;
case seven:
faceValue= "Seven";
break;
case eight:
faceValue= "Eight";
break;
case nine:
faceValue= "Nine";
break;
case ten:
faceValue= "Ten";
break;
case jack:
faceValue= "Jack";
break;
case queen:
faceValue= "Queen";
break;
case king:
faceValue= "King";
break;
}
}
//set the string representation of each suit
private void setSuitName()
{
switch(suit)
{
case diamonds:
suitName = "Diamonds";
break;
case clubs:
suitName= "Clubs";
break;
case spades:
suitName = "Spades";
break;
case hearts:
suitName = "Hearts";
break;
}
}
public String getFaceValue()
{
return faceValue;
}
public String getSuitName()
{
return suitName;
}
public String toString()
{
return faceValue+ " of " +suitName;
}
}
And Here is my current code... It's not much but this is as close as I have been able to get thus far:
import java.util.Random;
public class CardDeck
{
private DeckOfCards[] cards;
//create new deck of cards
public CardDeck()
{
cards = new DeckOfCards[52];
int index= 0;
int[] cardTypes = {DeckOfCards.ace, DeckOfCards.diamonds, DeckOfCards.spades, DeckOfCards.hearts};
for(int cardType : cardTypes)
{
for(int i = 1; i<=13; i++)
{
DeckOfCards card = new DeckOfCards();
cards[index++]= card;
}
}
}
//create shuffle method, use loop to generate random suit and random faceValue
public void shuffle()
{
System.out.println("Suffuling cards");
int loopCount = 53;
while (loopCount > 0) {
double index1 = Math.random();
double index2 = Math.random();
DeckOfCards temp = cards[index1];
cards[index1] = cards[index2];
cards[index2] = temp;
loopCount--;
}
}
}
Define a enum types for the rank and the suit. This provides type safety so that you don't accidentally pass a rank for a suit parameter or vice versa. The enumerated values also make good keys to use in maps to define scoring systems for different games and so on. Note also that enums can have properties and methods, so you can add user friendly names for values that way.
Then create a Card type that has a rank and a suit.
Iterate over the ranks, and for each rank, iterate over the suits. Create a new Card for each combination of rank and suit, and add it to a List; this is your deck. When your deck is built, you can shuffle it with a convenience method in Collections.
public final class Card {
public enum Rank {
ACE, DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING
}
public enum Suit {
SPADES, HEARTS, DIAMOND, CLUBS
}
private final Rank rank;
private final Suit suit;
public Card(Rank rank, Suit suit) {
this.rank = Objects.requireNonNull(rank);
this.suit = Objects.requireNonNull(suit);
}
public Rank getRank() {
return rank;
}
public Suit getSuit() {
return suit;
}
#Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (!(obj instanceof Card)) return false;
Card that = (Card) obj;
return (getRank() == that.getRank()) && (getSuit() == that.getSuit());
}
#Override
public int hashCode() {
return getRank().hashCode() * 31 + getSuit().hashCode();
}
#Override
public String toString() {
return getRank() + " of " + getSuit();
}
}
public class Deck {
private final List<? extends Card> cards;
public Deck(Collection<? extends Card> cards) {
this.cards = new ArrayList<>(cards);
}
public void shuffle(Random random) {
if (random == null) random = ThreadLocalRandom.current();
Collections.shuffle(cards, random);
}
public static Deck newStandardDeck() {
List<Card> cards = new ArrayList<>();
for (Card.Rank rank : Card.Rank.values()) {
for (Card.Suit suit : Card.Suit.values()) {
cards.add(new Card(rank, suit));
}
}
return new Deck(cards);
}
}
Your issue lies here:
double index1 = Math.random();
double index2 = Math.random();
Math.random() returns a double float between 0 and 1.
Try this instead:
Random r = new Random();
while(loopCount > 0) {
int index1 = r.nextInt(cards.length);
int index2 = r.nextInt(cards.length);
So there's some big issues with your code structure but i salvaged this.
The easiest solution is to create a sorted list of cards, one for each suite and value and then set each card to a random index. This will perform that on a field 'cards'
// create shuffle method, use loop to generate random suit and random faceValue
public void shuffle() {
System.out.println("Suffuling cards");
int loopCount = 0;
ArrayList<DeckOfCards> inOrder = new ArrayList<DeckOfCards>();
for(int i = 0; i < 54; i++)
{
inOrder.add(cards[i]);
}
DeckOfCards[] shuffled = new DeckOfCards[54];
for(int i = 0; i < 54; i++)
{
//Math.random()*size of inOrder will give you a double between 0 and size of in order.
//Round this down and convert to an int and you have a random index!
int randCardIndex = (int) (Math.floor(Math.random()*inOrder.size()));
//Grab the card and add it to the shuffled deck in the current position
shuffled[i] = inOrder.get(randCardIndex);
//Remove this card so it can no longer be grabbed
inOrder.remove(randCardIndex);
}
cards = shuffled;
}
Please change the name to Card instead of DeckOfCards. A list of Card objects becomes a deck of cards, so you don't want to call the object itself the deck.
The random function should follow a similar approach as the constructor of DeckOfCards in which your multiplier should be applied on top of the random number and be casted into an int. After that, your code should work fine. Card size 52 should be stored as a global private variable. Never use "magic numbers" without storing them in a variable and calling that variable. Both index1 and index2 should be the following:
double index1 = Math.random()*NUM_CARDS
Below your private array have the following variable: private final int NUM_CARDS = 52
Otherwise you are on the right track and the shuffling mechanism is good. It's just the random index generation gets a decimal number between 0 to 1.
When you have to debug, use the printing your variables technique. In this case, print out every value of index1 and index2 and check whether those values are being generated as intended. You can also try a less beginner friendly method called debug mode (cockroach icon) and double click on a line number to set a breakpoint at which you want the execution to pause and you can view all the variables stored in memory at that point of your code.

Highest value card found in deck

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.

How can I declare the suits Diamond and Hearts?

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();

How to assign enum variable to a numerical variable? Java

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;

Flow of control in java - multiple classes

I am a beginner to java and have been going through oracle's java tutorial. In those tutorials I came across a question involving multiple classes. The class called Deck uses class called Cards. I want to know if the class Deck ever uses the main method in class Cards. Does the line of flow ever go through the main method of Cards.
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";
}
}
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];
}
}
No, it does not. The main method implemented in this example is intended for testing purposes (note the asserts).
It's very typical, however I'd say a very bad, custom to have the main method in all the possible tutorials and examples. And yes, it confuses beginners.
Testing code should always be separated from the tested code. In a "normal" code for the good design. In a "school" code for the didactical reason, so the learners are not confused and see the good design even in the school code :)

Categories