Dear DIC visitor/member/anyone else interesting in making a card game in java,

When most of use began programming, we started looking for various project ideas to try. I've noticed card games come up a lot, so let's have a look at some ways to implement a card game. We will be focusing on the core of many card games, the cards and the deck.

The Card class is fairly simple, although it can be done a number of ways. I've chosen to use numeric variables for the internal data about the suit and rank, which will get converted to strings via predefined arrays when they need to be outputed. This lets us easily compare the suits and ranks (see if they're equal or sequential), without trying to use strings to represent them internally. If we used strings, we'd have to use

if ( card1.rank.equals("three") && card2.rank.equals("four") )

with a whole bunch of other checks for different numbers, as opposed to

So we have read-only suit and rank variables, a simple constructor, and a toString method. The class will be ultra fast as it knows which strings to output just by accessing indexes of static arrays. We don't even have to use String.ParseInt().

The Card class really isn't that complicated, so most of our time will be spent on the Deck. Our Deck class will have to make and dole out Cards. To hold our Cards, we can use a number of different storage methods/structures. I will show examples using an array and an ArrayList. Each storage method will have a constructor to make the cards, a drawFromDeck() method that will return a random card, and a getTotalCards() method that will return the number of cards left in the Deck. The hard part is, once we return a card we have to make sure it isn't used again.

Using Array:

package javacards;
import java.util.Random;
public class Deck {
private Card[] cards;
int i;
Deck()
{
i=51;
cards = new Card[52];
int x=0;
for (int a=0; a<=3; a++)
{
for (int b=0; b<=12; b++)
{
cards[x] = new Card(a,b);
x++;
}
}
}
public Card drawFromDeck()
{
Random generator = new Random();
int index=0;
do {
index = generator.nextInt( 52 );
} while (cards[index] == null);
i--;
Card temp = cards[index];
cards[index]= null;
return temp;
}
public int getTotalCards()
{
return i;
}
}
[code]
First we have a constructor which fills our deck will the cards of various suits and ranks. Every time we add a card at x we increment x to put us at a fresh spot.
drawFromDeck() returns a random card from our container. We need to get a random index and return that card. We have a post-test loop that finds an array index (less than 52) that isn't null. When we find one, we return its card and set it to null. Our deck might need to give feedback on how many cards are left, (maybe to determine if there are enough for another round of black jack or if we need to add all the cards back), so we make a variable i that represents the number cards left in the deck. i starts at 51 and is decremented everytime we take a card out. So if i is -1, then we know we're out of cards.
Now we need to write a test for this program. We want to make sure the cards that get drawn really are drawn in a random order. So we have main:
[code]
package javacards;
public class Main {
public static void main(String[] args)
{
Deck deck = new Deck();
Card C;
System.out.println( deck.getTotalCards() );
while (deck.getTotalCards()!= 0 )
{
C = deck.drawFromDeck();
System.out.println( C.toString() );
}
}

When we run this, we get a good look at how the cards would come off the deck. They seem random enough, so we're okay. However, this tutorial would be pretty int if I just ended it here, and many of you are probably looking at the drawFromDeck() method with disdain at its ineffeciency, so we press on......

This is really a pretty sloppy way of doing things, as we just keep trying to find an index in the array with a card in it. If the index doesn't have a card in it, we look in a new index, unti we finally get one. We really should only have to use one index, and we can do that if we make sure that we're only looking through places that actually have cards in them.

So to fix this, we use our variable i that represents the number of cards in the array that aren't used up yet. Now we need to make sure our selection comes only from that set of cards. Say the first card we take out is at index 4. We set that to null and decrement the number of cards. But index 4 is still null. We know we have 51 cards left, but we don't know where they are in the deck. There could be empty/null indexes all over the place, at 4, 7, 20, and all we can do is just keep our fingers crossed that we don't land on one of them. How about we organize our empty card spots a little better? Maybe we can switch the chosen card's empty spot with the last card in the deck? Let's put our i variable to work.

Our random index now is some number within the boundaries of the cards left, instead of always 52. If we have 40 cards left, index won't be 48. We get a random card, SWITCH IT'S NOW NULL LOCATION WITH THE LAST CARD IN THE DECK, and then return the random card. we picked the fourth card, and put the last card in its place. The null value we get when we take out the card at index 4 is now located at spot 51, the last spot in the deck, as opposed to some random spot in the middle of the deck. This ensures that the indexes up through i always have cards in them, and that the null values are always moved to the end of the array. When we get a random index between 0 and i, we can be 100% sure that there is a fresh card in that spot.

To test this method, we can use the exact same test code as we did for the first example, as all that's changed is the internal workings of the deck class. In fact, we will use that test code for all our Deck implementations.

We've implemented a lot of features with arrays that could've easily been done with generics, like an ArrayList (adding a card to the end of the array, removing a card by setting its place to null, keeping track of the size of the array, etc. ). An ArrayList has most of the features we need built in already, so we don't have to write our own code to do them.

We can just add a card to the end of the ArrayList with add(), as opposed to making our own variable to keep track of what index we're on. cards.size() automatically keeps track of how many cards are left in the array. When we return a card, we can actually remove it from the ArrayList, thus decrementing the size, leaving us with a collection that only has cards left in it. (as opposed to just replacing its spot with the last card in the array, and setting the last spot to null)

Run the test code again to make sure everything still works.

To mention other data structures, we could have used a linked list to hold the cards, but our primary purpose is to extract a card from the deck, not to iterate through the cards, making a linked list not the best choice.

One of the goals of OO programming is to emulate the real world. When we return a card from our deck, we remove it from the deck so it's not used again, just like a real dealer would. But when a dealer gives you a card, they just take it off the top of the deck, they don't fish through the deck to get a random card. They shuffle the deck, randomizing the cards before hand, so they can just pop cards off the top later and know that they're random. This leads us to another example:

We put the cards in the ArrayList, then randomly take 100 pairs of cards and switch them, shuffling our deck. To draw from the deck, we just return the last element/card, and then remove that card from the deck. All the randomization is done before hand in the constructor (prior to any actually dealing of the cards), making our drawFromDeck method much simpler and less processor intensive. Piece of cake!

I hoped you've enjoyed and learned something from this tutorial!

Please post any and all questions, comments, concerns, or commentary!

--------CrazyJugglerDrummer

This post has been edited by crazyjugglerdrummer: 20 June 2009 - 10:20 AM

Replies To: Deck of cards using various methods

Dear DIC visitor/member/anyone else interesting in making a card game in java,

When most of use began programming, we started looking for various project ideas to try. I've noticed card games come up a lot, so let's have a look at some ways to implement a card game. We will be focusing on the core of many card games, the cards and the deck.

The Card class is fairly simple, although it can be done a number of ways. I've chosen to use numeric variables for the internal data about the suit and rank, which will get converted to strings via predefined arrays when they need to be outputed. This lets us easily compare the suits and ranks (see if they're equal or sequential), without trying to use strings to represent them internally. If we used strings, we'd have to use

if ( card1.rank.equals("three") && card2.rank.equals("four") )

with a whole bunch of other checks for different numbers, as opposed to

So we have read-only suit and rank variables, a simple constructor, and a toString method. The class will be ultra fast as it knows which strings to output just by accessing indexes of static arrays. We don't even have to use String.ParseInt().

The Card class really isn't that complicated, so most of our time will be spent on the Deck. Our Deck class will have to make and dole out Cards. To hold our Cards, we can use a number of different storage methods/structures. I will show examples using an array and an ArrayList. Each storage method will have a constructor to make the cards, a drawFromDeck() method that will return a random card, and a getTotalCards() method that will return the number of cards left in the Deck. The hard part is, once we return a card we have to make sure it isn't used again.

Using Array:

package javacards;
import java.util.Random;
public class Deck {
private Card[] cards;
int i;
Deck()
{
i=51;
cards = new Card[52];
int x=0;
for (int a=1; a<=4; a++)
{
for (int b=1; b<=13; b++)
{
cards[x] = new Card(a,b);
x++;
}
}
}
public Card drawFromDeck()
{
Random generator = new Random();
int index=0;
do {
index = generator.nextInt( 52 );
} while (cards[index] == null);
i--;
Card temp = cards[index];
cards[index]= null;
return temp;
}
public int getTotalCards()
{
return i;
}
}
[code]
First we have a constructor which fills our deck will the cards of various suits and ranks. Every time we add a card at x we increment x to put us at a fresh spot.
drawFromDeck() returns a random card from our container. We need to get a random index and return that card. We have a post-test loop that finds an array index (less than 52) that isn't null. When we find one, we return its card and set it to null. Our deck might need to give feedback on how many cards are left, (maybe to determine if there are enough for another round of black jack or if we need to add all the cards back), so we make a variable i that represents the number cards left in the deck. i starts at 51 and is decremented everytime we take a card out. So if i is -1, then we know we're out of cards.
Now we need to write a test for this program. We want to make sure the cards that get drawn really are drawn in a random order. So we have main:
[code]
package javacards;
public class Main {
public static void main(String[] args)
{
Deck deck = new Deck();
Card C;
System.out.println( deck.getTotalCards() );
while (deck.getTotalCards()!= 0 )
{
C = deck.drawFromDeck();
System.out.println( C.toString() );
}
}

When we run this, we get a good look at how the cards would come off the deck. They seem random enough, so we're okay. However, this tutorial would be pretty int if I just ended it here, and many of you are probably looking at the drawFromDeck() method with disdain at its ineffeciency, so we press on......

This is really a pretty sloppy way of doing things, as we just keep trying to find an index in the array with a card in it. If the index doesn't have a card in it, we look in a new index, unti we finally get one. We really should only have to use one index, and we can do that if we make sure that we're only looking through places that actually have cards in them.

So to fix this, we use our variable i that represents the number of cards in the array that aren't used up yet. Now we need to make sure our selection comes only from that set of cards. Say the first card we take out is at index 4. We set that to null and decrement the number of cards. But index 4 is still null. We know we have 51 cards left, but we don't know where they are in the deck. There could be empty/null indexes all over the place, at 4, 7, 20, and all we can do is just keep our fingers crossed that we don't land on one of them. How about we organize our empty card spots a little better? Maybe we can switch the chosen card's empty spot with the last card in the deck? Let's put our i variable to work.

Our random index now is some number within the boundaries of the cards left, instead of always 52. If we have 40 cards left, index won't be 48. We get a random card, SWITCH IT'S NOW NULL LOCATION WITH THE LAST CARD IN THE DECK, and then return the random card. we picked the fourth card, and put the last card in its place. The null value we get when we take out the card at index 4 is now located at spot 51, the last spot in the deck, as opposed to some random spot in the middle of the deck. This ensures that the indexes up through i always have cards in them, and that the null values are always moved to the end of the array. When we get a random index between 0 and i, we can be 100% sure that there is a fresh card in that spot.

To test this method, we can use the exact same test code as we did for the first example, as all that's changed is the internal workings of the deck class. In fact, we will use that test code for all our Deck implementations.

We've implemented a lot of features with arrays that could've easily been done with generics, like an ArrayList (adding a card to the end of the array, removing a card by setting its place to null, keeping track of the size of the array, etc. ). An ArrayList has most of the features we need built in already, so we don't have to write our own code to do them.

We can just add a card to the end of the ArrayList with add(), as opposed to making our own variable to keep track of what index we're on. cards.size() automatically keeps track of how many cards are left in the array. When we return a card, we can actually remove it from the ArrayList, thus decrementing the size, leaving us with a collection that only has cards left in it. (as opposed to just replacing its spot with the last card in the array, and setting the last spot to null)

Run the test code again to make sure everything still works.

To mention other data structures, we could have used a linked list to hold the cards, but our primary purpose is to extract a card from the deck, not to iterate through the cards, making a linked list not the best choice.

One of the goals of OO programming is to emulate the real world. When we return a card from our deck, we remove it from the deck so it's not used again, just like a real dealer would. But when a dealer gives you a card, they just take it off the top of the deck, they don't fish through the deck to get a random card. They shuffle the deck, randomizing the cards before hand, so they can just pop cards off the top later and know that they're random. This leads us to another example:

We put the cards in the ArrayList, then randomly take 100 pairs of cards and switch them, shuffling our deck. To draw from the deck, we just return the last element/card, and then remove that card from the deck. All the randomization is done before hand in the constructor (prior to any actually dealing of the cards), making our drawFromDeck method much simpler and less processor intensive. Piece of cake!

That works if you want just a deck of cards, but what about a deck of cards that you'd want to do calculations on. For instance, in this code, in the array, Ace is at position 0, but it's value is not 0 when working with an actual card game. Can you elaborate on assigning values to each card as well?

That works if you want just a deck of cards, but what about a deck of cards that you'd want to do calculations on. For instance, in this code, in the array, Ace is at position 0, but it's value is not 0 when working with an actual card game. Can you elaborate on assigning values to each card as well?

eoswins it would be easy to make it give the right value when u return the rank u just need to make the arrays values the right ones that they are suppose to be like in a deck of cards a simple if statement or switch-case should do the trick like this:

i am trying to create a hand class to draw seven cards and store them in an array of Cards
and am not sure what is wrong i keep getting a null pointer exception. i am using the array List tutorial for
my deck class.

i am trying to create a hand class to draw seven cards and store them in an array of Cards
and am not sure what is wrong i keep getting a null pointer exception. i am using the array List tutorial for
my deck class.

Very well written tutorial. It's helped me a lot. One question though, how would I make a method that only draws a certain amount of cards? So it would take a int as a parameter and get that many cards?

Very well written tutorial. It's helped me a lot. One question though, how would I make a method that only draws a certain amount of cards? So it would take a int as a parameter and get that many cards?

To do this I made a separate class name CardPlayer who has a hand with a given handsize. Then modified the main so that it draws from the deck and gives it to the player.

I also modified the shuffle to use the Collections static method of shuffle and gave it its own method in the Deck class.

Wow pretty impressive for a starter,
I'm a starter as well, and I understant the code that'S written but for some reasons I just can't figure some codes by myself.
So frustrating, It's not my first course of programming but just can't get the hang of the OOP. I guess understanding the code is not enough to write what I want.
OK
What if I want to remove the top of the pile.

would I just change de 0 to 52
to the line return cards.remove(52); and why would .removeLast won't work

Thanks in advance

Diesel712, on 10 June 2015 - 06:06 AM, said:

Wow pretty impressive for a starter,
I'm a starter as well, and I understant the code that'S written but for some reasons I just can't figure some codes by myself.
So frustrating, It's not my first course of programming but just can't get the hang of the OOP. I guess understanding the code is not enough to write what I want.
OK
What if I want to remove the top of the pile.

ref- Deck class line 30
would I just change de 0 to 52
to the line return cards.remove(52); and why would .removeLast won't work

Wow pretty impressive for a starter,
I'm a starter as well, and I understant the code that'S written but for some reasons I just can't figure some codes by myself.
So frustrating, It's not my first course of programming but just can't get the hang of the OOP. I guess understanding the code is not enough to write what I want.
OK
What if I want to remove the top of the pile.

would I just change de 0 to 52
to the line return cards.remove(52); and why would .removeLast won't work

Thanks in advance

Diesel712, on 10 June 2015 - 06:06 AM, said:

Wow pretty impressive for a starter,
I'm a starter as well, and I understant the code that'S written but for some reasons I just can't figure some codes by myself.
So frustrating, It's not my first course of programming but just can't get the hang of the OOP. I guess understanding the code is not enough to write what I want.
OK
What if I want to remove the top of the pile.

ref- Deck class line 30
would I just change de 0 to 52
to the line return cards.remove(52); and why would .removeLast won't work

Thanks in advance

cards.remove(51) would work to remove from the other side of the pile because lists and arrays start with 0 in most programming language you have to subtract 1. .removeLast will work if you wrote a function in the class to call on the object.