There is SO MUCH beauty in code; the sheer amount of ways you can represent something is astounding.
This really becomes pronounced when we get Unit 5: Writing Classes and beyond in AP Computer Science A. We are about to enter Unit 6: Arrays (following the College Board’s CED), and I always look forward to seeing how students think and code with these data structures.
One thing I always love seeing is how students represent a deck of cards in a computer program.
For the first couple of years when I taught AP Computer Science A, we would always do a big project at the end of the arrays unit, where students would create a program that simulated a blackjack game.
I no longer do this project for a few reasons (the main one actually being that students just had such a hard time understanding how to play blackjack) but I always found that the way students represented a deck of cards in a program was so interesting.
The three top ways I have seen students represent a deck of cards: a single array, two arrays, and an array of card objects. I will show you the code for each of these and then explain how to do the following with each
- Randomly draw one card
- Randomly draw 4 unique cards
- Randomly draw a user-entered N unique cards
At the end of the blog post, you can find the link to your FREE copy of an array project using a deck of cards.
First Way: Create a single array with all 52 cards
MOST of my students start off doing this. In their head, the deck is a single array, and each card is an element, so for them, starting off this way makes sense. While this can work, it does make for some inefficient code. I always allow it though, if students are able to figure out a way to meet all requirements in a project. For some of them, this is just the easiest way they think!
Some students will start by trying to spell out all the card names like this:
String[] deck = {"Ace of Hearts", "Ace of Spades", /*etc*/};
They will then quickly realize that they do not like typing all of those names out, so instead, they will think of an abbreviation for the names of all the cards and then think about mapping the short hand name to the full name in a separate code snipet. Here is an example of a shorthand code used:
String[] cards = {"Ah", "Ad", "Ac", "As",
"2h", "2d", "2c", "2s",
"3h", "3d", "3c", "3s",
"4h", "4d", "4c", "4s",
"5h", "5d", "5c", "5s",
"6h", "6d", "6c", "6s",
"7h", "7d", "7c", "7s",
"8h", "8d", "8c", "8s",
"9h", "9d", "9c", "9s",
"10h", "10d", "10c", "10s",
"Jh", "Jd", "Jc", "Js",
"Qh", "Qd", "Qc", "Qs",
"Kh", "Kd", "Kc", "Ks"};
We can then have a code segment that maps this shorthand card notation to the full card name when you are ready to print. I created a method called “display” that I will use for this. Note that in the code “10h”, “10d”, “10c”, and “10s” are a different length than the rest of the shorthand cards, so the code segment takes that into consideration.
public static String display(int i, String[] cards){
String newStr;
//Get the rank
if(cards[i].substring(0,1).equals("A"))
newStr = "Ace of ";
else if(cards[i].substring(0,1).equals("J"))
newStr = "Jack of ";
else if(cards[i].substring(0,1).equals("Q"))
newStr = "Queen of ";
else if(cards[i].substring(0,1).equals("K"))
newStr = "King of ";
else if(cards[i].substring(0,1).equals("1"))
newStr = cards[i].substring(0,2) +" of ";
else
newStr = cards[i].substring(0,1) +" of ";
//Get the suit
if(cards[i].substring(0,2).equals("10")){
if(cards[i].substring(2,3).equals("h"))
newStr += "hearts";
else if(cards[i].substring(2,3).equals("d"))
newStr += "diamonds";
else if(cards[i].substring(2,3).equals("c"))
newStr += "clubs";
else if(cards[i].substring(2,3).equals("s"))
newStr += "spades";
}
else{
if(cards[i].substring(1,2).equals("h"))
newStr += "hearts";
else if(cards[i].substring(1,2).equals("d"))
newStr += "diamonds";
else if(cards[i].substring(1,2).equals("c"))
newStr += "clubs";
else if(cards[i].substring(1,2).equals("s"))
newStr += "spades";
}
return newStr;
}
Randomly Picking a Card
Despite not being traditionally shuffled, randomly picking a card from an order list is still a random selection. It would be the same as shuffling and choosing the first card on the top of the deck. The code for randomly picking a single card is fairly simple, and then to display the name of the card, we just make a method call to “display”:
//Randomly Picking a Card
int index = (int)(Math.random()*53);
System.out.println(display(index, cards));
Randomly Picking Multiple Cards
From here, it is not difficult to extend the code to pick a predetermined amount of cards (say 4 cards). You will just have to create 4 variables and then make sure that none of the numbers repeat (we don’t want to pick the same card twice).
In the code below, I create 4 variables, each with a random index. I then have a while loop that checks if any of the indexes are the same, which would indicate that the same card was chosen twice. I don’t want that, so if it is true, I want the random numbers to be regenerated.
Then I can use my “display” method to show all 4 random cards that were selected.
//Randomly pick 4 cards
int firstIndex = (int)(Math.random()*53);
int secondIndex = (int)(Math.random()*53);
int thirdIndex = (int)(Math.random()*53);
int fourthIndex = (int)(Math.random()*53);
while(firstIndex == secondIndex || firstIndex == thirdIndex || firstIndex == fourthIndex ||
secondIndex == thirdIndex || secondIndex == fourthIndex || thirdIndex == fourthIndex){
firstIndex = (int)(Math.random()*53);
secondIndex = (int)(Math.random()*53);
thirdIndex = (int)(Math.random()*53);
fourthIndex = (int)(Math.random()*53);
}
System.out.println(display(firstIndex, cards));
System.out.println(display(secondIndex, cards));
System.out.println(display(thirdIndex, cards));
System.out.println(display(fourthIndex, cards));
To have the user choose ANY amount though, without a predetermined number of variables, it gets difficult for beginner programmers (but fun for me!) Here is the code to do it. Note that this took me (an experienced programmer) about 30 minutes to create so I don’t find it realistic that a novice high schooler can do it, but I don’t even want to say “never”. Below this code segment is a better way of randomly selecting an undetermined number of cards.
//Randomly picking several cards without shuffling
//You cannot choose the same number more than once!
Scanner keyboard = new Scanner(System.in);
System.out.println("How many cards would you like to choose?");
int number = keyboard.nextInt();
String indexChosen = ""; //keep track of chosen indexes (2 digits)
for(int i = 0; i < number; i++){
int ranIndex = (int)(Math.random()*53);
boolean unique = false;
if(indexChosen.length() <= 2){
unique = true;
}
String temp = "";
while(!unique){
for(int j = 0; j < indexChosen.length() - 2; j += 2){
if(ranIndex <= 9){
temp += "0" + ranIndex;
}
else {
temp += ranIndex;
}
if(indexChosen.substring(j, j+1).equals(temp)){
ranIndex = (int)(Math.random()*53);
j = 0;
}
else{
unique = true;
}
}
}
if(ranIndex <= 9){
indexChosen += "0" + ranIndex;
}
else {
indexChosen += ranIndex;
}
System.out.println(display(ranIndex, cards));
}
A natural way around the above advance code would be to SHUFFLE the deck and then display the first N amount of cards off of the top of the deck. There are several algorithms used to shuffle but I used the following process:
For the entire length of the deck:
Starting at the first index, pick a random number representing a random index
Swap the cards at the first index with the random index
Move to the next index in the array
I then asked the user how many cards they would like to display and used that number as the stopping point in a for loop that displays the cards in the deck, starting at index 0:
for(int cardIndex = 0; cardIndex < cards.length; cardIndex++){
int randomNum = (int)(Math.random()*52);
//swapping algorithm
String temp2 = cards[cardIndex];
cards[cardIndex] = cards[randomNum];
cards[randomNum] = temp2;
}
System.out.println("How many cards would you like to choose?");
number = keyboard.nextInt();
for(int k = 0; k < number; k++){
System.out.println(display(k, cards));
}
Shuffling and then drawing off the “top” of the deck is a much more reasonable coding process and would be able be completed by your high schoolers.
Second Way: Create Two Arrays to Represent a Single Deck
While less popular, this is a way my “lazy” computer science students think of representing a deck (although, some say lazy and I say smart!). Creating two arrays usually follows the thought of creating one array, but realizing you have to keep track of 52 indexes in one array. So these students think of a way to work smarter and not harder.
For students who think of this solution, it is not a large leap for them to go from this to the third way: creating card objects.
The thought process that you can use two arrays stems from the idea that there are two data fields you need to keep track of from any card: a suit and a rank. Some students might use integers and map to the card names (like a modified version of what we did above), but Strings come naturally to a lot of students too. Here is one way to do this:
String[] suits = {"Hearts", "Diamonds", "Clubs", "Spades"};
String[] ranks = {Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
Some with a “dummy” first position, so that the remaining positions as Strings correspond to their index (an index of 1 is an Ace, an index of 2, is a two, etc.)
String[] ranks = {"na", "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
Randomly Choosing a Single Card
Again, despite not being traditionally shuffled, randomly picking a card from an order list is still a random selection. This time, you would need to randomly pick a suit and a rank. Since you have two separate String arrays with the information, displaying this will be much easier than the first way, since you do not need a “code mapping” to display the name of the card.
String[] suits = {"Hearts", "Diamonds", "Clubs", "Spades"};
String[] ranks = {"na", "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
int randSuit = (int)(Math.random()*4);
int randRank = (int)(Math.random()*13) + 1;
System.out.println(ranks[randRank] + " of " + suits[randSuit]);
Randomly Picking Multiple Cards
We can put this code into a for loop to generate picking 4 (or any set amount) of cards. Just remember that we do not want to choose the same card twice, so this code is a little longer to check to make sure that doesn’t happen!
//Randomly pick 4 cards
int randSuit1 = (int)(Math.random()*4);
int randRank1 = (int)(Math.random()*13) + 1;
System.out.println(ranks[randRank1] + " of " + suits[randSuit1]);
int randSuit2 = (int)(Math.random()*4);
int randRank2 = (int)(Math.random()*13) + 1;
while(randSuit1 == randSuit2 && randRank1 == randRank2){
randSuit2 = (int)(Math.random()*4);
randRank2 = (int)(Math.random()*13) + 1;
}
System.out.println(ranks[randRank2] + " of " + suits[randSuit2]);
int randSuit3 = (int)(Math.random()*4);
int randRank3 = (int)(Math.random()*13) + 1;
while((randSuit1 == randSuit3 && randRank1 == randRank3) || (randSuit2 == randSuit3 && randRank2 == randRank3)){
randSuit3 = (int)(Math.random()*4);
randRank3 = (int)(Math.random()*13) + 1;
}
System.out.println(ranks[randRank3] + " of " + suits[randSuit3]);
int randSuit4 = (int)(Math.random()*4);
int randRank4 = (int)(Math.random()*13) + 1;
while((randSuit1 == randSuit4 && randRank1 == randRank4) || (randSuit2 == randSuit4 && randRank2 == randRank4) ||
(randSuit3 == randSuit4 && randRank3 == randRank4)){
randSuit4 = (int)(Math.random()*4);
randRank4 = (int)(Math.random()*13) + 1;
}
System.out.println(ranks[randRank4] + " of " + suits[randSuit4]);
Once again, having the user determine how many cards to pick randomly gets tough with this setup (but very possible!). I won’t bore you with another way to do it, but I encourage you to try!
Shuffling with this setup isn’t really meaningful, since we set up our rank array for the ranks to match the indexes for easy referencing. Shuffling will get rid of that system, as well as not provide anything new for our random card draw. Again, possible, but messy and not something that we would want to trouble ourselves with when they are better options.
Third Way: An Array of Card Objects
Ah! OOP at its finest. Ideally, this would be how we want to represent our deck of cards. We always talk about how OOP is such a powerful concept, but it can be tough for our students to really see that in our AP Computer Science A class when we are just not making big enough programs for OOP to be meaningful to them. After walking through all of these ways to create a deck of cards in Java, hopefully, this array of Card objects would seem natural and more efficient!
First, you want your students to make your Card class. Each card has the properties of suit and rank. You want your standard constructors, along with accessors and mutators, plus a useful method that reports the name of the card! Just like our other setups, this can be done several ways, either with two instance variables of ints, two of Strings, or a mix of each. This is the fun part of programming; it can be however you think. Below is the complete Card class that I came up with, but just know that there are many ways your students might do this.
public class Card {
private int suit; //1 - Hearts, 2 - Clubs, 3 - Spades, 4 - Diamonds
private int rank; //1 - Ace, 2...10, 11-Jack, 12-Queen, 13-King
//Default Constructor - Card will be Ace of Hearts
public Card(){
suit = 1;
rank = 1;
}
public Card(int s, int r){
suit = s;
rank = r;
}
//Accessor Methods
public int getSuit(){ return suit; }
public int getRank(){ return rank; }
//Mutator Methods
public void setSuit(int s){ suit = s; }
public void setRank(int r){ rank = r; }
//return the name of the card e.g. "Ace of Hearts"
public String getName(){
String name = "";
if(rank == 1)
name = "Ace of ";
else if(rank == 11)
name = "Jack of ";
else if(rank == 12)
name = "Queen of ";
else if(rank == 13)
name = "King of ";
else
name = rank + " of ";
if(suit == 1)
name += "Hearts";
else if(suit == 2)
name += "Clubs";
else if(suit == 3)
name += "Spades";
else
name += "Diamonds";
return name;
}
}
Next, we want to create a Deck object. This object should construct a deck of cards. The deck of cards will be an array of 52 Card objects. When we create the deck, it will be like purchasing a new pack of cards; the suits and ranks will be in order. We then want a method that will shuffle the deck. We have seen how useful it is to be able to shuffle cards, so with any deck, we want to be able to shuffle it. The last thing we want this object to do is “draw” a card. This method will take the top card (after it has been shuffled) and then return the card. We will need an instance variable here to keep track of what position in the deck we are at.
Below is the complete Deck class I came up with. As always, remember that this can look different for everyone, but we want our deck to be able to be created, shuffled, and to deal a single card at a time.
public class Deck{
private Card[] deck; //This array will hold our 52 cards
private int position; //keeps track of position of cards delt
public Deck(){
//instantiate and populate a deck
//ignore index 0
//Cards go from deck[1] to deck[52]
deck = new Card[53];
for(int rank = 1; rank <=13; rank++) {
deck[rank] = new Card(1, rank); //heart of that rank
deck[rank+13] = new Card(2, rank); //club of that rank
deck[rank+26] = new Card(3, rank); //spade of that rank
deck[rank+39] = new Card(4, rank); //diamond of that rank
}
position = 1;
}
public void shuffle() {
//swap cards[i] with cards[randomNum]
for(int i = 1; i < deck.length; i++){
int randomNum = (int)(Math.random()*52) + 1; //ignore position 0
//swapping algorithm
Card temp = deck[i];
deck[i] = deck[randomNum];
deck[randomNum] = temp;
}
}
public Card draw(){
Card c = deck[position];
position++;
return c;
}
}
Now, in our Main (Driver) class, we can very easily draw a random card, 4 random cards, and a user-entered N amount of cards.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//Pick a random card
Deck cards = new Deck();
cards.shuffle();
System.out.println(cards.draw().getName());
System.out.println("\n\n");
//Pick 4 random cards
Deck cards2 = new Deck();
cards2.shuffle();
System.out.println(cards2.draw().getName());
System.out.println(cards2.draw().getName());
System.out.println(cards2.draw().getName());
System.out.println(cards2.draw().getName());
System.out.println("\n\n");
//Pick N random cards
Scanner keyboard = new Scanner(System.in);
System.out.println("How many cards do you want to draw?");
int num = keyboard.nextInt();
Deck cards3 = new Deck();
cards3.shuffle();
for(int i = 0; i < num; i++){
System.out.println(cards3.draw().getName());
}
}
}
You can see that the code is much easier to understand and follow, taking full advantage of those OOP concepts! When we put objects at the center of our code, instead of the logic of the code itself, it creates easy-to-navigate code and allows us to build onto it when we have other needs pop up!
Conclusion
I have a FREE “Deck of Cards” activity for you below. There are three parts to this activity: creating the deck, drawing cards from the deck, and creating a game with a deck of cards. Depending on the level of your students, you can have them complete this as a unit project, as a scaffolded in-class activity, or as a take-home assignment.
Unit 6: Arrays
Click below to get your FREE Arrays Project as a PDF.
If you have some advanced students who are interested in learning some Java beyond the CED, consider letting them research how to use enums to represent a deck of cards!
0 Comments