
Java Game Programming For Dummies - W. Holder, D. Bell
.pdf
Chapter 6: Blackjack 125
import java.awt.*;
i mport java.util.StringTokenizer;
public class BlackjackApplet extends java.applet.Applet
i mplements Runnable |
|
private Deck |
deck; |
private BlackjackHand |
dealer, lastActive; |
private BlackjackPlayer[] players; |
|
private int |
curPlayer; |
private Button |
newdeal, stand, hit, doubledown, |
|
split; |
private ThreadGroup |
appTG; |
private Panel |
dpan, ppan, bpan; |
public void init () {
int |
numPlayers = 1, deckSize = l, bankroll = 0; |
String |
param; |
String[] |
names = null; |
Thread curT = Thread.currentThread(); appTG = curT.getThreadGroup(); curT.setPriority(curT.getPriority() - 1); setLayout(new BorderLayout());
(continued)

126 Part 11: Up to Speed
(continued)
if ((param = getParameter( PLAYERS )) != null) StringTokenizer st = new StringTokenizer(param, names = new String[st.countTokens()];
for (numPlayers = 0; st,hasMoreTokens(); numPlayers++) names[numPlayers] = st.nextToken();
Card.initGraphics(this); deck = new Deck(deckSize);
players = new BlackjackPlayer[numPlayers];
Bpan = new Panel();
dpan.add(dealer = new BlackjackHand());
add( North , dpan); |
|
bpan = new Panel(); |
|
add( Center , bpan); |
|
bpan.add(newdeal |
= new Button( Deal )); |
bpan.add(new Label( |
)): |
bpan.add(stand |
= new Button( Stand )): |
bpan.add(hit |
= new Button( Hit )); |
bpan.add(doubledown = new Button( Double Down ));
bpan.add(split |
= new Button( Split )); |
setButtons(null); |
|
ppan = new Panel(); add( South , ppan);
for (int ii = 0; ii < numPlayers; ii++) players[ii] = new BlackjackPlayer(ppan,
names == null ? null : names[ii], bankroll);
public boolean action (Event evt, Object what) I i f (evt.target == newdeal)
new Thread(appTG, this).start(); else I
BlackjackPlayer player = getPlayert); i f (evt target == stand)
nextHand(false); else
BlackjackPlayerHand hand = player.getHand(); i f (evt.target == hit) i
hand.deal(deal());
if (hand.value() > 21) nextHand(false);
else setButtons(player);
Chapter 6: Blackjack 127
else if (evt.target == doubledown) I hand.deal(dea1()); player.addToBankroll(-hand.bet): hand.bet <<= 1;
nextHand(false);
else if (evt.target == split) { BlackjackPlayerHand splitHand =
player.newHand(hand.bet);
hand.split(splitHand);
hand.deal(deal());
splltHand.deal(deal()):
setButtons(player);
I else
return super.action(evt, what):
public synchronized void run () { newDeal():
newdeal.disable();
try I
BlackjackPlayerHand hand;
for (int card = 2; --card 7= 0: )
for (int pp = 0; pp < players.length; pp++)
i f ((hand = players[ppl.getHand()) != null) l hand.deal(deal());
Thread.sleep(500);
I dealer.deal(deal()); Thread.sleep(500);
F
if ((hand = nextHand(true)) != null) I setButtons(getPlayer());
wait(); // wait for players to play their hands
setButtons(null);
dealer.expose();
Thread.sleep(1000); i f (hand != null)
while (dealer.value() <= 16) { dealer.deal(deal()); Thread.sleep(500);
(continued)
28 Part I1: Up to Speed
(continued)
E
catch (InterruptedException e) 11
for (int pp = 0; pp < players.length; pp++) players[ppl.resolveDeal(dealer);
newdeal.enable();
I
BlackjackPlayer getPlayer () I
return curPlayer )- players.length ? null : players[curPlayerl;
BlackjackPlayer nextPlayer () I curP]ayer++;
return getPlayer();
BlackjackPlayerHand nextHand (boolean firstHand) {
BlackjackPlayer player = null;
BlackjackPlayerHand hand = null: i f (dealer.blackjack())
curPlayer = players.length;
else if ((player = getPlayer()) != null)
hand = firstHand ?
player.getHand() : player.nextHand();
while (player != null && hand == null)
if ((player = nextPlayer()) != null)
hand = player.getHand();
i f (player == null) I setButtons(null);
synchronized (this) I notify(); I // deal to dealer return null;
1
i f (hand.blackjack()) // skip this hand
return nextHand(false);
setButtons(player); return hand;
boolean newDeal ()
int ii = players.length;
boolean shuffled; curPlayer = 0;
if (shuffled = (deck.getSize() < ii * 3 + 3)) deck.reshuffle();
Chapter 6: Blackjack 129
dealer,clearHand();
while(--ii>=0){
players[iil.clearHands();
players[iij.newHand(0);
newdeal.enable();
setButtons(null); return shuffled;
private void setButtons (BlackjackPlayer player) I i f (lastActive != null) I
l astActive.setActive(false); l astActive = null;
stand.disable();
hit.disable();
split.disable();
doubledown.disable(); i f (player != null)
BlackjackPlayerHand hand = player.getHand(); i f (hand != null) I
(lastActive = hand).setActive(true): stand.enable();
int val = hand.value(); i f (val < 21)
hit.enable():
i € (player.getBankroll() >= hand.bet) I
i f (player.canSplit() && hand.canSplit()) split.enable(};
i f (val <= 11 && hand.cardCount() == 2) doubledown.enable();
private Card deal ()
try f return deck.deal(); )
catch (NoSuchElementException e) { deck.reshuffle();
return deal();
I
}Jl end class BlackjackApplet

130 Part II: Up to Speed
The HTML that loads the applet
The HyperText Markup Language (HTML) document invokes the Blackjack applet using the following applet tag:
<APPLET CODE=BlackjackApplet WIDTH=480 HEIGHT=460>
<PARAM NAME= PLAYERS VALUE= Doug,Wayne,Fast Freddy
</APPLET>
The B 1 a c k j a c k A p p 1 e t gets going like this:
1.HTML passes the player names to the applet.
The applet automatically adjusts the layout for more or fewer players.
2.The applet uses a B o r d e r L a y o u t to divide the applet into the dealer's hand at the top ( N o r th ), the button controls in the middle ( C e n -
te r ), and the players at the bottom ( S o u t h ).
3. i n i t ( ) creates a panel for each of the B o r d e r L ay o u t locations to hold the individual components.
The North location contains only the dealer's hand, but still uses a panel in order to prevent the border layout from resizing the dealer's hand, and cause border layout to resize the panel instead. Each of these panels uses the default F1 owLayout manager.
4. s e tB ut t o n s ( ) enables and disables the buttons to match the legal options for a given point in the game.
The state-driven approach determines by examining the state of the game the required state of the buttons.
5. d e a 1 ( ) deals cards from the deck and automatically reshuffles if the cards have all been dealt.
6.The applet spawns a new thread when the user presses the Deal button.
The thread controls the tempo of the deal from the run ( ) method.
7.After r u n ( ) deals the initial hands, the applet's Deal thread needs to wait for the players to play their hands.
run ( ) calls wa i t ( ) on the applet and waits for acti on () to handle the user options.
8. n ex t H a n d () determines the next hand to play and sets it as the active hand.
If the next hand is the dealer's hand, nextHand ( ) calls not i fy ( ) to wake up the Deal thread. When the Deal thread wakes up, run ( ) plays the dealer's hand, settles the bets with each player, enables the Deal button, and exits the thread.
Chapter 6: Blackjack 131
The players
Each player requires additional user interface elements:
-Label s to display the player's name and current bankroll
-A C h o i c e selector to allow the amount of the next bet to be selected
-A P a n e 1 to display the player's Blackjack hand(s)
B 1 |
a c k j a c k P 1 a y e r panel groups together these interface elements. A |
B 1 |
a c k j a c k P 1 a y e r also includes all the necessary methods and fields for |
keeping track of a player. The following code implements B 1 a c k j a c k P 1 a y e r:
i mport java.awt.*;
class BlackjackPlayer extends Panel {
public static final int STANDARD BET = 10;
public static final int STANDARD-BANKROLL = 1000;
private static int[] |
betAmount |
I l, 5, 10, 20, 30, 50, 100, 200, 500, 10001; |
|
private static int |
playerCount; |
private String |
name; |
private int |
l astBet, bankroll, curHand, |
|
numHands; |
private final BlackjackPlayerHand[] |
|
|
hands = new BlackjackPlayerHand[4]; |
private Label |
bankrollLabel; |
private Choice |
betEntry; |
private Panel |
handsPanel; |
BlackjackPlayerHand getHand () I
return curHand >= numHands ? null : hands[curHand];
l
i nt getHandlndex () i
return curl-and >= numHands ? 1 : curl-and;
I
BlackjackPlayerHand nextHand () curHand++; handsPanel.layout();
return getHand();
1
i nt getBankroll () ( return bankroll; }
i nt getActiveHandCount () I return numHands; l
(continued)

32 Part II: Up to Speed
(continued)
boolean canSplit () I return numHands < hands length; I BlackjackPlayer (Container parent) I
this(parent, null, STANDARD_BANKROLL);
I
BlackjackPlayer (Container parent, String name,
i nt bankroll) I
parent.add(this); setLayout(new BorderLayout()):
playerCount++; |
|
i f (name == null) |
|
name = Player |
+ playerCount; |
add( North , new |
Label (this.name = name, Label. CENTER)); |
i f (bankroll <= 0)
bankroll = STANDARD_BANKROLL;
String bankStr = Integer.toString(bankroll);'' Font font = new Font( Courier , Font.PLAIN, 10); bankrollLabel = new Label(bankStr, Label.RIGNT); betEntry = new Choice();
for (int ii = 0; ii < betAmount.1ength; ii++) betEntry.addItem(Integer.toString(betAmount[iil));
bankrollLabel.setFont(font);
betEntry.setFont(font): Panel pbank = new Panel(); add( Center , pbank); pbank.add(bankrol]Label); pbank.add(betEntry); addToBankroll(bankroll); setBet(STANDARDBET);
handsPanel = new Panel():
handsPanel.setLayout(new PlayerHandLayout(this, .3Of)); handsPanel.setBackground(Color.gray);
add( South , handsPanel);
for (int hh = 0; hh < hands.length; hh++) handsPanel.add(hands[hh] =
new BlackjackPlayerHand(this));
public boolean action (Event evt, Object what) i f (evt.target == betEntry)
setBet(Integer.parselnt(betEntry.getSelectedltem()));
Chapter 6: Blackjack 133
else
return super.action(evt, what); return true;
synchronized void clearHands () { while (numHands > 0)
hands[--numHandsl.clearHand(); curHand = 0; handsPanel.layout();
synchronized void resolveDeal (BlackjackHand dealer) I for (int hh = numHands; --hh >= 0; )
addToBankroll(hands[hh].winnings(dealer));
synchronized BlackjackPlayerHand newHand (int bet) I BlackjackPlayerHand result = null;
i f (bet == 0) bet = lastBet;
i f (numHands < hands.length && (bet = setBet(bet)) > 0)f result = hands[numHands++];
addToBankroll(-(result.bet = bet)); handsPanel.layout();
return result;
i nt setBet (int bet) { i f (bet > bankroll)
for (int i = betAmount.length;
i > 0 && (bet = betAmount[--i]) > bankroll; ); betEntry.select(Integer.toString(bet));
return lastBet = bet;
void addToBankroll (int amount) I this.bankroll += amount;
bankrollLabel.setText(Integer.teString(this.bankroll));
I /I end class BlackjackPlayer
4 Part II: Up to Speed
The responsibilities of a B 1 a c k j a c k P 1 a y e r are
V A B 1 a c k j a c k P 1 aye r can have up to four hands active at once. The
h and s C ]
- BlackjackPlayer uses a BorderLayout and places the name label in
the |
N o r t h |
location, the current bankroll and the bet selector in |
|
the |
C e n t e r , and the player's Blackjack hands in the S o u t h . |
||
- g e t H a n d ( ) |
and n |
ext H a n d ( ) return and update the current active |
|
hand. n ewH a n d ( ) |
activates a new hand after first checking that the |
player has enough money to cover the bet.
V The addToBankro110 and setBet( ) methods manage the player's money. These methods are responsible for making sure that the player
never gambles money he doesn't have.
V B 1 a c k j a c k P 1 aye r overrides a c t i o n ( ) to handle the events from the C h o i c e selector used to set the player's next bet.
The players' hands
The hand for a player is a specialized case of the B 1 a c k j a c k H a n d that the dealer uses, as discussed earlier in this chapter. On top of the dealer's hand's function, the player's hand has to handle the additional duties of wagering and splitting. The B 1 a c k j a c k P 1 a y e r H a n d extends the
B1 ackjackHand like this:
import java.awt.*;
class BlackjackPlayerHand extends BlackjackHand I i nt bet;
private boolean hasSplit;
BlackjackPlayerHand (Container parent) I super();
horizInset = 3; parent.add(this);
protected boolean isDealer () { return false boolean blackjack () {
return !hasSplit && super.blackjack();
1
boolean canSplit () I
return hand.size() == 2 && value(o) == value(1);