Making Multiple Decks of Cards Java

5.1k views Asked by At

Edit: I'm getting an error while trying to add the card to my originalDecks and dealDecks.

I think I have figured out how to create a single deck of cards [shown in the method Decks()], but my problem is that I have to create multiple decks of cards [n number of decks = n*52 number of cards]. I can't figure out how to utilize the n to make multiples of the same card. After creating the multiple decks, I think I can figure out the shuffle() and reset(), but getting multiple decks is giving me problems right now.

Note: I was thinking of creating an array of n decks, but I don't even know how to start this.

Card Class

/** class Card : for creating playing card objects
 *  it is an immutable class.
 *  Rank - valid values are 1 to 13
 *  Suit - valid values are 0 to 3
 *  Do not modify this class!
 */
class Card {

/* constant suits and ranks */
static final String[] Suit = {"Clubs", "Diamonds", "Hearts", "Spades" };
static final String[] Rank = {"","A","2","3","4","5","6","7","8","9","10","J","Q","K"};

/* Data field of a card: rank and suit */
private int cardRank;  /* values: 1-13 (see Rank[] above) */
private int cardSuit;  /* values: 0-3  (see Suit[] above) */

/* Constructor to create a card */
/* throw PlayingCardException if rank or suit is invalid */
public Card(int rank, int suit) throws PlayingCardException { 
if ((rank < 1) || (rank > 13))
    throw new PlayingCardException("Invalid rank:"+rank);
else
        cardRank = rank;
if ((suit < 0) || (suit > 3))
    throw new PlayingCardException("Invalid suit:"+suit);
else
        cardSuit = suit;
}

/* Accessor and toString */
/* You may impelemnt equals(), but it will not be used */
public int getRank() { return cardRank; }
public int getSuit() { return cardSuit; }
public String toString() { return Rank[cardRank] + " " + Suit[cardSuit]; }


/* Few quick tests here */
public static void main(String args[])
{
try 
        {
        Card c1 = new Card(1,3);    // A Spades
        System.out.println(c1);
        c1 = new Card(10,0);    // 10 Clubs
        System.out.println(c1);
        //c1 = new Card(10,5);        // generate exception here
    }
catch (PlayingCardException e)
    {
        System.out.println("PlayingCardException: "+e.getMessage());
    }
    }
}

Decks Class

/** class Decks represents : n decks of playing cards
 *  Use class Card to construct n * 52 playing cards!
 *
 *  Do not add new data fields!
 *  Do not modify any methods
 *  You may add private methods 
 */

class Decks {

/* this is used to keep track of original n*52 cards */
private List<Card> originalDecks;   

/* this starts with n*52 cards deck from original deck   */
/* it is used to keep track of remaining cards to deal */
/* see reset(): it resets dealDecks to a full deck      */
private List<Card> dealDecks;

/* number of decks in this object */
private int numberDecks;


/**
 * Constructor: Creates default one deck of 52 playing cards in originalDecks and
 *          copy them to dealDecks.
 *              initialize numberDecks=n
 * Note: You need to catch PlayingCardException from Card constructor
 *       Use ArrayList for both originalDecks & dealDecks
 * @throws PlayingCardException 
 */
public Decks() throws PlayingCardException
{
    // implement this method!
    int i, j;
    for (i=0;i<4;i++) 
    {
        for(j=1;j<14;j++) 
        {
            Card orcard = new Card(i,j);
            originalDecks.add(orcard);
            dealDecks.add(orcard);
        }
    }

}


/**
 * Constructor: Creates n decks (52 cards each deck) of playing cards in
 *              originalDecks and copy them to dealDecks.
 *              initialize numberDecks=n
 * Note: You need to catch PlayingCardException from Card constructor
 *       Use ArrayList for both originalDecks & dealDecks
 * @throws PlayingCardException 
 */
public Decks(int n) throws PlayingCardException
{
    // implement this method!
    int i, j;
    for (i=0;i<4;i++) 
    {
        for(j=1;j<14;j++) 
        {
            Card orcard = new Card(i,j);
            originalDecks.add(orcard);
            dealDecks.add(orcard);
        }
    }
}
4

There are 4 answers

7
aplassard On BEST ANSWER

You should be able to just loop through the step of creating decks of cards multiple times. Either add another loop through n before or in the for loop.

public Decks(int n) throws PlayingCardException
{
    // implement this method!
    int i, j;
    for (i=0;i<4;i++) 
    {
        for(j=1;j<14;j++) 
        {
            for(k=0;k<n;k++){
                Card orcard = new Card(i,j);
                originalDecks.add(orcard);
                dealDecks.add(orcard);
             }
        }
    }
}

OR

public Decks(int n) throws PlayingCardException
{
    // implement this method!
    int i, j;
    for(int k=0;k<n;k++){
        for (i=0;i<4;i++) 
        {
            for(j=1;j<14;j++) 
            {
                Card orcard = new Card(i,j);
                originalDecks.add(orcard);
                dealDecks.add(orcard);
            }
        }
    }
}
0
anonymous On

If you just want decks of cards, you know each deck has 52 cards. So why not just create an array of Cards multiple of 52 inside the class Deck?

public class Deck {
    private Card[] cards;
    private int dealIndex; // position of next card to deal

    public Deck(int n) { // n number of decks
        cards = new Card[52*n];
        dealIndex = 0;
        // Initialize cards here by creating instances of cards.
        // Maybe write a function to initialize 1 deck of cards and call this n times with appropriate index to cards array.
    }
}

The other thing to consider is use Enumeration inside your class Card to represent the SUIT and RANK.

Finally, implement Comparable to be able to compare Cards. You might want to create class Hand and also implement Comparable to be able to compare poker hands.

0
Erik On

You are on the right track but it will be a whole lot easier of you keep it all as object-oriented as possible.

Each playing card will have a Suit and Rank, and they are a range of predefined values. It makes sense to make them each enum values like so:

public enum PlayingCardSuit
{
    None(0),
    Spades(1),
    Diamonds(2),
    Hearts(3),
    Clubs(4);

    private int suit;

    private PlayingCardSuit(int suit)
    {
        this.suit = suit;
    }
}

public enum PlayingCardRank
{
    None(0),
    Ace(1),
    Two(2),
    Three(3),
    Four(4),
    Five(5),
    Size(6),
    Seven(7),
    Eight(8),
    Nine(9),
    Ten(10),
    Jack(11),
    Queen(12),
    King(13);

    private int rank;

    private PlayingCardRank(int rank)
    {
        this.rank = rank;
    }
}

Now, you can have a Card class which represents the Suit and Rank together. I also use a UUID to assign each card a randomized unique ID value. This makes it much easier to shuffle them by sorting on the UUID rather than do some complex ordering.

Here's the PlayingCard class:

import java.util.*;

public final class PlayingCard
{
    private UUID id;
    private PlayingCardSuit suit;
    private PlayingCardRank rank;

    public PlayingCard(PlayingCardSuit suit, PlayingCardRank rank)
    {
        this.id = UUID.randomUUID();
        this.suit = suit;
        this.rank = rank;
    }

    public UUID id()
    {
        return this.id;
    }

    public void setId(UUID id)
    {
         this.id = id;
    }

    public PlayingCardSuit suit()
    {
        return this.suit;
    }

    public PlayingCardRank rank()
    {
        return this.rank;
    }

    public String toString()
    {
        return String.format("%s of %s", this.rank, this.suit);
    }
}

Now a Deck is merely a fancy wrapper around a collection of Cards, with methods like shuffle() and drawCard(). It being its own class rather than an array is you get to encapsulate all the management from within and not have to worry about keeping track of 'which cards are left.' It does all that using a Stack collection.

import java.util.*;

public final class PlayingCardDeck
{
    private Stack<PlayingCard> deck;

    public PlayingCardDeck()
    {
        initializeDeck();
        shuffle();
    }

    private void initializeDeck()
    {
        deck = new Stack<PlayingCard>();

        for(final PlayingCardSuit suit : EnumSet.allOf(PlayingCardSuit.class))
        {
            // Skip the 'None' suit.
            if(suit == PlayingCardSuit.None) continue;

            for(final PlayingCardRank rank : EnumSet.allOf(PlayingCardRank.class))
            {
                // Skip the 'None' rank card.
                if(rank == PlayingCardRank.None) continue;

                PlayingCard card = new PlayingCard(suit, rank);
                deck.push(card);
            }
        }
    }

    public int size()
    {
        return deck.size();    
    }

    public void shuffle()
    {
        // Generate new UUIDs to randomize.
        for(final PlayingCard card : deck)
            card.setId(UUID.randomUUID());

        // Sort the deck based on the card UUID for randomization.
        Collections.sort(deck, new Comparator<PlayingCard>()
        {
            public int compare(PlayingCard a, PlayingCard b)
            {
                UUID aID = a.id();
                UUID bID = b.id();
                return aID.compareTo(bID); 
            }  
        });
    }

    public PlayingCard drawCard()
    {
        return deck.pop();
    }
}

It will generate all 52 cards of each suit and rank when created. It will also shuffle them (and can be shuffled again later). When you draw a card via drawCard(), it will remove the card from the top of the deck.

This may seem like overkill, but it's really organized approach and will make your life a lot easier when multiple decks come into play.

Here's the little driver class I had made to test:

public static void main(String[] args) 
{
    Untitled program = new Untitled();
    program.run();  
}

public void run()
{
    PlayingCardDeck deck = new PlayingCardDeck();

    System.out.println(String.format("Deck has %d cards in it.", deck.size()));

    int i = 0;
    while(deck.size() > 0)
    {
        PlayingCard card = deck.drawCard();
        System.out.println(String.format("[Card %2d]: Drew the %s card.", (++i), card.toString()));
    }

    System.out.println("Deck is empty.");
}

And the output (randomized):

Deck has 52 cards in it.
[Card  1]: Drew the Queen of Diamonds card.
[Card  2]: Drew the Eight of Clubs card.
[Card  3]: Drew the King of Clubs card.
[Card  4]: Drew the Queen of Hearts card.
[Card  5]: Drew the Four of Clubs card.
[Card  6]: Drew the Three of Diamonds card.
[Card  7]: Drew the Nine of Diamonds card.
[Card  8]: Drew the Ace of Diamonds card.
[Card  9]: Drew the Seven of Spades card.
[Card 10]: Drew the Two of Hearts card.
[Card 11]: Drew the Nine of Hearts card.
[Card 12]: Drew the Size of Clubs card.
[Card 13]: Drew the Jack of Diamonds card.
[Card 14]: Drew the Size of Hearts card.
[Card 15]: Drew the Three of Clubs card.
[Card 16]: Drew the Three of Spades card.
[Card 17]: Drew the Ten of Spades card.
[Card 18]: Drew the Jack of Hearts card.
[Card 19]: Drew the Five of Clubs card.
[Card 20]: Drew the Seven of Clubs card.
[Card 21]: Drew the Size of Diamonds card.
[Card 22]: Drew the Ten of Hearts card.
[Card 23]: Drew the Three of Hearts card.
[Card 24]: Drew the Ace of Spades card.
[Card 25]: Drew the Four of Hearts card.
[Card 26]: Drew the Eight of Diamonds card.
[Card 27]: Drew the Ace of Clubs card.
[Card 28]: Drew the Two of Clubs card.
[Card 29]: Drew the Nine of Spades card.
[Card 30]: Drew the Jack of Spades card.
[Card 31]: Drew the Ace of Hearts card.
[Card 32]: Drew the Seven of Hearts card.
[Card 33]: Drew the Five of Hearts card.
[Card 34]: Drew the Eight of Spades card.
[Card 35]: Drew the King of Hearts card.
[Card 36]: Drew the Jack of Clubs card.
[Card 37]: Drew the Size of Spades card.
[Card 38]: Drew the Five of Spades card.
[Card 39]: Drew the Five of Diamonds card.
[Card 40]: Drew the King of Diamonds card.
[Card 41]: Drew the Ten of Clubs card.
[Card 42]: Drew the Queen of Spades card.
[Card 43]: Drew the King of Spades card.
[Card 44]: Drew the Seven of Diamonds card.
[Card 45]: Drew the Four of Spades card.
[Card 46]: Drew the Queen of Clubs card.
[Card 47]: Drew the Ten of Diamonds card.
[Card 48]: Drew the Eight of Hearts card.
[Card 49]: Drew the Four of Diamonds card.
[Card 50]: Drew the Two of Diamonds card.
[Card 51]: Drew the Nine of Clubs card.
[Card 52]: Drew the Two of Spades card.
Deck is empty.
0
Asaf Pinhassi On

This is my implementation:

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

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

public static 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();
}
}