Leaked source code of windows server 2003
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.

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