Wednesday, April 17, 2013

Blackjack Refactored as Object Oriented Design

AP Computer Science Object Oriented Blackjack

AP Computer Science Object Oriented Blackjack

Introduction

Refactoring is a fancy name used in objected oriented programming for restructuring and redesigning code to make it more readable or more elegant or just easier to understand. In the case of the Blackjack Program example I purposely designed it to use very little object orientedness (if that's even a word). Now it's time to refactor the Blackjack code to take advantage of object oriented programming. I find the new code much more readable (hopefully you will as well). More importantly the new code structure will allow us to go beyond AP Computer Science constraints and turn this into a graphical card game. That will be the subject of another article.

What objects to make?

Blackjack object

The BlackJack object will be the place where the main routine resides. I used the style of object oriented programming I proposed in the previous "hello world". The main routine will instantiate a BlackJack object and call the 'run' method. All the program logic will be in the 'run' method. This may seem like a bit of overkill but what if you wanted to run a BlackJack server? Each player that logs in needs their own BlackJack game. Each game needs to run in a separate thread of execution (threading is a way of portioning off processor access so that objects do not have to wait for other objects to execute). While that may still seem like overkill if you pursue Computer Science as a major you will ultimately come across this 'pattern' of program structure. From my point of view this structure is easy to implement has no effect on performance is pure object oriented programming so why not.

PlayingCard object

When you grab a real deck of cards you will notice there are 52 objects with a back cover design and a face design. This is a natural object that we can model as an object in our program.

CardDeck object

The CardDeck object is the object model for a deck of cards. In computer terms the deck of cards is a 'container' for 'PlayingCard's.

Hand object

The Hand object is the object model of a set of cards. In the original program these were arrays with code for tracking the dealer hand and code for tracking the player hand. The Hand object greatly simplifies the code. Separate tracking is done by instantiating 2 'Hand' objects. A player 'Hand' and a dealer 'Hand'.

Unified Modeling Language

Many Computer Scientists are very poor artists. But sometimes a picture really is worth 1000 words. To standardize the drawing of object relationships and provide computer tools to assist the artistically challenge Unified Modeling Language was developed. The Object diagram is a box with the name of the Object (ie. Class) in the title of the box (located at the top of the box). Following the title are fields and methods listed below the title. Arrows can be drawn between the class objects to signify relationships and usage. You have probably seen some of these diagrams already while studying this topic.

The following represents the class objects created for the Blackjack program:

The above diagram represents the all the classes created to make the new BlackJack program. In the code that follows I have commented out the old code I used and tried to highlight the new code. It makes the code a little longer but it will give you an idea of the refactoring process.

The only thing that didn't fit well into the model is the scoring of the hands. This needs a little work. Even though this has been about BlackJack you would like to reuse the classes for other card games. Hands would be scored differently for different games. There is an object oriented way to handle this but it is a little beyond the scope of this article and level of programming. For now it's hard coded into the PlayingCard object so it's only good for BlackJack and you would have to adapt that class for a different type of game.

The Code

BlackJack Class Code

/*
 * BlackJack.java - main class that performs the black jack game
 */
package BlackJack;

import java.util.Scanner;

/**
 *
 * @author Nasty Old Dog
 */
public class BlackJack {

    int card_score[] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};
    CardDeck card;
    Hand player;
    Hand dealer;

    public BlackJack()
    {
        this.card = new CardDeck();
    }

    public void run() {
    //    CardDeck card = new CardDeck();

        this.card.display();
        this.card.shuffle();
        this.card.display();
        // This is the old code to test hands    
    /*
        card.dealPlayer();
        card.dealDealer();
        card.dealPlayer();
        card.dealDealer();

        card.displayHands();
        System.out.println("Player score = " + card.scoreHand(card.playerHand, card.pcards));
        System.out.println("Dealer score = " + card.scoreHand(card.dealerHand, card.dcards));
        // Reset hands
        card.resetHands();
         */

        // Now I just need to create the hand objects
        this.player = new Hand("Player Hand");
        this.dealer = new Hand("Dealer Hand");

        this.player.deal(card);
        this.dealer.deal(card);
        this.player.deal(card);
        this.dealer.deal(card);

        this.player.display();
        this.dealer.display();
        System.out.println("Player score = " + player.scoreHand());
        System.out.println("Dealer score = " + dealer.scoreHand());

        // Now to reset hands just create new ones
        this.player = new Hand("Player Hand");
        this.dealer = new Hand("Dealer Hand");

        String user_inp = " ";
        int bankroll = 1000;
        int bet = 0;           // if the user bets 0 quit the game loop

        // Need a Scanner for user input
        Scanner uinp = new Scanner(System.in);
        // game loop just loop forever
        while (true) {
            // Tell the user the amount of the bank roll 
            System.out.println("Bankroll = " + bankroll);
            // get bet
            System.out.print("Enter the amount you want to bet: ");
//            user_inp = uinp.nextLine();
//            bet = Integer.getInteger(user_inp).intValue();
            bet = uinp.nextInt();
            uinp.nextLine();
            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            this.card.shuffle();
            // Old way
            /*
            card.dealPlayer();
            card.dealDealer();
            card.dealPlayer();
            card.dealDealer();

            card.displayHands();
             */
            this.player.deal(card);
            this.dealer.deal(card);
            this.player.deal(card);
            this.dealer.deal(card);

            this.player.display();
            this.dealer.display();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;
            // Old:int scr = scr = card.scoreHand(card.playerHand, card.pcards);
            // New:
            int scr = this.player.scoreHand();
            while (scr != 21) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                String firstch = user_inp.substring(0, 1);
                if (firstch.equals("H") || firstch.equals("h")) {
                    // Old
                    /*
                    card.dealPlayer();
                    card.displayHands();
                    scr = card.scoreHand(card.playerHand, card.pcards);
                     * 
                     */
                    // New:
                    this.player.deal(card);
                    this.player.display();
                    scr = this.player.scoreHand();
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }
                    // Check if player at 21 and stop asking questions
                    if (scr == 21) {
                        break;
                    }

                } else if (firstch.equals("S") || firstch.equals("s")) {
                    break;
                } else {
                    // If we end up here it's because of a typo or wiseguy
                    // print error response and go back to looping
                    System.out.println("I don't understand: " + user_inp);
                }
            }
            if (bust) {
                System.out.println("BUST!! LOSER!!");
                // deduct bet from bankroll
                bankroll -= bet;
                // reset hands for next game
                // Old: card.resetHands();
                // New:
                this.player = new Hand("Player Hand");
                this.dealer = new Hand("Dealer Hand");

                continue; // go back to top of main loop and start new game
            }
            // Manually control dealer hand the same way
            // We will swap this out for code that will run the dealer rules 
            // automatically
            // Old: int dscr = card.scoreHand(card.dealerHand, card.dcards);
            // New:
            int dscr = dealer.scoreHand();
            while (true) {
                if (dscr < 17) {
                    System.out.println("Dealer Hand 16 or less: Must HIT");
                    // Old:
                    /*
                    card.dealDealer();
                    card.displayHands();
                    dscr = card.scoreHand(card.dealerHand, card.dcards);
                     * 
                     */
                    this.dealer.deal(card);
                    this.player.display();
                    this.dealer.display();
                    dscr = dealer.scoreHand();
                } else {
                    break;
                }
            }

            // Code to score the game and settle the bet will go here
            // For now assume we win every time
            System.out.println("Player score: " + scr + "   Dealer: " + dscr);
            if (scr > dscr) {
                System.out.println("You Win!!!");
                bankroll = bankroll + bet;
            } else if (dscr > 21) {
                System.out.println("You Win!! Dealer has BUSTED");
                bankroll += bet;
            } else if (scr == dscr) {
                System.out.println("PUSH");
            } else {
                System.out.println("LOSER!!!");
                bankroll -= bet;
            }
            // reset hands to play a new game
            this.player = new Hand("Player Hand");
            this.dealer = new Hand("Dealer Hand");
//Old:  card.resetHands();

        }
    }

    public static void main(String[] args) {
        BlackJack game = new BlackJack();

        game.run();
    }
}

CardDeck Class Code

/*
 * CardDeck.java - Greatly simplified version of a deck of cards. Cards are
 * represented internally as a number from 0 - 51 for a total of 52 cards
 * The class just deals with standard operations you would do with a deck:
 *  - deal
 *  - shuffle
 *  - display
 *  - a constructor to initialize the deck
 */
package BlackJack;

/**
 *
 * @author Nasty Old Dog
 */

public class CardDeck {

    PlayingCard deck[] = new PlayingCard[52];
    int deckidx = 0; // the location of the next card to be dealt

    public CardDeck() {
        for (int i = 0; i < 52; i++) {
            deck[i] = new PlayingCard(i);
        }
    }

    void shuffle() {
        int rindex;
        PlayingCard swap;

        for (int i = 0; i < 52; i++) {
            // each time through the loop there are less numbers to randomize
            // 52 - i to be exact. But then everything from 0 to i-1 has already
            // been selected at random so add i to the random number to get the
            // appropriate index
            rindex = (int) ((Math.random() * ((double) (52 - i))) + i);
            swap = deck[i];
            deck[i] = deck[rindex];
            deck[rindex] = swap;
        }
    }

    void display() {
        int card_val;
        int card_suit;
        for (int i = 0; i < 52; i++) {
            //card_val = deck[i]%13;
            //card_suit = deck[i]%4;
            System.out.print(this.deck[i].getCardText() + " ");
        }
        System.out.println();
    }

    //Old
    /*
    public PlayingCard deal() {
        if (this.deckidx < 52) {
            return this.deck[this.deckidx++]; // return the top card and increment to the next card
        } else {
            return this.deck[this.deckidx - 1];
        }
    }
    */
    //New: when we get to the end of the deck lets just reshuffle and keep
    // going
    public PlayingCard deal() {
        if (this.deckidx >= 52) {
            deckidx = 0;
            this.shuffle();
        }            
        return this.deck[this.deckidx++];
    }   
}

Hand Class Code

/*
 * Hand.java - a class that models a hand of cards as one would expect in 
 * any card game. For the purposes of the computer handling things the
 * following methods are implemented
 *  - display
 *  - sortHand (private)
 *  - scoreHand
 * 
 */
package BlackJack;

import java.util.ArrayList;

/**
 *
 * @author Nasty Old Dog
 */
public class Hand {
    ArrayList<PlayingCard> cards = new ArrayList<PlayingCard>();
    ArrayList<PlayingCard> sorted = new ArrayList<PlayingCard>();

    String displayName = "change in constructor";

    // Used to need the following in CardDeck to track this
    /*
    int playerHand[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int dealerHand[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
    int dcards = 0; // the number of cards in the dealer hand so far
    int pcards = 0; // the number of cards in the player hand so far
     */

    public Hand()
    {
        this.displayName = "Hand";
    }

    public Hand(String displayName)
    {
        this.displayName = displayName;
    }

    public void deal(CardDeck deck)
    {
       this.cards.add(deck.deal());
    }

    // All the commented code was needed because we did not have a 
    // good object model for how to handle Hands
    /*
    public void dealPlayer() {
        this.playerHand[pcards] = deal();
        this.pcards++;
    }

    public void dealDealer() {
        this.dealerHand[dcards] = deal();
        this.dcards++;
    }


    public void resetHands() {
        for (int i = 0; i < playerHand.length; i++) {
            playerHand[i] = 0;
            dealerHand[i] = 0;
        }
        dcards = 0;
        pcards = 0;
    }
    */
    private void sortHand() {
        // sort hand make Aces 11 for sorting purposes
        // Use the insertion sort code and modify it by using the card_value
        // method as the way to sort

        this.sorted = (ArrayList<PlayingCard>) this.cards.clone();

        // The clone statement does a deep copy of the array list
        // Just to prove it I print out the sorted field individually
        // If you had to copy individually (like for the AP) the code would
        // follow the structure below
        System.out.print("Cloned: ");
        for (PlayingCard i : this.sorted)
            System.out.print(i.getCardText() + " ");
        System.out.print("Size: " + this.sorted.size());
        System.out.println();
        PlayingCard tmp;
        for (int i = 1; i < this.sorted.size(); i++) {
            for (int j = i;
                    j > 0
                    && this.sorted.get(j).card_value() < this.sorted.get(j-1).card_value();
                    j--) {
                // swap values

                tmp = this.sorted.get(j);
                this.sorted.set(j, this.sorted.get(j - 1));
                this.sorted.set(j - 1, tmp);
            }
        }
    }

    public int scoreHand() {
        // No longer need this it is handled by keeping a sorted field 
        /*
        int tmp_hnd[] = new int[size];
        // Copy hand into a new array to play with without disturbing the
        // original hand
        for (int i = 0; i < size; i++) {
            tmp_hnd[i] = hnd[i];
        }
         * 
         */
        this.sortHand();
        int score = 0;
        for (PlayingCard i : this.sorted) {
            // Need to test each card to see if it is an ACE
            // If an ACE and score is < 11 use 11 as ACE value otherwise use 1
            // I haven't done a proof but I believe that checking the score
            // less than 11 is sufficient to handle ACEs and you won't bust a
            // hand incorrectly
            if (i.card_value() == 11) {
                // Processing ACE
                if (score >= 11) {
                    // ACEs must all be 1
                    score += 1;
                }
                else {
                    score += 11;
                }
            }
            else {
                // Just add card_value it's not an ACE
                score += i.card_value();
            }
        }
        return score;
    }

    public void display() {
        System.out.println(this.displayName);
        for (PlayingCard i : cards) {
            System.out.print(i.getCardText() + " ");
        // The commented code was necesary because hands were not objects
        // Now a hand knows how to display itself
        /*
        System.out.println("Player Hand  ");
        for (int i = 0; i < this.pcards; i++) {
            System.out.print(this.getCardText(this.playerHand[i]) + " ");
        }
        System.out.println();
        System.out.println("Dealer Hand:  ");
        for (int j = 0; j < this.dcards; j++) {
            System.out.print(this.getCardText(this.dealerHand[j]) + " ");
        }

        */
        }
        System.out.println();
    }

}

PlayingCard Class Code

/*
 * PlayingCard.java - Playing card class for BlackJack
 */
package BlackJack;

/**
 *
 * @author Nasty Old Dog
 */
public class PlayingCard {
    private int cardno;
    private int card_score[] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};
    //private int card_score[] = {1,2,3,4,5,6,7,8,9,10,10,10,10};
    private String faceVal = "A23456789TJQK";
    private String suit = "HDSC";

    public PlayingCard(int cardno)
    {
        this.cardno = cardno;
    }

    public PlayingCard(int cardno, int[] card_score)
    {
        this.cardno = cardno;
        this.card_score = card_score;
    }

    public int card_value()
    {
        return card_score[cardno % 13];
    }

    public String getCardText() {
        int card_val = this.cardno % 13;
        int card_suit = this.cardno % 4;
        return this.faceVal.substring(card_val, card_val + 1)
                + this.suit.substring(card_suit, card_suit + 1);
    }

}

Output 1

run:
AH 2D 3S 4C 5H 6D 7S 8C 9H TD JS QC KH AD 2S 3C 4H 5D 6S 7C 8H 9D TS JC QH KD AS 2C 3H 4D 5S 6C 7H 8D 9S TC JH QD KS AC 2H 3D 4S 5C 6H 7D 8S 9C TH JD QS KC 
8H AC AH 3D KC 2H 5C KH 7S 5H 7H 9C 2D 8C KD JD 5D 7C 6C 3S QD AS 4S 8S 3H 4C AD 6D 5S TS 9H 6H JS 6S JC 9D 8D TD 2C JH 4D 4H TH 7D QS QC QH TC 2S 9S KS 3C 
Player Hand
8H AH 
Dealer Hand
AC 3D 
Cloned: 8H AH Size: 2
Player score = 19
Cloned: AC 3D Size: 2
Dealer score = 14
Bankroll = 1000
Enter the amount you want to bet: 100
Player Hand
TS 8H 
Dealer Hand
9C KH 
Cloned: TS 8H Size: 2
Player Hand hit or stand? h
Player Hand
TS 8H 5D 
Cloned: TS 8H 5D Size: 3
BUST!! LOSER!!
Bankroll = 900
Enter the amount you want to bet: 100
Player Hand
5D TC 
Dealer Hand
7D AS 
Cloned: 5D TC Size: 2
Player Hand hit or stand? h
Player Hand
5D TC QS 
Cloned: 5D TC QS Size: 3
BUST!! LOSER!!
Bankroll = 800
Enter the amount you want to bet: 0
BUILD SUCCESSFUL (total time: 33 minutes 27 seconds)

Conclusion

Four classes:

  • Main class BlackJack
  • 2 that the main Class BlackJack uses
    • CardDeck
    • Hand
  • 1 class PlayingCards that is used by Hand and CardDeck

That's all it takes to make a card game. The full code is reproduced below sans the comments from the old code. This should give you a better feel for just what the Object Oriented style is doing for us.

References

UML Diagram made with PlantUML under emacs editor

  1. Plant UML website http://plantuml.sourceforge.net

Full Code sans comments

/*
 * BlackJack.java - main class that performs the black jack game
 */
package BlackJack;

import java.util.Scanner;

/**
 *
 * @author Nasty Old Dog
 */
public class BlackJack {

    int card_score[] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};
    CardDeck card;
    Hand player;
    Hand dealer;

    public BlackJack()
    {
        this.card = new CardDeck();
    }

    public void run() {

        this.card.display();
        this.card.shuffle();
        this.card.display();

        // Now I just need to create the hand objects
        this.player = new Hand("Player Hand");
        this.dealer = new Hand("Dealer Hand");

        this.player.deal(card);
        this.dealer.deal(card);
        this.player.deal(card);
        this.dealer.deal(card);

        this.player.display();
        this.dealer.display();
        System.out.println("Player score = " + player.scoreHand());
        System.out.println("Dealer score = " + dealer.scoreHand());

        // Now to reset hands just create new ones
        this.player = new Hand("Player Hand");
        this.dealer = new Hand("Dealer Hand");

        String user_inp = " ";
        int bankroll = 1000;
        int bet = 0;           // if the user bets 0 quit the game loop

        // Need a Scanner for user input
        Scanner uinp = new Scanner(System.in);
        // game loop just loop forever
        while (true) {
            // Tell the user the amount of the bank roll 
            System.out.println("Bankroll = " + bankroll);
            // get bet
            System.out.print("Enter the amount you want to bet: ");

            bet = uinp.nextInt();
            uinp.nextLine();

            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            this.card.shuffle();

            this.player.deal(card);
            this.dealer.deal(card);
            this.player.deal(card);
            this.dealer.deal(card);

            this.player.display();
            this.dealer.display();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;

            int scr = this.player.scoreHand();
            while (scr != 21) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                String firstch = user_inp.substring(0, 1);
                if (firstch.equals("H") || firstch.equals("h")) {
                    this.player.deal(card);
                    this.player.display();
                    scr = this.player.scoreHand();
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }
                    // Check if player at 21 and stop asking questions
                    if (scr == 21) {
                        break;
                    }

                } else if (firstch.equals("S") || firstch.equals("s")) {
                    break;
                } else {
                    // If we end up here it's because of a typo or wiseguy
                    // print error response and go back to looping
                    System.out.println("I don't understand: " + user_inp);
                }
            }
            if (bust) {
                System.out.println("BUST!! LOSER!!");
                // deduct bet from bankroll
                bankroll -= bet;

                this.player = new Hand("Player Hand");
                this.dealer = new Hand("Dealer Hand");

                continue; // go back to top of main loop and start new game
            }

            int dscr = dealer.scoreHand();
            while (true) {
                if (dscr < 17) {
                    System.out.println("Dealer Hand 16 or less: Must HIT");
                    this.dealer.deal(card);
                    this.player.display();
                    this.dealer.display();
                    dscr = dealer.scoreHand();
                } else {
                    break;
                }
            }

            // Code to score the game and settle the bet will go here
            // For now assume we win every time
            System.out.println("Player score: " + scr + "   Dealer: " + dscr);
            if (scr > dscr) {
                System.out.println("You Win!!!");
                bankroll = bankroll + bet;
            } else if (dscr > 21) {
                System.out.println("You Win!! Dealer has BUSTED");
                bankroll += bet;
            } else if (scr == dscr) {
                System.out.println("PUSH");
            } else {
                System.out.println("LOSER!!!");
                bankroll -= bet;
            }
            // reset hands to play a new game
            this.player = new Hand("Player Hand");
            this.dealer = new Hand("Dealer Hand");


        }
    }

    public static void main(String[] args) {
        BlackJack game = new BlackJack();

        game.run();
    }
}

// -----------------------------------------------------
/*
 * CardDeck.java - Greatly simplified version of a deck of cards. Cards are
 * represented internally as a number from 0 - 51 for a total of 52 cards
 * The class just deals with standard operations you would do with a deck:
 *  - deal
 *  - shuffle
 *  - display
 *  - a constructor to initialize the deck
 */
package BlackJack;

/**
 *
 * @author Nasty Old Dog
 */

public class CardDeck {

    PlayingCard deck[] = new PlayingCard[52];
    int deckidx = 0; // the location of the next card to be dealt

    public CardDeck() {
        for (int i = 0; i < 52; i++) {
            deck[i] = new PlayingCard(i);
        }
    }

    void shuffle() {
        int rindex;
        PlayingCard swap;

        for (int i = 0; i < 52; i++) {
            // each time through the loop there are less numbers to randomize
            // 52 - i to be exact. But then everything from 0 to i-1 has already
            // been selected at random so add i to the random number to get the
            // appropriate index
            rindex = (int) ((Math.random() * ((double) (52 - i))) + i);
            swap = deck[i];
            deck[i] = deck[rindex];
            deck[rindex] = swap;
        }
    }

    void display() {
        int card_val;
        int card_suit;
        for (int i = 0; i < 52; i++) {
            System.out.print(this.deck[i].getCardText() + " ");
        }
        System.out.println();
    }

    public PlayingCard deal() {
        if (this.deckidx >= 52) {
            deckidx = 0;
            this.shuffle();
        }            
        return this.deck[this.deckidx++];
    }   
}

//-------------------------------------------------

/*
 * Hand.java - a class that models a hand of cards as one would expect in 
 * any card game. For the purposes of the computer handling things the
 * following methods are implemented
 *  - display
 *  - sortHand (private)
 *  - scoreHand
 * 
 */
package BlackJack;

import java.util.ArrayList;

/**
 *
 * @author Nasty Old Dog
 */
public class Hand {
    ArrayList<PlayingCard> cards = new ArrayList<PlayingCard>();
    ArrayList<PlayingCard> sorted = new ArrayList<PlayingCard>();

    String displayName = "change in constructor";

    public Hand()
    {
        this.displayName = "Hand";
    }

    public Hand(String displayName)
    {
        this.displayName = displayName;
    }

    public void deal(CardDeck deck)
    {
       this.cards.add(deck.deal());
    }

    private void sortHand() {
        // sort hand make Aces 11 for sorting purposes
        // Use the insertion sort code and modify it by using the card_value
        // method as the way to sort

        this.sorted = (ArrayList<PlayingCard>) this.cards.clone();

        // The clone statement does a deep copy of the array list
        // Just to prove it I print out the sorted field individually
        // If you had to copy individually (like for the AP) the code would
        // follow the structure below
        System.out.print("Cloned: ");
        for (PlayingCard i : this.sorted)
            System.out.print(i.getCardText() + " ");
        System.out.print("Size: " + this.sorted.size());
        System.out.println();
        PlayingCard tmp;
        for (int i = 1; i < this.sorted.size(); i++) {
            for (int j = i;
                    j > 0
                    && this.sorted.get(j).card_value() < this.sorted.get(j-1).card_value();
                    j--) {
                // swap values

                tmp = this.sorted.get(j);
                this.sorted.set(j, this.sorted.get(j - 1));
                this.sorted.set(j - 1, tmp);
            }
        }
    }

    public int scoreHand() {
        this.sortHand();
        int score = 0;
        for (PlayingCard i : this.sorted) {
            // Need to test each card to see if it is an ACE
            // If an ACE and score is < 11 use 11 as ACE value otherwise use 1
            // I haven't done a proof but I believe that checking the score
            // less than 11 is sufficient to handle ACEs and you won't bust a
            // hand incorrectly
            if (i.card_value() == 11) {
                // Processing ACE
                if (score >= 11) {
                    // ACEs must all be 1
                    score += 1;
                }
                else {
                    score += 11;
                }
            }
            else {
                // Just add card_value it's not an ACE
                score += i.card_value();
            }
        }
        return score;
    }

    public void display() {
        System.out.println(this.displayName);
        for (PlayingCard i : cards) {
            System.out.print(i.getCardText() + " ");
        }
        System.out.println();
    }

}

//---------------------------------------------------------------

/*
 * PlayingCard.java - Playing card class for BlackJack
 */
package BlackJack;

/**
 *
 * @author Nasty Old Dog
 */
public class PlayingCard {
    private int cardno;
    private int card_score[] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};

    private String faceVal = "A23456789TJQK";
    private String suit = "HDSC";

    public PlayingCard(int cardno)
    {
        this.cardno = cardno;
    }

    public PlayingCard(int cardno, int[] card_score)
    {
        this.cardno = cardno;
        this.card_score = card_score;
    }

    public int card_value()
    {
        return card_score[cardno % 13];
    }

    public String getCardText() {
        int card_val = this.cardno % 13;
        int card_suit = this.cardno % 4;
        return this.faceVal.substring(card_val, card_val + 1)
                + this.suit.substring(card_suit, card_suit + 1);
    }

}

Author: Nasty Old Dog

No comments:

Post a Comment