Friday, April 5, 2013

Blackjack: No Fun if You Don't Keep Score

Blackjack: No Fun If You Don't Keep Score

Blackjack: No Fun If You Don't Keep Score

Modulo Rears its Ugly Head

Continuing on Blackjack example I said that we would hold off on keeping score because we needed a sort routine. I have written about the 3 sort routines that the AP exam concentrates on and for the use of scoring I just randomly picked insertion sort. Rather than reuse the object from the previous article I created a new method called 'sortHand'. The main reason for doing this is that the value used to represent the card is not the value needed to score the card.

Back when this program first started modulo was used to take a number from 0 - 51 and turn it into a face value index. That index was used against a string that represents the face of the card for display purposes. Now the same concept is used but instead of a String and int array is used that is initialized to hold the 13 values of the face values of the cards. Modulo 13 (%13) is used to take any card and turn it into it's face value index. It's all captured in the 'cardvalue' method. Finally the scoreHand method takes a hand and walks through the values and tallies a total for the hand.

There is still one thing missing and that is the alternate treatment of Aces. For now Aces = 11 and I am postponing dealing with multiple Aces and the possibility they need to be scored as 1 in some cases (Not too bad really, for many hands this will give the proper score).

public int card_value(int c)
{
    // I need an array of sort values 11,2,3,4,5,6,7,8,9,10,10,10,10
    int card_score[] = {11,2,3,4,5,6,7,8,9,10,10,10,10};
    // I will use modulo 13 again to take a card and convert to face value
    // then use that to index into the card_score array for the sort value
    return card_score[c%13];
}


public void sortHand(int[] hnd)
{ 
    // 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

    int tmp;
    for (int i = 1; i < hnd.length; i++) {
        for (int j = i; 
                j > 0 && 
                this.card_value(hnd[j]) < this.card_value(hnd[j - 1]); 
                j--) {
            // swap values
            tmp = hnd[j];
            hnd[j] = hnd[j-1];
            hnd[j-1] = tmp;
        }
    }
}

public int scoreHand(int[] hnd)
{
    int tmp_hnd[] = new int[hnd.length];
    // Copy hand into a new array to play with without disturbing the
    // original hand
    for (int i = 0; i < hnd.length; i++)
    {
        tmp_hnd[i] = hnd[i];
    }
    this.sortHand(tmp_hnd);
    // tmp_hnd is now sorted must step through it and make a score
    // for now lets just treat values as score_value does and not
    // adjust for aces if the hand goes bust
    int score = 0;
    for (int i : tmp_hnd)
    {
        score += card_value(i);
    }
    return score;
}

// add some println to main to test the code
public static void main(String[] args) {
    CardDeck card = new CardDeck();

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

    card.dealPlayer();
    card.dealDealer();
    card.dealPlayer();
    card.dealDealer();

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

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 
8C 9H AS 5C 5S AC 6H QC QS JC JD 8H AH 9S AD 3D 3S 7C KC KS 2D TS 7S 3H KD 2S 8D 2C 4S 6D QH 5D TH 9D 9C 6C JS 7D 4C KH TC 4H TD 5H 7H 2H QD 6S 8S 4D 3C JH 
Player Hand  
8C AS 
Dealer Hand:  
9H 5C 

Player score = 217
Dealer score = 212
Bankroll = 1000
Enter the amount you want to bet: 

0
BUILD SUCCESSFUL (total time: 3 minutes 11 seconds)

That didn't work out quite right. The problem is in the way I designed the "hands". They are int arrays but I made them a fixed length of 20 because blackjack hands can vary in the number of cards they can hold in each game. If you look over the original blackjack code you will notice there are 2 field variables dcards and pcards. These track the current number of cards in the hands.

How did the score get so high? It's because the hand arrays use 0 as the filler for unused portion of the hand. If you go over the code carefully you will notice that a card of '0' is equivalent to an Ace. Under the current scoring function an Ace always has a value of 11. The loops in scoreHand go through each of the 20 locations for the given hand. So for the player hand it will be scored as 8 + 11 * 19 = 217 (the 11 aces are counted as 1 ace for the original ace dealt and then 18 fake aces because that's the way I initialized the hand array). The reader should be able to verify that this is the same calculation for the dealer hand (hint 9 + 5 + 11 * 18).

Bad Object Oriented Design

Yes indeed. I have done this purposefully. After I finish this program I am going to rewrite (refactor) it in an Object Oriented fashion. The purpose is two fold. One to show you how to hack things up quickly and see they work just as well as an object oriented design. The second reason is sometimes Objects are more obvious once you see some code in place. Certainly this is not the way you would design for the AP exam, but in real life being able to see an Object embedded in hacked code is a necessary skill to have. I hope it will also show that Object Oriented programming helps to clean the code up and add real world meaning to what is going on in the code.

Continued Hacking

I can fix the problem in an easy but ugly way by modifying the scoreHand method to accept the int field tracking the size of the hand. This is what the fix looks like:

    public int scoreHand(int[] hnd,int size)
    {
        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(tmp_hnd);
        // tmp_hnd is now sorted must step through it and make a score
        // for now lets just treat values as score_value does and not
        // adjust for aces if the hand goes bust
        int score = 0;
        for (int i : tmp_hnd)
        {
            score += card_value(i);
        }
        return score;
    }

   // then in main the testing statements are as follows
    public static void main(String[] args) {
        CardDeck card = new CardDeck();

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

        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();

       // ... game code
}

Output 2

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 6H TD 2H 7S QC 4C 7D 9D KH 3H JH 2C 6S 5S QH 9H AH 5H 5C 9C 4D AC 4H QD 9S 2D KD 2S 7C 8D 5D 3S JD 8S 7H 6C TS QS 3C 4S 8C TH JS KS AS JC TC 6D AD 3D KC 
Player Hand  
8H TD 
Dealer Hand:  
6H 2H 

Player score = 18
Dealer score = 8
Bankroll = 1000
Enter the amount you want to bet: 

Using the scoreHand Method

Now that scoreHand works it can be used in the game control loop. The manual control where the user has to enter HIT or STAND for both dealer and player will still be in effect. But now the game control loop is able to detect when the Player goes BUST (has a hand > 21) or when the dealer goes BUST. Add in some println's to say WINNER and LOSER. Finally adjust the player's bankroll based on the WIN or LOSE situation. There is also one more event that can happen in the game a TIE (aka PUSH). Here the bankroll is left alone and a new hand is started (the bet is "PUSHed" back to the player). So play with the following code and even though the user has to HIT and STAND for the dealer it works almost like a real game of blackjack.

    public static void main(String[] args) {
        CardDeck card = new CardDeck();

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

        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();

        // CardDeck card = new CardDeck();

        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();
            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            card.shuffle();

            card.dealPlayer();
            card.dealDealer();
            card.dealPlayer();
            card.dealDealer();

            card.displayHands();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;
            int scr = scr = card.scoreHand(card.playerHand, card.pcards);
            while (true) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealPlayer();
                    card.displayHands();
                    scr = card.scoreHand(card.playerHand, card.pcards);
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }

                } else if (user_inp.equals("STAND")) {
                    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
                card.resetHands();
                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
            int dscr = dscr = card.scoreHand(card.dealerHand, card.dcards);
            while (true) {
                System.out.print("Dealer Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealDealer();
                    card.displayHands();
                    dscr = card.scoreHand(card.dealerHand, card.dcards);
                    if (dscr > 21) {
                        // Player has gone bust
                        break;
                    }
                } else if (user_inp.equals("STAND")) {
                    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);
                }
            }

            // Code to score the game and settle the bet will go here
            // For now assume we win every time
            dscr = card.scoreHand(card.dealerHand, card.dcards);
            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
            card.resetHands();
        }
    }

Output 3

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 
9H JH KD 7S 4H 2S 2H 3C QC 9D KH KC AH 7C 5S 8H 8S 3S 9C 2C AC TD QD QS 6S 8C TS AS 8D KS QH AD 3D JC 5C TH 3H 5D 7D TC 6C 5H 7H JD 4D 4S 2D JS 4C 6D 9S 6H 
Player Hand  
9H KD 
Dealer Hand:  
JH 7S 

Player score = 19
Dealer score = 17
Bankroll = 1000
Enter the amount you want to bet: 50
Player Hand  
6D 3C 
Dealer Hand:  
AC 5D 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
6D 3C KD 
Dealer Hand:  
AC 5D 

Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
6D 3C KD 
Dealer Hand:  
AC 5D AS 

Player score: 19   Dealer: 27
You Win!! Dealer has BUSTED
Bankroll = 1050
Enter the amount you want to bet: 50
Player Hand  
4C TH 
Dealer Hand:  
6D 9C 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
4C TH 
Dealer Hand:  
6D 9C 9H 

Player score: 14   Dealer: 24
You Win!! Dealer has BUSTED
Bankroll = 1100
Enter the amount you want to bet: 50
Player Hand  
8D JH 
Dealer Hand:  
TD 9S 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
8D JH QD 
Dealer Hand:  
TD 9S 

BUST!! LOSER!!
Bankroll = 1050
Enter the amount you want to bet: 50
Player Hand  
9H 2H 
Dealer Hand:  
8D 2C 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
9H 2H TS 
Dealer Hand:  
8D 2C 

Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
9H 2H TS 
Dealer Hand:  
8D 2C KH 

Dealer Hand hit or stand? STAND
Player score: 21   Dealer: 20
You Win!!!
Bankroll = 1100
Enter the amount you want to bet: 50
Player Hand  
2H JS 
Dealer Hand:  
8C 9C 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
2H JS 7D 
Dealer Hand:  
8C 9C 

Player Hand hit or stand? STAND
Dealer Hand hit or stand? STAND
Player score: 19   Dealer: 17
You Win!!!
Bankroll = 1150
Enter the amount you want to bet: 50
Player Hand  
TH 7D 
Dealer Hand:  
8H 3H 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? STAND
Dealer Hand hit or stand? HIT
Player Hand  
TH 7D 
Dealer Hand:  
8H 3H 6C 

Dealer Hand hit or stand? STAND
Player score: 17   Dealer: 17
PUSH
Bankroll = 1150
Enter the amount you want to bet: 0
BUILD SUCCESSFUL (total time: 1 minute 41 seconds)

Automatic Dealer Play

The dealer loop is greatly simplified when automatic play is implemented. There is one condition to check

  • dealer hand <= 16

If it is HIT the hand and check for bust otherwise loop and if it's >16 the program will 'break' out of the loop then and check how the score of the game went

The code is cleaned up to avoid the overuse of the scoreHand method. With the automatic dealer code it became obvious only a few scoreHand statements were necessary if they were strategically placed.

Here is the new main code with the automatic dealer processing:

    public static void main(String[] args) {
        CardDeck card = new CardDeck();

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

        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();

        // CardDeck card = new CardDeck();

        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();
            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            card.shuffle();

            card.dealPlayer();
            card.dealDealer();
            card.dealPlayer();
            card.dealDealer();

            card.displayHands();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;
            int scr = scr = card.scoreHand(card.playerHand, card.pcards);
            while (true) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealPlayer();
                    card.displayHands();
                    scr = card.scoreHand(card.playerHand, card.pcards);
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }

                } else if (user_inp.equals("STAND")) {
                    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
                card.resetHands();
                continue; // go back to top of main loop and start new game
            }
            // Automatically Control the dealer loop
            // one simple if statement does it all
            int dscr = dscr = card.scoreHand(card.dealerHand, card.dcards);
            while (true) {
                if (dscr < 17) {
                    System.out.println("Dealer Hand 16 or less: Must HIT");
                    card.dealDealer();
                    card.displayHands();
                    dscr = card.scoreHand(card.dealerHand, card.dcards);
                } 
                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
            card.resetHands();
        }
    }

Output 4

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 
4C 9D TC 7C AS JD 7D 2C 3C 6S 6H QH 6C 9H 2D AD 5C KH 3H KD 3D JH 6D TD QS 8C 9C QD 7S JC 3S QC JS 9S 4H 4S TH 8H 4D TS 5H 8S 2H AC 5S 7H KS 8D 2S 5D AH KC 
Player Hand  
4C TC 
Dealer Hand:  
9D 7C 

Player score = 14
Dealer score = 16
Bankroll = 1000
Enter the amount you want to bet: 50
Player Hand  
7D 6C 
Dealer Hand:  
KC JD 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
7D 6C KD 
Dealer Hand:  
KC JD 

BUST!! LOSER!!
Bankroll = 950
Enter the amount you want to bet: 50
Player Hand  
KS 7C 
Dealer Hand:  
9H 5D 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? STAND
Dealer Hand 16 or less: Must HIT
Player Hand  
KS 7C 
Dealer Hand:  
9H 5D 2H 

Dealer Hand 16 or less: Must HIT
Player Hand  
KS 7C 
Dealer Hand:  
9H 5D 2H JH 

Player score: 17   Dealer: 26
You Win!! Dealer has BUSTED
Bankroll = 1000
Enter the amount you want to bet: 50
Player Hand  
5C QD 
Dealer Hand:  
TH 7S 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
5C QD 4S 
Dealer Hand:  
TH 7S 

Player Hand hit or stand? STAND
Player score: 19   Dealer: 17
You Win!!!
Bankroll = 1050
Enter the amount you want to bet: 50
Player Hand  
2C AH 
Dealer Hand:  
6C 4D 

Player Hand hit or stand? I don't understand: 
Player Hand hit or stand? HIT
Player Hand  
2C AH 8S 
Dealer Hand:  
6C 4D 

Player Hand hit or stand? STAND
Dealer Hand 16 or less: Must HIT
Player Hand  
2C AH 8S 
Dealer Hand:  
6C 4D 6H 

Dealer Hand 16 or less: Must HIT
Player Hand  
2C AH 8S 
Dealer Hand:  
6C 4D 6H TC 

Player score: 21   Dealer: 26
You Win!! Dealer has BUSTED
Bankroll = 1100
Enter the amount you want to bet: 0
BUILD SUCCESSFUL (total time: 6 minutes 45 seconds)

Conclusion

It almost plays like a real game of blackjack. The scoring still has that minor problem of dealing with the situation of when Aces = 1 instead of 11. The programming model for hands needs some work. I would rather add cards to hands dynamically and let the length of the int array be the actual number of cards in the hand. I will let the reader think about how to handle the scoring for Aces and in the meantime below is the full code so far.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package apcompsci;

/**
 *
 * @author Nasty Old Dog
 */
import java.util.Scanner;

public class CardDeck {

    int deck[] = new int[52];
    String faceVal = "A23456789TJQK";
    String suit = "HDSC";

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

    void shuffle() {
        int rindex;
        int 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;
        }
    }

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

    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.getCardText(deck[i]) + " ");
        }
        System.out.println();
    }
    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
    int deckidx = 0; // the location of the next card to be dealt

    public int 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];
        }
    }

    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;
    }

    public int card_value(int c) {
        // I need an array of sort values 11,2,3,4,5,6,7,8,9,10,10,10,10
        int card_score[] = {11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10};
        // I will use modulo 13 again to take a card and convert to face value
        // then use that to index into the card_score array for the sort value
        return card_score[c % 13];
    }

    public void sortHand(int[] hnd) {
        // 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

        int tmp;
        for (int i = 1; i < hnd.length; i++) {
            for (int j = i;
                    j > 0
                    && this.card_value(hnd[j]) < this.card_value(hnd[j - 1]);
                    j--) {
                // swap values
                tmp = hnd[j];
                hnd[j] = hnd[j - 1];
                hnd[j - 1] = tmp;
            }
        }
    }

    public int scoreHand(int[] hnd, int size) {
        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(tmp_hnd);
        // tmp_hnd is now sorted must step through it and make a score
        // for now lets just treat values as score_value does and not
        // adjust for aces if the hand goes bust
        int score = 0;
        for (int i : tmp_hnd) {
            score += card_value(i);
        }
        return score;
    }

    public void displayHands() {
        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();
        System.out.println();
    }

    public static void main(String[] args) {
        CardDeck card = new CardDeck();

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

        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();

        // CardDeck card = new CardDeck();

        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();
            // bet == 0 is the signal to quit loop and end program
            if (bet == 0) {
                break;
            }

            card.shuffle();

            card.dealPlayer();
            card.dealDealer();
            card.dealPlayer();
            card.dealDealer();

            card.displayHands();

            // Need a loop to handle HIT or STAND commands
            boolean bust = false;
            int scr = scr = card.scoreHand(card.playerHand, card.pcards);
            while (true) {
                System.out.print("Player Hand hit or stand? ");
                user_inp = uinp.nextLine();
                if (user_inp.equals("HIT")) {
                    card.dealPlayer();
                    card.displayHands();
                    scr = card.scoreHand(card.playerHand, card.pcards);
                    if (scr > 21) {
                        // Player has gone bust
                        bust = true;
                        break;
                    }

                } else if (user_inp.equals("STAND")) {
                    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
                card.resetHands();
                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
            int dscr = dscr = card.scoreHand(card.dealerHand, card.dcards);
            while (true) {
                if (dscr < 17) {
                    System.out.println("Dealer Hand 16 or less: Must HIT");
                    card.dealDealer();
                    card.displayHands();
                    dscr = card.scoreHand(card.dealerHand, card.dcards);
                } 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
            card.resetHands();
        }
    }
}

Author: Nasty Old Dog

No comments:

Post a Comment