Oct 98 Prog Challenge
Volume Number: 14
Issue Number: 10
Column Tag: Programmer's Challenge
October 98 Programmer's Challenge
by Bob Boonstra, Westford, MA
Hearts
A number of past Challenges have been based on games where one player competed
against another player. This month the Challenge is based on the four-handed game of
Hearts. Hearts is a card game where one attempts to avoid taking tricks containing
hearts or the queen of spades.
The prototype for the code you should write is:
#if defined(__cplusplus)
#pragma enumsalwaysint on
typedef enum {kNoSuit=0, kSpade, kHeart, kDiamond,
kClub} Suit;
typedef enum {kNoSpot=0, k2, k3, k4, k5, k6, k7, k8, k9, k10,
kJack, kQueen, kKing, kAce} Spot;
typedef enum {kPassLeft=0, kPassRight, kPassAcross,
kNoPass} Pass;
typedef struct Card {
Suit suit;
Spot spot;
} Card;
pascal void InitTournament(
const UInt16 numPlayers,
/* number of players in the tournament, indexed by seat */
const UInt16 gameEndingScore
/* game is over when one player reaches this score */
);
pascal void InitGame(
const Uint32 playerID[4], /* Identifier for players in this hand,
indexed
by seat */
const UInt16 yourSeat /* your seat at the table, 0..3 */
);
pascal void SelectPass(
const Card dealtHand[13], /* cards you are dealt */
const Pass passDirection,
/* direction you are passing, rotates kPassLeft, kPassRight,
kPassAcross, kNoPass */
UInt16 passedCards[3] /* index in dealtHand of cards you choose
to pass */
);
pascal void PlayTrick(
const UInt16 trickNumber, /* 13 tricks per hand, 0..12 */
const UInt16 trickLeader, /* which player leads this trick */
const Card yourHand[13], /* your cards at the beginning of this
trick */
const Card cardsPlayed[4],
/* cards already played this trick, indexed by
seat */
/* entries from [trickLeader] to [yourSeat-1 (mod
4)] are
valid */
UInt16 *yourPlay /* index into yourHand of the card you choose to
play */
);
pascal void TrickResults(
const Card lastTrick[4], /* cards played on previous trick,
indexed by
seat */
const UInt16 trickWinner /* which player won this trick */
);
pascal void HandResults(
const SInt16 pointsThisHand[4],
/* points earned by each player this hand, -26
.. 25 */
const SInt32 cumPoints[4]
/* cumulative points earned by each player
this game */
/* both pointsThisHand and cumPoints are indexed by seat number
*/
/* your points are pointsThisHand[yourSeat] */
);
#if defined(__cplusplus)
}
#endif
At the beginning of the tournament, your InitTournament routine will be called with
the number of participating players (numPlayers) and the gameEndingScore. Before
each game, your InitGame routine will be called to provide you with the playerID
identifiers of the players involved in this game and your position at the table
(yourSeat) relative to the other players. A game consists of a sequence of hands, each
of which consists of 13 tricks. At the end of a hand, each player is awarded points based
on the cards in the tricks he has taken, one point for each heart taken and 13 points for
the queen of spades, with the objective being to take the fewest points. A player who
captures all the hearts and the queen of spades, however, is said to "shoot the moon
and receives -26 points. At the end of each hand, your HandResults routine will be
called to confirm the number of points received by each player (pointsThisHand) and
the cumulative number of points earned by each player during this game (cumPoints).
At the beginning of a hand, each player is dealt 13 cards (dealtHand) and selects three
cards to pass to another player. The passDirection rotates from passing left
(kPassLeft, where player [i] passes to player [i+1], mod 4), to passing right
(kPassRight, player [i] passes to player [i-1]), to passing across (kPassAcross,
player [i] passes to player [i+2]), to not passing (kNoPass). Your SelectPass routine
is called at the beginning of each hand with your dealtHand and the passDirection; you
select the cards to be passed and return in passedCards the index in dealtHand of the
cards you want to pass.
Each trick, your PlayTrick and TrickResults routines will be called. PlayTrick
provides you with the seat index of the player leading this trick, the cards in your
hand at the beginning of this trick, and the cards already played on this trick. On the
first trick, yourHand will be the same as dealtHand, except that the cards you passed
will be replaced by the cards that were passed to you. On subsequent tricks, yourHand
will be unchanged except to remove the card you played on the previous trick (by
changing the suit and spot fields to kNoSuit and kNoSpot, respectively). When
PlayTrick is called, you select the card you wish to play and return in yourPlay its
index in yourHand. After all four players have played, your TrickResults routine will
be called to identify the winner of the trick (trickWinner) and all of the cards played
on the lastTrick.
The two of clubs is led on the first trick of each hand - the test code will ensure that
the PlayTrick routine of the player who has the two of clubs is called first on that
trick. The player who won the previous trick leads the next trick. Hearts may not be
led until a point card has been played on an earlier trick, unless a player has only
hearts left in his hand. The queen of spades may be led at any time.
If the number of entries is reasonable, the tournament will have each player compete
against every combination of other players in all possible seat arrangements. If the