[java] Deck of cards JAVA

I have created my deck of cards that deals every card and a suit until there is no card remaining. For my project, I need to split it up into 3 classes which includes a driver class. I first created one class with everything so I knew how to make it all work.

public class DeckOfCards2 {
  public static void main(String[] args) {
    int[] deck = new int[52];
    String[] suits = {"Spades", "Hearts", "Diamonds", "Clubs"};
    String[] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};

    // Initialize cards
    for (int i = 0; i < deck.length; i++) {
      deck[i] = i;
    }

    // Shuffle the cards
    for (int i = 0; i < deck.length; i++) {
      int index = (int)(Math.random() * deck.length);
      int temp = deck[i];
      deck[i] = deck[index];
      deck[index] = temp;
    }

    // Display the all the cards
    for (int i = 0; i < 52; i++) {
      String suit = suits[deck[i] / 13];
      String rank = ranks[deck[i] % 13];
      System.out.println( rank + " of " + suit);
    }
  }
}

Now trying to split it up into 3 classes. I am getting red sqiggle lines on ALL my deck/suit variables on my DeckOfCards class. I dont know how to fix it.

public class DeckOfCards {
  private Card theCard;
  private int remainingCards = 52;

  DeckOfCards() {
    theCard = new Card();   
  }

  public void shuffle(){
    for (int i = 0; i < deck.length; i++) {
       int index = (int)(Math.random() deck.length);
       int temp = deck[i];
       deck[i] = deck[index];
       deck[index] = temp;
       remainingCards--;
     }
  }

  public void deal(){
    for (int i = 0; i < 52; i++) {
       String suit = suits[deck[i] / 13];
       String rank = ranks[deck[i] % 13];
       System.out.println( rank + " of " + suit);
       System.out.println("Remaining cards: " + remainingCards);
     }
   }
}

Card class:

public class Card {
  int[] deck = new int[52];
  String[] suits = {"Spades", "Hearts", "Diamonds", "Clubs"};
  String[] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};

  Card() {
    for (int i = 0; i < deck.length; i++) {
      deck[i] = i;
    }
  }
}

Dealer class

public class Dealer {
  public static void main(String[]args){
    System.out.println("The deck will randomly print out a card from a full deck each time");

    DeckOfCards player = new DeckOfCards();
    player.deal();
  }
}

This question is related to java

The answer is


There are many errors in your code, for example you are not really calling your deck by just typing deck in your Shuffle method. You can only call it by typing theCard.deck

I have changed your shuffle method:

public void Shuffle(){
    for (int i = 0; i < theCard.deck.length; i++) {
        int index = (int)(Math.random()*theCard.deck.length );
        int temp = theCard.deck[i];
        theCard.deck[i] = theCard.deck[index];
        theCard.deck[index] = temp;
        remainingCards--;
    }
}

Also, as it is said you have structural problem. You should name classes as you understand in real life, for example, when you say card, it is only one card, when you say deck it is supposed to be 52+2 cards. In this way your code would be more understandable.


There is a lot of error in your program.

  1. Calculation of index. I think it should be Math.random()%deck.length

  2. In the display of card. According to me, you should make a class of card which has rank suit and make the array of that class type

If you want I can give you the Complete structure of that but it is better if u make it by yourself


This is my implementation:

public class CardsDeck {
    private ArrayList<Card> mCards;
    private ArrayList<Card> mPulledCards;
    private Random mRandom;

public enum Suit {
    SPADES,
    HEARTS,
    DIAMONDS,
    CLUBS;
}

public enum Rank {
    TWO,
    THREE,
    FOUR,
    FIVE,
    SIX,
    SEVEN,
    EIGHT,
    NINE,
    TEN,
    JACK,
    QUEEN,
    KING,
    ACE;
}

public CardsDeck() {
    mRandom = new Random();
    mPulledCards = new ArrayList<Card>();
    mCards = new ArrayList<Card>(Suit.values().length * Rank.values().length);
    reset();
}

public void reset() {
    mPulledCards.clear();
    mCards.clear();
    /* Creating all possible cards... */
    for (Suit s : Suit.values()) {
        for (Rank r : Rank.values()) {
            Card c = new Card(s, r);
            mCards.add(c);
        }
    }
}


public static class Card {

    private Suit mSuit;
    private Rank mRank;

    public Card(Suit suit, Rank rank) {
        this.mSuit = suit;
        this.mRank = rank;
    }

    public Suit getSuit() {
        return mSuit;
    }

    public Rank getRank() {
        return mRank;
    }

    public int getValue() {
        return mRank.ordinal() + 2;
    }

    @Override
    public boolean equals(Object o) {
        return (o != null && o instanceof Card && ((Card) o).mRank == mRank && ((Card) o).mSuit == mSuit);
    }


}

/**
 * get a random card, removing it from the pack
 * @return
 */
public Card pullRandom() {
    if (mCards.isEmpty())
        return null;

    Card res = mCards.remove(randInt(0, mCards.size() - 1));
    if (res != null)
        mPulledCards.add(res);
    return res;
}

/**
 * Get a random cards, leaves it inside the pack 
 * @return
 */
public Card getRandom() {
    if (mCards.isEmpty())
        return null;

    Card res = mCards.get(randInt(0, mCards.size() - 1));
    return res;
}

/**
 * Returns a pseudo-random number between min and max, inclusive.
 * The difference between min and max can be at most
 * <code>Integer.MAX_VALUE - 1</code>.
 *
 * @param min Minimum value
 * @param max Maximum value.  Must be greater than min.
 * @return Integer between min and max, inclusive.
 * @see java.util.Random#nextInt(int)
 */
public int randInt(int min, int max) {
    // nextInt is normally exclusive of the top value,
    // so add 1 to make it inclusive
    int randomNum = mRandom.nextInt((max - min) + 1) + min;
    return randomNum;
}


public boolean isEmpty(){
    return mCards.isEmpty();
}
}

import java.util.List;
import java.util.ArrayList;
import static java.lang.System.out;
import lombok.Setter;
import lombok.Getter;
import java.awt.Color;


public class Deck {

private static @Getter List<Card> deck = null;

final int SUIT_COUNT = 4;
final int VALUE_COUNT = 13;

public Deck() {
    deck = new ArrayList<>();
    Card card = null;
    int suitIndex = 0, valueIndex = 0;
    while (suitIndex < SUIT_COUNT) {
        while (valueIndex < VALUE_COUNT) {
            card = new Card(Suit.values()[suitIndex], FaceValue.values()[valueIndex]);
            valueIndex++;
            deck.add(card);
        }
        valueIndex = 0;
        suitIndex++;
    }
}

private enum Suit{CLUBS("Clubs", Color.BLACK), DIAMONDS("Diamonds", Color.RED),HEARTS("Hearts", Color.RED), SPADES("Spades", Color.BLACK);

    private @Getter String name = null;
    private @Getter Color color = null;

    Suit(String name) {
        this.name = name;
    }

    Suit(String name, Color color) {
        this.name = name;
        this.color = color;
    }
}

private enum FaceValue{ACE(1), TWO(2), THREE(3),
    FOUR(4), FIVE(5), SIX(6), SEVEN(7), EIGHT (8), NINE(9), TEN(10),
    JACK(11), QUEEN(12), KING(13);

    private @Getter int cardValue = 0;

    FaceValue(int value) {
        this.cardValue = value;
    }
}

private class Card {

    private @Getter @Setter Suit suit = null;

    private @Getter @Setter FaceValue faceValue = null;

    Card(Suit suit, FaceValue value) {
        this.suit = suit;
        this.faceValue = value;
    }

    public String toString() {
        return getSuit() + " " + getFaceValue();
    }

    public String properties() {
        return getSuit().getName() + " " + getFaceValue().getCardValue();
    }

}

public static void main(String...inputs) {
    Deck deck = new Deck();
    List<Card> cards = deck.getDeck();
    cards.stream().filter(card -> card.getSuit().getColor() != Color.RED && card.getFaceValue().getCardValue() > 4).map(card -> card.toString() + " " + card.properties()).forEach(out::println);   
}

}


First you have an architectural issue with your classes. You moved the property deck inside your class Card. But of couse it is a property of the card deck and thus has to be inside class DeckOfCards. The initialization loop should then not be in the constructor of Card but of your deck class. Moreover, the deck is an array of int at the moment but should be an array of Cards.

Second, inside method Deal you should refer to suits as Card.suits and make this member static final. Same for ranks.

And last, please stick to naming conventions. Method names are always starting with a lower case letter, i.e. shuffle instead of Shuffle.


public class shuffleCards{

    public static void main(String[] args) {

        String[] cardsType ={"club","spade","heart","diamond"};
        String [] cardValue = {"Ace","2","3","4","5","6","7","8","9","10","King", "Queen", "Jack" };

        List<String> cards = new ArrayList<String>();
        for(int i=0;i<=(cardsType.length)-1;i++){
            for(int j=0;j<=(cardValue.length)-1;j++){
                cards.add(cardsType[i] + " " + "of" + " " + cardValue[j]) ;
            }
        }

        Collections.shuffle(cards);
        System.out.print("Enter the number of cards within:" + cards.size() + " = ");

        Scanner data = new Scanner(System.in);
        Integer inputString = data.nextInt();
        for(int l=0;l<= inputString -1;l++){
            System.out.print( cards.get(l)) ;
        }    
    }
}

I think the solution is just as simple as this:

Card temp = deck[cardAindex];
deck[cardAIndex]=deck[cardBIndex]; 
deck[cardBIndex]=temp;

Here is some code. It uses 2 classes (Card.java and Deck.java) to accomplish this issue, and to top it off it auto sorts it for you when you create the deck object. :)

import java.util.*;

public class deck2 {
    ArrayList<Card> cards = new ArrayList<Card>();

    String[] values = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
    String[] suit = {"Club", "Spade", "Diamond", "Heart"};

    static boolean firstThread = true;
    public deck2(){
        for (int i = 0; i<suit.length; i++) {
            for(int j=0; j<values.length; j++){
                this.cards.add(new Card(suit[i],values[j]));
            }
        }
        //shuffle the deck when its created
        Collections.shuffle(this.cards);

    }

    public ArrayList<Card> getDeck(){
        return cards;
    }

    public static void main(String[] args){
        deck2 deck = new deck2();

        //print out the deck.
        System.out.println(deck.getDeck());
    }

}


//separate class

public class Card {


    private String suit;
    private String value;


    public Card(String suit, String value){
        this.suit = suit;
        this.value = value;
    }
    public Card(){}
    public String getSuit(){
        return suit;
    }
    public void setSuit(String suit){
        this.suit = suit;
    }
    public String getValue(){
        return value;
    }
    public void setValue(String value){
        this.value = value;
    }

    public String toString(){
        return "\n"+value + " of "+ suit;
    }
}

As somebody else already said, your design is not very clear and Object Oriented.

The most obvious error is that in your design a Card knows about a Deck of Cards. The Deck should know about cards and instantiate objects in its constructor. For Example:

public class DeckOfCards {
    private Card cards[];

    public DeckOfCards() {
        this.cards = new Card[52];
        for (int i = 0; i < ; i++) {
            Card card = new Card(...); //Instantiate a Card
            this.cards[i] = card; //Adding card to the Deck
        }
     }

Afterwards, if you want you can also extend Deck in order to build different Deck of Cards (for example with more than 52 cards, Jolly etc.). For Example:

public class SpecialDeck extends DeckOfCards {
   ....

Another thing that I'd change is the use of String arrays to represent suits and ranks. Since Java 1.5, the language supports Enumeration, which are perfect for this kind of problems. For Example:

public enum Suits {
    SPADES, 
    HEARTS, 
    DIAMONDS,
    CLUBS;  
}

With Enum you get some benefits, for example:

1) Enum is type-safe you can not assign anything else other than predefined Enum constants to an Enum variable. For Example, you could write your Card's constructor as following:

public class Card {

   private Suits suit;
   private Ranks rank;

public Card(Suits suit, Ranks rank) {
    this.suit = suit;
    this.rank = rank;
}

This way you are sure to build consistent cards that accept only values ??of your enumeration.

2) You can use Enum in Java inside Switch statement like int or char primitive data type (here we have to say that since Java 1.7 switch statement is allowed also on String)

3) Adding new constants on Enum in Java is easy and you can add new constants without breaking existing code.

4) You can iterate through Enum, this can be very helpful when instantiating Cards. For Example:

/* Creating all possible cards... */
for (Suits s : Suits.values()) {
    for (Ranks r : Ranks.values()) {
         Card c = new Card(s,r);
    }  
}

In order to not invent again the wheel, I'd also change the way you keep Cards from array to a Java Collection, this way you get a lot of powerful methods to work on your deck, but most important you can use the Java Collection's shuffle function to shuffle your Deck. For example:

private List<Card> cards = new ArrayList<Card>();

//Building the Deck...

//...

public void shuffle() {
    Collections.shuffle(this.cards); 
}

There is something wrong with your design. Try to make your classes represent real world things. For example:

  • The class Card should represent one card, that is the nature of a "Card". The Card class does not need to know about Decks.
  • The Deck class should contain 52 Card objects (plus jokers?).