Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

431 lines
12 KiB

  1. /***************************************************************************/
  2. /** Microsoft Windows **/
  3. /** Copyright(c) Microsoft Corp., 1991, 1992 **/
  4. /***************************************************************************/
  5. /****************************************************************************
  6. comp2.cpp
  7. Aug 92, JimH
  8. May 93, JimH chico port
  9. Logic for computer player to select cards to play when not holding
  10. the lead, and initializing data tables is here.
  11. ****************************************************************************/
  12. #include "hearts.h"
  13. #include "main.h"
  14. #include "resource.h"
  15. #include "debug.h" // undef _DEBUG instead to remove messages
  16. /****************************************************************************
  17. computer::SelectCardToPlay
  18. computer player chooses a card to play.
  19. ****************************************************************************/
  20. void computer::SelectCardToPlay(handinfotype &h, BOOL bCheating)
  21. {
  22. TRACE1("<%d> ", id);
  23. Setup(h); // calculate values of private vars
  24. SLOT s;
  25. if (bFirst) // am I leading?
  26. s = SelectLeadCard(h);
  27. else
  28. s = SelectNonLeadCard(h);
  29. ASSERT(s >= 0);
  30. ASSERT(s < MAXSLOT);
  31. ASSERT(cd[s].IsValid());
  32. SetMode(WAITING);
  33. cd[s].Play(); // mark card as played
  34. h.cardplayed[id] = &(cd[s]); // update handinfo
  35. // inform other players
  36. ::move.playerid = id;
  37. ::move.cardid = cd[s].ID();
  38. ::move.playerled = h.playerled;
  39. ::move.turn = h.turn;
  40. ddeServer->PostAdvise(hszMove);
  41. // inform gamemeister
  42. ::pMainWnd->PostMessage(WM_COMMAND, IDM_REF);
  43. TRACE0("\n");
  44. }
  45. /****************************************************************************
  46. computer::SelectNonLeadCard
  47. This is where cards to play are selected when the computer player is
  48. not leading.
  49. ****************************************************************************/
  50. SLOT computer::SelectNonLeadCard(handinfotype &h)
  51. {
  52. BOOL bFirstTrick = (cardled != NULL) && (cardled->ID() == TWOCLUBS);
  53. // If we have at least one card of the led suit...
  54. if (sHighCard[nSuitLed] != EMPTY)
  55. {
  56. TRACE0("can follow suit. ");
  57. // If there's only one card of this suit, return it.
  58. if (sHighCard[nSuitLed] == sLowCard[nSuitLed])
  59. {
  60. TRACE0("must ");
  61. PLAY(sHighCard[nSuitLed]);
  62. return sHighCard[nSuitLed];
  63. }
  64. // if it's the first trick, play the high club
  65. if (bFirstTrick)
  66. {
  67. TRACE0("might as well ");
  68. PLAY(sHighCard[nSuitLed]);
  69. return sHighCard[nSuitLed];
  70. }
  71. // If I am the last player in this trick, and I've won the hand anyway,
  72. // return highest legal card (unless it's the queen of spades.)
  73. if (bLast && (nLowVal[nSuitLed] > currentval))
  74. {
  75. TRACE0("must win trick. ");
  76. if (sHighCard[nSuitLed] != sBlackLady)
  77. {
  78. PLAY(sHighCard[nSuitLed]);
  79. return sHighCard[nSuitLed];
  80. }
  81. else
  82. {
  83. TRACE0("avoid queen. ");
  84. PLAY(sLowCard[nSuitLed]);
  85. return sLowCard[nSuitLed];
  86. }
  87. }
  88. // If I am the last player and I CAN win the trick....
  89. if (bLast && (nHighVal[nSuitLed] > currentval))
  90. {
  91. TRACE0("can win. ");
  92. // Don't grab the trick if there aren't enough low cards
  93. // left in hand. The lead may be hard to lose!
  94. if (nLowestVal < 7) // i.e., card val < 8
  95. {
  96. if ((nPoints == 0) && (sHighCard[nSuitLed] != sBlackLady))
  97. {
  98. TRACE0("go for it. ");
  99. PLAY(sHighCard[nSuitLed]);
  100. return sHighCard[nSuitLed];
  101. }
  102. // Take a few hearts if it means losing a high spade.
  103. if ((!h.bQSPlayed) && nSuitLed == SPADES && nPoints < 4)
  104. {
  105. if (nHighVal[SPADES] > QUEEN)
  106. {
  107. TRACE0("sacrifice hearts to lose high spade. ");
  108. PLAY(sHighCard[SPADES]);
  109. return sHighCard[SPADES];
  110. }
  111. }
  112. TRACE0("decline. ");
  113. }
  114. else
  115. {
  116. TRACE0("no low cards. ");
  117. }
  118. }
  119. // Otherwise, try to find the highest safe card to play...
  120. SLOT safe = SafeCard(h);
  121. if (safe != EMPTY)
  122. {
  123. // if someone other than me is potentially shooting,
  124. // hold back high cards.
  125. if (h.bShootingRisk && h.bHumanShooter && (h.nMoonShooter != id))
  126. {
  127. TRACE0("2nd ");
  128. SLOT s2 = CardBelow(safe);
  129. if (s2 != EMPTY)
  130. safe = s2;
  131. }
  132. TRACE0("highest safe card. ");
  133. PLAY(safe);
  134. return safe;
  135. }
  136. // And if that fails, just play the lowest card.
  137. TRACE0("no safe card, choose lowest. ");
  138. if (sLowCard[nSuitLed] != sBlackLady)
  139. {
  140. PLAY(sLowCard[nSuitLed]);
  141. return sLowCard[nSuitLed];
  142. }
  143. else
  144. {
  145. TRACE0("try to avoid queen. ");
  146. PLAY(sHighCard[nSuitLed]);
  147. return sHighCard[nSuitLed];
  148. }
  149. }
  150. TRACE0("can't follow suit. ");
  151. // At this point, there are no cards of the led suit. The first
  152. // priority is to try to sluff off the queen of spades.
  153. if (!bFirstTrick || !::pMainWnd->IsFirstBloodEnforced())
  154. {
  155. if (sBlackLady != EMPTY)
  156. {
  157. TRACE0("gotcha! Queen of Spades. ");
  158. return sBlackLady;
  159. }
  160. }
  161. // The next priority is to dump high spades (if queen not yet played).
  162. if ((!h.bQSPlayed) && (nHighVal[SPADES] > QUEEN))
  163. {
  164. TRACE0("lose high spade. ");
  165. PLAY(sHighCard[SPADES]);
  166. return sHighCard[SPADES];
  167. }
  168. // The next priority is to find the most vulnerable suit
  169. int mvsuit = BestSuitToDump(!bFirstTrick);
  170. // There is an unusual situation which must be checked for explicitly.
  171. // It's possible BestSuitToDump may return SPADES, and the high card
  172. // is the queen. This would still be illegal if it was first round.
  173. if (bFirstTrick && ::pMainWnd->IsFirstBloodEnforced() && mvsuit == SPADES)
  174. {
  175. SLOT s = sHighCard[mvsuit];
  176. if (cd[s].ID() == BLACKLADY)
  177. {
  178. if (sHighCard[DIAMONDS] != EMPTY) // we know there's no clubs
  179. mvsuit = DIAMONDS;
  180. else if (sLowCard[SPADES] != sHighCard[SPADES])
  181. {
  182. TRACE0("dump low spade. ");
  183. return sLowCard[SPADES];
  184. }
  185. else
  186. mvsuit = HEARTS;
  187. }
  188. }
  189. // if someone other than me is potentially shooting, hold back high cards
  190. if (h.bShootingRisk && h.bHumanShooter && (h.nMoonShooter != id) &&
  191. (sHighCard[mvsuit] != sLowCard[mvsuit]))
  192. {
  193. SLOT s = sHighCard[mvsuit];
  194. SLOT s2 = CardBelow(s);
  195. if (s2 != EMPTY)
  196. s = s2;
  197. #ifdef _DEBUG
  198. TRACE1("hold high %c. ", suitid[mvsuit]);
  199. #endif
  200. PLAY(s);
  201. return s;
  202. }
  203. #ifdef _DEBUG
  204. TRACE1("dump %c. ", suitid[mvsuit]);
  205. #endif
  206. PLAY(sHighCard[mvsuit]);
  207. return sHighCard[mvsuit];
  208. }
  209. /****************************************************************************
  210. computer::SafeCard
  211. Returns highest safe card or EMPTY if no safe card found.
  212. ****************************************************************************/
  213. SLOT computer::SafeCard(handinfotype &h)
  214. {
  215. // Special check. If Ace of Spades is current trick winner, play the
  216. // Queen of Spades rather than the King, even though the King is higher.
  217. if ((sBlackLady!=EMPTY) && (nSuitLed==SPADES) && (currentval==(KING+1)))
  218. return sBlackLady;
  219. // Look for highest card of same suit that won't win trick.
  220. SLOT sSafe = EMPTY; // highest safe slot
  221. int nSafeVal = -1; // value of highest safe card
  222. for (SLOT s = 0; s < MAXSLOT; s++)
  223. {
  224. if (cd[s].IsValid())
  225. {
  226. if (cd[s].Suit() == nSuitLed)
  227. {
  228. int v = cd[s].Value2();
  229. // If card is safe (v < currentval) and card is highest
  230. // safe card found so far (v > nSaveVal)...
  231. if ((v < currentval) && (v > nSafeVal))
  232. {
  233. sSafe = s;
  234. nSafeVal = v;
  235. }
  236. }
  237. }
  238. }
  239. return sSafe;
  240. }
  241. /****************************************************************************
  242. computer::Setup
  243. Set up reference tables for high and low cards in each suit, etc.
  244. ****************************************************************************/
  245. void computer::Setup(handinfotype &h)
  246. {
  247. cardled = h.cardplayed[h.playerled];
  248. if (cardled)
  249. {
  250. nSuitLed = cardled->Suit();
  251. nValueLed = cardled->Value2();
  252. }
  253. else
  254. {
  255. nSuitLed = EMPTY;
  256. nValueLed = EMPTY;
  257. }
  258. nPoints = 0; // points in hand already
  259. // Initialize Tables
  260. for (int suit = 0; suit < MAXSUIT; suit++) // highs and lows by suit
  261. {
  262. sHighCard[suit] = EMPTY;
  263. sLowCard[suit] = EMPTY;
  264. nHighVal[suit] = ACE - 1; // lower than any real card
  265. nLowVal[suit] = KING + 2; // higher than any real card
  266. }
  267. sHighestCard = EMPTY; // highs and lows regardless of suit
  268. sLowestCard = EMPTY;
  269. nHighestVal = ACE - 1;
  270. nLowestVal = KING + 2;
  271. // Determine currentval (the value of the winning card so far) and nPoints.
  272. currentval = nValueLed;
  273. for (int i = 0; i < MAXPLAYER; i++)
  274. {
  275. card *c = h.cardplayed[i];
  276. if (c->IsValid())
  277. {
  278. // First, determine if there are any point cards in play.
  279. if (c->Suit() == HEARTS)
  280. nPoints++;
  281. if (c->ID() == BLACKLADY)
  282. nPoints += 13;
  283. // Then, find the highest card (on table) of the led suit.
  284. if (c->Suit() == nSuitLed)
  285. {
  286. int v = c->Value2();
  287. if (v > currentval)
  288. currentval = v;
  289. }
  290. }
  291. }
  292. // Calculate if we're leading or completing this trick.
  293. bFirst = (h.playerled == id);
  294. bLast = (((h.playerled + (MAXPLAYER-1)) % MAXPLAYER) == id);
  295. // Special check for the Queen of Spades
  296. sBlackLady = EMPTY; // assume we don't have it
  297. // Collect information on high and low cards in each suit.
  298. for (SLOT s = 0; s < MAXSLOT; s++)
  299. {
  300. if (cd[s].IsValid())
  301. {
  302. int suit = cd[s].Suit();
  303. int v = cd[s].Value2();
  304. if (cd[s].ID() == BLACKLADY)
  305. sBlackLady = s;
  306. if (v < nLowVal[suit])
  307. {
  308. nLowVal[suit] = v;
  309. sLowCard[suit] = s;
  310. }
  311. if (v < nLowestVal)
  312. {
  313. nLowestVal = v;
  314. sLowestCard = s;
  315. }
  316. if (v > nHighVal[suit])
  317. {
  318. nHighVal[suit] = v;
  319. sHighCard[suit] = s;
  320. }
  321. if (v > nHighestVal)
  322. {
  323. nHighestVal = v;
  324. sHighestCard = s;
  325. }
  326. }
  327. }
  328. }