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!
1 Answer 1
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:
- Requesting the input from the user
- Playing the game
- Updating the score
- 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.
Explore related questions
See similar questions with these tags.
Ace
should beACE
orhearts
should beHEARTS
, the reason why is because the items inside an enumeration are constants. Btw nice project. \$\endgroup\$Delete
Link to the right of theEdit
link. \$\endgroup\$