I've written a basic command line Blackjack game for java, I ran into an unexpected problem while coding it, and this prompted the following question what is the best way to end an'action' sequence in java. I.e. should we use a do while loop or should we use a while(boolean)?
I know there must be a logic error somewhere in my code, but I cannot find it. When I run the code, I expect to be told what my hand is, and to be asked if I want to stand or hit, like this:
Welcome to Blackjack!
Dealer stands on 17
Your current balance is €100
Please enter you bet, between €5 and €25. Your bet must be less than your bank,
and be a multiple of 5:
5
House holds: ? + 4 of Clubs
You hold: Jack of Hearts Queen of Hearts
For a total score of: 20.
Would you like to hit or stand? (h or s):
However I receive this section printed twice:
House holds: ? + 4 of Clubs
You hold: Jack of Hearts Queen of Hearts
For a total score of: 20.
The part of the code that I think may be relevant is
while (play) {
// Print out the two hands to the console
System.out.print("House holds: ? + ");
// The print hand action takes sn array and a boolean, if false
// it sets the amount of cards to print for each hand to the
// hand length - 1, so on the first round it will show 1 card.
// If set to true it prints all cards in the hand.
Blackjack.printHand(dealer, false);
System.out.println();
System.out.print("You hold: ");
Blackjack.printHand(player, true);
System.out.println();
System.out.println("For a total score of: "
+ Blackjack.calculateScore(player) + ".");
// This checks for Blackjack
if (Blackjack.blackjack(player, dealer) == 1) {
System.out.println("Blackjack! Player has won!");
bank += bet;
System.out.print("The dealer had ");
Blackjack.printHand(dealer, true);
System.out.println();
done = true;
break;
}
System.out.println();
System.out.print("Would you like to hit or stand? (h or s): ");
String hitOrStand = input.nextLine();
I'm not sure if I'm using the boolean 'play' correctly. Just in case the issue isn't with this section, I'll include the full (rather tedious) code below. Thank you very much.
import java.util.*;
public class TestBlackjack {
// Declare and initialise the bank at €100
static int bank = 100;
public static void main(String[] args) {
// Originally the game is not finished
boolean gameFinished = false;
boolean play = true;
// Until game is finished, play a game of Blackjack
while (gameFinished == false) {
// Create a scanner object
Scanner input = new Scanner(System.in);
boolean done = false;
System.out
.println("Welcome to Blackjack!\nDealer stands on 17\nYour current balance is €"
+ bank
+ "\nPlease enter you bet, between €5 and €25. Your bet must be less than your bank,\nand be a multiple of 5: ");
int bet = input.nextInt();
while (bet > 25 || bet < 5 || bet % 5 != 0 || bet > bank) {
System.out
.print("Please re-enter you bet, this must be either 5, 10, 15, 20 or 25\nand be less than €"
+ bank + ": ");
bet = input.nextInt();
}
// Declare and populate a deck array, and declare a hand array for
// each player
int[] deck = DeckOfCards.deck();
int[] player = new int[12];
int[] dealer = new int[12];
// Start a new game of Blackjack
Blackjack.setupNewGame(deck, player, dealer);
while (play) {
// Print out the two hands to the console
System.out.print("House holds: ? + ");
// The print hand action takes sn array and a boolean, if false
// it sets the amount of cards to print for each hand to the
// hand length - 1, so on the first round it will show 1 card.
// If set to true it prints all cards in the hand.
Blackjack.printHand(dealer, false);
System.out.println();
System.out.print("You hold: ");
Blackjack.printHand(player, true);
System.out.println();
System.out.println("For a total score of: "
+ Blackjack.calculateScore(player) + ".");
// This checks for Blackjack
if (Blackjack.blackjack(player, dealer) == 1) {
System.out.println("Blackjack! Player has won!");
bank += bet;
System.out.print("The dealer had ");
Blackjack.printHand(dealer, true);
System.out.println();
done = true;
break;
}
System.out.println();
System.out.print("Would you like to hit or stand? (h or s): ");
String hitOrStand = input.nextLine();
System.out.println();
System.out.println();
// If the user inputs h or H, it calls the hit method from the
// Blackjack class
if (hitOrStand.equals("h") || hitOrStand.equals("H")) {
Blackjack.hit(deck, player);
// If the new score for the user is greater than 21, they
// are bust
if (Blackjack.calculateScore(player) > 21) {
System.out.print("You hold: ");
Blackjack.printHand(player, true);
System.out.println();
System.out.println("Your score is: "
+ Blackjack.calculateScore(player)
+ " You are bust.\nHouse wins.");
// Subtract the bet from the bank
bank -= bet;
// Game is done
done = true;
break;
}
// Else, if the user stands, break out of this loop and
// continue the game
} else if (hitOrStand.equals("s") || hitOrStand.equals("S")) {
break;
}
}
// If the hit did not bust the user
if (!done) {
// Automate AI response, to stand on 17
Blackjack.finishDealersPlay(deck, dealer);
System.out.print("House holds: ");
Blackjack.printHand(dealer, true);
System.out.println("For a score of "
+ Blackjack.calculateScore(dealer));
System.out.println();
// Call the calculate winnings to see who has won
if (Blackjack.calculateWinnings(player, dealer) == 1) {
System.out.println("You win.");
// Update the bank
bank += bet;
} else if (Blackjack.calculateWinnings(player, dealer) == 0) {
System.out.println("Push.");
} else if (Blackjack.calculateWinnings(player, dealer) == -1) {
System.out.println("House wins.");
bank -= bet;
}
}
// Sends the game back to the beginning of the loop if the player
// wants to play again
System.out.print("Would you like to play again(y/n)? ");
String playAgain = input.nextLine();
if (playAgain.equals("y")) {
// Place a line in the console before the start of the new game
System.out.println();
continue;
} else {
System.out.println("Thanks for playing!");
System.exit(0);
}
}
}
}
class DeckOfCards {
/*
* Returns an integer representing a card in the deck. Between shuffles, the
* same card will never be returned twice
*/
public static int drawCard(int[] deck) {
// Assign i a random value between 1 and 52
int i = (int) (Math.random() * 52);
// Assign card the value of deck at position i
int card = deck[i];
// Update the value of deck at position i to 0, in order to identify
// that it has been drawn
deck[i] = -1;
// While the value drawn for card is 0, run the selection process again
while (card == -1) {
i = (int) (Math.random() * 52);
card = deck[i];
}
// Return the value for card
return card;
}
/* Shuffle the "deck" of ints */
public static void shuffle(int[] deck) {
// Run for the length of the deck array
for (int i = 0; i < deck.length; i++) {
// Generate a random index to use
int index = (int) (Math.random() * deck.length);
// Declare a holder variable to hold the value of deck at position i
int holder = deck[i];
// Set the value of deck at position i to deck at the random index
deck[i] = deck[index];
// Swap the value that was at position i into position index
deck[index] = holder;
}
}
/* Creates a "deck" of ints */
static int[] deck() {
// Declare and initialise an array
int[] deck = new int[52];
for (int i = 0; i < deck.length; i++)
deck[i] = i;
return deck;
}
}
class Blackjack {
/*
* Set up the game: perform a shuffle, "deal" 2 cards to both the dealer and
* player
*/
public static void setupNewGame(int[] deck, int[] player, int[] dealer) {
// Set all values to -1 as 0 is actually equal to the ace of spades
for (int i = 0; i < player.length; i++) {
player[i] = -1;
dealer[i] = -1;
}
// Shuffle the deck
DeckOfCards.shuffle(deck);
// Deal to player, dealer, player and then dealer
player[0] = DeckOfCards.drawCard(deck);
dealer[0] = DeckOfCards.drawCard(deck);
player[1] = DeckOfCards.drawCard(deck);
dealer[1] = DeckOfCards.drawCard(deck);
}
/* Deal another card to the player */
public static void hit(int[] deck, int[] player) {
int count = 0;
// Find the first element with a value of -1
for (int i = 0; i < player.length; i++) {
if (player[i] != -1) {
count++;
}
}
// Assign the value to that element.
player[count] = DeckOfCards.drawCard(deck);
}
/*
* Takes a hand and a boolean for Parameters, and prints the value and suit
* of hand
*/
public static void printHand(int[] hand, boolean isPlayer) {
String[] suits = { "Spades", "Hearts", "Diamonds", "Clubs" };
String[] values = { "Ace", "2", "3", "4", "5", "6", "7", "8", "9",
"10", "Jack", "Queen", "King" };
// Declare and initialise a counter for amount of cards to reveal for
// the players hand
int playerCounter = 2;
// Declare and initialise a counter for amount of cards to reveal for
// the AI's hand
int AiCounter = 1;
if (isPlayer) {
for (int i = 0; i < playerCounter; i++) {
String suit = suits[hand[i] / 13];
String value = values[hand[i] % 13];
System.out.print(value + " of " + suit + " ");
}
} else {
for (int j = 0; j < AiCounter; j++) {
String suit = suits[hand[j] / 13];
String value = values[hand[j] % 13];
System.out.print(value + " of " + suit + " ");
}
AiCounter++;
}
}
/*
* Automates the dealer's play after the player stands. Dealer draws a new
* card until he has 17 or greater
*/
public static void finishDealersPlay(int[] deck, int[] dealer) {
// Calls the calculateScore method to check the Dealers score, if its
// less than, 17, calls the hit method to augment the dealers hand
while (calculateScore(dealer) < 17) {
hit(deck, dealer);
}
}
/* Take in two hands, and checks if either scores 21. */
public static int blackjack(int[] player, int[] dealer) {
if ((calculateScore(player) == 21 && calculateScore(dealer) != 21)
&& player[2] == -1) {
return 1;
}
if ((calculateScore(player) == 21 && calculateScore(dealer) == 21)
&& player[2] == -1) {
return 0;
}
return -1;
}
/*
* Expects an int array representing a Blackjack hand as a parameter.
* Returns the score from the card representation
*/
public static int calculateScore(int[] hand) {
// Originally score is 0
int score = 0;
// Originially no ace has been played
boolean acePlayed = false;
for (int i = 0; i < hand.length; i++) {
// Add ten for the 'picture' cards, excluding the Ace
if (hand[i] % 13 > 9) {
score += 10;
// Add 11 for any Aces played
} else if (hand[i] % 13 == 0) {
score += 11;
// Set the boolean for acePlayed to true
acePlayed = true;
} else {
// Add the numerical value of any other card
score += hand[i] % 13 + 1;
}
}
// If the score with the ace is greater than 21, delete 10 from the
// score, to make the ace equal 1
if (score > 21 && acePlayed == true) {
score -= 10;
}
// Return the computed score
return score;
}
/* Computes who has won */
public static int calculateWinnings(int[] player, int[] dealer) {
if ((calculateScore(player) <= 21)
&& (calculateScore(dealer) < calculateScore(player))
|| calculateScore(dealer) > 21) {
// Player wins
return 1;
}
else if (calculateScore(player) == calculateScore(dealer)) {
// Push
return 0;
}
// Dealer wins
return -1;
}
}
true- its value does not seem to change.