4
\$\begingroup\$

I posted yesterday about my first attempt at a Blackjack game. After I received much helpful advice I tried my best to fix up my code. I was wondering what you would think about round two!

Edit: I also wanted to implement the ability to split a hand if you have two of the same card. My User class already has a split method that adds another hand; what do you think would be the best way to go about adding this feature?

Card

package Blackjack;

class Card {
private final int rank;
private final int suit;
private static String[] ranks = { "Joker", "Ace", "Two", "Three", "Four",
        "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Jack", "Queen",
        "King" };
private static String[] suits = { "Clubs", "Diamonds", "Hearts", "Spades" };

Card(int suit, int values) {
    this.rank = values;
    this.suit = suit;
}

public String toString() {
    return ranks[rank] + " of " + suits[suit];
}

public int getRank() {
    return rank;
}

public int getSuit() {
    return suit;
}

public int getValue() {
    int value=0;
    if (rank > 10) {
        value = 10;
    } else if (rank == 1) {
        value = 11;
    } else {
        value = rank;
    }
    return value;
}
}

Deck

package Blackjack;

import java.util.ArrayList;
import java.util.Random;

class Deck {
private ArrayList<Card> deck;

Deck() {
    deck = new ArrayList<Card>();
    for (int i = 0; i < 4; i++) {
        for (int j = 1; j <= 13; j++) {
            deck.add(new Card(i, j));
        }
    }
}

public void shuffle() {
    Random random = new Random();
    Card temp;
    for (int i = 0; i < 200; i++) {
        int index1 = random.nextInt(deck.size() - 1);
        int index2 = random.nextInt(deck.size() - 1);
        temp = deck.get(index2);
        deck.set(index2, deck.get(index1));
        deck.set(index1, temp);
    }
}

public Card drawCard() {
    return deck.remove(0);
}
}

Hand

package Blackjack;

import java.util.ArrayList;
import java.util.Arrays;

class Hand {
private ArrayList<Card> hand;
private int handValue;
private int aceCounter;

Hand(Deck deck) {
    hand = new ArrayList<>();
    aceCounter = 0;
    handValue = 0;
    for (int i = 0; i < 2; i++) {
        hand.add(deck.drawCard());
    }
    Card[] aHand = new Card[]{};
    aHand = hand.toArray(aHand);
    for (int i = 0; i < aHand.length; i++) {
        handValue += aHand[i].getValue();
        if (aHand[i].getValue() == 11) {
            aceCounter++;
        }
        while (aceCounter > 0 && handValue > 21) {
            handValue -= 10;
            aceCounter--;
        }
    }
}

public void Hit(Deck deck) {
    hand.add(deck.drawCard());
    Card[] aHand = new Card[]{};
    aHand = hand.toArray(aHand);
    handValue = 0;
    aceCounter=0;
    for (int i = 0; i < aHand.length; i++) {
        handValue += aHand[i].getValue();
        if (aHand[i].getValue() == 11) {
            aceCounter++;
        }
        while (aceCounter > 0 && handValue > 21) {
            handValue -= 10;
            aceCounter--;
        }
    }
}

public int getHandSize() {
    return hand.size();
}

public int getHandValue() {
    return handValue;
}

public Card getCard(int cardnum) {
    Card[] aHand = new Card[]{};
    aHand = hand.toArray(aHand);
    return aHand[cardnum-1];
}

public String toString(){
    String hands ="";
    Card[] aHand = new Card[]{};
    aHand = hand.toArray(aHand);
    for(int i=0; i<aHand.length-1; i++) {
        hands = hands + aHand[i].toString() + ", ";
    }
    hands = hands + aHand[aHand.length-1].toString();
    return hands;
}   
}

Player

package Blackjack;

import java.util.ArrayList;
import java.util.Arrays;

class Player {
ArrayList<Hand> hand;

Player() {
    hand = new ArrayList<Hand>();
}

public boolean hasBlackJack(int handnum) {
    Hand[] aHand = new Hand[] {};
    aHand = hand.toArray(aHand);
    return (aHand[handnum-1].getHandSize() == 2 && aHand[handnum-1].getHandValue() == 21);
}

public boolean hasBusted() {
    Hand[] aHand = new Hand[] {};
    aHand = hand.toArray(aHand);
    return (aHand[0].getHandValue() > 21);
}

public Hand getHand(int handnum) {
    Hand[] aHand = new Hand[] {};
    aHand = hand.toArray(aHand);
    return aHand[handnum-1];
}

public void getNewHand(Deck deck) {
    hand.clear();
    Hand myHand = new Hand(deck);
    hand.add(myHand);
}
}

User

package Blackjack;

import java.util.ArrayList;
import java.util.Arrays;

class User extends Player {
private int cash;
private int bet;
private String name;

User() {
}

public int getCash() {
    return cash;
}

public int getBet() {
    return bet;
}

public String getName() {
    return name;
}

public void setCash(int money) {
    cash = money;
}

public void setBet(int money) {
    bet = money;
}

public void setName(String username) {
    name = username;
}

public void split(Deck deck) {
    Hand hand2 = new Hand(deck);
    hand.add(hand2);
}

public void doubleDown() {
    cash=cash-bet;
    bet=2*bet;
}

public void win() {
    cash=cash+2*bet;
}
public void push() {
    cash=cash+bet;
}
public void blackJack() {
    cash=cash+3*bet;
}

public boolean hasSplit() {
    return hand.size()==2;
}

public boolean hasFiveCardTrick(int handnum) {
    Hand[] aHand = new Hand[]{};
    aHand = hand.toArray(aHand);
    Hand myHand = aHand[handnum-1];
    return(myHand.getHandSize()==5 && myHand.getHandValue()<21);
}

}

Dealer

package Blackjack;

import java.util.ArrayList;
import java.util.Arrays;

class Dealer extends Player {

Dealer() {
}

public void showFirstCard() {
    Card[] firstCard = new Card[] {};
    firstCard = hand.toArray(firstCard);
    System.out.println("[" + firstCard[0] + "]");
}

public boolean wantsToHit() {
    Hand[] aHand = new Hand[]{};
    aHand = hand.toArray(aHand);
    return aHand[0].getHandValue()<17;
}

public void showHand() {
    System.out.println(hand);
}

public void takeTurn(Deck deck) {
    Hand[] aHand = new Hand[]{};
    aHand = hand.toArray(aHand);
    while (wantsToHit()) {
        System.out.println("The dealer hits.");
        aHand[0].Hit(deck);
        if (hasBusted()) {
            break;
        }
    }
    System.out.println("The dealer stands.");
}
}

Input

package Blackjack;

import java.util.Scanner;

class Input {
private Output outputter;
Input(Output outputs) {
    outputs = outputter;
}

public String getName() {
    Scanner scan = new Scanner(System.in);
    String name = scan.nextLine();
    return name;
}

public int getCash() {
    Scanner money = new Scanner(System.in);
    int cash = money.nextInt();
    return cash;
}

public int getBet(int cash) {
    Scanner sc = new Scanner(System.in);
    int bet = sc.nextInt();
        while (bet > cash) {
            outputter.cannotBet();
            outputter.askBet();
            bet=sc.nextInt();
        }
    return bet;
}

public boolean choiceIsYes() {
    Scanner doubledown = new Scanner(System.in);
    String doubled = doubledown.nextLine();
    while (!isyesorno(doubled)) {
        outputter.yesOrNo();
        doubled = doubledown.nextLine();
    }
    return doubled.equals("yes");
}

public boolean isyesorno(String answer) {
    return (answer.equals("yes") || answer.equals("no"));
}

public boolean choiceisHit() {
    Scanner hitter = new Scanner(System.in);
    String hit = hitter.nextLine();
    while(!ishitorstand(hit)) {
        outputter.yesOrNo();
        hit = hitter.nextLine();
    }
    return hit.equals("hit");
}

public boolean ishitorstand(String hit) {
    return (hit.equals("hit") || hit.equals("stand"));
}

}

Output

package Blackjack;

class Output {

Output(){
}

public void askName() {
    System.out.println("Hi! What is your name?");
}

public void greeting(String name) {
    System.out.println("Hello, "+name+", let's play some Blackjack!");
}

public void askCash() {
    System.out.println("How much cash do you want to start with?");
}

public void tellCashStart(int cash) {
    System.out.println("You start with cash: "+cash);
}

public void showCash(int cash) {
    System.out.println("Cash: "+cash);
}

public void cannotBet() {
    System.out.println("You cannot bet more money than you have!");
}

public void askBet() {
    System.out.println("How much do you wish to bet?");
}

public void showBet(int bet) {
    System.out.println("Money on the table: " + bet);
}

public void showHand(User user) {
    System.out.println("Here is your hand: ");
    System.out.println(user.getHand(1));
}

public void showDealerFirstCard(Dealer dealer) {
    System.out.println("The dealer is showing:");
    Hand hand = dealer.getHand(1);
    System.out.println(hand.getCard(1));
}

public void showDealerHand(Dealer dealer) {
    System.out.println("Here is the dealer's hand:");
    System.out.println(dealer.getHand(1));
}

public void askDoubleDown() {
    System.out.println("Would you like to double down?");
}

public void yesOrNo() {
    System.out.println("Please answer yes or no.");
}

public void hasDoubledDown() {
    System.out.println("You have opted to double down!");
}

public void insurance() {
    System.out.println("The dealer is showing ace! Would you like insurance?");
}

public void hasInsurance() {
    System.out.println("You have opted for insurance!");
}

public void split() {
    System.out.println("You have two of the same card- would you like to split?");
}

public void hasSplit() {
    System.out.println("You have opted to split!");
}

public void splitHands(User user) {
    System.out.println("Here are your hands:");
    System.out.println(user.getHand(1));
    System.out.println(user.getHand(2));
}

public void dealerBlackJack() {
    System.out.println("The dealer has Blackjack!");
}

public void userBlackJack() {
    System.out.println("You have BlackJack!");
    System.out.println("You win 2x your money back!");
}

public void win() {
    System.out.println("Congratulations, you win!");
}

public void lose() {
    System.out.println("Sorry, you lose!");
}

public void push() {
    System.out.println("It's a push!");
    System.out.println("You get your money back.");
}

public void hitOrStand() {
    System.out.println("Would you like to hit or stand?");
}

public void enterHitorStand() {
    System.out.println("Please enter hit or stand.");
}

public void playAgain() {
    System.out.println("Would you like to play again?");
}

public void cashTotal(int cash) {
    System.out.println("Your cash total is: "+cash);
    System.out.println("Enjoy your winnings!");
}

public void cashTotalZero(int cash) {
    System.out.println("Your total cash is: "+cash);
    System.out.println("You ran out of cash!");
}

public void hasFiveCardTrick() {
    System.out.println("You have a five card trick!");
}

public void winInsurance() {
    System.out.println("The dealer does have Blackjack!");
    System.out.println("You have won your insurance.");
}

public void loseInsurance() {
    System.out.println("Sorry, the dealer does not have Blackjack.");
    System.out.println("You have lost your insurance");
}

public void busted() {
    System.out.println("You busted!");
}

public void dealerBusted() {
    System.out.println("The dealer busted!");
}
}

BlackJack Game

package Blackjack;

public class BlackJackGame {

public static void main(String[] args) {
    Output output = new Output();
    Input input = new Input(output);
    output.askName();
    output.greeting(input.getName());
    output.askCash();
    User user = new User();
    Dealer dealer = new Dealer();
    user.setCash(input.getCash());
    while (user.getCash() > 0) {
        Deck deck = new Deck();
        deck.shuffle();
        user.getNewHand(deck);
        dealer.getNewHand(deck);
        output.showCash(user.getCash());
        output.askBet();
        user.setBet(input.getBet(user.getCash()));
        user.setCash(user.getCash() - user.getBet());
        output.showCash(user.getCash());
        output.showBet(user.getBet());
        output.showHand(user);
        output.showDealerFirstCard(dealer);
        if (dealer.getHand(1).getCard(1).getRank() == 1) {
            output.insurance();
            if (input.choiceIsYes()) {
                if (dealer.hasBlackJack(1)) {
                    output.winInsurance();
                    user.win();
                    output.showCash(user.getCash());
                } else {
                    output.loseInsurance();
                    output.showCash(user.getCash());
                }
            }
        }
        if (user.hasBlackJack(1) && dealer.hasBlackJack(1)) {
            output.userBlackJack();
            output.dealerBlackJack();
            output.push();
            user.push();
        } else if (user.hasBlackJack(1)) {
            user.blackJack();
            output.userBlackJack();
            output.win();
        } else if (dealer.hasBlackJack(1)) {
            output.dealerBlackJack();
            output.lose();
        } else {
            if (2 * user.getBet() < user.getCash()) {
                output.askDoubleDown();
                if (input.choiceIsYes()) {
                    user.doubleDown();
                    output.showCash(user.getCash());
                    output.showBet(user.getBet());
                }
            }
            output.hitOrStand();
            while (input.choiceisHit()) {
                user.getHand(1).Hit(deck);
                output.showHand(user);
                output.hitOrStand();
                if (user.hasBusted()) {
                    output.busted();
                    output.lose();
                    break;
                }
                if (user.hasFiveCardTrick(1)) {
                    output.hasFiveCardTrick();
                    output.win();
                    user.win();
                    break;
                }
            }
            if(!user.hasBusted()) {
                dealer.takeTurn(deck);
                output.showDealerHand(dealer);
                if (dealer.hasBusted()) {
                    output.dealerBusted();
                    output.win();
                    user.win();
                } else {
                    if ((21 - user.getHand(1).getHandValue()) < (21 - dealer
                            .getHand(1).getHandValue())) {
                        output.win();
                        user.win();
                    }
                    if ((21 - user.getHand(1).getHandValue()) == (21 - dealer
                            .getHand(1).getHandValue())) {
                        output.push();
                        user.push();
                    }
                    if ((21 - user.getHand(1).getHandValue()) > (21 - dealer
                            .getHand(1).getHandValue())) {
                        output.lose();
                    }
                }
            }
        }
        output.showCash(user.getCash());
        output.playAgain();
        if (!input.choiceIsYes()) {
            break;
        }

    }
    if (user.getCash() == 0) {
        output.cashTotalZero(user.getCash());
    }
    output.cashTotal(user.getCash());
}
}
\$\endgroup\$
  • 1
    \$\begingroup\$ It would be nice if you summarized the improvements you made. \$\endgroup\$ – 200_success Jun 4 '15 at 22:42
  • \$\begingroup\$ Can you explain in a bit better detail what the changes are? Think of the questions "Which, what and why" (currently you only answer 'which'). See meta.codereview.stackexchange.com/a/1066/31562 \$\endgroup\$ – Simon Forsberg Jun 4 '15 at 22:43
  • \$\begingroup\$ okay will do! before I had only a dealer, card, and deck class. My blackjack game class ran the whole game, include printing, taking input, and taking output. The bulk of comments I got were about class organization so I added the classes player, user, input, and output and made it so my blackjack game class didn't violate the single functionality rule and only ran the game. I also reformatted it to look like typical java format. \$\endgroup\$ – Jared Jun 4 '15 at 23:12
  • \$\begingroup\$ I am asking for another review for feedback on how i did addressing each of the issues my previous version had and for any additional tips users may have for me. Thanks! \$\endgroup\$ – Jared Jun 4 '15 at 23:13
3
\$\begingroup\$

Structure

Your structure is a lot better. There are a couple of things I would do differently, but generally it's good.

  • a Hand doesn't really need a deck, just a card (it makes more logical sense, I think).
  • I think you have many Hands in Player because of splitting? That makes sense. But your hasBlackJack etc methods only handle the first hand, so that makes it useless. I would probably move those check methods directly into Hand.
  • I would let choiceisHit return a Action enum, which could be Hit, Stay, Split, etc. This will make it a lot easier to add other actions later on (double, split, surrender, etc).
  • your main method is too long, it's really hard to find the pieces you are interested in, which will make it really hard to change it or extend it. I would at least create a method for one round of blackjack and one method for the setup at the beginning.

Arrays and Lists

I noted this last time, but as you still convert lists to arrays, I think maybe you don't know how to handle lists on their own?

Generally - if you don't have a good reason to do it differently-, you should stick with the collection you have. If it's an array, handle the array. If it's a list, handle the list.

Eg this:

for (int i = 0; i < 2; i++) {
    hand.add(deck.drawCard());
}
Card[] aHand = new Card[]{};
aHand = hand.toArray(aHand);
for (int i = 0; i < aHand.length; i++) {
    handValue += aHand[i].getValue();
    if (aHand[i].getValue() == 11) {
        aceCounter++;
    }
    while (aceCounter > 0 && handValue > 21) {
        handValue -= 10;
        aceCounter--;
    }
}

Can be rewritten without the array like this:

for (int i = 0; i < 2; i++) {
    hand.add(deck.drawCard());
}
for (Card card : hand) {
    handValue += card.getValue();
    if (card.getValue() == 11) {
        aceCounter++;
    }
    while (aceCounter > 0 && handValue > 21) {
        handValue -= 10;
        aceCounter--;
    }
}

Personally, I would handle the value counting in getHandValue on the fly, to avoid the trouble with the aces and the duplication in Hand and Hit (you could also avoid this by just calling Hit twice in your constructor).

You do the same conversion from list to array in a couple of other places as well. Eg this:

public Card getCard(int cardnum) {
    Card[] aHand = new Card[]{};
    aHand = hand.toArray(aHand);
    return aHand[cardnum-1];
}

could be this:

public Card getCard(int cardnum) {
    return hand.get(cardnum);
}

Same in toString, hasBlackJack, hasBusted, etc.

Naming

  • your naming isn't always consistent. Eg getNewHand returns nothing, while getHand returns a hand. getNewHand should probably be something like dealHand.
  • choiceIsYes retrieves user input, while isyesorno does not. I would use the getX naming pattern you used for the other methods here.
  • always use camelCase (see eg ishitorstand).
  • again, methods should start with a lower-case character, so they are not confused with classes/constructors.

Misc

  • in drawCard you do not check if there is still a card left, which will lead to a nullpointer exception when there aren't.
  • you still have your shuffle method which can be replaced by Collections.shuffle(deck);.
\$\endgroup\$
  • \$\begingroup\$ Thank you very much. I will definitely clean up the main method and fix all the method and variable names. You're right- i do not really know how to handle lists on their own very well. \$\endgroup\$ – Jared Jun 5 '15 at 16:10
  • \$\begingroup\$ I am pretty unfamiliar with this syntax: for (Card card : hand). I also didn't know how to do the Collections.shuffle thing but i will replace my shuffle method with it now. One other thing I am unfamiliar with that you used in your response is the action enums. I will look into those. Once again, thank you for the very detailed response. \$\endgroup\$ – Jared Jun 5 '15 at 16:16
  • \$\begingroup\$ @Jared enums are basically classes light (action enums aren't a thing, I just meant an enum called Action). for (Card card : hand) { // your code } is called an enhanced for loop. It is shorthand for for (int i = 0; i < hand.size(); i++) { Card card = hand.get(i); // your code } \$\endgroup\$ – tim Jun 5 '15 at 16:23
  • \$\begingroup\$ ahh. thank you very much for clarification and the link \$\endgroup\$ – Jared Jun 5 '15 at 16:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.