Skip to main content
edited tags
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
Source Link
Nilzone-
  • 1.4k
  • 2
  • 15
  • 28

OOP implementation of BlackJack in Java

This code is not done, but still fully functional.

But, before I continue I'd really appreciate some input on the code-structure as is.

AbstractHand.java

package com.tn.deck;

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


public abstract class AbstractHand<T extends Suitable & Rankable> {
    protected List<T> hand = new ArrayList<>();

    public void drawCard(T o) {
        hand.add(o);
    }

    public void drawCards(T[] o) {
        hand.addAll(Arrays.asList(o));
    }

    public abstract void status();
    public abstract int calculateScore();
}

Deck.java

package com.tn.deck;


public interface Deck<T extends Suitable & Rankable> {
    T dealCard();
    T[] dealCards(int n);
    void shuffle();
}

Rankable.java

package com.tn.deck;


public interface Rankable<T extends Comparable<T>> {
    boolean isConsecutive(T other);
}

Suitable.java

package com.tn.deck;


public interface Suitable<T extends Comparable<T>> {
    boolean isSameSuit(T other);
}

Card.java

package com.tn.blackjack;

import com.tn.deck.Rankable;
import com.tn.deck.Suitable;



public class Card implements Suitable<Card>, Rankable<Card>, Comparable<Card> {
    private final Suit suit;
    private final Rank rank;

    Card(Suit suit, Rank rank) {
        this.suit = suit;
        this.rank = rank;
    }

    public Suit getSuit() {
        return suit;
    }

    public Rank getRank() {
        return rank;
    }

    public void print() {
        System.out.printf("%s%s ", suit.getIcon(), rank.getName());
    }

    @Override
    public boolean isConsecutive(Card other) {
        return 1 + rank.ordinal() == other.rank.ordinal() ||
                rank.ordinal() - 1 == other.rank.ordinal();
    }

    @Override
    public boolean isSameSuit(Card other) {
        return suit.equals(other.suit);
    }

    @Override
    public int compareTo(Card other) {
        if(rank.getValue() == other.getRank().getValue() &&
                suit.getIcon().equals(other.getSuit().getIcon())) {
            return 0;
        } else if(rank.getValue() < other.getRank().getValue()) {
            return -1;
        } else {
            return 1;
        }
    }
}

CardDeck.java

package com.tn.blackjack;

import com.tn.deck.Deck;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;


public class CardDeck implements Deck<Card> {
    private static final Random rand = new Random(System.nanoTime());
    private List<Card> deck;
    private List<Card> dealtCards;

    CardDeck(Suit[] suits, Rank[] ranks) {
        this.deck = initializeDeckWith(suits, ranks);
        this.dealtCards = new ArrayList<>();
        shuffle();
    }

    private List<Card> initializeDeckWith(Suit[] suits, Rank[] ranks) {
        List<Card> newDeck = new ArrayList<>();
        for(Suit suit : suits) {
            for(Rank rank : ranks) {
                newDeck.add(new Card(suit, rank));
            }
        }
        return newDeck;
    }

    @Override
    public Card dealCard() {
        if(deck.size() < 1) {
            throw new IllegalStateException("Deck is empty");
        }
        int index = rand.nextInt(deck.size());
        Card card = deck.get(rand.nextInt(index));
        deck.remove(index);
        dealtCards.add(card);

        return card;
    }

    @Override
    public Card[] dealCards(int n) {
        if(deck.size() < n) {
            throw new IllegalStateException("Not enough cards left in deck");
        }

        Card[] cardsToDeal = new Card[n];
        for(int i = 0; i < n; i++) {
            int index = rand.nextInt(deck.size());
            Card card = deck.get(index);
            deck.remove(index);
            cardsToDeal[i] = card;
            dealtCards.add(card);
        }
        return cardsToDeal;
    }

    @Override
    public void shuffle() {
        Collections.shuffle(deck);
    }
}

Dealer.java

package com.tn.blackjack;

import com.tn.deck.AbstractHand;


public class Dealer extends AbstractHand<Card> {
    private CardDeck deck;

    Dealer() {
        this.deck = new CardDeck(Suit.getSuits(), Rank.getRanks());
    }

    public void startInitialDealingOfCards(Player[] players) {
        for(Player player : players) {
            Card[] initialCards = deck.dealCards(2);
            player.drawCards(initialCards);
        }
        Card[] dealersInitialCards = deck.dealCards(2);
        drawCards(dealersInitialCards);
    }

    @Override
    public void status() {
        System.out.printf("%nThe Dealer, has the following hand:%n");
        hand.forEach(Card::print);
        System.out.printf("( score of %d )", calculateScore());
    }

    @Override
    public int calculateScore() {
        return hand.stream().mapToInt(card -> card.getRank().getValue()).sum();
    }
}

Player.java

package com.tn.blackjack;

import com.tn.deck.AbstractHand;


public class Player extends AbstractHand<Card> {
    private int id;

    Player(int id) {
        this.id = id;
    }

    @Override
    public void status() {
        System.out.printf("%nPlayer %d, has the following hand:%n", id);
        hand.forEach(Card::print);
        System.out.printf("( score of %d )", calculateScore());
    }

    @Override
    public int calculateScore() {
        return hand.stream().mapToInt(card -> card.getRank().getValue()).sum();
    }
}

Rank.java

package com.tn.blackjack;


public enum Rank {
    TWO("2", 2), THREE("3", 3), FOUR("4", 4), FIVE("5", 5),
    SIX("6", 6), SEVEN("7", 7), EIGHT("8", 8), NINE("9", 9), TEN("10", 10),
    JACK("J", 10), QUEEN("Q", 10), KING("K", 10), ACE("A", 11);

    private final String name;
    private final int value;

    Rank(String name, int value) {
        this.name = name;
        this.value = value;
    }

    public static Rank[] getRanks() {
        return new Rank[] {
                TWO, THREE, FOUR, FIVE,
                SIX, SEVEN, EIGHT, NINE, TEN,
                JACK, QUEEN, KING, ACE
        };
    }

    public String getName() {
        return name;
    }

    public int getValue() {
        return value;
    }
}

Suit.java

package com.tn.blackjack;


public enum Suit {
    SPADE("\u2660"),
    HEART("\u2665"),
    DIAMOND("\u2666"),
    CLUB("\u2663");

    private final String icon;

    Suit(String icon) {
        this.icon = icon;
    }

    public static Suit[] getSuits() {
        return new Suit[] { SPADE, HEART, DIAMOND, CLUB };
    }

    public String getIcon() {
        return icon;
    }
}

Game.java

package com.tn.blackjack;

import java.util.Arrays;


public class Game {
    private Dealer dealer;
    private Player[] players;

    public Game() {
        this.dealer = new Dealer();
        this.players = new Player[] {
                new Player(1),
                new Player(2)
        };
    }

    public void start() {
        dealer.startInitialDealingOfCards(players);
        dealer.status();
        Arrays.stream(players).forEach(Player::status);
    }
}