|
|
/***************************************************************************/ /** Microsoft Windows **/ /** Copyright(c) Microsoft Corp., 1991, 1992 **/ /***************************************************************************/
/****************************************************************************
comp2.cpp
Aug 92, JimH May 93, JimH chico port
Logic for computer player to select cards to play when not holding the lead, and initializing data tables is here.
****************************************************************************/
#include "hearts.h"
#include "main.h"
#include "resource.h"
#include "debug.h" // undef _DEBUG instead to remove messages
/****************************************************************************
computer::SelectCardToPlay
computer player chooses a card to play.
****************************************************************************/
void computer::SelectCardToPlay(handinfotype &h, BOOL bCheating) { TRACE1("<%d> ", id);
Setup(h); // calculate values of private vars
SLOT s; if (bFirst) // am I leading?
s = SelectLeadCard(h); else s = SelectNonLeadCard(h);
ASSERT(s >= 0); ASSERT(s < MAXSLOT); ASSERT(cd[s].IsValid());
SetMode(WAITING); cd[s].Play(); // mark card as played
h.cardplayed[id] = &(cd[s]); // update handinfo
// inform other players
::move.playerid = id; ::move.cardid = cd[s].ID(); ::move.playerled = h.playerled; ::move.turn = h.turn;
ddeServer->PostAdvise(hszMove);
// inform gamemeister
::pMainWnd->PostMessage(WM_COMMAND, IDM_REF); TRACE0("\n"); }
/****************************************************************************
computer::SelectNonLeadCard
This is where cards to play are selected when the computer player is not leading.
****************************************************************************/
SLOT computer::SelectNonLeadCard(handinfotype &h) { BOOL bFirstTrick = (cardled != NULL) && (cardled->ID() == TWOCLUBS);
// If we have at least one card of the led suit...
if (sHighCard[nSuitLed] != EMPTY) { TRACE0("can follow suit. ");
// If there's only one card of this suit, return it.
if (sHighCard[nSuitLed] == sLowCard[nSuitLed]) { TRACE0("must "); PLAY(sHighCard[nSuitLed]); return sHighCard[nSuitLed]; }
// if it's the first trick, play the high club
if (bFirstTrick) { TRACE0("might as well "); PLAY(sHighCard[nSuitLed]); return sHighCard[nSuitLed]; }
// If I am the last player in this trick, and I've won the hand anyway,
// return highest legal card (unless it's the queen of spades.)
if (bLast && (nLowVal[nSuitLed] > currentval)) { TRACE0("must win trick. "); if (sHighCard[nSuitLed] != sBlackLady) { PLAY(sHighCard[nSuitLed]); return sHighCard[nSuitLed]; } else { TRACE0("avoid queen. "); PLAY(sLowCard[nSuitLed]); return sLowCard[nSuitLed]; } }
// If I am the last player and I CAN win the trick....
if (bLast && (nHighVal[nSuitLed] > currentval)) { TRACE0("can win. ");
// Don't grab the trick if there aren't enough low cards
// left in hand. The lead may be hard to lose!
if (nLowestVal < 7) // i.e., card val < 8
{ if ((nPoints == 0) && (sHighCard[nSuitLed] != sBlackLady)) { TRACE0("go for it. "); PLAY(sHighCard[nSuitLed]); return sHighCard[nSuitLed]; }
// Take a few hearts if it means losing a high spade.
if ((!h.bQSPlayed) && nSuitLed == SPADES && nPoints < 4) { if (nHighVal[SPADES] > QUEEN) { TRACE0("sacrifice hearts to lose high spade. "); PLAY(sHighCard[SPADES]); return sHighCard[SPADES]; } } TRACE0("decline. "); } else { TRACE0("no low cards. "); } }
// Otherwise, try to find the highest safe card to play...
SLOT safe = SafeCard(h); if (safe != EMPTY) { // if someone other than me is potentially shooting,
// hold back high cards.
if (h.bShootingRisk && h.bHumanShooter && (h.nMoonShooter != id)) { TRACE0("2nd "); SLOT s2 = CardBelow(safe); if (s2 != EMPTY) safe = s2; }
TRACE0("highest safe card. "); PLAY(safe); return safe; }
// And if that fails, just play the lowest card.
TRACE0("no safe card, choose lowest. "); if (sLowCard[nSuitLed] != sBlackLady) { PLAY(sLowCard[nSuitLed]); return sLowCard[nSuitLed]; } else { TRACE0("try to avoid queen. "); PLAY(sHighCard[nSuitLed]); return sHighCard[nSuitLed]; } }
TRACE0("can't follow suit. ");
// At this point, there are no cards of the led suit. The first
// priority is to try to sluff off the queen of spades.
if (!bFirstTrick || !::pMainWnd->IsFirstBloodEnforced()) { if (sBlackLady != EMPTY) { TRACE0("gotcha! Queen of Spades. "); return sBlackLady; } }
// The next priority is to dump high spades (if queen not yet played).
if ((!h.bQSPlayed) && (nHighVal[SPADES] > QUEEN)) { TRACE0("lose high spade. "); PLAY(sHighCard[SPADES]); return sHighCard[SPADES]; }
// The next priority is to find the most vulnerable suit
int mvsuit = BestSuitToDump(!bFirstTrick);
// There is an unusual situation which must be checked for explicitly.
// It's possible BestSuitToDump may return SPADES, and the high card
// is the queen. This would still be illegal if it was first round.
if (bFirstTrick && ::pMainWnd->IsFirstBloodEnforced() && mvsuit == SPADES) { SLOT s = sHighCard[mvsuit]; if (cd[s].ID() == BLACKLADY) { if (sHighCard[DIAMONDS] != EMPTY) // we know there's no clubs
mvsuit = DIAMONDS; else if (sLowCard[SPADES] != sHighCard[SPADES]) { TRACE0("dump low spade. "); return sLowCard[SPADES]; } else mvsuit = HEARTS; } }
// if someone other than me is potentially shooting, hold back high cards
if (h.bShootingRisk && h.bHumanShooter && (h.nMoonShooter != id) && (sHighCard[mvsuit] != sLowCard[mvsuit])) { SLOT s = sHighCard[mvsuit]; SLOT s2 = CardBelow(s); if (s2 != EMPTY) s = s2;
#ifdef _DEBUG
TRACE1("hold high %c. ", suitid[mvsuit]); #endif
PLAY(s); return s; }
#ifdef _DEBUG
TRACE1("dump %c. ", suitid[mvsuit]); #endif
PLAY(sHighCard[mvsuit]); return sHighCard[mvsuit]; }
/****************************************************************************
computer::SafeCard
Returns highest safe card or EMPTY if no safe card found.
****************************************************************************/
SLOT computer::SafeCard(handinfotype &h) { // Special check. If Ace of Spades is current trick winner, play the
// Queen of Spades rather than the King, even though the King is higher.
if ((sBlackLady!=EMPTY) && (nSuitLed==SPADES) && (currentval==(KING+1))) return sBlackLady;
// Look for highest card of same suit that won't win trick.
SLOT sSafe = EMPTY; // highest safe slot
int nSafeVal = -1; // value of highest safe card
for (SLOT s = 0; s < MAXSLOT; s++) { if (cd[s].IsValid()) { if (cd[s].Suit() == nSuitLed) { int v = cd[s].Value2();
// If card is safe (v < currentval) and card is highest
// safe card found so far (v > nSaveVal)...
if ((v < currentval) && (v > nSafeVal)) { sSafe = s; nSafeVal = v; } } } }
return sSafe; }
/****************************************************************************
computer::Setup
Set up reference tables for high and low cards in each suit, etc.
****************************************************************************/
void computer::Setup(handinfotype &h) { cardled = h.cardplayed[h.playerled]; if (cardled) { nSuitLed = cardled->Suit(); nValueLed = cardled->Value2(); } else { nSuitLed = EMPTY; nValueLed = EMPTY; }
nPoints = 0; // points in hand already
// Initialize Tables
for (int suit = 0; suit < MAXSUIT; suit++) // highs and lows by suit
{ sHighCard[suit] = EMPTY; sLowCard[suit] = EMPTY; nHighVal[suit] = ACE - 1; // lower than any real card
nLowVal[suit] = KING + 2; // higher than any real card
}
sHighestCard = EMPTY; // highs and lows regardless of suit
sLowestCard = EMPTY; nHighestVal = ACE - 1; nLowestVal = KING + 2;
// Determine currentval (the value of the winning card so far) and nPoints.
currentval = nValueLed; for (int i = 0; i < MAXPLAYER; i++) { card *c = h.cardplayed[i]; if (c->IsValid()) { // First, determine if there are any point cards in play.
if (c->Suit() == HEARTS) nPoints++;
if (c->ID() == BLACKLADY) nPoints += 13;
// Then, find the highest card (on table) of the led suit.
if (c->Suit() == nSuitLed) { int v = c->Value2();
if (v > currentval) currentval = v; } } }
// Calculate if we're leading or completing this trick.
bFirst = (h.playerled == id); bLast = (((h.playerled + (MAXPLAYER-1)) % MAXPLAYER) == id);
// Special check for the Queen of Spades
sBlackLady = EMPTY; // assume we don't have it
// Collect information on high and low cards in each suit.
for (SLOT s = 0; s < MAXSLOT; s++) { if (cd[s].IsValid()) { int suit = cd[s].Suit(); int v = cd[s].Value2();
if (cd[s].ID() == BLACKLADY) sBlackLady = s;
if (v < nLowVal[suit]) { nLowVal[suit] = v; sLowCard[suit] = s; }
if (v < nLowestVal) { nLowestVal = v; sLowestCard = s; }
if (v > nHighVal[suit]) { nHighVal[suit] = v; sHighCard[suit] = s; }
if (v > nHighestVal) { nHighestVal = v; sHighestCard = s; } } } }
|