0

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;
    }
}
3
  • Please an SSCCE Commented Nov 29, 2013 at 7:17
  • based upon this code, play could be replaced with true - its value does not seem to change. Commented Nov 29, 2013 at 7:17
  • While reading ints, you're not consuming newline character (added when user pressed ENTER) - see my longer answer below. Commented Nov 29, 2013 at 9:50

2 Answers 2

1

Your loops aside, the reason why you have these lines displayed twice is because:

  • when reading bet, you are using

    bet = input.nextInt();
    

which will read an int the user entered, BUT user pressed ENTER after the number, which in turn inserts newline character and nextInt() doesn't consume it

  • later in the code, you are using:

    String hitOrStand = input.nextLine();
    

and nextLine() will consume that newline character.

  • hitOrStand equals to newline character now, so all the comparisons you do later ('h' or 'H', 's' or 'S') will evaluate to false, and you're back to the beginning of while(play) loop.

There are few ways to fix this, eg:

  • consuming newline character by using input.nextLine() after each nextXXX() method you use;
  • using bet = Integer.parseInt(input.nextLine()) instead of input.nextInt()

and probably some others. Here's how it could look:

int bet = input.nextInt();

//add nextLine() to consume newline character
input.nextLine();

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();

    //add nextLine() to consume newline character
    input.nextLine();
}

Please read more about scanner class here Also note that you are not checking for invalid user input, so your program will break if it's expecting number, and is given a string, but I'll leave that out as an improvement opportunity for you :)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for the reply. I've read up on the scanner class and fixed the code. Cheers.
0

You set done to true, but you never set play to false or gameFinished to true. You may want to rethink the semantics of these three booleans and how they relate.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.