I've been trying to make this method for the deck to deal, but once it deals 52 cards it goes onto an infinite loop.
I am aware this is because I have it to generate a random number until it gets a card that has not been set, but once all cards are set, the condition will never be true, therefore infinite loop.
Even though I know my problem, I don't know how to fix it. I've been trying for hours. I want to throw an exemption once it reaches 52 cards, but it never reaches that if statement once it goes into infinite loop.
public PlayingCard deal() {
Random swift = new Random();
int index = swift.nextInt(DECK_SIZE);
cardsInDeck = DECK_SIZE;
int i = 51;
while (this.deck[index] == false||i==cardsInDeck) {index = swift.nextInt(DECK_SIZE);}
if(i==cardsInDeck) { throw new RuntimeException("Empty Deck");}
PlayingCard.CardRank[] Ranking = PlayingCard.CardRank.values();
PlayingCard.CardSuit[] Suiting = PlayingCard.CardSuit.values();
PlayingCard.CardRank Rank = Ranking[index % 13];
PlayingCard.CardSuit Suit = Suiting[index % 4];
PlayingCard selected = new PlayingCard(Suit, Rank);
this.deck[index] = false;
i++;
cardsInDeck--;
return selected;
}
=============================================================================
the whole code
import java.util.Random;
public class DeckOfCards {
public static final int DECK_SIZE = 52;
//Instance Variables
private boolean[] deck; //An implicit set of 52 Playing-Cards
private int cardsInDeck;//Number of cards currently in the deck
private Random dealer; //Used to rendomly select a card to be dealt
//Constructor
public DeckOfCards() {
this.deck = new boolean[DECK_SIZE];
int index = 0;
for (PlayingCard.CardSuit Suit : PlayingCard.CardSuit.values()) {
for (PlayingCard.CardRank Rank : PlayingCard.CardRank.values()) {
PlayingCard card = new PlayingCard(Suit, Rank);
deck[index] = true;
index++;
}
}
}
//Collect all 52 Playing-Cards into the deck
public void shuffle() {
/*Random shuffle = new Random();
for (int j = 0; j < this.deck.length; j++) {
int k = shuffle.nextInt(this.deck.length);
boolean temp = this.deck[j];
this.deck[j] = this.deck[k];
this.deck[k] = temp;*/
int index = 0;
for (PlayingCard.CardSuit Suit : PlayingCard.CardSuit.values()) {
for (PlayingCard.CardRank Rank : PlayingCard.CardRank.values()) {
PlayingCard card = new PlayingCard(Suit, Rank);
deck[index] = true;
index++;
}
}
}
//Simulate dealing a randomly selected card from the deck
//Dealing from an empty deck results in a RuntimeException
public PlayingCard deal() {
Random swift = new Random();
int index = swift.nextInt(DECK_SIZE);
cardsInDeck = DECK_SIZE;
int i = 0;
while (this.deck[index] == false&&i>0) {index = swift.nextInt(DECK_SIZE);}
if(i>cardsInDeck) { throw new RuntimeException("Empty Deck");}
PlayingCard.CardRank[] Ranking = PlayingCard.CardRank.values();
PlayingCard.CardSuit[] Suiting = PlayingCard.CardSuit.values();
PlayingCard.CardRank Rank = Ranking[index % 13];
PlayingCard.CardSuit Suit = Suiting[index % 4];
PlayingCard selected = new PlayingCard(Suit, Rank);
this.deck[index] = false;
i++;
cardsInDeck--;
return selected;
}
==================================================================
public static void main(String[] args) {
DeckOfCards myDeck = new DeckOfCards();
myDeck.shuffle();
for (int p = 1; p <= 4; p++) {
for (int c = 1; c <= 13; c++) {
System.out.print(myDeck.deal() + " ");
}
System.out.println();
}
try {
System.out.println(myDeck.deal());
} catch (RuntimeException rte) {
System.out.println(rte.getMessage());
}
}
}
I've been trying to make this method for the deck to deal, but once it deals 52 cards it goes onto an infinite loop.
The easy way to deal a deck of cards is to:
Place all cards in an ArrayList.
Call Collections.shuffle() on that list;
Deal out the cards in the order in which they appear in the shuffled list.
The code will be a lot simpler than what you have right now, and will be much easier to debug.
have you tried something like this in the while
while ((this.deck[index] == false||i==cardsInDeck)&&i<52)
?
Once you start picking random indexes, it is too late. You need to test whether the deck has any cards first.
if (cardsInDeck <= 0) ...throw an exception?...
while (this.deck[index] == false) {index = swift.nextInt(DECK_SIZE);}
You need to initialize cardsInDeck correctly (set to DECK_SIZE not in deal but in shuffle and the constructor). You want the invariant that cardsInDeck is equal to the number of indexes for which deck[index]==true.
Related
EDIT: I have partially resolved the issue. I had previously removed the for loop fro it's own method and put it into main for it to work, but for some reason it was not working this time. That's because a new Cards object was being initialized (underneath //The Flop comment), which I guess reset the deck. If i remove that and place the loop there instead of it's own method, it works. However, the issue still happens within the method because I need to create a new object to "communicate" with the deck class. I will try to either pass in the object as an argument or set it somewhere accessible and see if that works, then I will re-edit this post.
Edit 2: Passing in the Cards Object as an argument has worked! Will post as answer.
Start of post:
I'm trying to write a Texas Hold 'em game for my class. I'm trying to use methods to tidy up the main(). Unfortunately, it seams Cards are being duplicated between the other arrays I have (The Player's Hand, Opponents Hand, and Board. I don't seem to be on my teacher's favorites list so he doesn't provide much help when asked for it.
Here is the main class:
public class PokerGame
{
private int pot = 0;
public static void main(String[] args)
{
//Create Objects to connect classes.
Deck Cards = new Deck(0, "s");
Player Player = new Player();
Opponents Op1 = new Opponents();
//Bring deck into this main class.
Deck[] aDeck = new Deck[52];
Deck[] fDeck = Cards.buildDeck(aDeck);
Deck[] mDeck = Cards.shuffle(fDeck, 100);
//Create the Board and Hand arrays.
Deck[] Board = new Deck[5];
Deck[] Burned = new Deck[3];
Deck[] pHand = new Deck[2];
Deck[] o1Hand = new Deck[2];
int count;
for(count = 0; count < pHand.length; count++)
{
pHand[count] = Cards.deal(mDeck);
System.out.println("P " + pHand[count].namedRank + " of " + pHand[count].s);
o1Hand[count] = Cards.deal(mDeck);
}
System.out.println("o1 " + o1Hand[0].namedRank + " of " + o1Hand[0].s);
System.out.println("o1 " + o1Hand[1].namedRank + " of " + o1Hand[1].s);
//The Flop
Cards = new Deck(0, "s");
Burned[0] = Cards.deal(mDeck);
Board = flop(Board, mDeck);
//The Turn
Burned[1] = Cards.deal(mDeck);
Board[3] = Cards.deal(mDeck);
System.out.println("\n\n");
System.out.println("Now the Board is...");
for(int b = 0; b < 4; b++)
{
System.out.println(Board[b].namedRank + " of " + Board[b].s);
}
showdown(Board, pHand, o1Hand);
}
public static Deck[] flop(Deck[] Board, Deck[] mDeck)
{
Deck Cards = new Deck(0, "s");
System.out.println();
System.out.println("The Board is...");
for(int b = 0; b < 3; b++)
{
Board[b] = Cards.deal(mDeck);
System.out.println(Board[b].namedRank + " of " + Board[b].s);
}
return Board;
}
And this is the Deck class where I shuffle and deal.
public class Deck
{
public Deck[] Deck = new Deck[52];
private int index = 0;
public int rank;
public String s;
public String namedRank;
private int x = 0;
/**
* Constructor for card Objects
*
* Cannot get to work, not sure where issue is.
*/
public Deck(int rank, String s)
{
if(rank == 1)
{
this.rank = 14;
}
else
{
this.rank = rank;
}
String numRank = String.valueOf(rank);
if(this.rank == 11)
{
this.namedRank = "Jack";
}
else if(this.rank == 12)
{
this.namedRank = "Queen";
}
else if(this.rank == 13)
{
this.namedRank = "King";
}
else if(this.rank == 14)
{
this.namedRank = "Ace";
}
else
{
this.namedRank = numRank;
}
this.s = s;
}
/**
* Assigns each element in the array a card
*
* #param Deck array before elements assigned
* #return Deck array after elemnts assigned
*/
public Deck[] buildDeck(Deck[] fDeck)
{
String[] suit = {"Club", "Diamond", "Heart", "Spade"};
int c;
String of = " of ";
for(c = 0; c < suit.length; c++)
{
for(rank = 1; rank < 14; rank++)
{
s = suit[c];
fDeck[x] = new Deck(rank, s);
x++;
}
}
return fDeck;
}
/**
* Shuffles the cards by picking to random numbers and switching them
*
* #param Deck array after elemetns assigned
* #return Deck array after elements are mixed up
*/
public Deck[] shuffle(Deck[] mDeck, int shuffle)
{
for(int count = 0; count < shuffle; count++)
{
int f = ((int)(Math.random() * 100) % 51 + 1);
int s = 0;
Deck move = mDeck[f];
mDeck[f] = mDeck[s];
mDeck[s] = move;
}
return mDeck;
}
/**
* Deals the cards and keeps track by incrasing the index
*
* #param Deck array after elements are mixed up
* #return single Deck array element at whatever position int index is at
*/
public Deck deal(Deck[] dDeck)
{
index++;
return dDeck[index];
}
}
Literally any help is much appreciated as I've been scratching my head on this for a long time already. Will be continuing what I can mess around with before I have to head to work.
I am creating an instance deck of cards that should display all 52 cards when built, then it should shuffle the cards and deal 5. After this the menu should prompt for either another 5 to be dealt, or the deck to be reshuffled, which adds all the drawn cards back in, or to exit the application. However, when I run the app, it just displays null for all 52 cards, and each card that is dealt. The application worked and almost met all the specification before I talked with my instructor, and what I have now is where I got during/ after our talk. I'm not sure what I'm doing wrong and could really use the help. Just for clarification I will post the requirements, then the code. I appreciate the help.
At startup, it constructs a Deck of Cards
52 distinct cards running from Ace - King, of suit Heart, Club, Diamond, or Spade
Shuffle the cards!!
For proof, print out all 52 cards to the console in a useful, readable way.
Then, deal the top five cards to the console (meaning print them to the console)
After all of this, allow the user choose between dealing the next five cards, reshuffling the deck, or quitting the application.
If the user chooses to deal the next 5 cards, do so based on which cards have not yet been dealt. DO NOT RESHUFFLE.
If the user chooses to reshuffle, simply repeat the process of shuffling, printing the deck, and dealing the top five cards.
If the user chooses to quit the application, simply end the app.
The code I'm practicing encapsulation so I will post each class broken up as is in eclipse.
Driver
public class Driver {
public static void main(String[] args) throws IOException {
DeckRun.run();
}
}
DeckRun
public class DeckRun {
static Card[] d1 = new Card[52];
public static void run() throws IOException {
printDeck();
System.out.println("");
Deal.dealCards(d1);
System.out.println("");
menu();
}
public static void printDeck() {
for (Card c : d1) {
System.out.println(c);
}
}
public static void menu() throws IOException{
BufferedReader readRacer = new BufferedReader(new InputStreamReader(System.in));
int menu = 0;
do {
System.out.println("Press 1 to be dealt 5 random cards.");
System.out.println("Press 2 to shuffle all the cards back into the deck.");
System.out.println("Press 3 to quit the application.");
String input = readRacer.readLine();
menu = Integer.parseInt(input);
switch (menu) {
case 1: Deal.dealCards(d1);
break;
case 2: System.out.println("The deck has been shuffled.");
Deck[] d1 = new Deck[52];
break;
case 3: System.out.println("I'm not bad, I'm just drawn that way.");
break;
}
} while (menu != 3);
}
}
Card
public class Card {
private Rank rank; // Variable to assign a card its rank.
private Suit suit; // Variable to assign a card its suit.
public Card (Rank rank, Suit suit) { // Constructor to build a card.
this.rank = rank;
this.suit = suit;
}
public Rank getRank() { // Retrieves the card's rank from the enum Rank.
return rank;
}
public Suit getSuit() { // Retrieves the card's suit from the enum Suit.
return suit;
}
#Override
public String toString() { //
return rank + " OF " + suit;
}
}
Deck
public class Deck {
private Card[] cards;
public Deck() {
int numberOfRanks = 13;
int numberOfSuits = 4;
int numberOfCards = numberOfRanks * numberOfSuits;
Rank[] rank = Rank.values();
Suit[] suit = Suit.values();
cards = new Card[numberOfCards];
for (int i = 0; i < numberOfRanks; i++) {
for (int j = 0; j < numberOfSuits; j++) {
cards[j * numberOfRanks + i] = new Card(rank[i], suit[j]);
}
}
}
public void shuffleCards() {
Random rand = new Random();
for (int c = rand.nextInt(6) + 5; c > 0; c--) {
for (int i = cards.length - 1; i > 0; i--) {
int index = rand.nextInt(i + 1);
Card card = cards[index];
cards[index] = cards[i];
cards[i] = card;
}
}
}
}
Deal
public class Deal {
private static int counter = 0;
public static void dealCards(Card[] d1) {
for (int i = 0; i < 5; i++) {
counter++;
System.out.println(d1[counter]);
if (counter == 50) {
System.out.println("Almost all cards have been used, please reshuffle.");
}
}
}
}
Rank (Enum)
public enum Rank { ACE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT,
NINE, TEN, JACK, QUEEN, KING, }
Suit (Enum)
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES, }
Not really sure where the issue is, but what I've changed today is after realizing I need an instance of the deck, my professor helped me understand that instead of a method for the deck of cards in class Deck, i needed a constructor. I believe I'm going down the right path but I am just utterly stumped. Any help is appreciated and if you can explain my errors so I may learn and progress even more thanks.
In main you are calling DeckRun.run(), let's take a look at your definition of this method. It calls printDeck which iterates over an array of cards (d1), which is never populated. That's why you are getting a bunch of NULLs.
Your DeckRun should have an instance of Deck instead of cards array
public class DeckRun {
private Deck deck = new Deck();
public static void run() throws IOException {
printDeck();
System.out.println("");
Deal.dealCards(deck.getCards());
System.out.println("");
menu();
}
public static void printDeck() {
for (Card c : deck.getCards()) {
System.out.println(c);
}
}
public static void menu() throws IOException{
BufferedReader readRacer = new BufferedReader(new InputStreamReader(System.in));
int menu = 0;
do {
System.out.println("Press 1 to be dealt 5 random cards.");
System.out.println("Press 2 to shuffle all the cards back into the deck.");
System.out.println("Press 3 to quit the application.");
String input = readRacer.readLine();
menu = Integer.parseInt(input);
switch (menu) {
case 1:
Deal.dealCards(deck.getCards());
break;
case 2:
System.out.println("The deck has been shuffled.");
deck.shuffleCards();
break;
case 3:
System.out.println("I'm not bad, I'm just drawn that way.");
break;
}
} while (menu != 3);
}
}
you also need to add a getter for cards in Deck
so your problem lays in this loop
for (int i = 0; i < numberOfRanks; i++) {
for (int j = 0; j < numberOfSuits; j++) {
cards[j * numberOfRanks + i] = new Card(rank[i], suit[j]);
}
}
J*numOfRanks +i is basically saying 0*4 = 0+0 = 0
and so on, causing problems. To make this simpler i would recommend a 2D array, making 4 columns for the suits and 13 rows for the ranks then a similar loop would work perfectly. please let me know if this helps!
Okay guys. The answer was simple. I deleted the deal class, and moved the method to the deck class. I initialized the counter as a private, class-level int, which fixed the repetition issue. I will post the finished code below, so you can see.
DeckRun Class
public class DeckRun {
static Deck d1 = new Deck();
public static void run() throws IOException {
printDeck();
System.out.println("");
d1.dealCards();
System.out.println("");
menu();
}
public static void printDeck() {
System.out.println(d1.toString());
}
public static void menu() throws IOException{
BufferedReader readRacer = new BufferedReader(new InputStreamReader(System.in));
int menu = 0;
do {
System.out.println("Press 1 to be dealt 5 random cards.");
System.out.println("Press 2 to shuffle all the cards back into the deck.");
System.out.println("Press 3 to quit the application.");
String input = readRacer.readLine();
menu = Integer.parseInt(input);
switch (menu) {
case 1: d1.dealCards();
System.out.println("");
break;
case 2: System.out.println("The deck has been shuffled.");
d1.shuffleCards();
System.out.println("");
break;
case 3: System.out.println("I'm not bad, I'm just drawn that way.");
break;
}
} while (menu != 3);
}
}
Deck Class
public class Deck {
private Card[] cards;
public Deck() {
int numberOfRanks = 13;
int numberOfSuits = 4;
int numberOfCards = numberOfRanks * numberOfSuits;
Rank[] rank = Rank.values();
Suit[] suit = Suit.values();
cards = new Card[numberOfCards];
for (int i = 0; i < numberOfRanks; i++) {
for (int j = 0; j < numberOfSuits; j++) {
cards[i * numberOfSuits + j] = new Card(rank[i], suit[j]);
}
}
}
public void shuffleCards() {
Random rand = new Random();
counter = 0;
for (int c = rand.nextInt(6) + 5; c > 0; c--) {
for (int i = cards.length - 1; i > 0; i--) {
int index = rand.nextInt(i + 1);
Card card = cards[index];
cards[index] = cards[i];
cards[i] = card;
}
}
}
private int counter = 0;
public void dealCards() {
try{
for (int i = 0; i < 5; i++) {
counter++;
System.out.println(cards[counter]);
if (counter == 50) {
System.out.println("Almost all cards have been used, please reshuffle.");
// Either return 1 card or an array of 5 cards.
}
}
} catch (ArrayIndexOutOfBoundsException aioobe){
System.out.println("Caught an ArrayIndexOutOfBoundsException. Reshuffling deck.");
shuffleCards();
}
}
#Override
public String toString() {
String deckOfCards = "";
for (Card c : cards) {
deckOfCards += c.toString() + "\n";
}
return deckOfCards;
}
}
That is all I had to fix, but I appreciate the help. Thanks everyone.
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 7 years ago.
I just started learning Java required for my course.
Everything seems fine, no syntax errors but when I run my code I have an error
Exception in thread "main" java.lang.NullPointerException
at Deck.<init>(Deck.java:18)
at MainDriver.main(MainDriver.java:17)
Here is my code.
Class Card
public abstract class Card {
public CardValue value;
public CardSuit suit;
CardValue [] cardvalue = CardValue.values();
CardSuit [] cardsuit = CardSuit.values();
public Card () {
value = cardvalue[0];
suit = cardsuit[0];
}
public String toString() {
return this.suit + " of " + this.value;
}
abstract boolean CardCompare(Card P1, Card P2);
}
Class Deck
import java.util.Random;
public class Deck {
Card[] playingCards = new Card[52];
public Deck() {
int cardNumber = 0;
CardValue [] cardvalue = CardValue.values();
CardSuit [] cardsuit = CardSuit.values();
for (int i = 0; i < 4; i++)
{
for(int j = 0; j < 13; j++) //Error here (Deck.java:18)
{
playingCards[cardNumber].value = cardvalue[j];
cardNumber++;
}
playingCards[cardNumber].suit = cardsuit[i];
}
}
public Card draw() {
Random rand = new Random();
int cardDraw = rand.nextInt(52);
return playingCards[cardDraw];
}
}
Class Main
public class MainDriver extends Card{
static final int HANDS = 52;
boolean CardCompare(Card P1, Card P2)
{
if (P1.value.ordinal() > P2.value.ordinal())
return true;
else if (P1.suit.ordinal() > P2.suit.ordinal())
return true;
else return false;
}
public static void main(String[] args) {
Deck player1 = new Deck(); //Some reason there's a error here too (MainDriver.java:17)
Deck player2 = new Deck();
int player1Score = 0, player2Score = 0;
int CardCounter = 0;
while(CardCounter < 52)
{
player1.draw();
player2.draw();
System.out.println(player1 + " " + player2);
CardCounter++;
}
System.out.printf("Final score: Player 1--%d; Player 2--%d", player1Score, player2Score);
}
}
I don't understand why the MainDriver.java:17 is having an error at all. I used abstract in Card because I will also extend it with other class(have not worked on yet) and I will define a different boolean through there. I also have trouble with comparing the cards in the main driver.
I did not include CardValue and CardSuit but they're public enums with suits(Clubs, Diamonds, Hearts, Spades) & values(Two, Three, all the way to Jack, Queen, King, Ace).
If you think you are getting an NPE at this line:
for(int j = 0; j < 13; j++) //Error here (Deck.java:18)
you are mistaken. An NPE at that line is impossible. Nothing in that particular line uses reference types in any way.
Check that you have recompiled all of your code and that the version of the source code matches the compiled classes that you are using.
If we allow for your mistake with building / running, then #Eran has identified a plausible cause of the NPEs.
It's more likely the error is here :
playingCards[cardNumber].value = cardvalue[j];
since you never assign a new Card to playingCards[cardNumber], which is null.
Change your loop to :
for (int i = 0; i < 4; i++)
{
for(int j = 0; j < 13; j++)
{
playingCards[cardNumber] = new Card ();
playingCards[cardNumber].value = cardvalue[j];
cardNumber++;
}
playingCards[cardNumber].suit = cardsuit[i];
}
Also change
public abstract class Card
to
public class Card
Since you can't instantiate an abstract class.
I have an assignment to create a deck of cards and deal five random cards. I finally got it "working" but I need help with a couple things. One I just read that java now has a shuffle method to shuffle a list. We're on arrays right now so I think arrays were wanted is there a way to use the shuffle method with an array? If not can someone guide me in switching to a list? I think it will help with answer my next question. The only thing left for me to do is somehow state how many cards are left in the deck after the 5 random cards are dealt. However, seeing as how I'm using an array and you cannot remove items from an array because it's fixed (right?) I wanted to see if there was a way to simulate removing the cards from the array so that they aren't dealt again? Or would it just be easier to turn the arrays into a list/collection?
Here is my code. Any help is greatly appreciated. Also, I'll take any suggestions on cleaning the code up too...
public class CardGame {
public static void main (String [] args) {
DeckOfCards deck = new DeckOfCards();
//call shuffle
deck.shuffle(1000);
Card b;
for (int i = 0; i < 5; i++) {
b = deck.deal();
System.out.println("Deal a card: " + b);
}
}
}
class Card {
public static final int SPADE = 4;
public static final int HEART = 3;
public static final int CLUB = 2;
public static final int DIAMOND = 1;
private static final String[] Suit = {"*", "Hearts", "Clubs", "Spades", "Diamonds"};
private static final String[] Rank = {"*", "*", "Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
private int cardSuit;
private int cardRank;
public Card( int suit, int rank ) {
if ( rank == 1 )
cardRank = 14; // Give Ace the rank 14
else
cardRank = (int) rank;
cardSuit = (int) suit;
}
public int suit() {
return ( this.cardSuit );
}
public String suitStr() {
return( this.Suit[ this.cardSuit ] );
}
public int rank() {
return ( this.cardRank );
}
public String rankStr() {
return ( Rank[ this.cardRank ] );
}
public String toString() {
return ( Rank[ this.cardRank ] + " of "+ Suit[ this.cardSuit ] );
}
}
class DeckOfCards {
public static final int NEWCARDS = 52;
private Card[] deckOfCards; // Contains all 52 cards
private int currentCard; // deal THIS card in deck
public DeckOfCards( ) {
deckOfCards = new Card[ NEWCARDS ];
int i = 0;
for (int suit = Card.DIAMOND; suit <= Card.SPADE; suit++)
for ( int rank = 1; rank <= 13; rank++ )
deckOfCards[i++] = new Card(suit, rank);
currentCard = 0;
}
//shuffle(n): shuffle the deck
public void shuffle(int n) {
int i, j, k;
for ( k = 0; k < n; k++ ){
i = (int) ( NEWCARDS * Math.random() ); // Pick 2 random cards
j = (int) ( NEWCARDS * Math.random() ); // in the deck
//swap these randomly picked cards
Card temp = deckOfCards[i];
deckOfCards[i] = deckOfCards[j];
deckOfCards[j] = temp;
}
currentCard = 0; // Reset current card to deal
}
//deal(): deal deckOfCards[currentCard] out
public Card deal() {
if (currentCard < NEWCARDS) {
return ( deckOfCards[currentCard++] );
}
else{
System.out.println("Out of cards error");
return ( null ); // Error;
}
}
public String toString() {
String s = "";
int k;
k = 0;
for ( int i = 0; i < 4; i++ ) {
for ( int j = 1; j <= 13; j++ )
s += (deckOfCards[k++] + " ");
s += "\n";
}
return (s);
}
}
After all the help I decided to rewrite my code and here is what I got but I'm having a little trouble bringing it all together and making it work!
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CardGame {
public static void main (String [] args) {
DeckOfCards deck = new DeckOfCards();
//call shuffle
deck.shuffle();
Card b;
for (int i = 0; i < 5; i++) {
b = deck.deal();
System.out.println("Deal a card: " + b);
}
}
}
class Card {
enum Suit {
HEARTS(1),
CLUBS(2),
DIAMONDS(3),
SPADES(4);
private int suitValue;
private Suit (int suitValue)
{
this.suitValue = suitValue;
}
public int getSuitValue()
{
return suitValue;
}
}
private Suit suit;
private Value value;
public Card (Suit suit, Value value)
{
this.suit = suit;
this.value = value;
}
public Suit getSuit() {
return suit;
}
public Value getValue() {
return value;
}
/*
public int compareTo(Card o) {
return 0;
}
} */
class DeckOfCards
{
private List<Card> cards = new ArrayList<Card>();
public DeckOfCards () {
for (Suit suit : Suit.values()) {
for (Value value : Value.values()) {
Card card = new Card(suit, value);
cards.add(card);
}
}
}
public List<Card> getCards() {
return cards;
}
public void shuffleDeckOfCards() {
Collections.shuffle(cards);
}
public String toString() {
return this.Value + " of "+ this.Suit;
}
}
Here is a fully working sample program which demonstrates all the things you need - Shuffling and removing cards from an array.
Sample Card class:
public class Card {
private String value = "";
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Card(String value) {
super();
this.value = value;
}
}
Sample program:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
public class CardGame {
public static void main(String[] args) {
List<Card> pack = new ArrayList<Card>();
Card c1 = new Card("c1");
Card c2 = new Card("c2");
Card c3 = new Card("c3");
pack.add(c1);
pack.add(c2);
pack.add(c3);
System.out.print("List : ");
CardGame.displayCardList(pack);
Card[] packArr = cardListToArray(pack);
System.out.print("Array : ");
CardGame.displayCardArray(packArr);
// http://stackoverflow.com/questions/4228975/how-to-randomize-arraylist
long seed = System.nanoTime();
Collections.shuffle(pack, new Random(seed));
System.out.print("Shuffle List : ");
CardGame.displayCardList(pack);
packArr = cardListToArray(pack);
System.out.print("Shuffle Array : ");
CardGame.displayCardArray(packArr);
System.out.print("Remove Card from Array : ");
CardGame.removeCardFromArray(packArr, new Card("c1"));
CardGame.displayCardArray(packArr);
}
public static boolean removeCardFromArray(Card[] packArr, Card card) {
boolean cardFound = false;
for (int i = 0; i < packArr.length; i++) {
if (packArr[i].getValue().equalsIgnoreCase(card.getValue())) {
packArr[i] = null;
cardFound = true;
break;
}
}
return cardFound;
}
public static Card[] cardListToArray(List<Card> pack) {
Card[] packArr = new Card[pack.size()];
for (int i = 0; i < pack.size(); i++) {
packArr[i] = pack.get(i);
}
return packArr;
}
public static void displayCardList(List<Card> pack) {
for (Card c : pack) {
System.out.print(c.getValue() + ", ");
}
System.out.println();
}
public static void displayCardArray(Card[] packArr) {
for (Card c : packArr) {
if (c == null) {
System.out.print("REMOVED, ");
} else {
System.out.print(c.getValue() + ", ");
}
}
System.out.println();
}
}
Card
In the Card class the suits should be an enum. You can create the enum like this.
enum Suit {
SPADE,
HEART,
CLUB,
DIAMOND
};
Then the class should hold a variable of it's current suit like
Suit suit;
You can change the value of it very easily.
suit = Suit.HEART;
If you must use an index to access a suit you could use
suit = Suit.values()[index];
When getting the rank of the card you could use
return Rank[suit.ordinal()];
The name of the functions in the Card class are not the typical names you should use. Some of these should be getters. I would recommend names like getSuit() and getSuitName(), you want names that just by reading them you can understand what they do. Names like suit() are a little confusing, they don't tell you what they are doing with suit.
DeckOfCards
In the DeckOfCards class, when initializing the deck use a for each loop for the suits.
for (Suit suit : Suits.values()) {
...
}
This will loop over every suit.
If you wanted to switch over to a List you should declare your private variable deckOfCards to be an ArrayList.
private List<Card> deckOfCards = new ArrayList<>();
If you haven't worked with lists before, this is creating a list of Card objects. The diamond operator (<>) assumes the object type from the type you specified before (Card) This is a java 7 feature, if you are working with older version you would use
new ArrayList<Card>();
Instead of tracking your position in the deck, you add a card with the add() function
deckOfCards.add(card);
This would allow you to use Collections.shuffle(deckOfCards) to shuffle the cards around randomly.
To access a card, you use the get(int i) function
deckOfCards.get(index);
If you are still using arrays, when you are shuffling use a Random object. Throw a
Random random = new Random();
in the begging of your class. The inside of the for loop could look like this
int i = random.nextInt(NEWCARDS);
int j = random.nextInt(NEWCARDS);
Card temp = deckOfCards[i];
deckOfCards[i] = deckOfCards[j];
deckOfCards[j] = temp;
In the shuffle function I would change the names of i, j, and k. Variable K should be called i because it is the iterator. Variable j and k should be renamed to more meaningful names.
If you want to convert Arrays to lists you can use
Arrays.asList(new ArrayList<Card>());
And the opposite of that, to convert back to an array.
list.toArray();//This will return an array of Objects[]
Card[] cards = new Card[NEWCARDS];
list.toArray(cards)//This will store the list into the array cards.
//Note if the lists is bigger than the array it is storing it in, the function will return a new array that can hold all of the elemnents in the list.
Note: In these example I have been using ArrayList, there are other implementations of the List class which you may want to research.
Personal Preference
I would remove the parenthesis off of the return statements except on your toString() for the Card class.
You have some extra spaces when using parenthesis in your code such as your DeckOfCards constructor. I would make it like so
public DeckOfCards() {
There also shouldn't be spaces surrounding the stuff inside parenthesis such as
i = (int) ( NEWCARDS * Math.random() );
//should be
i = (int) (NEWCARDS * Math.random());
In my game's code, I am trying to add a card to hand. As soon as I do, my array is out of bounds. Everything looks right, but maybe I'm missing something.
FYI, one and two are Player instances. Relevant code from Main class (sorry about the formatting. i suck at transferring it to Stack Overflow):
import java.util.*;
public class Program {
public static void main(String args[]) {
String[] rank = {"two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "jack", "queen", "king", "ace"};
String[] suit = {"hearts", "diamonds", "spades", "clubs"};
Scanner scan = new Scanner(System.in);
String something = "yes", something2 = "yes"; //Use with while loop
String winner = "yes"; //Use for while loop
String temp; //Use with setting names
Card[] deck = new Card[52]; //Deck array
int playercount = 0;
Player one = new Player("temp");
Player two = new Player("temp");
Player three = new Player("temp");
Player four = new Player("temp");
while (something2.equals("yes") || playercount < 2) { //Add players to game
System.out.println("Would a(nother) player like to join?");
something2 = scan.nextLine();
System.out.println();
if (something2.equals("yes")) {
if (playercount <= 4) {
if (playercount == 0) {
System.out.println("What is your name: ");
Player one1 = new Player(scan.nextLine());
one = one1;
playercount++;
System.out.println();
}
else if (playercount == 1) {
System.out.println("What is your name: ");
Player two2 = new Player(scan.nextLine());
two = two2;
playercount++;
System.out.println();
}
else if (playercount == 2) {
System.out.println("What is your name: ");
Player three3 = new Player(scan.nextLine());
three = three3;
playercount++;
System.out.println();
}
else if (playercount == 3) {
System.out.println("What is your name: ");
Player four4 = new Player(scan.nextLine());
four = four4;
playercount++;
System.out.println();
}
else {System.out.println("Only four players are allowed.");
something2 = "no";}
}
}
else if (playercount < 2) {
System.out.println("You need at least two players...");
System.out.println();
}
else something2 = "no";
}
//Start game
while (something.equals("yes")) {
//Prepare game
Card.makeDeck(deck, rank, suit);
deck = Card.getDeck();
Card.shuffle(deck);
deck = Card.getDeck();
//Deal cards
if (playercount == 2) {
for (int i = 1; i < 8; i++) {
one.addCard(Card.draw(deck));
deck = Card.getDeck();
two.addCard(Card.draw(deck));
deck = Card.getDeck();
}
}
else if (playercount == 3) {
for (int i = 1; i < 8; i++) {
one.addCard(Card.draw(deck));
deck = Card.getDeck();
two.addCard(Card.draw(deck));
deck = Card.getDeck();
three.addCard(Card.draw(deck));
deck = Card.getDeck();
}
}
else {
for (int i = 1; i < 8; i++) {
one.addCard(Card.draw(deck));
deck = Card.getDeck();
two.addCard(Card.draw(deck));
deck = Card.getDeck();
three.addCard(Card.draw(deck));
deck = Card.getDeck();
four.addCard(Card.draw(deck));
deck = Card.getDeck();
}
}
}
}
}
Card class:
import java.util.*;
public class Card {
private String suit;
private String rank;
private static int temp = 0, temp2 = 0; //Use for reseting rank and suit
private static Card temp3; //Use for draw method
private static int temp4; //Use for shuffle method
private static Card[] deck = new Card[52];
//Constructors
public Card() {
this.rank = "two";
this.suit = "hearts";
}
public Card(String r, String s) {
this.rank = r;
this.suit = s;
}
//Mutators
//Make deck
public static void makeDeck(Card[] c, String[] r, String[] s) {
for (int i = 0; i < c.length; i++) {
c[i] = new Card(r[temp], s[temp2]);
temp++; temp2++;
//Reset rank and suit
if (temp > 12)
temp = 0;
if (temp2 > 3)
temp2 = 0;
}
deck = c;
}
//Accessors
//Return deck
public static Card[] getDeck() {
return deck;
}
//Shuffle
public static Card[] shuffle(Card[] c) {
for (int i = 0; i < c.length; i++) {
int rand = (int)(Math.random()*(i + 1));
//Don't let anything be in a slot that doesn't exist
while (rand > c.length) {
temp4 = (int)Math.random();
rand -= temp4;
}
if (rand < 0)
rand += temp4;
Card temp = c[i];
c[i] = c[rand];
c[rand] = temp;
}
deck = c;
return deck;
}
//Draw
public static Card draw(Card[] c) {
if (c != null) {
for (int i = 0; i < c.length; i++) {
if (c[i] != null) {
try {
return c[i];
} finally {
c[i] = null;} //Remove i from c
}
}
}
return null;
}
}
Player class:
import java.util.*;
public class Player {
private String name;
private Card[] hand = new Card[52];
private int handsize = 0;
//Constructor
public Player(String n) {
name = n;
}
//Mutators
public void addCard(Card c) {
hand[handsize] = c;
handsize++;
}
//Accessors
public String getName() {
return name;
}
public Card[] getHand() {
return hand;
}
}
Your draw method is broken.
// get the first non-null Card from the cards "c".
public static Card draw(Card[] c) {
if (c != null) {
for (int i = 0; i < c.length; i++) {
if (c[i] != null) {
try {
return c[i];
} finally {
// now remove element i from the `c` array.
c[i] = null;
}
}
}
}
return null;
}
The problem is with your loop
while (something.equals("yes"))
There's nothing that sets something to any other value, so this loop just goes around endlessly, until all the players have more than 52 cards. Once someone has more than 52 cards, adding a new card causes the exception.
I think you need to remove this while. The code inside it should only be run once.
I think the order of your code is incorrect (hard to tell with this code)
for (int i = 1; i < 8; i++)
{
one.addCard(Card.draw(deck));
deck = Card.getDeck();
two.addCard(Card.draw(deck));
deck = Card.getDeck();
}
maybe should be
for (int i = 1; i < 8; i++)
{
deck = Card.getDeck();
one.addCard(Card.draw(deck));
deck = Card.getDeck();
two.addCard(Card.draw(deck));
}
Update
Also
public void addCard(Card c) {
hand[handsize] = c;
handsize++;
}
handsize is never incremented - it is always 0