home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / gdi / reversi / reversi.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  38KB  |  1,551 lines

  1. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
  2. //  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
  3. //  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
  4. //  PARTICULAR PURPOSE.
  5. //
  6. //  Copyright (C) 1993-1997  Microsoft Corporation.  All Rights Reserved.
  7. //
  8. //  PROGRAM: Reversi.c
  9. //
  10. //  PURPOSE: Reversi Sample Game
  11. //
  12. //  FUNCTIONS:
  13. //  UpdateCursor() - Update the cursor position
  14. //  checkdepth() - Update Skill menu items
  15. //  clearboard() - Clear board and set starting pieces
  16. //  RevCreate() - Called on WM_CREATE messages
  17. //  printboard() - Draws game pieces on board
  18. //  ClearMessageTop() - Clears message bar
  19. //  ShowMessageTop() - Displays string in message bar
  20. //  drawboard() - Draws game board
  21. //  RevPaint() - Called on WM_PAINT messages
  22. //  FlashMessageTop() - Sets up system timer for callback procedure
  23. //  RevMessage() - Outputs flashing message at top of window
  24. //  flashsqr() - Flashes game piece
  25. //  RevMouseMove() - Update cursor to show legality of move
  26. //  ShowBestMove() - Update cursor and mouse position to show best move
  27. //  gameover() - Find a human reply to the computers move
  28. //  paintmove() - Make a move and show the results
  29. //  RevMenu() - Called on WM_COMMAND messages
  30. //  RevInit() - Initializes window data and registers window
  31. //  RevMouseClick() - Handle mouse click or keyboard space or CR
  32. //  Next() - Find next square
  33. //  Previous() - Find previous square
  34. //  ShowNextMove() - Show next legal move
  35. //  RevChar() - Called on WM_KEYDOWN messages
  36. //  InverseMessage() - Callback - inverts message bitmap or kills timer
  37. //  ReversiWndProc() - Processes messages for "Reversi" window
  38. //  AboutDlgProc() - processes messages for "About" dialog box
  39. //  WinMain() - calls initialization function, processes message loop
  40. //
  41. //  SPECIAL INSTRUCTIONS: N/A
  42. //
  43.  
  44. #include <windows.h>
  45. #include <windowsx.h>
  46. #include <process.h>
  47. #include <stdlib.h>
  48. #include "reversi.h"
  49.  
  50. // Exported procedures called from other modules
  51. LONG APIENTRY ReversiWndProc(HWND, UINT, WPARAM, LONG);
  52. LONG APIENTRY InverseMessage(HWND, UINT, WPARAM, LONG);
  53.  
  54. // Global variables
  55. PSTR    pDisplayMessage;
  56. HBRUSH  hbrBlack;
  57. HBRUSH  hbrPat;
  58. HBRUSH  hbrWhite;
  59. HBRUSH  hbrRed;
  60. HBRUSH  hbrGreen;
  61. HBRUSH  hbrBlue;
  62. HBRUSH  hbrHuman;
  63. HBRUSH  hbrComputer;
  64. WNDPROC lpprocInverseMessage;
  65. HANDLE  hInst;
  66. HANDLE  curIllegal;
  67. HANDLE  curLegal;
  68. HANDLE  curThink;
  69. HANDLE  curBlank;
  70. BOOL    fThinking = FALSE;
  71. BOOL    fCheated = FALSE;
  72. INT     direc[9] = {9, 10, 11, 1, -1, -9, -10, -11, 0};
  73. WORD     prevCheck;
  74. BYTE    board[max_depth+2][BoardSize];
  75. INT     fPass;
  76. INT     flashtimes;
  77. INT     count;
  78. INT     MessageOn;
  79. INT     charheight;
  80. INT     charwidth;
  81. INT     xscr;
  82. CHAR    strBuf[80];
  83. BOOL    bMouseDownInReversi = FALSE;
  84. INT     xExt;
  85. INT     yExt;
  86. INT     Bx;
  87. INT     By;
  88. INT     ASPECT;
  89. INT     COLOR;
  90. INT     TXMIN;
  91. INT     TYMIN = 45;
  92. INT     dimension;
  93. BOOL    ffirstmove;
  94.  
  95. CHAR    szReversi[20];
  96. CHAR    szReversiPractice[40];
  97. CHAR    szPass[30];
  98. CHAR    szMustPass[30];
  99. CHAR    szTie[30];
  100. CHAR    szLoss[30];
  101. CHAR    szWon[30];
  102. CHAR    szWonPost[30];
  103. CHAR    szLossPost[30];
  104. CHAR    szAbout[20];
  105. CHAR    szIllegal[70];
  106. CHAR    szNoPass[70];
  107. CHAR    szHelpFile[15];
  108.  
  109. HANDLE  hAccel;
  110.  
  111. POINT   MousePos;
  112. FARPROC lpprocAbout;
  113.  
  114. INT     depth;
  115. INT     BestMove[max_depth+2];
  116. HDC     hDisp;
  117. HWND    hWin;
  118. INT     moves[61] = {11,18,81,88, 13,31,16,61,
  119.                      38,83,68,86, 14,41,15,51,
  120.                      48,84,58,85, 33,36,63,66,
  121.                      34,35,43,46, 53,56,64,65,
  122.                      24,25,42,47, 52,57,74,75,
  123.                      23,26,32,37, 62,67,73,76,
  124.                      12,17,21,28, 71,78,82,87,
  125.                      22,27,72,77,
  126.               0};
  127.  
  128. // declarations of functions in rev.c
  129. INT NEAR PASCAL minmax(BYTE b[max_depth + 2][100], INT move, INT friendly,
  130.     INT enemy, INT ply, INT vmin, INT vmax);
  131. VOID NEAR PASCAL makemove(BYTE b[], INT move, INT friendly, INT enemy);
  132. INT NEAR PASCAL legalcheck(BYTE b[], INT move, INT friendly, INT enemy);
  133.  
  134. #define LONG2POINT(l, pt)               ((pt).x = (SHORT)LOWORD(l), (pt).y = (SHORT)HIWORD(l))
  135.  
  136. //
  137. //  FUNCTION: UpdateCursor()
  138. //
  139. //  PURPOSE:  Update the cursor position
  140. //
  141. //  COMMENTS:
  142. //
  143. //      To use UpdateCursor,  set the global var MousePos.x and MousePos.y
  144. //      and make the call.  The cursor will appear at the new position
  145. //
  146.  
  147. VOID NEAR PASCAL UpdateCursor(
  148. HWND    hwnd)
  149. {
  150.   POINT curpoint;
  151.  
  152.   curpoint.x = MousePos.x;
  153.   curpoint.y = MousePos.y;
  154.   ClientToScreen(hwnd, (LPPOINT)&curpoint);
  155.   SetCursorPos(curpoint.x, curpoint.y);
  156. }
  157.  
  158.  
  159. //
  160. //  FUNCTION: checkdepth()
  161. //
  162. //  PURPOSE:  Update Skill menu items
  163. //
  164.  
  165. VOID NEAR PASCAL checkdepth(
  166. HWND hWindow,
  167. WORD  d)
  168. {
  169.   HMENU hMenu;
  170.  
  171.   hMenu = GetMenu(hWindow);
  172.   CheckMenuItem(hMenu, prevCheck, MF_UNCHECKED);
  173.   CheckMenuItem(hMenu, d, MF_CHECKED);
  174.   prevCheck = d;
  175. }
  176.  
  177.  
  178. //
  179. //  FUNCTION: clearboard()
  180. //
  181. //  PURPOSE:  Clear board and set starting pieces
  182. //
  183.  
  184. VOID NEAR PASCAL clearboard(
  185. BYTE b[max_depth+2][BoardSize])
  186. {
  187.   register INT  i,j;
  188.   INT           k;
  189.  
  190.   for (i=0; i<=max_depth ; i++)
  191.       for (j=0 ; j<=99 ; j++)
  192.           b[i][j] = edge;
  193.  
  194.     for (i=0 ; i<=max_depth ; i++)
  195.       {
  196.         for (j=11 ; j<=81 ; j=j+10)
  197.             for (k=j ; k<j+8 ; k++)
  198.                 b[i][k] = empty;
  199.  
  200.         b[i][45]=computer;
  201.         b[i][54]=computer;
  202.         b[i][44]=human;
  203.         b[i][55]=human;
  204.       }
  205. }
  206.  
  207.  
  208. //
  209. //  FUNCTION: RevCreate()
  210. //
  211. //  PURPOSE:  Called on WM_CREATE messages
  212. //
  213.  
  214. VOID NEAR PASCAL RevCreate(
  215. register HWND   hWindow)
  216.  
  217. {
  218.   register HDC  hDC;
  219.   TEXTMETRIC    charsize;           // characteristics of the characters
  220.  
  221.   MessageOn   = FALSE;
  222.   hDC = GetDC(hWindow);
  223.   GetTextMetrics(hDC, (LPTEXTMETRIC)&charsize);
  224.  
  225.   charheight = charsize.tmHeight;
  226.   charwidth = charsize.tmAveCharWidth;
  227.  
  228.   ReleaseDC(hWindow, hDC);
  229.  
  230.   if (COLOR == TRUE)
  231.     {
  232.       hbrComputer = hbrBlue;
  233.       hbrHuman = hbrRed;
  234.     }
  235.   else
  236.     {
  237.       hbrComputer = hbrBlack;
  238.       hbrHuman = hbrWhite;
  239.     }
  240.  
  241.   TXMIN = 45 * ASPECT;
  242.  
  243.   clearboard(board);
  244.  
  245.   fPass = PASS;   // Okay to pass on first move
  246.   depth = 1;
  247.   prevCheck = EASY;
  248.   ffirstmove = TRUE;
  249.   checkdepth(hWindow, prevCheck);
  250. }
  251.  
  252.  
  253. //
  254. //  FUNCTION: printboard()
  255. //
  256. //  PURPOSE:  Draws game pieces on board
  257. //
  258.  
  259. VOID NEAR PASCAL printboard(
  260. BYTE b[max_depth+2][BoardSize])
  261.  
  262. {
  263.   register INT  i,j;
  264.   INT sq;
  265.  
  266.   for (i=0; i < 8; i++)
  267.     {
  268.       for (j=0; j < 8; j++)
  269.         {
  270.           if ((sq = (INT)b[0][i*10+j+11]) != empty)
  271.             {
  272.               if (sq == computer)
  273.                   SelectObject(hDisp, hbrComputer);
  274.               else
  275.                   SelectObject(hDisp, hbrHuman);
  276.  
  277.               Ellipse(hDisp,
  278.                       Bx+2*ASPECT+i*xExt,
  279.                       By+2+j*yExt,
  280.                       Bx+2*ASPECT + i*xExt + xExt-4*ASPECT,
  281.                       By+2+j*yExt + yExt-4);
  282.             }
  283.         }
  284.     }
  285. }
  286.  
  287.  
  288. //
  289. //  FUNCTION: ClearMessageTop()
  290. //
  291. //  PURPOSE:  Clears message bar
  292. //
  293.  
  294. VOID NEAR PASCAL ClearMessageTop(
  295. HDC     hDC)
  296.  
  297. {
  298.   if (MessageOn == TRUE)
  299.     {
  300.       flashtimes = count + 1;
  301.       SelectObject(hDC, (COLOR) ? hbrGreen : hbrWhite);
  302.       PatBlt(hDC, 0, 0, xscr, charheight, PATCOPY);
  303.       MessageOn = FALSE;
  304.     }
  305. }
  306.  
  307.  
  308. //
  309. //  FUNCTION: ShowMessageTop()
  310. //
  311. //  PURPOSE:  Displays string in message bar
  312. //
  313.  
  314. VOID NEAR PASCAL ShowMessageTop(
  315. HDC     hDC,
  316. PSTR    string)
  317.  
  318. {
  319. #if defined (WIN16) 
  320.   INT   dx;
  321.   INT   sizeRet;
  322.   #define WIDTH(x)  sizeRet
  323. #else
  324.   LONG  dx;
  325.   SIZE  sizeRet;        
  326.   #define WIDTH(x)  sizeRet.cx
  327. #endif
  328.   
  329.   pDisplayMessage = string;
  330.   ClearMessageTop(hDC);
  331.   SelectObject(hDC, hbrWhite);
  332.   PatBlt(hDC, 0, 0, xscr, charheight, PATCOPY);
  333.   SetBkMode(hDC, TRANSPARENT);
  334.   GetTextExtentPoint(hDC, (LPSTR)string, lstrlen(string), &sizeRet);
  335.   dx = WIDTH(x);
  336.   TextOut(hDC, (INT)(xscr - dx)/2, 0, (LPSTR)string, lstrlen(string));
  337.   MessageOn = TRUE;
  338.   SetBkMode(hDC, OPAQUE);
  339. }
  340.  
  341.  
  342. //
  343. //  FUNCTION: drawboard()
  344. //
  345. //  PURPOSE:  Draws game board
  346. //
  347.  
  348. VOID NEAR PASCAL drawboard(
  349. BYTE b[max_depth+2][BoardSize])
  350. {
  351.   register INT  i;
  352.   INT           lcx,lcy;
  353.   register INT  xdimension;
  354.   INT           xLineExt,yLineExt;
  355.  
  356.   yLineExt = 8 * yExt;
  357.   xLineExt = 8 * xExt;
  358.   xdimension = dimension * ASPECT;
  359.  
  360.   SelectObject(hDisp, hbrBlack);
  361.   PatBlt(hDisp, Bx+2*xdimension, By+2*dimension, xLineExt, yLineExt, PATCOPY);
  362.   //MUnrealizeObject(hbrPat);
  363.   SelectObject(hDisp, hbrPat);
  364.   PatBlt(hDisp, Bx, By, xLineExt, yLineExt, PATCOPY);
  365.  
  366.   SelectObject(hDisp, hbrBlack);
  367.   for (i=Bx; i <= Bx + xLineExt; i += xExt)
  368.       PatBlt(hDisp, i, By, ASPECT, yLineExt, PATCOPY);
  369.  
  370.   for (i=By; i <= By + yLineExt; i += yExt)
  371.       PatBlt(hDisp, Bx, i, xLineExt, 1, PATCOPY);
  372.  
  373.   lcx = Bx+xLineExt;
  374.   lcy = By+yLineExt;
  375.  
  376.   //MUnrealizeObject(hbrPat);
  377.   SelectObject(hDisp, hbrPat);
  378.  
  379.   for (i=1; i < xdimension; ++i)
  380.       PatBlt(hDisp, lcx+i, By+i/ASPECT, 1, yLineExt, PATCOPY);
  381.  
  382.   
  383.   for (i=1; i < dimension; ++i)   // Fill in bottom edge of puzzle.
  384.       PatBlt(hDisp, Bx+i*ASPECT, lcy+i, xLineExt, 1, PATCOPY);
  385.  
  386.   SelectObject(hDisp, hbrBlack);
  387.  
  388.   MoveToEx(hDisp, lcx, By, NULL);
  389.   LineTo(hDisp, lcx+xdimension, By+dimension);
  390.   LineTo(hDisp, lcx+xdimension, lcy+dimension);
  391.   LineTo(hDisp, Bx+xdimension, lcy+dimension);
  392.   LineTo(hDisp, Bx, lcy);
  393.   MoveToEx(hDisp, lcx+xdimension, lcy+dimension, NULL);
  394.   LineTo(hDisp, lcx, lcy);
  395.  
  396.   printboard(b);
  397. }
  398.  
  399.  
  400. //
  401. //  FUNCTION: RevPaint()
  402. //
  403. //  PURPOSE:  Called on WM_PAINT messages
  404. //
  405.  
  406. VOID NEAR PASCAL RevPaint(
  407. HWND    hWindow,
  408. HDC     hDC)
  409.  
  410. {
  411.   register INT  Tx, Ty;
  412.   INT           xLineExt, yLineExt;
  413.   RECT          lpSize;
  414.  
  415.   hDisp = hDC;    // Since it is easy to resize we'll do it on every repaint
  416.   hWin  = hWindow;
  417.   SetBkMode(hDisp, OPAQUE);
  418.   GetClientRect(hWindow, (LPRECT)&lpSize);
  419.   xscr = Tx = lpSize.right - lpSize.left;
  420.   Ty = lpSize.bottom - lpSize.top;
  421.  
  422.   if (Tx < Ty*ASPECT)    // Dont go below minimum size
  423.     {
  424.       if (Tx < TXMIN)
  425.           Tx = TXMIN;
  426.       xExt = Tx / (9 + 1);
  427.       yExt = xExt / ASPECT;
  428.     }
  429.   else
  430.     {
  431.       if (Ty < TYMIN)
  432.           Ty = TYMIN;
  433.       yExt = Ty / (9 + 1);
  434.       xExt = yExt * ASPECT;
  435.     }
  436.   yLineExt = 8 * yExt;
  437.   xLineExt = 8 * xExt;
  438.   dimension = yLineExt/30;
  439.  
  440.   Bx = (Tx > xLineExt) ? (Tx - xLineExt) / 2 : 0;
  441.   By = (Ty > yLineExt) ? (Ty - yLineExt) / 2 : 0;
  442.  
  443.   drawboard(board);
  444.  
  445.   if (MessageOn)
  446.     {
  447.       ShowMessageTop(hDisp, pDisplayMessage);
  448.       PatBlt(hDC, 0, 0, xscr, charheight, DSTINVERT);
  449.     }
  450. }
  451.  
  452.  
  453. //
  454. //  FUNCTION: FlashMessageTop()
  455. //
  456. //  PURPOSE:  Sets up system timer for callback procedure
  457. //
  458.  
  459. VOID NEAR PASCAL FlashMessageTop(
  460. HWND    hWindow)
  461. {
  462.   flashtimes = 0;
  463.   count = 4;
  464.   SetTimer(hWindow, 666, 200, (WNDPROC)lpprocInverseMessage);    /* Timer ID is 666 */
  465. }
  466.  
  467.  
  468. //
  469. //  FUNCTION: RevMessage()
  470. //
  471. //  PURPOSE:  Outputs flashing message at top of window
  472. //
  473.  
  474. VOID NEAR PASCAL RevMessage(
  475. HWND            hWindow,
  476. HDC             hDC,
  477. register CHAR   *pS,
  478. INT             n,
  479. CHAR            *pchPostStr)
  480. {
  481.   register CHAR *pch;
  482.  
  483.   pch = strBuf;
  484.   while (*pS)
  485.       *pch++ = *pS++;
  486.  
  487.   if (n)
  488.     {
  489.       if (n / 10)
  490.           *pch++ = (CHAR)(n / 10 + '0');
  491.       *pch++ = (CHAR)(n % 10 + '0');
  492.     }
  493.  
  494.   if (pchPostStr)
  495.     {
  496.       while (*pchPostStr)
  497.           *pch++ = *pchPostStr++;
  498.     }
  499.   *pch = '\0';
  500.  
  501.   ShowMessageTop(hDC, strBuf);
  502.   FlashMessageTop(hWindow);
  503. }
  504.  
  505.  
  506. //
  507. //  FUNCTION: flashsqr()
  508. //
  509. //  PURPOSE:  Flashes game piece
  510. //
  511.  
  512. VOID NEAR PASCAL flashsqr(
  513. register HDC    hDC,
  514. INT             x1,
  515. INT             y1,
  516. INT             Ex,
  517. INT             Ey,
  518. INT             color,
  519. BOOL            fBlankSquare,
  520. INT             n)
  521.  
  522. {
  523.   register INT  i;
  524.  
  525.   if (fBlankSquare)
  526.       SelectObject(hDC, GetStockObject(NULL_PEN));
  527.  
  528.   SetCursor(curBlank);
  529.  
  530.   for (i=0; i < n; ++i)
  531.     {
  532.       if (color == 1)
  533.           color = 2;
  534.       else
  535.           color = 1;
  536.  
  537.       if (color == 1)
  538.           SelectObject(hDC,hbrComputer);
  539.       else
  540.           SelectObject(hDC, hbrHuman);
  541.  
  542.       SetBkMode(hDC, OPAQUE);
  543.       Ellipse(hDC, x1, y1, x1+Ex, y1+Ey);
  544.     }
  545.  
  546.   if (fBlankSquare)
  547.     {
  548.       //MUnrealizeObject(hbrPat);
  549.       SelectObject(hDC, hbrPat);
  550.       Ellipse(hDC, x1, y1, x1+Ex, y1+Ey);
  551.     }
  552.   else
  553.       SetCursor(curThink);
  554. }
  555.  
  556.  
  557. //
  558. //  FUNCTION: RevMouseMove()
  559. //
  560. //  PURPOSE:  Update cursor to show legality of move
  561. //
  562.  
  563. VOID NEAR PASCAL RevMouseMove(
  564. POINT   point)
  565.  
  566. {
  567.   INT     move;
  568.   INT     Si, Sj;
  569.   INT     yLineExt = 8 * yExt;
  570.   INT     xLineExt = 8 * xExt;
  571.   HANDLE  cur;
  572.  
  573.   MousePos.x = point.x;
  574.   MousePos.y = point.y;
  575.  
  576.   if(xExt ==0 || yExt == 0)
  577.       return;
  578.  
  579.   cur = curIllegal;
  580.  
  581.   if ((point.x > Bx) && (point.x < (Bx+xLineExt)) && (point.y > By) && (point.y < (By+yLineExt)))
  582.     {
  583.       Si = (point.x - Bx) / xExt;
  584.       Sj = (point.y - By) / yExt;
  585.       move = Si * 10 + Sj + 11;
  586.       if (legalcheck(board[0], move, human, computer))
  587.           cur = curLegal;
  588.     }
  589.   SetCursor(cur);
  590. }
  591.  
  592.  
  593. //
  594. //  FUNCTION: ShowBestMove()
  595. //
  596. //  PURPOSE:  Update cursor and mouse position to show best move
  597. //
  598.  
  599. VOID NEAR PASCAL ShowBestMove(
  600. HWND hwnd)
  601.  
  602. {
  603.   HDC           hdc;
  604.   INT           sq;
  605.   register INT  x, y;
  606.   INT           *pMoves;
  607.   BOOL          bDone;
  608.  
  609.   if (fPass == PASS && !ffirstmove)
  610.       return;
  611.  
  612.   if (!fCheated)
  613.       SetWindowText(hwnd, (LPSTR)szReversiPractice);
  614.  
  615.   fCheated = TRUE;
  616.   SetCursor(curThink);
  617.   fThinking = TRUE;
  618.  
  619.   if (ffirstmove)
  620.     {
  621.       x = 4;    // HACK: Hardcode the first move hint.
  622.       y = 2;
  623.     }
  624.   else
  625.     {
  626.       if (depth == 1)
  627.         {
  628.           bDone = FALSE;
  629.           pMoves = moves;
  630.           sq = *pMoves;
  631.           while (!bDone)
  632.             {
  633.               sq = *pMoves;
  634.               if (legalcheck(board[0], sq, human, computer))
  635.                   bDone = TRUE;
  636.               else
  637.                   pMoves++;
  638.             }
  639.           y = (sq - 11) % 10;
  640.           x = (sq - 11) / 10;
  641.         }
  642.       else
  643.         {
  644.           minmax(board, BestMove[0],  computer, human, 1, -infin, infin);
  645.           y = (BestMove[1] - 11) % 10;
  646.           x = (BestMove[1] - 11) / 10;
  647.         }
  648.     }
  649.  
  650.   MousePos.x = (x * xExt) + Bx + xExt/2;
  651.   MousePos.y = (y * yExt) + By + yExt/2;
  652.  
  653.   UpdateCursor(hwnd);
  654.  
  655.   hdc = GetDC(hwnd);
  656.  
  657.   x = x * xExt + Bx + 2 * ASPECT;
  658.   y = y * yExt + By + 2;
  659.  
  660.   flashsqr(hdc, x, y, xExt - 4 * ASPECT, yExt - 4, computer, TRUE, 3);
  661.  
  662.   fThinking = FALSE;
  663.  
  664.   ReleaseDC(hwnd, hdc);
  665.  
  666.   RevMouseMove(MousePos);
  667. }
  668.  
  669.  
  670. //
  671. //  FUNCTION: gameover()
  672. //
  673. //  PURPOSE:  Find a human reply to the computers move
  674. //
  675. //  COMMENTS:
  676. //
  677. //      As a side effect set flag fPass if the human
  678. //      has a legal move.
  679. //
  680.  
  681. VOID NEAR PASCAL gameover(
  682. register HWND   hWindow,
  683. HDC             hDC,
  684. BYTE            b[max_depth + 2][BoardSize],
  685. INT             r)
  686.  
  687. {
  688.   register INT  i;
  689.   INT           cc;
  690.   INT           hc;
  691.   INT           sq;
  692.   INT           reply2;
  693.   INT           *pMoves;
  694.  
  695.   pMoves = moves;
  696.   fPass = PASS;
  697.   reply2 = PASS;
  698.   while ((sq = *pMoves++) != 0)
  699.     {
  700.       if (legalcheck(b[0], sq, human, computer))
  701.           fPass = sq;
  702.       else if (legalcheck(b[0], sq, computer, human))
  703.           reply2 = sq;
  704.     }
  705.  
  706.   if (fPass == PASS)
  707.     {
  708.       if ((r == PASS) || (reply2 == PASS))
  709.         {
  710.           hc = 0;
  711.           cc = 0;
  712.           for (i=11; i <= 88; i++)
  713.             {
  714.               if (b[0][i] == human)
  715.                   hc++;
  716.               else if (b[0][i] == computer)
  717.                   cc++;
  718.             }
  719.  
  720.           if (hc > cc)
  721.               RevMessage(hWindow, hDC, szWon, hc-cc, szWonPost);
  722.           else if (hc < cc)
  723.               RevMessage(hWindow, hDC, szLoss, cc-hc, szLossPost);
  724.           else
  725.               RevMessage(hWindow, hDC, szTie, 0, NULL);
  726.         }
  727.       else
  728.         {
  729.           RevMessage(hWindow, hDC, szMustPass, 0, NULL);
  730.         }
  731.     }
  732.   else if (r == PASS)
  733.     {
  734.       RevMessage(hWindow, hDC, szPass, 0, NULL);
  735.     }
  736. }
  737.  
  738.  
  739. //
  740. //  FUNCTION: paintmove()
  741. //
  742. //  PURPOSE:  Make a move and show the results
  743. //
  744.  
  745. VOID NEAR PASCAL paintmove(
  746. BYTE    b[BoardSize],
  747. INT     move,
  748. BYTE    friendly,
  749. BYTE    enemy)
  750. {
  751.   INT           d;
  752.   INT           sq;
  753.   INT           *p;
  754.   register INT  i,j;
  755.   INT           color;
  756.  
  757.   if (move != PASS)
  758.     {
  759.       if (friendly == computer)
  760.         {
  761.           SelectObject(hDisp, hbrComputer);
  762.           color = 1;
  763.         }
  764.       else
  765.         {
  766.           SelectObject(hDisp, hbrHuman);
  767.           color = 2;
  768.         }
  769.  
  770.       i = ((move - 11) / 10) * xExt + Bx + 2 * ASPECT;
  771.       j = ((move - 11) % 10) * yExt + By + 2;
  772.       Ellipse(hDisp, i, j, i + xExt - 4 * ASPECT, j + yExt - 4);
  773.       flashsqr(hDisp, i, j, xExt - 4 * ASPECT, yExt - 4, color, FALSE, 4);
  774.  
  775.       p = direc;
  776.       while ((d = *p++) != 0)
  777.         {
  778.           sq=move;
  779.           if (b[sq += d] == enemy)
  780.            {
  781.              while(b[sq += d] == enemy)
  782.                 ;
  783.              if (b[sq] == (BYTE)friendly)
  784.                {
  785.                  while(b[sq -= d] == enemy)
  786.                    {
  787.                      board[0][sq] = b[sq] = friendly;
  788.                      i = ((sq - 11)/10)*xExt+Bx+2*ASPECT;
  789.                      j = ((sq - 11)%10)*yExt+By+2;
  790.                      Ellipse(hDisp, i, j, i + xExt-4*ASPECT, j + yExt-4);
  791.                    }
  792.                }
  793.            }
  794.         }
  795.       b[move]=friendly;
  796.     }
  797. }
  798.  
  799.  
  800. //
  801. //  FUNCTION: RevMenu()
  802. //
  803. //  PURPOSE:  Called on WM_COMMAND messages
  804. //
  805.  
  806. VOID NEAR PASCAL RevMenu(
  807. register HWND   hWindow,
  808. INT             idval)
  809.  
  810. {
  811.   HDC           hDC;
  812.   register INT  cmd;
  813.  
  814.   if (fThinking)
  815.       return;
  816.  
  817.   hWin = hWindow;
  818.  
  819.   switch (idval)
  820.     {
  821.       case EXIT:
  822.           PostMessage(hWindow, WM_CLOSE, 0, 0L);
  823.           break;
  824.  
  825.       case MN_HELP_ABOUT:
  826.           DialogBox(hInst, MAKEINTRESOURCE(3), hWindow, (WNDPROC)lpprocAbout);
  827.           break;
  828.  
  829.       case MN_HELP_INDEX:
  830.           //TEMPFIX WinHelp(hWindow, (LPSTR)szHelpFile, HELP_INDEX, 0L);
  831.           break;
  832.  
  833.       case MN_HELP_USINGHELP:
  834.           //TEMPFIX WinHelp(hWindow, (LPSTR)NULL, HELP_HELPONHELP, 0L);
  835.           break;
  836.  
  837.       case MN_HELP_KEYBOARD:
  838.           cmd = 0x1e;
  839.           goto HelpCommon;
  840.  
  841.       case MN_HELP_COMMANDS:
  842.           cmd = 0x20;
  843.           goto HelpCommon;
  844.  
  845.       case MN_HELP_PLAYING:
  846.           cmd = 0x21;
  847.           goto HelpCommon;
  848.  
  849.       case MN_HELP_RULES:
  850.           cmd = 0x22;
  851. HelpCommon:
  852.           //TEMPFIX WinHelp(hWindow, (LPSTR)szHelpFile, HELP_CONTEXT, (DWORD)cmd);
  853.           break;
  854.  
  855.       case HINT:
  856.           ShowBestMove(hWindow);
  857.           return;
  858.           break;
  859.  
  860.       case NEW:
  861.           SetWindowText(hWindow , (LPSTR)szReversi);
  862.           ffirstmove = TRUE;
  863.           hDisp = hDC = GetDC(hWindow);
  864.           fCheated = FALSE;
  865.           SetBkMode(hDisp, OPAQUE);
  866.           ClearMessageTop(hDC);
  867.           fPass = PASS;
  868.           clearboard(board);
  869.           drawboard(board);
  870.           ReleaseDC(hWindow, hDC);
  871.           hDisp = 0;
  872.           break;
  873.  
  874.       case EASY:
  875.           depth = 1;                      // MUST BE AT LEAST 1.
  876.           checkdepth(hWindow, EASY);      // KEEP HANDS OFF!
  877.           break;
  878.  
  879.       case MEDIUM:
  880.           depth = 2;
  881.           checkdepth(hWindow, MEDIUM);
  882.           break;
  883.  
  884.       case HARD:
  885.           depth = 4;
  886.           checkdepth(hWindow, HARD);
  887.           break;
  888.  
  889.       case VHARD:
  890.           depth = 6;
  891.           checkdepth(hWindow, VHARD);
  892.           break;
  893.  
  894.       case PASS:
  895.           if (fPass == PASS)
  896.             {
  897.               hDisp = hDC = GetDC(hWindow);
  898.               SetBkMode(hDisp, OPAQUE);
  899.               fThinking = TRUE;
  900.               ClearMessageTop(hDC);
  901.               SetCursor(curThink);
  902.               ReleaseDC(hWindow, hDC);
  903.               hDisp = 0;
  904.               minmax(board, PASS, human, computer, 0, -infin, infin);
  905.               hDisp = hDC = GetDC(hWindow);
  906.               paintmove(board[0], BestMove[0], (BYTE)computer, (BYTE)human);
  907.               gameover(hWindow, hDC, board, BestMove[0]);
  908.               SetCursor(curIllegal);
  909.               fThinking = FALSE;
  910.               ReleaseDC(hWindow, hDC);
  911.               hDisp = 0;
  912.             }
  913.           else
  914.               MessageBox(hWindow, (LPSTR)szNoPass, (LPSTR)szReversi, MB_OK | MB_ICONASTERISK);
  915.           break;
  916.     }
  917. }
  918.  
  919.  
  920. //
  921. //  FUNCTION: RevInit()
  922. //
  923. //  PURPOSE:  Initializes window data and registers window 
  924. //
  925.  
  926. BOOL NEAR PASCAL RevInit(
  927. HANDLE hInstance)
  928.  
  929. {
  930.   register PWNDCLASS    pRevClass;
  931.   HDC                   hdc;
  932.  
  933.   hbrWhite = GetStockObject(WHITE_BRUSH);
  934.   hbrBlack = GetStockObject(BLACK_BRUSH);
  935.   hbrPat   = GetStockObject(LTGRAY_BRUSH);
  936.  
  937.   if (!hbrPat)
  938.       return(FALSE);
  939.   ffirstmove = TRUE;
  940.   hdc = GetDC((HWND)NULL);
  941.  
  942.   COLOR = GetDeviceCaps(hdc, BITSPIXEL) > 1;
  943.  
  944.   if (GetDeviceCaps(hdc, VERTRES) == 200)
  945.       ASPECT = 2;
  946.   else
  947.       ASPECT = 1;
  948.   ReleaseDC((HWND)NULL, hdc);
  949.  
  950.   hbrRed        = (HBRUSH)CreateSolidBrush(RGB(0xFF,0,0));
  951.   hbrGreen      = (HBRUSH)CreateSolidBrush(RGB(0,0xFF,0));
  952.   hbrBlue       = (HBRUSH)CreateSolidBrush(RGB(0,0,0xFF));
  953.  
  954.   if (!hbrRed || !hbrGreen || !hbrBlue)
  955.       return(FALSE);
  956.  
  957.   LoadString(hInstance, 3,  (LPSTR)szReversi, 20);
  958.   LoadString(hInstance, 4,  (LPSTR)szReversiPractice, 40);
  959.   LoadString(hInstance, 5,  (LPSTR)szPass, 30);
  960.   LoadString(hInstance, 6,  (LPSTR)szMustPass, 30);
  961.   LoadString(hInstance, 7,  (LPSTR)szTie, 30);
  962.   LoadString(hInstance, 8,  (LPSTR)szLoss, 30);
  963.   LoadString(hInstance, 9,  (LPSTR)szWon, 30);
  964.   LoadString(hInstance, 10, (LPSTR)szAbout, 20);
  965.   LoadString(hInstance, 11, (LPSTR)szLossPost, 30);
  966.   LoadString(hInstance, 12, (LPSTR)szWonPost, 30);
  967.   LoadString(hInstance, 13, (LPSTR)szIllegal, 70);
  968.   LoadString(hInstance, 14, (LPSTR)szNoPass, 70);
  969.   LoadString(hInstance, 15, (LPSTR)szHelpFile, 15);
  970.  
  971.   hAccel = LoadAccelerators(hInstance, (LPSTR)"MAINACC");
  972.   pRevClass = (PWNDCLASS)((CHAR *)LocalAlloc(LMEM_ZEROINIT, sizeof(WNDCLASS)));
  973.   if (!pRevClass)
  974.       return(FALSE);
  975.  
  976.   curLegal   = LoadCursor(NULL, IDC_CROSS);
  977.   curIllegal = LoadCursor(NULL, IDC_ARROW);
  978.   curThink   = LoadCursor(NULL, IDC_WAIT);
  979.   curBlank   = LoadCursor(hInstance, MAKEINTRESOURCE(1));
  980.   if (!curLegal || !curIllegal || !curThink || !curBlank)
  981.       return(FALSE);
  982.   pRevClass->hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(3));
  983.  
  984.   pRevClass->lpszClassName = (LPSTR)"Reversi";
  985.   pRevClass->hbrBackground = ((COLOR) ? hbrGreen : hbrWhite);
  986.   pRevClass->lpfnWndProc   = ReversiWndProc;
  987.   pRevClass->lpszMenuName  = MAKEINTRESOURCE(1);
  988.   pRevClass->hInstance    = hInstance;
  989.   pRevClass->style         = CS_VREDRAW | CS_HREDRAW | CS_BYTEALIGNCLIENT;
  990.  
  991.   if (!RegisterClass((LPWNDCLASS)pRevClass))
  992.     {
  993.       LocalFree((HANDLE)pRevClass);
  994.       return(FALSE);
  995.     }
  996.   LocalFree((HANDLE)pRevClass);
  997.  
  998.   return(TRUE);
  999. }
  1000.  
  1001.  
  1002. //
  1003. //  FUNCTION: RevMouseClick()
  1004. //
  1005. //  PURPOSE:  Handle mouse click or keyboard space or CR 
  1006. //
  1007.  
  1008. VOID NEAR PASCAL RevMouseClick(
  1009. HWND  hWnd,
  1010. POINT point)
  1011. {
  1012.   INT     move;
  1013.   INT     Si, Sj;
  1014.   INT     yLineExt = 8 * yExt;
  1015.   INT     xLineExt = 8 * xExt;
  1016.   HDC     hDC;
  1017.  
  1018.   MousePos.x = point.x;
  1019.   MousePos.y = point.y;
  1020.  
  1021.   if (xExt == 0 || yExt == 0)
  1022.       return;
  1023.  
  1024.   if ((point.x > Bx) && (point.x < (Bx+xLineExt)) && (point.y > By) && (point.y < (By+yLineExt)))
  1025.     {
  1026.       Si = (point.x - Bx) / xExt;
  1027.       Sj = (point.y - By) / yExt;
  1028.       move = Si * 10 + Sj + 11;
  1029.       if (legalcheck(board[0], move, human, computer))
  1030.         {
  1031.           board[0][move] = human;
  1032.           ffirstmove = FALSE;
  1033.           fThinking = TRUE;
  1034.           SetCursor(curThink);
  1035.  
  1036.           hDisp = hDC = GetDC(hWnd);
  1037.           ClearMessageTop(hDC);
  1038.  
  1039.           minmax(board, move, human, computer, 0, -infin, infin);
  1040.           makemove(board[0], move, human, computer);
  1041.  
  1042.           hDisp = hDC;
  1043.  
  1044.           paintmove(board[0], BestMove[0], computer, human);
  1045.           gameover(hWnd, hDC, board, BestMove[0]);
  1046.  
  1047.           ReleaseDC(hWnd, hDC);
  1048.           hDisp = 0;
  1049.  
  1050.           SetCursor(curIllegal);
  1051.           fThinking = FALSE;
  1052.         }
  1053.       else
  1054.           MessageBox(hWnd, (LPSTR)szIllegal, (LPSTR)szReversi, MB_OK | MB_ICONASTERISK);
  1055.    }
  1056. }
  1057.  
  1058.  
  1059. //
  1060. //  FUNCTION: Next()
  1061. //
  1062. //  PURPOSE:  Find next square 
  1063. //
  1064.  
  1065. VOID NEAR PASCAL Next(
  1066. register INT *px,
  1067. register INT *py)
  1068.  
  1069. {
  1070.   (*px)++;
  1071.   if (*px > 7)
  1072.     {
  1073.       *px = 0;
  1074.       (*py)++;
  1075.       if (*py > 7)
  1076.           *py = 0;
  1077.     }
  1078. }
  1079.  
  1080.  
  1081. //
  1082. //  FUNCTION: Previous()
  1083. //
  1084. //  PURPOSE:  Find previous square 
  1085. //
  1086.  
  1087. VOID NEAR PASCAL Previous(
  1088. register INT *px,
  1089. register INT *py)
  1090. {
  1091.   (*px)--;
  1092.   if (*px < 0)
  1093.     {
  1094.       *px = 7;
  1095.       (*py)--;
  1096.       if (*py < 0)
  1097.           *py = 7;
  1098.     }
  1099. }
  1100.  
  1101.  
  1102. //
  1103. //  FUNCTION: ShowNextMove()
  1104. //
  1105. //  PURPOSE:  Show next legal move 
  1106. //
  1107.  
  1108. VOID NEAR PASCAL ShowNextMove(
  1109. HWND    hwnd,
  1110. BOOL    fforward)
  1111. {
  1112.   INT       x, y;
  1113.   INT       potentialmove;
  1114.   BOOL      done;
  1115.  
  1116.   if (fPass == PASS && !ffirstmove)   // Watch out for infinite loops
  1117.       return;
  1118.  
  1119.   x = (MousePos.x - Bx) / xExt;
  1120.   y = (MousePos.y - By) / yExt;
  1121.  
  1122.   done = FALSE;
  1123.   while (!done)
  1124.     {
  1125.       do
  1126.         {
  1127.           if (fforward)
  1128.               Next(&x, &y);
  1129.           else
  1130.               Previous(&x, &y);
  1131.         }
  1132.       while ((board[0][potentialmove = (x * 10 + y + 11)]) != empty);
  1133.  
  1134.       fThinking = TRUE;
  1135.       if (legalcheck(board[0], potentialmove, human, computer))
  1136.           done = TRUE;
  1137.  
  1138.       fThinking = FALSE;
  1139.     }
  1140.  
  1141.   MousePos.x = x * xExt + Bx + xExt / 2;
  1142.   MousePos.y = y * yExt + By + yExt / 2;
  1143.  
  1144.   UpdateCursor(hwnd);
  1145.   RevMouseMove(MousePos);
  1146. }
  1147.  
  1148.  
  1149. //
  1150. //  FUNCTION: RevChar()
  1151. //
  1152. //  PURPOSE:  Called on WM_KEYDOWN messages 
  1153. //
  1154.  
  1155. VOID NEAR PASCAL RevChar(
  1156. HWND            hwnd,
  1157. register WORD   code)
  1158. {
  1159.   INT   a;
  1160.   POINT curpoint;
  1161.  
  1162.   curpoint.x = curpoint.y = 1;
  1163.   switch (code)
  1164.     {
  1165.       case 0x27:
  1166.           MousePos.x += xExt;
  1167.           break;
  1168.  
  1169.       case 0x28:
  1170.           MousePos.y += yExt;
  1171.           break;
  1172.  
  1173.       case 0x25:
  1174.           curpoint.x = (MousePos.x - Bx)/xExt;
  1175.           MousePos.x -= xExt;
  1176.           break;
  1177.  
  1178.       case 0x26:
  1179.           curpoint.y = (MousePos.y - By)/yExt;
  1180.           MousePos.y -= yExt;
  1181.           break;
  1182.  
  1183.       case 0x24:
  1184.           curpoint.y = (MousePos.y - By)/yExt;
  1185.           curpoint.x = (MousePos.x - Bx)/xExt;
  1186.           MousePos.y -= yExt;
  1187.           MousePos.x -= xExt;
  1188.           break;
  1189.  
  1190.       case 0x21:
  1191.           curpoint.y = (MousePos.y - By)/yExt;
  1192.           MousePos.y -= yExt;
  1193.           MousePos.x += xExt;
  1194.           break;
  1195.  
  1196.       case 0x23:
  1197.           curpoint.x = (MousePos.x - Bx)/xExt;
  1198.           MousePos.y += yExt;
  1199.           MousePos.x -= xExt;
  1200.           break;
  1201.  
  1202.       case 0x22:
  1203.           MousePos.y += yExt;
  1204.           MousePos.x += xExt;
  1205.           break;
  1206.  
  1207.       case 0x0020:
  1208.       case 0x000D:
  1209.           if (!fThinking)
  1210.               RevMouseClick(hwnd, MousePos);
  1211.           return;
  1212.  
  1213.       case 0x0009:
  1214.           if (fThinking)
  1215.               break;
  1216.           if (GetKeyState(VK_SHIFT) < 0)
  1217.               ShowNextMove(hwnd, FALSE);    // look backwards
  1218.           else
  1219.               ShowNextMove(hwnd, TRUE);     // look forwards
  1220.           return;
  1221.  
  1222.       default:
  1223.           return;
  1224.     }
  1225.  
  1226.   if (((a = ((MousePos.x - Bx) / xExt)) >7) || a <= 0)
  1227.       MousePos.x = Bx + xExt / 2;             /* wrap around horizontally */
  1228.  
  1229.   if (a > 8 || (curpoint.x == 0 && a == 0))
  1230.       MousePos.x = (7*xExt) + Bx + xExt / 2 ;
  1231.  
  1232.   if ( ((a = ((MousePos.y - By) / yExt)) >7) || a <= 0)
  1233.       MousePos.y = By + yExt / 2;
  1234.  
  1235.   if ( a > 8 || (curpoint.y == 0 && a == 0))
  1236.       MousePos.y = (7*yExt) + By + yExt / 2;
  1237.  
  1238.   MousePos.x = ((MousePos.x - Bx) / xExt) * xExt + Bx + xExt / 2;
  1239.   MousePos.y = ((MousePos.y - By) / yExt) * yExt + By + yExt / 2;
  1240.   UpdateCursor(hwnd);
  1241.   RevMouseMove(MousePos);
  1242. }
  1243.  
  1244.  
  1245. //
  1246. //  FUNCTION: InverseMessage()
  1247. //
  1248. //  PURPOSE:  Callback - inverts message bitmap or kills timer 
  1249. //
  1250.  
  1251. LONG APIENTRY InverseMessage(
  1252. register HWND   hWindow,
  1253. UINT            message,
  1254. WPARAM          wParam,
  1255. LONG            lParam)
  1256. {
  1257.   HDC   hDC;
  1258.  
  1259.   message;
  1260.   wParam;
  1261.   lParam;
  1262.  
  1263.   if (flashtimes <= count)
  1264.     {
  1265.       hDC = GetDC(hWindow);
  1266.       PatBlt(hDC, 0, 0, xscr, charheight, DSTINVERT);
  1267.       flashtimes++;
  1268.       ReleaseDC(hWindow, hDC);
  1269.     }
  1270.   else
  1271.       KillTimer(hWindow, 666);
  1272.   return(0L);
  1273. }
  1274.  
  1275.  
  1276. //
  1277. //  FUNCTION: ReversiWndProc()
  1278. //
  1279. //  PURPOSE:  Processes messages for "Reversi" window  
  1280. //
  1281.  
  1282. LONG APIENTRY ReversiWndProc(
  1283. HWND            hWnd,
  1284. register UINT   message,
  1285. WPARAM          wParam,
  1286. LONG            lParam)
  1287. {
  1288.   HMENU         hm;
  1289.   PAINTSTRUCT   ps;
  1290.   POINT         curpoint;
  1291.  
  1292.   switch (message)
  1293.     {
  1294.       case WM_COMMAND:
  1295.           RevMenu(hWnd, GET_WM_COMMAND_ID(wParam, lParam));
  1296.           break;
  1297.  
  1298.       case WM_INITMENU:                 // disable the menu if thinking
  1299.           hm = GetMenu(hWnd);
  1300.           if (fThinking)
  1301.             {
  1302.               EnableMenuItem(hm, 0, MF_DISABLED | MF_BYPOSITION);
  1303.               EnableMenuItem(hm, 1, MF_DISABLED | MF_BYPOSITION);
  1304.             }
  1305.           else
  1306.             {
  1307.               EnableMenuItem(hm, 0, MF_ENABLED | MF_BYPOSITION);
  1308.               EnableMenuItem(hm, 1, MF_ENABLED | MF_BYPOSITION);
  1309.             }
  1310.           break;
  1311.  
  1312.       case WM_CREATE:
  1313.           RevCreate(hWnd);
  1314.           hWin = hWnd;
  1315.           break;
  1316.  
  1317.       case WM_CLOSE:
  1318.           return(DefWindowProc(hWnd, message, wParam, lParam));
  1319.  
  1320.       case WM_DESTROY:
  1321.           //if (MGetModuleUsage(hInst) == 1)
  1322.             {
  1323.               // check this because the green brush is used as the class
  1324.               // background brush if we are on a color system in which
  1325.               // case we don't handle the brush deletion, Windows does
  1326.               if (!COLOR)
  1327.                 DeleteObject(hbrGreen);
  1328.  
  1329.               DeleteObject(hbrRed);
  1330.               DeleteObject(hbrBlue);
  1331.             }
  1332.  
  1333.           // In case WinHelp keys off hWindow, we need to do the HELP_QUIT
  1334.           // here instead of when there is just one instance of help...
  1335.           //
  1336.           //TEMPFIX WinHelp(hWnd, (LPSTR)szHelpFile, HELP_QUIT, 0L);
  1337.  
  1338.           PostQuitMessage(0);
  1339.           break;
  1340.  
  1341.       case WM_KEYDOWN:
  1342.           if (IsIconic(hWnd))
  1343.               return 0L;
  1344.           RevChar(hWnd, (WORD)wParam);
  1345.           break;
  1346.  
  1347.       case WM_ACTIVATE:
  1348.           if (!GetSystemMetrics(SM_MOUSEPRESENT))
  1349.             {
  1350.               if (GET_WM_ACTIVATE_STATE(wParam, lParam))
  1351.                 {
  1352.                   if (GET_WM_ACTIVATE_HWND(wParam, lParam) != hWnd)
  1353.                     {
  1354.                       curpoint.x = MousePos.x;
  1355.                       curpoint.y = MousePos.y;
  1356.                       ClientToScreen(hWnd, (LPPOINT)&curpoint);
  1357.                       SetCursorPos(curpoint.x, curpoint.y);
  1358.                       RevMouseMove(MousePos);
  1359.                       ShowCursor(GET_WM_ACTIVATE_STATE(wParam, lParam));
  1360.                     }
  1361.                 }
  1362.               else
  1363.                   ShowCursor(wParam);
  1364.             }
  1365.           if (wParam && (!HIWORD(lParam)))
  1366.               SetFocus(hWnd);
  1367.           break;
  1368.  
  1369.       case WM_PAINT:
  1370.           BeginPaint(hWnd, (LPPAINTSTRUCT)&ps);
  1371.           RevPaint(hWnd, ps.hdc);
  1372.           EndPaint(hWnd, (LPPAINTSTRUCT)&ps);
  1373.           break;
  1374.  
  1375.       case WM_MOUSEMOVE:
  1376.           {
  1377.           POINT pt;
  1378.  
  1379.           LONG2POINT(lParam, pt);  // convert LONG lParam to POINT structure
  1380.           if (!fThinking)
  1381. #ifdef ORGCODE      
  1382.               RevMouseMove(MAKEPOINT(lParam));
  1383. #else
  1384.               RevMouseMove(pt);
  1385. #endif
  1386.           else
  1387.               SetCursor(curThink);
  1388.           break;
  1389.           }
  1390.       case WM_LBUTTONDOWN:
  1391.           SetCapture(hWnd);
  1392.           bMouseDownInReversi = TRUE;
  1393.           break;
  1394.  
  1395.       case WM_LBUTTONUP:
  1396.           {
  1397.           POINT pt;
  1398.  
  1399.           LONG2POINT(lParam, pt);  // convert LONG lParam to POINT structure
  1400.  
  1401.           ReleaseCapture();
  1402.           if (!fThinking && bMouseDownInReversi)
  1403. #ifdef ORGCODE
  1404.               RevMouseClick(hWnd, MAKEMPOINT(lParam));
  1405. #else
  1406.               RevMouseClick(hWnd, pt);
  1407. #endif
  1408.           bMouseDownInReversi = FALSE;
  1409.           break;
  1410.           }
  1411.       case WM_TIMER:
  1412.           // This should never be called.
  1413.           break;
  1414.  
  1415.       case WM_VSCROLL:
  1416.       case WM_HSCROLL:
  1417.               break;
  1418.  
  1419.       default:
  1420.           return(DefWindowProc(hWnd, message, wParam, lParam));
  1421.           break;
  1422.       }
  1423.   return(0L);
  1424. }
  1425.  
  1426. //
  1427. //  FUNCTION: AboutDlgProc(HWND, WORD, WORD, LONG)
  1428. //
  1429. //  PURPOSE:  Processes messages for "About" dialog box
  1430. //
  1431. //  MESSAGES:
  1432. //
  1433. //      WM_INITDIALOG - initialize dialog box
  1434. //      WM_COMMAND    - Input received
  1435. //
  1436.  
  1437. BOOL APIENTRY AboutDlgProc(
  1438. HWND        hDlg,
  1439. WORD        message,
  1440. WORD        wParam,
  1441. LONG        lParam)
  1442.  
  1443. {
  1444.   if (message == WM_COMMAND)
  1445.     {
  1446.       EndDialog(hDlg, TRUE);
  1447.       return(TRUE);
  1448.     }
  1449.   if (message == WM_INITDIALOG)
  1450.       return(TRUE);
  1451.   else
  1452.       return(FALSE);
  1453.   UNREFERENCED_PARAMETER(wParam);   
  1454.   UNREFERENCED_PARAMETER(lParam);   
  1455. }
  1456.  
  1457.  
  1458. //
  1459. //  FUNCTION: WinMain
  1460. //
  1461. //  PURPOSE: calls initialization function, processes message loop
  1462. //
  1463.  
  1464. int APIENTRY WinMain(
  1465.     HINSTANCE hInstance,
  1466.     HINSTANCE hPrev,
  1467.     LPSTR     lpCmdLine,
  1468.     int       cmdShow
  1469. ) {
  1470.   HWND hWnd;
  1471.   MSG   msg;
  1472.  
  1473.   hInst = hInstance;
  1474.   if (!hPrev)
  1475.     {
  1476.       if (!RevInit(hInstance))
  1477.           return(FALSE);
  1478.     }
  1479.   else
  1480.     {
  1481.       if (fThinking)
  1482.           return FALSE;
  1483. #ifdef WIN16
  1484.       GetInstanceData(hPrev, (PSTR)&hbrBlack,           sizeof(HBRUSH));
  1485.       GetInstanceData(hPrev, (PSTR)&hbrPat,             sizeof(HBRUSH));
  1486.       GetInstanceData(hPrev, (PSTR)&hbrWhite,           sizeof(HBRUSH));
  1487.       GetInstanceData(hPrev, (PSTR)&hbrRed,             sizeof(HBRUSH));
  1488.       GetInstanceData(hPrev, (PSTR)&hbrBlue,            sizeof(HBRUSH));
  1489.       GetInstanceData(hPrev, (PSTR)&hbrGreen,           sizeof(HBRUSH));
  1490.       GetInstanceData(hPrev, (PSTR)&hbrComputer,        sizeof(HBRUSH));
  1491.       GetInstanceData(hPrev, (PSTR)&hbrHuman,           sizeof(HBRUSH));
  1492.       GetInstanceData(hPrev, (PSTR)&curIllegal,         sizeof(HCURSOR));
  1493.       GetInstanceData(hPrev, (PSTR)&curLegal,           sizeof(HCURSOR));
  1494.       GetInstanceData(hPrev, (PSTR)&curThink,           sizeof(HCURSOR));
  1495.       GetInstanceData(hPrev, (PSTR)&curBlank,           sizeof(HCURSOR));
  1496.       GetInstanceData(hPrev, (PSTR)&prevCheck,          sizeof(prevCheck));
  1497.       GetInstanceData(hPrev, (PSTR)&depth,              sizeof(depth));
  1498.       GetInstanceData(hPrev, (PSTR)direc,               sizeof(direc));
  1499.       GetInstanceData(hPrev, (PSTR)moves,               sizeof(moves));
  1500.       GetInstanceData(hPrev, (PSTR)szReversi,           20);
  1501.       GetInstanceData(hPrev, (PSTR)szReversiPractice,   40);
  1502.       GetInstanceData(hPrev, (PSTR)szPass,              10);
  1503.       GetInstanceData(hPrev, (PSTR)szMustPass,          20);
  1504.       GetInstanceData(hPrev, (PSTR)szTie,               15);
  1505.       GetInstanceData(hPrev, (PSTR)szLoss,              15);
  1506.       GetInstanceData(hPrev, (PSTR)szWon,               15);
  1507.       GetInstanceData(hPrev, (PSTR)szAbout,             20);
  1508.       GetInstanceData(hPrev, (PSTR)&COLOR,              sizeof(INT));
  1509.       GetInstanceData(hPrev, (PSTR)&ASPECT,             sizeof(INT));
  1510.       GetInstanceData(hPrev, (PSTR)&hAccel,             2);
  1511.       GetInstanceData(hPrev, (PSTR)szIllegal,           70);
  1512.       GetInstanceData(hPrev, (PSTR)szNoPass,            70);
  1513.       GetInstanceData(hPrev, (PSTR)szHelpFile,          15);
  1514. #endif // WIN16     
  1515.     }
  1516.   lpprocInverseMessage = (WNDPROC)MakeProcInstance((FARPROC)(LPVOID)InverseMessage, hInstance);
  1517.  
  1518.   TYMIN = 45;
  1519.   fThinking = FALSE;
  1520.  
  1521.   lpprocAbout = MakeProcInstance((FARPROC)AboutDlgProc, hInstance);
  1522.   hWnd = CreateWindow((LPSTR) "Reversi",
  1523.                 fCheated ? (LPSTR)szReversiPractice : (LPSTR)szReversi,
  1524.                 WS_TILEDWINDOW,
  1525.                 CW_USEDEFAULT,
  1526.                 0,
  1527.                 (GetSystemMetrics(SM_CXSCREEN) >> 1),
  1528.                 (GetSystemMetrics(SM_CYSCREEN) * 4 / 5),
  1529.                 (HANDLE)NULL,
  1530.                 (HANDLE)NULL,
  1531.                 (HANDLE)hInstance,
  1532.                 NULL);
  1533.  
  1534.   if (!hWnd)
  1535.       return(FALSE);
  1536.  
  1537.   ShowWindow(hWnd, cmdShow);
  1538.   UpdateWindow(hWnd);
  1539.  
  1540.   // Messaging Loop
  1541.   while (GetMessage((LPMSG)&msg, NULL, 0, 0))
  1542.     {
  1543.       if (!TranslateAccelerator(msg.hwnd, hAccel, (LPMSG)&msg))
  1544.         {
  1545.           TranslateMessage((LPMSG)&msg);
  1546.           DispatchMessage((LPMSG)&msg);
  1547.         }
  1548.     }
  1549.   return(0);
  1550. }
  1551.