June 1998 Programmer's Challenge
Blackjack
Mail solutions to:
<mailto:progchallenge@mactech.com>,
and copy
<mailto:bob_boonstra@mactech.com>
Due Date: 11:59PM, ET, 1 June 1998
This month we welcome you to the Programmer's Challenge Casino,
grease your palm with 1000 Programmer's Challenge Credits (not to be
confused with Challenge points) furnished by the house, and invite
you to spend a few milliseconds at our Challenge Blackjack table.
The prototype for the code you should write is:
#if defined (__cplusplus)
extern "C" {
#endif
#pragma enumsalwaysint on
typedef enum {kHiddenSuit=0,kClub,kDiamond,kHeart,kSpade}
Suit;
typedef enum { kHiddenSpot=0,
kAce,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10,kJack,kQueen,kKing
} Spot;
typedef struct Card { /* suit and spots for a card */
Suit suit;
Spot spot;
} Card;
typedef enum {
kStandPat=0, /* no more cards for this hand */
kClaimBlackjack, /* if your initial cards are Ace and a
face card */
/* the following values request another card */
kSplitAndHitMe, /* only valid with initial pair showing
*/
kHitMe, /* request another card for this hand
*/
/* the following values request one more card */
kDoubleDownAndHitMe /* only valid with initial two cards */
} Action;
typedef enum { /* results of your request for a card
*/
/* this result is possible anytime after a rule violation
*/
kIllegalPlay=-1, /* illegal play causes loss of your bet
*/
/* these results are possible after you request another card
*/
kNoResult=0, /* play again if you like */
kYouWin5CardCharlie, /* you have five cards and do not bust,
you win */
kYouBust, /* your card puts you over 21, you lose
*/
/* this result is only possible after you kClaimBlackjack in
the initial callback */
kYouWinBlackjack, /* you have Blackjack and dealer does not,
you win */
/* this result is only possible after initial callback for a
game */
kDealerWinsBlackjack, /* dealer has Blackjack, you do not, no
card dealt, you lose */
/* these results are possible after you kStandPat or
kClaimBlackjack */
kPush, /* dealer has same score, no win or loss
*/
/* these results are possible after you kStandPat */
kDealerBusts, /* dealer went over 21, you win */
kDealerWinsHiTotal, /* dealer has lower total, you lose */
kYouWinHiTotal /* you have lower total, you win */
} Result;
typedef void BetProc( /* place a bet for this */
unsigned int betAmount, /* amount you bet, must be >= minBet
and <= maxBet */
Card yourHand[2], /* your initial hand */
Card dealerHand[2] /* dealers initial hand, first card is hidden
*/
);
typedef Result HitProc( /* returns result for this hand */
Action yourAction, /* hit me or not, split or not after initial
pair, */
/* double down or not after initial two cards */
Boolean insurance, /* TRUE requests insurance when eligible
*/
/* these items are always returned */
Card yourCards[], /* all of your cards, including a new hit
*/
int *numYourCards, /* number of cards in yourCards */
/* these items are returned when result is not kNoResult */
Card dealerCards[], /* dealers hand, with hidden card revealed
*/
/* (helps with card counting) */
int *numDealerCards, /* number of cards in dealers hand */
int *yourWinnings /* winnings are positive, loss is negative
*/
);
void InitBlackjack(
int numDecks, /* number of decks used by the dealer,
2..10*/
int yourBankroll, /* number of credits you have to start
*/
int minBet, /* minimum bet for each hand */
int maxBet, /* maximum bet for each hand */
BetProc makeABet, /* callback to place a wager */
HitProc hitMe /* callback to get a card */
);
Boolean Blackjack( /* return true to keep playing, false to cash
in */
Boolean newDeck /* true when dealer starts with fresh
numDecks decks of cards */
);
#if defined (__cplusplus)
}
#endif
Play at the Challenge Casino begins with a call to InitBlackjack,
where you are told how many decks the house uses (numDecks), how many
Credits you have to work with (yourBankroll) courtesy of the house,
the minimum (minBet) / maximum (maxBet) bet per hand at the Casino,
how to place a bet (the makeABet callback) and how ask for another
card (the hitMe callback). Business is slow at the Casino, and you
are the only player at the table.
After the call to InitBlackjack, your Blackjack routine will be
called repeatedly until you run out of Credits (in which case we show
you the door) or until you decide to cash in. The house is certain
that you are not a card counter, so they make it very obvious when
they are starting with a fresh set of numDecks decks of cards by
setting the newDeck parameter.
The first thing your Blackjack routine should do is call the
makeABet callback to make a wager and obtain your first cards. The
dealer also receives two cards, one of which you can see and one of
which is face down (kHiddenSuit and kHiddenSpot). The dealer's hidden
card will be revealed to you only at the end of the hand. After you
get your cards, you can repeatedly request an additional card by
calling hitMe with yourAction set to kHitMe until you believe you
will win the hand or you bust. Another card will be added to
yourCards and *numYourCards will be incremented. You win at Blackjack
by obtaining a hand total that is less than or equal to 21 and at the
same time is higher than the total in the dealer's hand. Cards are
counted at their face value (i.e., (int)theCard.spot), except for
aces and picture cards (Jacks, Queens, Kings). Picture cards are
counted with a value of 10. Aces can be counted as either 1 or 11, at
the option of the player. (In our game, the hitMe routine will score
Aces to your best advantage, giving you the highest possible hand
total without exceeding 21.)
As long as your card total does not exceed 21, hitMe will return
kNoResult and you may keep playing. If your total exceeds 21, hitMe
will return kYouBust, in which case you lose regardless of what the
dealer holds. If you draw a fifth card without going bust, you have a
Five Card Charlie, hitMe returns kYouWin5CardCharlie, and you win.
When you are finished requesting additional cards, you should call
hitMe with yourAction set to kStandPat. The dealer will then draw
cards until s/he has a total of 17 or more, and hitMe will return
kDealerBusts if the dealer's total exceeds 21, kDealerWinsHiTotal if
the dealer's total is greater than yours, kYouWinHiTotal if your
total is greater than the dealer's, or kPush if your total and the
dealer's are the same. In addition, *yourWinnings is set to the net
change in yourBankroll. In the case of a tie, or 'push',
*yourWinnings is set to zero. In all cases, the dealer's full hand is
provided in dealerHand once the result of the hand is determined, and
*numDealerCards is set to the number of entries in dealerHand.
If your first two cards are an ace and a 10-valued card (a ten or
a face card), you should call hitMe with yourAction set to
kClaimBlackjack and hitMe will return with kYouWinBlackjack (unless
the dealer also has a blackjack). If the dealer's first two cards are
an ace and a 10-valued card, the dealer has a blackjack and hitMe
will return kDealerWinsBlackjack, unless both you and the dealer have
a blackjack, in which case the result is kPush. No additional cards
are dealt when either player has blackjack.
You have the option of 'doubling down' after looking at your first
two cards by calling hitMe with yourAction set to
kDoubleDownAndHitMe. The hitMe routine will double your bet, give you
one more card, play the dealer's hand, and return the result.
If your first two cards are identical in value, you may 'split'
the hand and play each card separately. You do this by calling hitMe
with yourAction set to kSplitAndHitMe. Play the first hand as usual,
but instead of returning when the hand is finished, call hitMe with
yourAction set to kSplitAndHitMe again to play the second hand. You
may only split on the initial two cards, not on any subsequent pairs.
You cannot double down on a split hand.
When the dealer's exposed card is an ace, you are allowed to
request insurance of one half of your original bet. If the dealer has
a blackjack, insurance protects you from losing your initial bet
(i.e., your net winnings are zero). If the dealer does not have
blackjack, you lose the insurance amount and win or lose the initial
bet based on how the hand plays out.
Oh, and for those of you that think gambling doesn't pay, we must
insist that you actually wager those Challenge Credits initially
provided by the house. Your point total will be reduced by a
'freeloader penalty', the number of your initial yourBankroll of
Credits that you fail to wager. Once you have wagered yourBankroll
credits, you are free to continue playing or retire with your
remaining funds without penalty.
The Challenge winner will be the player that accumulates the most
points, where:
Points = Credits at game end, milliseconds played, freeloader
penalty
This will be a native PowerPC Challenge, using the CodeWarrior
environment. Solutions may be coded in C, C++, or Pascal.
|