Skip to main content
4 of 4
replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/

Deck of cards implementation

Update: Simple Blackjack implementation

I was playing Blackjack in a phone app and decided to try to do the game in Java, using the console for a start. So far I'd like to review the deck of cards implementation. I decided to use an OOP approach with the classes Value, Suit, Card and Deck.

First of all, I'd like to get some feedback and pieces of advice about how I decided to structure my code. Is there anything wrong? Should something be done differently?

import java.util.Stack;
import java.util.Random;
import java.util.Collections;

public class Blackjack {

    public static String capitalizeFully(String str) {
        String s = new String();

        for (int i = 1; i < str.length(); i++) {
            s += Character.toLowerCase(str.charAt(i));
        }

        return Character.toUpperCase(str.charAt(0)) + s;
    }

    public static class Value {

        private int value;
        private static final String[] string_values = {
            "Ace",
            "Two",
            "Three",
            "Four",
            "Five",
            "Six",
            "Seven",
            "Eight",
            "Nine",
            "Ten",
            "Jack",
            "Queen",
            "King"
        };

        public Value(int value) throws IllegalArgumentException {
            if (value < 1 || value > 13) {
                throw new IllegalArgumentException("Invalid card value (must be between 1 and 13).");
            }
            this.value = value;
        }

        public Value(String value) throws IllegalArgumentException {
            int i = 0;
            String val = capitalizeFully(value);

            while (i < string_values.length && !val.equals(string_values[i])) {
                i++;
            }

            if (i == string_values.length) {
                throw new IllegalArgumentException("Invalid card value.");
            } else {
                this.value = i + 1;
            }
        }

        public String toString() {
            return string_values[value - 1];
        }
    }

    public static class Suit {

        private String name;
        private static final String[] string_names = {
            "Hearts",
            "Diamonds",
            "Clubs",
            "Spades"
        };

        public Suit(String name) throws IllegalArgumentException {
            int i = 0;
            String n = capitalizeFully(name);

            while (i < string_names.length && !n.equals(string_names[i])) {
                i++;
            }

            if (i == string_names.length) {
                throw new IllegalArgumentException("Invalid suit name.");
            } else {
                this.name = n;
            }
        }

        public String toString() {
            return name;
        }
    }

    public static class Card {

        private Value value;
        private Suit suit;

        public Card(Value value, Suit suit) {
            this.value = value;
            this.suit = suit;
        }

        public Card(int value, Suit suit) {
            this.value = new Value(value);
            this.suit = suit;
        }

        public Card(String value, Suit suit) {
            this.value = new Value(value);
            this.suit = suit;
        }

        public Card(Value value, String suit) {
            this.value = value;
            this.suit = new Suit(suit);
        }

        public Card(int value, String suit) {
            this.value = new Value(value);
            this.suit = new Suit(suit);
        }

        public Card(String value, String suit) {
            this.value = new Value(value);
            this.suit = new Suit(suit);
        }

        public String toString() {
            String str = value + " of " + suit;
            return str;
        }
    }

    public static class Deck {

        private Stack<Card> deck;
        private static final int number = 52;

        public Deck() {
            deck = new Stack<Card>();
            Suit hearts, diamonds, clubs, spades;

            hearts = new Suit("hearts");
            diamonds = new Suit("diamonds");
            clubs = new Suit("clubs");
            spades = new Suit("spades");

            Suit[] suits = { hearts, diamonds, clubs, spades };

            for (int i = 0; i < suits.length; i++) {
                for (int j = 1; j <= 13; j++) {
                    deck.push(new Card(j, suits[i]));
                }
            }
        }

        public void shuffle() {
            long seed = System.nanoTime();
            Collections.shuffle(deck, new Random(seed));
        }

        public void add(Card card) {
            deck.push(card);
        }

        public Card draw() {
            return deck.pop();
        } 

        public String toString() {
            String str = new String();
            for (int i = 0; i < deck.size(); i++) {
                str += deck.get(i) + "\n";
            }
            return str;
        }
    }

    public static <T> void p(T output) {
        System.out.println(output);
    }

    public static void main(String[] args) {
        
        Deck deck = new Deck();
        deck.shuffle();
        p(deck);
    }
}

However, this is an implementation for just the 52-card standard deck. How about different decks, with different suits and a different range of values? I thought maybe it'd be a good idea that instead of hardcoding these attributes, I could make an alternative implementation where the user can define his/her own set of suits and range of values, so the deck is constructed given these set of choices.

For example:

Value[] values = { new Value("As", 1), new Value("Dos", 2), ..., new Value("Rey", 12) };
Suit[] suits = { new Suit("Oros"), new Suit("Sotas"), new Suit("Espadas"), new Suit("Bastos") };

Deck spanish_deck = new Deck(suits, values);

Does this second alternative make sense? Is it a good approach?

Update: Simple Blackjack implementation

dabadaba
  • 341
  • 4
  • 13