1.11M Members

Help with card deck class

 
0
 

Hi all,

I'm working through the java tutorials on sun.com and trying to create a card class and a deck class which populates with card objects. Having trouble getting things running and I'm not sure where the problem is, pasted below are the card class and deck class, I'd appreciate if someone could take a look and let me know if they can see the problem.
The main methods in each class are just for testing purposes. SingleCard seems to work fine and my problem with the deck class is that it seems to default to returning the joker result(end of deck)

I'm just trying to accomplish a full draw through the deck at the moment with program ending at deck end(I am aware that the code as it stands draws only 1 card from the deck, I was waiting to get 1 card drawn successfully before putting in a loop to iterate through the deck)

Card class -

package cardDeck;
import java.util.*;

public class SingleCard {
	private Random rnd = new Random();
	private final String[] rank = {"Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King","Joker"};
	private final String[] suit = {"Diamonds","Hearts","Clubs","Spades"};
	private static String pickedRank;
	private static String pickedSuit;
	
	protected SingleCard()
	{
		pickedRank = rank[rnd.nextInt(13)];
		pickedSuit = suit[rnd.nextInt(4)];
	}
	protected SingleCard(int selectedSuit)
	{
		if (selectedSuit >= 0 && selectedSuit <=3)
		{
			pickedRank = rank[rnd.nextInt(13)];
			pickedSuit = suit[selectedSuit];
		}
		else
		{
			pickedRank = rank[rnd.nextInt(13)];
			pickedSuit = suit[0];
		}
	}
	
	protected SingleCard(int selectedSuit, int selectedRank)
	{
		if (selectedRank >= 0 && selectedRank <=12)
		{
			pickedRank = rank[selectedRank];
			pickedSuit = suit[selectedSuit];
		}
		else
		{
			pickedRank = rank[rnd.nextInt(13)];
			pickedSuit = suit[0];
		}
	}
	
	protected String getSuit()
	{
		return pickedSuit;
	}
	
	protected String getRank()
	{
		return pickedRank;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) 
	{
		new SingleCard();
		System.out.println("You have picked the " + pickedRank + " of " + pickedSuit + ".");
		
	}


}

Deck Class

package cardDeck;
import java.util.*;

public class FullDeck 
	{
	private int noOfCards = 52;
	private SingleCard[][] deck = new SingleCard[4][13];
	private int[][] shuffleDeckControlArray = new int[4][13];
	private SingleCard[] shuffledDeck = new SingleCard[52];
	private int topOfDeck = 0;
	private Random rnd = new Random();
	private static SingleCard joker = new SingleCard(0, 13);
	
	/*randomise deck with second array of 1's and 0's to mark drawn and not, use local noofcards to load
	 * 52 slot 1d array called shuffleddeck then use the end of this array to deal the deck from , 
	 * shortening the number of cards as they are drawn using the noofcards static variable, if redealing same deck
	 * in order set no of cards to 52 again.Complete drawcard method
	 */
	protected FullDeck()
	{
		int noOfUnshuffledCards = 52;//control for randomly picking card order to add to deck
		
		for(int i = 0; i < 4;i++)   //creates a new 52 card deck, ordered
		{
			for(int j = 0; j < 13; j++)
			{
				deck[i][j] = new SingleCard(i,j); 
			}
		}
		
		for(int k = 0; k < 4; k++) //populate the control array with 0's
		{
			for(int l = 0; l < 13; l++)
			{
				shuffleDeckControlArray[k][l] = 0;
			}
		}
		
		
		
		while(noOfUnshuffledCards != 0)
		{
			boolean cardPicked = false;
			while(cardPicked == false)
			{
				int m = rnd.nextInt(4);
				int n = rnd.nextInt(13);
			
					if(shuffleDeckControlArray[m][n] == 0)
					{
						shuffledDeck[topOfDeck] = deck[m][n];
						topOfDeck ++;
						noOfUnshuffledCards --;
						shuffleDeckControlArray[m][n] = 1;
						cardPicked = true;
						
					}
					
			}
					
				
			
		}
	}
	
	protected SingleCard drawCard()
	{
		if(noOfCards != 0)
			{
			noOfCards --;
			SingleCard drawnCard = shuffledDeck[topOfDeck];
			topOfDeck --;
			return drawnCard;
			}
		else
		{
			return joker;
		}
		
	}
	
	public static void main(String args[])
	{
		FullDeck myDeck = new FullDeck();
		if(myDeck.drawCard() != joker)
		{
			System.out.println(myDeck.drawCard().getRank() + " of " + myDeck.drawCard().getSuit());
		}
		else
		{
			System.out.println("End of Deck");
			System.exit(0);
		}
		
	}
	
	
	}
 
0
 

Do you get any errors? Please copy and paste them here.

 
0
 

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 52
at cardDeck.FullDeck.drawCard(FullDeck.java:71)
at cardDeck.FullDeck.main(FullDeck.java:85)
when running main method in eclipse(I'm used to using blueJ so took me a while to find the terminal output)

Obviously I have an array going too high somewhere, perhaps the noOfCards and local number should be set to 51 instead?

 
0
 

Ah think I have it, the topOfDeck variable was used as my control for loading the shuffled deck stack which gave an indexoutofbounds when deck was full(position 52 in a 52 slot array not existing) I changed shuffledDeck[topOfDeck]; to shuffledDeck[topOfDeck-1] and ran ok.

The problem now is a logical error, every time I run the method it returns "King of Spades". Any thoughts?

I have a feeling the problem lies in the method call for drawing the card but this is my first cross-class program using object references so feeling a bit like I'm stabbing in the dark at the moment :)

 
1
 

Ok solved, the logical error was that I had defined the pickedSuit and pickedRank fields as static in the SingleCard class, meaning that the last card generated(king of spades) was the reference for all of the SingleCards. I think I have the gist of the static keyword now.

In effect I was replacing every card in the deck with the new card when filling with my for loop. Hopefully it'll all be plain sailing from here, thanks again for the help.

 
1
 

This is great - the only help you needed was "tell us what the error is" and it looks like you took it from there - and you explained your error nicely, so anyone reading this can get a sense of what was going wrong.

 
0
 

I may have spoken a bit too soon, everything is working fine from what I can tell but the deck will only draw 18 cards before exiting and I'm going to take a bit of a break for a few hours. I'm posting the "fixed" code for both classes here so that it can be compared to the earlier code with the mistakes in it.

The return from the current main method is 18 random cards then "end of deck", I think the joker must be being called through some minor error but fresh eyes would be greatly appreciated.

SingleCard class

package cardDeck;
import java.util.*;

public class SingleCard {
	private Random rnd = new Random();
	private final String[] rank = {"Ace","2","3","4","5","6","7","8","9","10","Jack","Queen","King","Joker"};
	private final String[] suit = {"Diamonds","Hearts","Clubs","Spades"};
	private  String pickedRank;
	private  String pickedSuit;
	
	protected SingleCard()
	{
		pickedRank = rank[rnd.nextInt(13)];
		pickedSuit = suit[rnd.nextInt(4)];
	}
	protected SingleCard(int selectedSuit)
	{
		if (selectedSuit >= 0 && selectedSuit <=3)
		{
			pickedRank = rank[rnd.nextInt(13)];
			pickedSuit = suit[selectedSuit];
		}
		else
		{
			pickedRank = rank[rnd.nextInt(13)];
			pickedSuit = suit[0];
		}
	}
	
	protected SingleCard(int selectedSuit, int selectedRank)
	{
		if (selectedRank >= 0 && selectedRank <=12)
		{
			pickedRank = rank[selectedRank];
			pickedSuit = suit[selectedSuit];
		}
		else
		{
			pickedRank = rank[rnd.nextInt(13)];
			pickedSuit = suit[0];
		}
	}
	
	protected String getSuit()
	{
		return pickedSuit;
	}
	
	protected String getRank()
	{
		return pickedRank;
	}
}

FullDeck class

package cardDeck;
import java.util.*;

public class FullDeck 
	{
	private int noOfCards = 52;
	private SingleCard[][] deck = new SingleCard[4][13];
	private int[][] shuffleDeckControlArray = new int[4][13];
	private SingleCard[] shuffledDeck = new SingleCard[52];
	private int topOfDeck = 0;
	private Random rnd = new Random();
	private static SingleCard joker = new SingleCard(0, 13);
	int cardCount = 0;
	
	
	/*randomise deck with second array of 1's and 0's to mark drawn and not, use local noofcards to load
	 * 52 slot 1d array called shuffleddeck then use the end of this array to deal the deck from , 
	 * shortening the number of cards as they are drawn using the noofcards static variable, if redealing same deck
	 * in order set no of cards to 52 again.Complete drawcard method
	 */
	protected FullDeck()
	{
		int noOfUnshuffledCards = 52;//control for randomly picking card order to add to deck
		
		
		for(int i = 0; i < 4;i++)   //creates a new 52 card deck, ordered
		{
			for(int j = 0; j < 13; j++)
			{
				deck[i][j] = new SingleCard(i,j); 
			}
		}
		
		for(int k = 0; k < 4; k++) //populate the control array with 0's
		{
			for(int l = 0; l < 13; l++)
			{
				shuffleDeckControlArray[k][l] = 0;
			}
		}
		
		
		
		while(noOfUnshuffledCards != 0)
		{
			boolean cardPicked = false;
			while(cardPicked == false)
			{
				int m = rnd.nextInt(4);
				int n = rnd.nextInt(13);
			
					if(shuffleDeckControlArray[m][n] == 0)
					{
						shuffledDeck[topOfDeck] = deck[m][n];
						topOfDeck ++;
						noOfUnshuffledCards --;
						shuffleDeckControlArray[m][n] = 1;
						cardPicked = true;
						
					}
					
			}
					
				
			
		}
	}
	
	protected SingleCard drawCard()
	{
		if(noOfCards != 0)
			{
			noOfCards --;
			SingleCard drawnCard = shuffledDeck[topOfDeck-1];
			topOfDeck --;
			return drawnCard;
			}
		else
		{
			return joker;
		}
		
	}
	
	public static void main(String args[])
	{
		FullDeck myDeck = new FullDeck();
		for(;;)
			{
			if(myDeck.drawCard() != joker)
			
				{
					System.out.println(myDeck.drawCard().getRank() + " of " + myDeck.drawCard().getSuit());
					myDeck.cardCount ++;
				}
				else
				{
					System.out.println("End of Deck");
					System.out.println(myDeck.cardCount);
					System.exit(0);
				}
			}
	}
	
	
	}

And a sample output from terminal -

3 of Clubs
Queen of Spades
7 of Diamonds
3 of Spades
6 of Hearts
7 of Clubs
10 of Spades
10 of Clubs
Ace of Spades
9 of Clubs
10 of Diamonds
5 of Diamonds
10 of Hearts
5 of Hearts
9 of Clubs
9 of Clubs
2 of Spades
Jack of Diamonds
End of Deck
18

Thanks again, I'll probably be back on in a few hours

 
1
 

You need to debug your program by adding some println() statements to show how values change. For example add the following first thing in the drawCard() method and look at the output:

System.out.println("noOfCards=" + noOfCards);
 
0
 

Thanks popped that in and I can see that noOfCards is decrementing for 3 times for every time a card is returned, I'm having some problems tracking down the reason for the issue but I can confirm the deck is properly populated - terminal output with your suggested debugging code and also code to print the shuffledDeck array.

Position 0 has 5 of Spades
Position 1 has 2 of Clubs
Position 2 has Queen of Diamonds
Position 3 has Queen of Hearts
Position 4 has King of Spades
Position 5 has King of Clubs
Position 6 has 8 of Diamonds
Position 7 has 6 of Spades
Position 8 has 10 of Clubs
Position 9 has 3 of Spades
Position 10 has 6 of Diamonds
Position 11 has 5 of Clubs
Position 12 has 7 of Spades
Position 13 has Ace of Spades
Position 14 has Ace of Clubs
Position 15 has 2 of Spades
Position 16 has 3 of Hearts
Position 17 has Jack of Clubs
Position 18 has 2 of Diamonds
Position 19 has 4 of Diamonds
Position 20 has 7 of Diamonds
Position 21 has 4 of Spades
Position 22 has 9 of Diamonds
Position 23 has 8 of Hearts
Position 24 has 3 of Diamonds
Position 25 has Jack of Diamonds
Position 26 has 8 of Clubs
Position 27 has 6 of Clubs
Position 28 has Jack of Hearts
Position 29 has Queen of Clubs
Position 30 has King of Diamonds
Position 31 has 3 of Clubs
Position 32 has King of Hearts
Position 33 has 4 of Hearts
Position 34 has 6 of Hearts
Position 35 has 5 of Hearts
Position 36 has Ace of Hearts
Position 37 has 5 of Diamonds
Position 38 has 7 of Hearts
Position 39 has 10 of Spades
Position 40 has Queen of Spades
Position 41 has 4 of Clubs
Position 42 has 2 of Hearts
Position 43 has 9 of Hearts
Position 44 has 7 of Clubs
Position 45 has Ace of Diamonds
Position 46 has 9 of Clubs
Position 47 has 8 of Spades
Position 48 has 10 of Diamonds
Position 49 has 9 of Spades
Position 50 has 10 of Hearts
Position 51 has Jack of Spades
noOfCards=52
noOfCards=51
noOfCards=50
10 of Spades
noOfCards=49
noOfCards=48
noOfCards=47
8 of Clubs
noOfCards=46
noOfCards=45
noOfCards=44
7 of Hearts
noOfCards=43
noOfCards=42
noOfCards=41
4 of Spades
noOfCards=40
noOfCards=39
noOfCards=38
7 of Diamonds
noOfCards=37
noOfCards=36
noOfCards=35
5 of Hearts
noOfCards=34
noOfCards=33
noOfCards=32
King of Clubs
noOfCards=31
noOfCards=30
noOfCards=29
Queen of Hearts
noOfCards=28
noOfCards=27
noOfCards=26
8 of Diamonds
noOfCards=25
noOfCards=24
noOfCards=23
8 of Diamonds
noOfCards=22
noOfCards=21
noOfCards=20
7 of Diamonds
noOfCards=19
noOfCards=18
noOfCards=17
Jack of Hearts
noOfCards=16
noOfCards=15
noOfCards=14
Ace of Spades
noOfCards=13
noOfCards=12
noOfCards=11
5 of Diamonds
noOfCards=10
noOfCards=9
noOfCards=8
10 of Spades
noOfCards=7
noOfCards=6
noOfCards=5
King of Spades
noOfCards=4
noOfCards=3
noOfCards=2
Queen of Clubs
noOfCards=1
noOfCards=0
noOfCards=0
5 of Diamonds
noOfCards=0
End of Deck
18

 
1
 

So the problem seems to be that you're drawing three cards each time through. How could that come about?

Or perhaps I should say: Yes, your problem is that you're drawing three cards each time through, and you'll probably see it the next time you look.

 
0
 

So the problem seems to be that you're drawing three cards each time through. How could that come about?

Or perhaps I should say: Yes, your problem is that you're drawing three cards each time through, and you'll probably see it the next time you look.

Ah is it that everytime I reference the draw method it is being executed?

if(myDeck.drawCard() != joker)

System.out.println(myDeck.drawCard().getRank() + " of " + myDeck.drawCard().getSuit());
					myDeck.cardCount ++;

So I should probably call the method once within the loop, assign the current card to a local class variable and then use the qualified names to retrieve the suit and rank info from the stored card reference?

If this is the case it's good to know my class code was done ok and I just screwed up the testing main method :)

 
0
 

Yep that was it, thanks a million for all the help and I appreciate not being handed the answer straight up I doubt I'll make the same mistake with the methods from here on :D

Final working code pasted below for anybody having similiar issues, the exercise is in the classes section of the java online tutorial - Sun Java Tutorial

package cardDeck;
import java.util.*;

public class FullDeck 
	{
	private int noOfCards = 52;
	private SingleCard[][] deck = new SingleCard[4][13];
	private int[][] shuffleDeckControlArray = new int[4][13];
	private SingleCard[] shuffledDeck = new SingleCard[52];
	private int topOfDeck = 0;
	private Random rnd = new Random();
	private static SingleCard joker = new SingleCard(0, 13);
	private int cardCount = 0;
	private SingleCard currentCard;
	
	
	
	/*randomise deck with second array of 1's and 0's to mark drawn and not, use local noofcards to load
	 * 52 slot 1d array called shuffleddeck then use the end of this array to deal the deck from , 
	 * shortening the number of cards as they are drawn using the noofcards static variable, if redealing same deck
	 * in order set no of cards to 52 again.Complete drawcard method
	 */
	protected FullDeck()
	{
		int noOfUnshuffledCards = 52;//control for randomly picking card order to add to deck
		
		
		for(int i = 0; i < 4;i++)   //creates a new 52 card deck, ordered
		{
			for(int j = 0; j < 13; j++)
			{
				deck[i][j] = new SingleCard(i,j); 
			}
		}
		
		for(int k = 0; k < 4; k++) //populate the control array with 0's
		{
			for(int l = 0; l < 13; l++)
			{
				shuffleDeckControlArray[k][l] = 0;
			}
		}
		
		
		
		while(noOfUnshuffledCards != 0)
		{
			boolean cardPicked = false;
			while(cardPicked == false)
			{
				int m = rnd.nextInt(4);
				int n = rnd.nextInt(13);
			
					if(shuffleDeckControlArray[m][n] == 0)
					{
						shuffledDeck[topOfDeck] = deck[m][n];
						topOfDeck ++;
						noOfUnshuffledCards --;
						shuffleDeckControlArray[m][n] = 1;
						cardPicked = true;
						
					}
					
			}
					
				
			
		}
	}
	
	protected SingleCard drawCard()
	{
		System.out.println("noOfCards=" + noOfCards);
		if(noOfCards != 0)
			{
			SingleCard drawnCard = shuffledDeck[topOfDeck-1];
			topOfDeck --;
			noOfCards --;
			return drawnCard;
			}
		else
		{
			return joker;
		}
		
	}
	
	public static void main(String args[])
	{
		FullDeck myDeck = new FullDeck();
		for(int i = 0; i< myDeck.shuffledDeck.length;i++)
		{
			System.out.println("Position " + i + " has " + myDeck.shuffledDeck[i].getRank() + " of " + myDeck.shuffledDeck[i].getSuit());
		}
		for(;;)
			{
			myDeck.currentCard = myDeck.drawCard();
			if( myDeck.currentCard != joker)
			
				{
					System.out.println(myDeck.currentCard.getRank() + " of " + myDeck.currentCard.getSuit());
					myDeck.cardCount ++;
				}
				else
				{
					System.out.println("End of Deck");
					System.out.println(myDeck.cardCount);
					System.exit(0);
				}
			}
	}
	
	
	}
Question Answered as of 3 Years Ago by NormR1 and jon.kiparsky
 
0
 

This might not a be good solution. Globals have a way of coming back to bite you.
Have a local variable to hold the current card:

myDeck.currentCard = myDeck.drawCard();
vs
SingleCard currentCard = myDeck.drawCard();

 
0
 

Thanks for pointing that out, I was working with global variables, static and final so much that I completely forgot about local variables towards the end :)

You
This question has already been solved: Start a new discussion instead
Post:
Start New Discussion
Tags Related to this Article