7
\$\begingroup\$

So this is a blackjack game, any feedback or tips on what I should remove from the code that is not needed is very appreciated.

Note: some of the names of classes or variables are in Swedish but it should not interfere with understanding the code I think.

Blackjack.java

import java.util.Scanner;

class Card {
    private final Face face;

    private final Suit suit;

    public Card(Face face, Suit suit) {
        this.face = face;
        this.suit = suit;
    }

    public Face getFace() {
        return face;
    }
    public Suit getSuit() {
        return suit;
    }

    @Override
    public String toString() {
        return face + " of " + suit;
    }
}

enum Face {
    Ace(11), Deuce(2), Three(3), Four(4), Five(5), Six(6), Seven(7), Eight(8), Nine(9), Ten(10), Jack(10), Queen(10), King(10);

    private final int value;

    private Face(int value) {
        this.value = value;
    }
    
    public int getValue() {
        return value;
    }
}

enum Suit {
    hearts, spades, diamonds, clubs;
}

public class BlackJack {
    public static void main(String[] args) {

        int wins = 0;
        int losses = 0;

        Scanner scanner = new Scanner(System.in);
        String input;
        
        //Clear Terminal from file paths
        System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");
        
        //Start loop
        do {

            //Clear Terminal from last game
            System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");System.out.println(" ");

            //Create players, shuffle deck and turn gameOver off
            Player player = new Player("You");
            Player dealer = new Player("Dealer");
            Deck deck = new Deck();
            deck.shuffle();
            boolean gameOver = false;

            //Get cards for player
            player.addCard(deck.draw());
            player.addCard(deck.draw());
            System.out.print(player.getHandAsString(false));
            System.out.println("Total: " + player.getHandSum());
            System.out.println("");System.out.println("");

            //Get cards for dealer
            dealer.addCard(deck.draw());
            dealer.addCard(deck.draw());

            

            //Player turn
            do {
                if (player.getHandSum() == 21) {
                    System.out.println("Super lucky Blackjack! You win.");
                    wins = wins + 1;
                    gameOver = true;
                    break;
                }
                if (player.getHandSum() > 21) {
                    System.out.println("Super unlucky! You lost.");
                    losses = losses + 1;
                    gameOver = true;
                    break;
                }

                System.out.println("");System.out.println("");
                System.out.println("Draw or stay?");
                do {
                    input = scanner.nextLine();
                } while (!input.equalsIgnoreCase("Draw") && !input.equalsIgnoreCase("Stay"));

                //Draw
                if (input.equalsIgnoreCase("Draw")) {
                    player.addCard(deck.draw());
                    System.out.println("");
                    System.out.print(player.getHandAsString(false));
                    System.out.println("Total: " + player.getHandSum());
                    System.out.println("");System.out.println("");
                    if (player.getHandSum() == 21) {
                        System.out.println("Blackjack! You win.");
                        wins = wins + 1;
                        gameOver = true;
                    }
                    if (player.getHandSum() > 21) {
                        System.out.println("You busted with " + player.getHandSum() + " in your hand. Dealer wins!");
                        losses = losses + 1;
                        gameOver = true;
                    }
                }
                //Stay
                if (input.equalsIgnoreCase("stay")) {
                    System.out.println("You have chosen to stay. Your hand: " + player.getHandSum());
                }
            } while (input.equalsIgnoreCase("Draw") && !gameOver);

            //Dealer turn
            if (!gameOver) {
                System.out.println("");System.out.println("");System.out.println("");System.out.println("");System.out.println("");
                System.out.println("________________________________________________________________________");
                System.out.println("Dealers turn");
                System.out.println("________________________________________________________________________");
                
                System.out.println("");
                System.out.print(dealer.getHandAsString(false));
                
                System.out.println(dealer.getHandSum());
                System.out.println("");System.out.println(""); 

                if (dealer.getHandSum() == 21) {
                    System.out.println("Blackjack! Dealer won.");
                    losses = losses + 1;
                    gameOver = true;
                }
            }
            while (!gameOver) {
                if (dealer.getHandSum() <= 17) {
                    //Draw card
                    dealer.addCard(deck.draw());
                    System.out.println(dealer.getVem() + " drew another card");
                    System.out.println("");
                    System.out.print(dealer.getHandAsString(false));
                    System.out.println(dealer.getHandSum());
                    System.out.println("");System.out.println(""); 
                    
                    if (dealer.getHandSum() == 17) {
                        if (player.getHandSum() == 17) {
                            System.out.println("Dealer won.");
                            losses = losses + 1;
                            gameOver = true;
                        }
                    }

                    if (dealer.getHandSum() == 18) {
                        if (player.getHandSum() == 18) {
                            System.out.println("Dealer won.");
                            losses = losses + 1;
                            gameOver = true;
                        }
                    }

                    if (dealer.getHandSum() == 19) {
                        if (player.getHandSum() == 19) {
                            System.out.println("Dealer won.");
                            losses = losses + 1;
                            gameOver = true;
                        }
                    }
                    
                    if (dealer.getHandSum() == 20) {
                        if (player.getHandSum() == 20) {
                            System.out.println("It's a draw!");
                            gameOver = true;
                        }
                    }

                    if (dealer.getHandSum() == 21) {
                        System.out.println("Blackjack! Dealer won.");
                        losses = losses + 1;
                        gameOver = true;
                    }
                    if (dealer.getHandSum() > 21) {
                        System.out.println("Dealer busted with " + dealer.getHandSum() + " in their hand. You win!");
                        wins = wins + 1;
                        gameOver = true;
                    }

                } else {
                    //Stay
                    System.out.println("Dealer chose to stay!");
                    System.out.println("");
                    int totalDealerSum = dealer.getHandSum();
                    int totalPlayerSum = player.getHandSum();

                    if (totalDealerSum > totalPlayerSum) {
                        System.out.println("Both players decided to stay. The Dealer won with a total of " + totalDealerSum + " in their hand.");
                        losses = losses + 1;
                    } else {
                        System.out.println("Both players decided to stay. You win with a total of " + totalPlayerSum + " in your hand.");
                        wins = wins + 1;
                    }
                    gameOver = true;
                }
            }

            //New game? And Score
            System.out.println("");System.out.println("");System.out.println("");
            
            if(wins==1 && losses==0){
                System.out.println("You have won " + wins + " time and lost " + losses + " times.");
            }
            if(wins==0 && losses==1){
                System.out.println("You have won " + wins + " times and lost " + losses + " time.");
            }
            
            if(wins>1 && losses>1){
                System.out.println("You have won " + wins + " times and lost " + losses + " times.");
            }
            if(wins==0 && losses>1){
                System.out.println("You have won " + wins + " times and lost " + losses + " times.");
            }
            if(wins>1 && losses==0){
                System.out.println("You have won " + wins + " times and lost " + losses + " times.");
            }

            if(wins>1 && losses==1){
                System.out.println("You have won " + wins + " times and lost " + losses + " time.");
            }
            if(wins==1 && losses==1){
                System.out.println("You have won " + wins + " time and lost " + losses + " time.");
            }
            if(wins==1 && losses>1){
                System.out.println("You have won " + wins + " time and lost " + losses + " times.");
            }

            System.out.println("");
            System.out.println("Play again?");
            do {
                input = scanner.nextLine();
            } while (!input.equalsIgnoreCase("Yes") && !input.equalsIgnoreCase("No"));
            

        } while (input.equalsIgnoreCase("Yes"));
        
        scanner.close();
    }
}

Deck.java

import java.util.ArrayList;
import java.util.Collections;

public class Deck {

    private final ArrayList<Card> cards;

    public Deck() {
        cards = new ArrayList<Card>();
        // populate deck with cards
        for (Suit suit : Suit.values()) {
            for (Face face : Face.values()) {
                cards.add(new Card(face, suit));
            }
        }
    }

    public void shuffle() {
        Collections.shuffle(cards);
    }

    public Card draw() {
        return cards.remove(0);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < cards.size(); i++) {
            sb.append(i + 1);
            sb.append('/');
            sb.append(cards.size());
            sb.append(' ');
            sb.append(cards.get(i));
            sb.append('\n');
        }
        return sb.toString();
    }
}

Player.java

import java.util.ArrayList;

//Player class
public class Player {

    private final String vem;

    private final ArrayList<Card> hand;

    public Player(String vem) {
        this.vem = vem;
        this.hand = new ArrayList<Card>();
    }

    public String getVem() {
        return vem;
    }

    public void addCard(Card card) {
        hand.add(card);
    }

    public int getHandSum() {
        int handSum = 0;
        for (Card card : hand) {
            handSum += card.getFace().getValue();
        }
        return handSum;
    }

    public String getHandAsString(boolean b) {
        StringBuilder sb = new StringBuilder();
        sb.append(vem); //'s'\
        sb.append('\n');
        for (int i = 0; i < hand.size(); i++) {
            if (i == 0 && b) {
                sb.append('\n');
            } else {
                sb.append(hand.get(i));
                sb.append('\n');
            }
        }
        return sb.toString();
    }
}

Thank you for any help, tips or feedback!

\$\endgroup\$
5
  • \$\begingroup\$ Welcome to CodeReview@SE. Please (re)visit How do I ask a Good Question? to find why at least one used wants to change the title of this question. \$\endgroup\$ – greybeard Jan 20 at 21:43
  • \$\begingroup\$ The Main function in your Blackjack class has a lot going on. You should think about how you can break down what's going on the the loops into smaller functions. You could also add some additional objects to help with that, for example one to manage and store the Win & Loss counts could help keep that part organised. \$\endgroup\$ – Amicable Jan 20 at 22:06
  • \$\begingroup\$ It's necessary to say that enum items should be in upper snake case. Example: Ace should be ACE or hearts should be HEARTS, the reason why is because the items inside an enumeration are constants. Btw nice project. \$\endgroup\$ – Miguel Avila Jan 21 at 3:45
  • \$\begingroup\$ Once you have an answer please don't edit the question. Please see What should I do after after someone answers?. With 4 up votes on this question there isn't really a good reason to delete it. \$\endgroup\$ – pacmaninbw Jan 21 at 21:53
  • \$\begingroup\$ In the future if you want to delete your question, you should look to the Delete Link to the right of the Edit link. \$\endgroup\$ – pacmaninbw Jan 21 at 21:57
7
\$\begingroup\$

Nice project, find below my suggestions.

Clearing the terminal

There are more than 20 System.out.println(" ") in one line and then again a few lines below. Create a method to clear the terminal and shorten the code with a for-loop. There are also other ways to clear the terminal.

Duplicated code

  • Requesting the input from the user is duplicated more than once. You can create a method for that which accepts a custom question.
  • Boolean operators: there are many if conditions that test only with ==. Make use of && and || in combination with <= and >= to reduce duplicated code.

Formatting with correct plurals

This part:

if(wins==1 && losses==0){
    System.out.println("You have won " + wins + " time and lost " + losses + " times.");
}
if(wins==0 && losses==1){
    System.out.println("You have won " + wins + " times and lost " + losses + " time.");
}

if(wins>1 && losses>1){
    System.out.println("You have won " + wins + " times and lost " + losses + " times.");
}
if(wins==0 && losses>1){
    System.out.println("You have won " + wins + " times and lost " + losses + " times.");
}
if(wins>1 && losses==0){
    System.out.println("You have won " + wins + " times and lost " + losses + " times.");
}

if(wins>1 && losses==1){
    System.out.println("You have won " + wins + " times and lost " + losses + " time.");
}
if(wins==1 && losses==1){
    System.out.println("You have won " + wins + " time and lost " + losses + " time.");
}
if(wins==1 && losses>1){
    System.out.println("You have won " + wins + " time and lost " + losses + " times.");
}

Can be shortened to:

String pluralWins = wins == 1 ? "" : "s";
String pluralLosses = losses == 1 ? "" : "s";
System.out.printf("You have won %d time%s and lost %d time%s.%n", wins, pluralWins, losses, pluralLosses);

Design

The main method seems to have a lot of responsibility. It includes:

  1. Requesting the input from the user
  2. Playing the game
  3. Updating the score
  4. Printing the output to the console

This makes BlackJack hard to:

  • Test: there is no easy way to unit test the game, only manually.
  • Extend: for example, adding a player.
  • Reuse: it's not easy to reuse BlackJack in another application where for example the user interacts via the network.

To improve it, part of step 2 can be moved into the BlackJack class. Ideally, there shouldn't be user interaction in the BlackJack class, only in the main. This is an idea:

main method
  initialize score
  while user wants to play
    create a new BlackJack object
    while !blackJack.isGameOver()
      play game
    update score

A BlackJack object represents one game, and its methods allow one to start and play the game.

In this way, the methods of BlackJack can be unit tested, and the class can be reused and extended more easily.

Naming

A more common name for face (in the class Card) is rank. The name face can be confused with face-up/down.

Performance

The method Player#getHandSum is called often and every time it calculates the sum iterating on all the cards. Consider to cache the sum and update it only when Player#addCard is called.

\$\endgroup\$

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.