/******************************************************************
*
*   Reversi
*
*   A desktop program for the Apple IIGS.
*
*   Reversi is a board game played between two players.	 This
*   program will play against an opponent (probably you, but you
*   could play it against another program), or it will play
*   itself (useful when you are learning).
*
*   To play the game, the black piece goes first; the human
*   plays black by default (the game allows this to be changed).
*   The object of the game is to try to trap enemy pieces
*   between one of your existing pieces and the new piece to
*   be played.
*
*   The game is so popular and well known that there are several
*   commercial versions available, and all come with rules and
*   basic strategy hints.  Many fine books are also available
*   from your local book store.	 When looking, you should note
*   that the game is also sold under the name Othello.
*
*   The program itself is provided as a real-world example of
*   using the desktop.	Unlike the other samples on this disk,
*   this program was designed as a working game, not as a
*   sample.  For that reason, some problems that can be avoided
*   by careful choice of a sample are handled here - like
*   scrolling without the help of TaskMaster (to avoid scrolling
*   a small part of the Moves window).
*
*   To learn how the program works, start with the main event
*   loop at the end of the program, and examine how it handles
*   each event.	 The move selection procedure, FindMove, is the
*   only place where an event loop is not used.	 That function
*   uses a technique called an alpha-beta search to find the best
*   move.  To understand that search, you may refer to text books
*   on artificial intelligence, or to any one of several fine
*   articles, mostly dealing with chess, that appeared in Byte
*   Magazine in the early 1980's.
*
*   Note that the program is contained in two files:  the first
*   part of the source program is in the file named
*   REVERSI1.CC, while the second part of the source is in the
*   file named REVERSI2.CC.  The ORCA/C append command is used
*   at the end of the first file to automatically begin
*   compilation of the second source file.
*
*   Original Pascal version by Mike Westerfield
*
*   C translation by Barbara Allred
*
*   Copyright 1987-1989
*   Byte Works, Inc.
*
*******************************************************************/

#pragma keep "Reversi"
#pragma lint -1

#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include <orca.h>

#include <types.h>
#include <quickdraw.h>
#include <qdaux.h>
#include <misctool.h>
#include <event.h>
#include <control.h>
#include <window.h>
#include <menu.h>
#include <desk.h>
#include <lineedit.h>
#include <dialog.h>

#define squareWidth  52				  /* width of one square      */
#define squareHeight 20				  /* height of one square     */

#define blank	      0				  /* square colors	      */
#define blackPiece    1
#define whitePiece    2
#define border	      3

#define apple_AboutReversi 257			  /* menu names/numbers	      */

#define file_NewGame	   258
#define file_Quit	   259

#define edit_UndoLastMove  270
#define edit_Cut 	   271
#define edit_Copy	   272
#define edit_Paste	   273
#define edit_Clear	   274

#define level_1Ply	   262
#define level_2Ply	   263
#define level_3Ply	   264
#define level_4Ply	   265
#define level_5Ply	   266
#define level_6Ply	   267
#define level_7Ply	   268
#define level_8Ply	   269

#define options_SelfPlay 	   280
#define options_ComputerPlaysWhite 281
#define options_Pass		   282
#define options_ShowScoreWindow	   283
#define options_ShowMovesWindow	   284


typedef int BOOL;				    /* simulate boolean types */

enum   alertKind { norml, stop, note, caution }; 	   /* kinds of alerts */
							   /* move list:      */
struct moveListType { int  num;				   /*	#legal moves  */
		      char moves [60]; };		   /*	list of moves */


/* Global variables */

static int  ply = 1;		      /* set initial playing level to 1	      */
static int  color = whitePiece;	      /* color the computer plays	      */
static int  currentColor;	      /* color to move next		      */
static int  movesMade;		      /* # moves, by playing level, made      */
static int  topMove;		      /* 1st visible move in moves list	      */
static int  event;		      /* event #; returned by TaskMaster      */
static int  moveHeight;		      /* current height of move window	      */
static int  charHeight;		      /* size of a character		      */
static int  moves [61];		      /* list of moves made		      */

static int  disp  [8] =		      /* move displacements		      */
{ 9, 10, 11, -1, 1, -9, -10, -11 };

static int  bSc	  [300] =	      /* square scores for 3 portions of game */
{    0,	   0,	 0,    0,    0,	   0,	 0,    0,    0,	   0,	 0,  500,  -20,
   100,	  50,	50,  100,  -20,	 500,	 0,    0,  -20, -250,	-2,   -2,   -2,
    -2, -250,  -20,    0,    0,	 100,	-2,   30,   10,	  10,	30,   -2,  100,
     0,	   0,	50,   -2,   10,	   2,	 2,   10,   -2,	  50,	 0,    0,   50,
    -2,	  10,	 2,    2,   10,	  -2,	50,    0,    0,	 100,	-2,   30,   10,
    10,	  30,	-2,  100,    0,	   0,  -20, -250,   -2,	  -2,	-2,   -2, -250,
   -20,	   0,	 0,  500,  -20,	 100,	50,   50,  100,	 -20,  500,    0,    0,
     0,	   0,	 0,    0,    0,	   0,	 0,    0,    0,	   0,	 0,    0,    0,
     0,	   0,	 0,    0,    0,	   0,	 0,  500,  -20,	 200,	50,   50,  200,
   -20,	 500,	 0,    0,  -20, -250,	15,   10,   10,	  15, -250,  -20,    0,
     0,	 200,	15,   35,   20,	  20,	35,   15,  200,	   0,	 0,   50,   10,
    20,	  15,	15,   20,   10,	  50,	 0,    0,   50,	  10,	20,   15,   15,
    20,	  10,	50,    0,    0,	 200,	15,   35,   20,	  20,	35,   15,  200,
     0,	   0,  -20, -250,   15,	  10,	10,   15, -250,	 -20,	 0,    0,  500,
   -20,	 200,	50,   50,  200,	 -20,  500,    0,    0,	   0,	 0,    0,    0,
     0,	   0,	 0,    0,    0,	   0,	 0,    0,    0,	   0,	 0,    0,    0,
     0,	   0,	 0,  400,  -20,	 100,	75,   75,  100,	 -20,  400,    0,    0,
   -20, -300,	60,   10,   10,	  60, -300,  -20,    0,	   0,  100,   60,   50,
     5,	   5,	50,   60,  100,	   0,	 0,   75,   10,	   5,	30,   30,    5,
    10,	  75,	 0,    0,   75,	  10,	 5,   30,   30,	   5,	10,   75,    0,
     0,	 100,	60,   50,    5,	   5,	50,   60,  100,	   0,	 0,  -20, -300,
    60,	  10,	10,   60, -300,	 -20,	 0,    0,  400,	 -20,  100,   75,   75,
   100,	 -20,  400 };

static BOOL done;		      /* are we done yet?		      */
static BOOL selfPlay;		      /* computer-human or computer-computer  */
static BOOL movesLeft;		      /* are there legal moves left?	      */
static BOOL updateMoves; 	      /* does entire list need updating?      */
static BOOL showScoreWindow;	      /* is scoreWindow visible? 	      */
static BOOL showMovesWindow;	      /* is movesWindow visible? 	      */
static BOOL movesNotFront;	      /* is Moves window the front window?    */

static char board [100]; 	      /* main game board 		      */
static char msg	  [256]; 	      /* for builing alert strings	      */

				      /* strings for SetItem calls	      */
static char selfPlayStr	       [] = "--Self Play";
static char computerPlayStr    [] = "--Play Computer";
static char computerPlaysBlack [] = "--Computer Plays Black";
static char computerPlaysWhite [] = "--Computer Plays White";

static WmTaskRec lastEvent;		 /* last event returned in event loop */

static ParamList wParms =			  /* parameters for NewWindow */
       { 78, 0x80E4, NULL, 0, 0, 0, 0, 0, NULL, 0, 0, squareHeight * 8,
	 squareWidth * 8, squareHeight * 8, squareWidth * 8, 0, 0, 0, 0, 0, 0,
	 NULL, NULL, NULL, 32, 32, 32 + squareHeight * 8, 32 + squareWidth * 8,
	 (GrafPortPtr) topMost, NULL };
static ParamList boardParms, scoreParms, movesParms;	  /* window parameter */
							  /*   records	      */

static GrafPortPtr boardWindow;		/* pointer to the game board window   */
static GrafPortPtr scoreWindow;		/* pointer to the score window	      */
static GrafPortPtr movesWindow;		/* pointer to the Moves window	      */

static CtlRecHndl growHandle;		/* Moves window's grow box            */
static CtlRecHndl vScrollHandle; 	/* Moves window's vertical scroll bar */


/* Utility routines */

/****************************************************************
*
* DoAlert - Create an alert box
*
* Input:
*      kind - kind of alert
*      msg  - alert message
*
****************************************************************/
void DoAlert (enum alertKind kind, char *msg)
{
static ItemTemplate button =				      /* button item  */
       { 1, 36, 15, 0, 0, buttonItem, "\pOK", 0, 0, NULL };

static ItemTemplate message =				      /* message item */
       { 100, 5, 100, 90, 280, itemDisable+statText, NULL, 0, 0, NULL };

static AlertTemplate alertRec =				      /* alert box    */
       { 50, 180, 107, 460, 2, 0x80, 0x80, 0x80, 0x80, NULL, NULL, NULL };


SetForeColor (0);					   /* set text colors */
SetBackColor (15);

message.itemDescr	= msg;				/* init. non-constant */
alertRec.atItemList [0] = (ItemTempPtr) &button; 	/*   template fields  */
alertRec.atItemList [1] = (ItemTempPtr) &message;

switch (kind) {
   case norml:	   Alert (&alertRec, NULL);
		   break;

   case stop:	   StopAlert (&alertRec, NULL);
		   break;

   case note:	   NoteAlert (&alertRec, NULL);
		   break;

   case caution:   CautionAlert (&alertRec, NULL);
		   break;

   default:	   printf ("Error in DoAlert\n");
		   exit (-1);
		   break;
   }
} /* DoAlert */


/****************************************************************
*
* Even - Returns an even number by incrementing odd parameters;
*	 for move list calculations
*
* Input:
*      i - integer tested for being even
*
* Output:
*      i if i is even; i+1 if i is odd
*
****************************************************************/
int Even (int i)
{
if (i & 0x0001)
   return i+1;
else
   return i;
} /* Even */


/* Routines involved in playing the game */

/****************************************************************
*
* Plot - Plot a point
*
* Input:
*      h - horizontal pixel of point
*      v - vertical pixel of point
*
****************************************************************/
void Plot (int h, int v)
{
MoveTo (h, v);
LineTo (h, v);
} /* Plot */


/****************************************************************
*
* DrawSquare - Draw a square on the game board
*
* Input:
*      square - number of square to draw
*      col    - color of square to draw
*
****************************************************************/
void DrawSquare (int square, int col)
{
#define penBlack 0					/* pen colors	      */
#define penGreen 2
#define penWhite 3

Rect r;							/* square's rectangle */

StartDrawing (boardWindow);			 /* draw to our window	      */
r.h2 = (square % 10) * squareWidth - 1;		 /* set up square's rectangle */
r.v2 = (square / 10) * squareHeight - 1;
r.h1 = r.h2 - squareWidth + 1;
r.v1 = r.v2 - squareHeight + 1;

SetSolidPenPat (penGreen);			 /* draw background of square */
PaintRect (&r);
SetSolidPenPat (penBlack);			 /* draw edge of square	      */
MoveTo (r.h1, r.v2);
LineTo (r.h2, r.v2);
LineTo (r.h2, r.v1);

switch (square) {			   /* draw "corner" dots, if required */

   case 22: case 26: case 62: case 66:
       Plot (r.h2-1, r.v2-1);
       break;

   case 23: case 27: case 63: case 67:
       Plot (r.h1, r.v2-1);
       break;

   case 32: case 36: case 72: case 76:
       Plot (r.h2-1, r.v1);
       break;

   case 33: case 37: case 73: case 77:
       Plot (r.h1, r.v1);
       break;

   default:
       break;
   }

if (col != blank) {				    /* draw the piece, if any */
   if (col == whitePiece)
       SetSolidPenPat (penWhite);
   PaintOval (&r);
   }
} /* DrawSquare */


/****************************************************************
*
* DrawBoard - Draw (or redraw) the entire game board
*
****************************************************************/

void DrawBoard (void)
{
int i;							     /* loop variable */
int col; 						     /* column #      */

for (i = 11; i <= 88; i++) {
   col = i % 10;
   if ((col != 0) && (col != 9))
       DrawSquare (i, board[i]);
   }
} /* DrawBoard */


/****************************************************************
*
* GetMoves - Create a list of legal moves
*
* Input:
*      board	- game board to search for moves
*      color	- color of piece for which conducting search
*      moveList - record of moves to make
*
****************************************************************/
void GetMoves (char board[], int color, struct moveListType *moveList)
{
int index;				  /* square being checked	      */
int tindex;				  /* work index			      */
int enemyColor = color ^ 3;		  /* temp variable for enemy color    */
int dir; 				  /* direction being checked	      */
struct moveListType lMoveList;		  /* local move list - for efficiency */

lMoveList.num = 0;				     /* no moves so far	      */
for (index = 11; index < 90; index++) {		     /* loop over all squares */

   if (board[index] == blank)			  /* check only empty squares */

       for (dir = 0; dir < 8; dir++) {		  /* loop in all 8 directions */
	   tindex = index + disp[dir];		  /* see if there's a capture */
	   if (board[tindex] == enemyColor) {	  /*   in this direction      */
	       while (board[tindex] == enemyColor)	 /* skip enemy pieces */
		   tindex += disp[dir];
	       if (board[tindex] == color) {	    /* if last piece is ours, */
						    /*	 move is legal	      */
		   lMoveList.moves [lMoveList.num] = index;
		   lMoveList.num++;
		   goto Out;
		   }
	       }
	   }
Out: ;
 }
*moveList = lMoveList;					  /* return move list */
} /* GetMoves */


/****************************************************************
*
* CheckForDone - Check if game is over
*
****************************************************************/
void CheckForDone (void)
{
struct moveListType moveList;		   /* for checking # of moves	      */
char string [10];			   /* for converting scores to strings*/
int  wcnt, bcnt; 			   /* # pieces for each side	      */
int  i;					   /* loop variable		      */

GetMoves (board, whitePiece, &moveList);
if (! moveList.num) {
   GetMoves (board, blackPiece, &moveList);
   if (! moveList.num) {
       for (i = 11, wcnt = 0, bcnt = 0; i < 90; i++) {
	   if (board[i] == whitePiece)
	       wcnt++;
	   else if (board[i] == blackPiece)
	       bcnt++;
	   }
       if (wcnt == bcnt)
	   strcpy (msg, "The game is overs. It\ris a draw.");

       else {
	   if (wcnt > bcnt)
	       strcpy (msg, "White");
	   else
	       strcpy (msg, "Black");
	   strcat (msg, " wins by a score\rof ");
	   sprintf (string, "%d", bcnt); 	       /* convert scores to strings */
	   strcat (msg, string);
	   strcat (msg, " to ");
	   sprintf (string, "%d", wcnt);
	   strcat (msg, string);
	   }
       DoAlert (note, c2pstr (msg));
       movesLeft = false;
       }
   }
} /* CheckForDone */


/****************************************************************
*
* ScoreEdge - Score an edge of the game board by these rules:
*
*   1. An edge must have at least one empty square to be scored.
*   2. If there is a single space between friendly pieces, score -100.
*   3. If there are two spaces between friendly pieces, score 30.
*   4. If there are three spaces between friendly pieces, score -50.
*   5. If there is a solid line of enemy pieces between friendly
*      pieces, score -150;
*
* Input:
*      edge - array of edge squares to score
*
* Output:
*      score of edges
*
****************************************************************/
int ScoreEdge (int edge[])
{
BOOL atLeastOneBlank;			     /* for checking rule #1	      */
int  s = 0, rs;				     /* for computing scores	      */
int  enemyColor; 			     /* temp variable for enemy color */
int  i, j;				     /* loop variables		      */

atLeastOneBlank = false; 				  /* check rule 1     */
for (i = 1; i < 9; i++)
   atLeastOneBlank = atLeastOneBlank || (edge[i] == blank);

if (atLeastOneBlank)					  /* check all edge   */
   for (i = 1; i < 8; i++)				  /*   positions      */
       if ((edge[i] == blackPiece) || (edge[i] == whitePiece)) {
	   enemyColor = edge[i] ^ 3;
	   j = i + 1;
	   if (edge[j] == enemyColor) {			  /* check rule 5     */
	       while (edge[j] == enemyColor)
		   j++;
	       if (edge[j] == edge[i])
		   if (enemyColor == whitePiece)
		       s -= 150;
		   else
		       s += 150;
	       }
	   else if (edge[j] == blank) {			  /* check rules 2..4 */
	       while (edge[j] == blank)
		   j++;
	       if (edge[j] == edge[i]) {
		   switch (j - i) {
		       case 2: rs = -100;		  /* score rule 2     */
			       break;

		       case 3: rs = 30;			  /* score rule 3     */
			       break;

		       case 4: rs = -50; 		  /* score rule 4     */
			       break;

		       default:	 break;
		       }

		   if (edge[i] == whitePiece)
		       s -= rs;
		   else
		       s += rs;
		   } /* if */
	       } /* else if */
	   } /* if */
   return s;
} /* ScoreEdge */


/****************************************************************
*
* Score - Score the game board passed
*
* Input:
*      board - game board to score
*
* Output:
*      score of game board
*
****************************************************************/
int Score (char board[])
{
int s = 0, rs;					/* temp variables for scoring */
int pi;						/* game portion index	      */
int numPieces = 0;				/* # pieces on board	      */
int edge [10];					/* for scoring edges	      */
int i;						/* loop variable 	      */

for (i = 11; i < 90; i++)			/* loop over all squares      */
   if (board[i] == whitePiece) { 		/* add 4 for black, decrement */
       s -= 4;					/*   4 for white 	      */
       numPieces++;
       }
   else if (board[i] == blackPiece) {
       s += 4;
       numPieces++;
       }

if (numPieces < 24)			       /* set index into board scores */
   pi = 0;				       /*   by part of game this is   */
else if (numPieces < 44)
   pi = 100;
else
   pi = 200;

for (i = 11; i < 90; i++)		       /* loop over all squares,      */
					       /*    summing square values    */
   if ((board[i] == blackPiece) || (board[i] == whitePiece)) {

       if ((i == 12) || (i == 21) || (i == 22)) /* squares adjacent to corners */
	 {				       /*   get special treatment     */
	   if ((board[11] == blackPiece) || (board[11] == whitePiece))
	       rs = 10;
	   else
	       rs = bSc[pi+i];
	   }

       else if ((i == 17) || (i == 27) || (i == 28)) {
	   if ((board[18] == blackPiece) || (board[18] == whitePiece))
	       rs = 10;
	   else
	       rs = bSc[pi+i];
	   }

       else if ((i == 71) || (i == 72) || (i == 82)) {
	   if ((board[81] == blackPiece) || (board[81] == whitePiece))
	       rs = 10;
	   else
	       rs = bSc[pi+i];
	   }

       else if ((i == 77) || (i == 78) || (i == 87)) {
	   if ((board[88] == blackPiece) || (board[88] == whitePiece))
	       rs = 10;
	   else
	       rs = bSc[pi+i];
	   }

       else
	   rs = bSc[pi+i];

       if (board[i] == whitePiece)
	   s -= rs;
       else
	   s += rs;
       }

for (i = 0; i < 10; i++) 				 /* score top edge    */
   edge[i] = board[10+i];
s += ScoreEdge (edge);

for (i = 0; i < 10; i++) 				 /* score bottom edge */
   edge[i] = board[i+80];
s += ScoreEdge (edge);

for (i = 0; i < 10; i++) 				 /* score left edge   */
   edge[i] = board[1+i*10];
s += ScoreEdge (edge);

for (i = 0; i < 10; i++) 				 /* score right edge  */
   edge[i] = board[8+i*10];
s += ScoreEdge (edge);

return s;						 /* return the score  */
} /* Score */


/****************************************************************
*
* MakeAMove - Make a move on the main playing board
*
* Input:
*      index - board index of move to make
*      col   - color of player making move
*
****************************************************************/
void MakeAMove (int index, int col)
{
#define pause 100			     /* index for pause		      */

int dir; 				     /* loop variable for directions  */
int tindex;				     /* temp index; for captures      */
int enemyColor;				     /* temp variable for enemy color */
int i;					     /* loop variable		      */

moves[++movesMade] = index;			    /* record the move	      */
DrawSquare (index, col); 			    /* flash the piece played */
for (i = 0; i < pause; i++)
   ;
DrawSquare (index, blank);
for (i = 0; i < pause; i++)
    ;
DrawSquare (index, col);

board[index] = col;				/* make the move on the board */
enemyColor   = col ^ 3;				/* set enemy color	      */
for (dir = 0; dir < 8; dir++) {			/* loop in all 8 directions   */
   tindex = index + disp[dir];			/* see if there's a capture   */
   if (board[tindex] == enemyColor) {		/*   in this direction	      */

       while (board[tindex] == enemyColor)	/* skip enemy pieces	      */
	   tindex += disp[dir];

       if (board[tindex] == col) {	    /* if last piece is ours, capture */
	   tindex = index + disp[dir];

	   while (board[tindex] != col) {
	       DrawSquare (tindex, col);
	       board[tindex]  = col;
	       tindex	     += disp[dir];
	       } /* while */
	   } /* if */
       } /* if */
   } /* for */
} /* MakeAMove */


/****************************************************************
*
* EndScore - Compute an end-game score (no more moves) for passed board
*
* Input:
*      board - game board to score
*
* Output:
*      score of game board passed
*
****************************************************************/
int EndScore (char board[])
{
int s = 0;						/* work copy of score */
int i;							/* loop variable      */

for (i = 11; i < 90; i++)			/* count difference in pieces */
   if (board[i] == whitePiece)
       s--;
   else if (board[i] == blackPiece)
       s++;

if (s < 0)					      /* set the return value */
   return INT_MIN + 65 + s;
else if (s > 0)
   return INT_MAX - 65 + s;
else
   return 0;
} /* EndScore */


static char boardName [] = "\pReversi";		/* names of Reversi's windows */
static char scoreName [] = "\pScores";
static char movesName [] = "\pMoves";


/****************************************************************
*
* ScoreMove - Find the score for a particular move
*
* Input:
*      board - game board to make move on
*      index - move to make
*      s     - best score at previous level
*      col   - color computer is playing
*      level - current playing level
*
* Output:
*      score for chosen move
*
****************************************************************/
int ScoreMove (char board[], int index, int s, int col, int level)
{
int bscore;				    /* best score from this level     */
int bmove;				    /* best move from this level      */
int enemyColor;				    /* color of the enemy peices      */
int dir; 				    /* direction loop variable	      */
int tindex;				    /* temp board index; for captures */
int i;					    /* loop variable		      */
struct moveListType moveList;		    /* list of legal moves	      */
char   lBoard [100];			    /* local copy of game board	      */

/* Make the move passed */

memcpy (lBoard, board, 100);		   /* make local copy of passed board */

enemyColor = col ^ 3;			      /* set enemy color 	      */
if (index) {				      /* if there was a move, make it */
   lBoard[index] = col;			      /* make the move on the board   */
   for (dir = 0; dir < 8; dir++) {	      /* loop in all 8 directions     */
       tindex = index + disp[dir];	      /* see if there's a capture in  */
       if (lBoard[tindex] == enemyColor) {    /*   this direction	      */
	   while (lBoard[tindex] == enemyColor)		  /* skip enemy pieces */
	       tindex += disp[dir];
	   if (lBoard[tindex] == col) {	    /* if last piece is ours, capture */
	       tindex = index + disp[dir];
	       while (lBoard[tindex] != col) {
		   lBoard[tindex] =  col;
		   tindex	+= disp[dir];
		   }
	       } /* if */
	   } /* if */
       } /* for */
   } /* if */


/* Part 2:  Score the board */

if (level == ply)			  /* if at max depth, score is static */
   return Score (lBoard);

else {					  /* else pick from available moves   */
   GetMoves (lBoard, enemyColor, &moveList);	 /* get a list of legal moves */
   if (enemyColor == whitePiece) 	 /* init. score is worst possible, so */
       bscore = INT_MAX; 		 /*  that any alternative is selected */
   else
       bscore = INT_MIN;
   if (! moveList.num) { 		/* if no moves, check for end of game */
       GetMoves (lBoard, col, &moveList);
       if (! moveList.num)
	   bscore = EndScore (lBoard);
       else
	   bscore = ScoreMove (lBoard, 0, bscore, enemyColor, level+1);
       }

   else {
       for (i = 0; i < moveList.num; i++) {	/* scan/score available moves */
	   s = ScoreMove (lBoard, moveList.moves[i], bscore, enemyColor,
			  level+1);
	   if (enemyColor == whitePiece) {     /* if this is the best so far, */
					       /*    remember the move	      */
	       if (s < bscore) {
		   bscore = s;
		   bmove  = moveList.moves[i];
		   }
	       }
	    else {
	       if (s > bscore) {
		   bscore = s;
		   bmove  = moveList.moves[i];
		   }
	       } /* else */
	   } /* for */
       } /* else */
   return bscore;
   } /* else */
} /* ScoreMove */


/****************************************************************
*
* FindMove - Make a computer-generated move
*
* Input:
*      col - color computer is playing
*
****************************************************************/
void FindMove (int col)
{
struct moveListType moveList;		     /* list of legal moves	   */
int bmove;				     /* best move from this level  */
int bscore;				     /* best score from this level */
int s;					     /* work copy of score	   */
int i;					     /* loop variable		   */

WaitCursor ();				     /* change to the watch cursor */
GetMoves (board, col, &moveList);	     /* get a list of legal moves  */
if (moveList.num == 1)			/* if there's only 1 move, make it */
   MakeAMove (moveList.moves[0], col);
else if (moveList.num > 1) {		/* if there's more than 1, initial */
   if (col == whitePiece)		/*   score is worst possible, so   */
       bscore = INT_MAX; 		/*   any alternative is selected   */
   else
       bscore = INT_MIN;

   for (i = 0; i < moveList.num; i++) {		/* scan/score available moves */
       s = ScoreMove (board, moveList.moves[i], bscore, col, 1);
       if (col == whitePiece) {
	   if (s < bscore) {			   /* if this is best so far, */
	       bscore = s;			   /*	remember the move     */
	       bmove = moveList.moves[i];
	       }
	   }
       else {					   /* if color is black then  */
	   if (s > bscore) {
	       bscore = s;
	       bmove  = moveList.moves[i];
	       }
	   }
       }
   MakeAMove (bmove, col);			  /* make the best move found */
   }

else {							    /* no legal moves */
   strcpy (msg, "\pI cannot move, so I\rmust pass.\r");
   InitCursor ();
   DoAlert (note, msg);
   WaitCursor ();
   }

InitCursor ();					  /* back to the arrow cursor */
CheckForDone ();
} /* FindMove */


/****************************************************************
*
* NewGame - Set up the board for a new game
*
****************************************************************/
void NewGame (void)
{
Rect r;				       /* rectangle for clearing Moves window */
GrafPortPtr port;		       /* graph port pointer		      */
int i;				       /* loop variable			      */
int col, row;			       /* row, column numbers		      */

static void DrawMoves (void);	       /* subroutines called by NewGame	      */
static void DrawScore (void);

/* Write the contents of the Scores window */

for (i = 0; i < 100; i++) {			 /* initialize the game board */
   col = i % 10;
   row = i / 10;
   if ((!row) || (!col) || (row == 9) || (col == 9))
       board[i] = border;
   else
       board[i] = blank;
   }
board[44] = whitePiece;	   board[55] = whitePiece;
board[45] = blackPiece;	   board[54] = blackPiece;

currentColor = blackPiece;		 /* black moves first		      */
movesLeft    = true;			 /* the game is not over yet...	      */
movesMade    = 0;			 /* empty the moves list 	      */
topMove	     = 1;			 /* first visible move in moves list  */
updateMoves  = true;			 /* draw entire list		      */

if (showMovesWindow) {			 /* if move list is visible, clear it */
  port = GetPort ();			 /* save the graph port		      */
  StartDrawing (movesWindow);		 /* draw to the Moves window	      */
  GetPortRect (&r);			 /* get the rectangle		      */
  EraseRect (&r);			 /* erase the window's contents       */
  DrawControls (movesWindow);		 /* draw the controls		      */
  SetPort (port);			 /* restore the old graph port	      */
  DrawMoves ();				 /* draw the pieces		      */
  }
if (showScoreWindow)
   DrawScore (); 			 /* redraw the Scores window	      */
} /* NewGame */


/* Initialization routines */


/****************************************************************
*
* InitMenus - Create and draw the initial menu bar
*
****************************************************************/
void InitMenus (void)
{
InsertMenu (NewMenu (">>  Options  \\N5\r"	   /* create the Options menu */
		     "--Self Play\\N280\r"
		     "--Computer Plays Black\\N281\r"
		     "---\\N514D\r"
		     "--Pass\\N282\r"
		     "--Show Score Window\\N283\r"
		     "--Show Moves Window\\N284\r"
		     ".\r"), 0);

InsertMenu (NewMenu (">>  Level  \\N4\r" 	     /* create the Level menu */
		     "--1 Ply\\N262\r"
		     "--2 Ply\\N263\r"
		     "--3 Ply\\N264\r"
		     "--4 Ply\\N265\r"
		     "--5 Ply\\N266\r"
		     "--6 Ply\\N267\r"
		     "--7 Ply\\N268\r"
		     "--8 Ply\\N269\r"
		     ".\r"), 0);

InsertMenu (NewMenu (">>  Edit  \\N3\r"		      /* create the Edit menu */
		     "--Undo Last Move\\N270D*Zz\r"
		     "---\\N512D\r"
		     "--Cut\\N271D*Xx\r"
		     "--Copy\\N272D*Cc\r"
		     "--Paste\\N273D*Vv\r"
		     "--Clear\\N274D\r"
		     ".\r"), 0);

InsertMenu (NewMenu (">>    File  \\N2\r"	      /* create the File menu */
		     "--New Game\\N258*Nn\r"
		     "---\\N513D\r"
		     "--Quit\\N259*Qq\r"
		     ".\r"), 0);

InsertMenu (NewMenu (">>@\\XN1\r"		     /* create the Apple menu */
		     "--About Reversi\\N257\r"
		     "---\\N513D\r"
		     ".\r"), 0);

FixAppleMenu (1);			       /* add desk accessories	      */
FixMenuBar ();				       /* draw the completed menu bar */
DrawMenuBar ();
CheckMItem (true, level_1Ply);		       /* check ply 1		      */
} /* InitMenus */


/****************************************************************
*
* InitVariables - Initialize global variables
*
****************************************************************/
void InitVariables (void)
{
Rect r;				     /* rectangle for finding height of chars */

CharBounds ('A', &r);			    /* find the height of a character */
charHeight = r.h2 - r.h1;
NewGame ();				   /* set up the board for a new game */
}


/****************************************************************
*
* InitWindow - Draw the game board's window
*
****************************************************************/
void InitWindow (void)
{
#define scoreWidth 96			     /* width of Score, Moves windows */

Rect r;					     /* for setting sizes of controls */

boardParms	  = wParms;			   /* create the board window */
boardParms.wTitle = boardName;
boardWindow	  = NewWindow (&boardParms);

scoreParms		= wParms;		  /* create the Scores window */
scoreParms.wTitle	= scoreName;
scoreParms.wFrameBits	= 0xC0C4;
scoreParms.wDataH	= 29;
scoreParms.wDataW	= scoreWidth;
scoreParms.wMaxH 	= 29;
scoreParms.wMaxW 	= scoreWidth;
scoreParms.wPosition.v1 = 32;
scoreParms.wPosition.h1 = 640 - 32 - scoreWidth;
scoreParms.wPosition.v2 = 61;
scoreParms.wPosition.h2 = 640 - 32;
scoreWindow		= NewWindow (&scoreParms);

movesParms		= scoreParms;		   /* create the Moves window */
movesParms.wTitle	= movesName;
movesParms.wDataH	= 112;
movesParms.wPosition.v1 = 80;
movesParms.wPosition.v2 = 192;
movesWindow		= NewWindow (&movesParms);

r.h1 = scoreWidth - 23;					 /* create a grow box */
r.h2 = scoreWidth + 1;
r.v1 = 100;    r.v2 = 113;
growHandle = NewControl (movesWindow, &r, NULL, 0, 0, 0, 0, (void *) 0x08000000,
			 0L, NULL);

r.v1 = 0;      r.v2 = 101;				 /* create scroll bar */
vScrollHandle = NewControl (movesWindow, &r, NULL, 3, 0, 112, 25,
			    (void *) 0x06000000, 0L, NULL);

moveHeight = 112;			  /* set height of window	      */
SelectWindow (boardWindow);		  /* make game board the front window */
} /* InitWindow */


/* Action Routines */


/****************************************************************
*
* WriteMove - Write a move on the screen
*
* Input:
*      move - move to write
*
****************************************************************/
void WriteMove (int move)
{
printf ("%c%d ", (char) (move % 10 - 1 + 'A'), 9 - move / 10);
} /* WriteMove */


/****************************************************************
*
* DrawMoves - Write the contents of the Moves window
*
****************************************************************/
void DrawMoves (void)
{
GrafPortPtr port;			      /* graphics port		      */
Rect r;					      /* rectangle for drawing colors */
int  i, n;				      /* index variables 	      */

if (showMovesWindow) {
   port = GetPort ();			     /* save the current graph port   */
   StartDrawing (movesWindow);		     /* draw to the Score window      */
   SetForeColor (0);			     /* black pen on white background */
   SetBackColor (15);

   if (updateMoves) {
       SetSolidPenPat (0);			  /* draw black column header */
       r.v1 = 5;   r.h1 = 26;
       r.v2 = 13;  r.h2 = 40;
       PaintOval (&r);
       r.v1 = 5;   r.h1 = 47;			  /* draw white column header */
       r.v2 = 13;  r.h2 = 61;
       PaintOval (&r);
       SetSolidPenPat (15);
       r.v1 = 6;   r.h1 = 48;
       r.v2 = 12;  r.h2 = 60;
       PaintOval (&r);
       }

   if (movesMade > 0) {					    /* draw the moves */
       MoveTo (2, 25);
       i = topMove;
       n = (i + 1) / 2;

       while (i <= movesMade) {
	   if ((updateMoves) || (i > movesMade - 2)) {
	       if (n < 10)
		   printf (" ");
	       printf ("%2d: ", n);
	       WriteMove (moves[i]);
	       if (i + 1 <= movesMade)
		   WriteMove (moves[i+1]);
	       else
		   printf ("      ");
	       }

	   printf ("\r");
	   n++;
	   i += 2;
	   }
       printf ("                \r");	 /* blank the last line (for scrolls) */
       SetCtlParams (Even (movesMade) / 2 * charHeight, moveHeight - 25,
		     vScrollHandle);		     /* update the thumb size */
       SetPort (port);				/* restore the old graph port */
       }
   updateMoves = false;		       /* complete update is no longer needed */
   }
} /* DrawMoves */


/****************************************************************
*
* DrawScore - Write the contents of the Score window
*
****************************************************************/
void DrawScore (void)
{
int i;						     /* loop variable	      */
int wcnt, bcnt;					     /* for counting pieces   */
GrafPortPtr port;				     /* current graphics port */

if (showScoreWindow) {
   port = GetPort ();			     /* save the graph port	      */
   StartDrawing (scoreWindow);		     /* draw to the score window      */
   SetForeColor (0);			     /* black pen on white background */
   SetBackColor (15);
   MoveTo (2, 10);			     /* start at upper left corner    */

   for (i = 11, wcnt = 0, bcnt = 0; i < 90; i++) /* count the pieces on board */
       if (board[i] == whitePiece)
	   wcnt++;
       else if (board[i] == blackPiece)
	   bcnt++;
   printf ("White: %d  \rBlack: %d  \r", wcnt, bcnt);	  /* write the scores */
   printf ("Score: %d          \r", Score (board));
   SetPort (port);				/* restore the old graph port */
   }
} /* DrawScore */


/****************************************************************
*
* MenuShowMovesWindow - Hide or show the Moves window
*
****************************************************************/
void MenuShowMovesWindow (void)
{
GrafPortPtr port;				     /* current graphics port */

showMovesWindow = ! showMovesWindow;		   /* reverse window's status */
CheckMItem (showMovesWindow, options_ShowMovesWindow);
ShowHide (showMovesWindow, movesWindow);
if (showMovesWindow) {				    /* if visible, draw it... */
   updateMoves = true;				       /* draw the moves list */
   DrawMoves ();
   port = GetPort ();				       /* save the graph port */
   StartDrawing (movesWindow);			       /* redraw the controls */
   SetPort (port);
   }
SelectWindow (boardWindow);
} /* MenuShowMovesWindow */


/****************************************************************
*
* MenuShowScoreWindow - Hide or show the Score window
*
****************************************************************/
void MenuShowScoreWindow (void)
{
showScoreWindow = ! showScoreWindow;
CheckMItem (showScoreWindow, options_ShowScoreWindow);
ShowHide (showScoreWindow, scoreWindow);
SelectWindow (boardWindow);
DrawScore ();
} /* MenuShowScoreWindow */


/****************************************************************
*
* MenuAbout - Show the About dialog
*
****************************************************************/
void MenuAbout (void)
{
strcpy (msg, "\pReversi 1.0\rCopyright 1989\rByte Works, Inc.\r"
	     "\rBy Mike Westerfield");
DoAlert (note, msg);
} /* MenuAbout */


/****************************************************************
*
* MenuColor - Change the color the computer plays
*
****************************************************************/
void MenuColor (void)
{
if (color == whitePiece) {
   SetMItem (computerPlaysWhite, options_ComputerPlaysWhite);
   color = blackPiece;
   }
else {
   SetMItem (computerPlaysBlack, options_ComputerPlaysWhite);
   color = whitePiece;
   }
} /* MenuColor */


/****************************************************************
*
* MenuPass - Player wants to pass
*
****************************************************************/
void MenuPass (void)
{
struct moveListType moveList;	       /* for seeing if there are legal moves */

GetMoves (board, currentColor, &moveList);	 /* get a list of legal moves */
if (! moveList.num)			  /* OK to pass if there are no moves */
   currentColor ^= 3;
else {					  /* error to pass if there are moves */
   strcpy (msg, "\pYou have legal moves\rso you cannot pass.\r");
   DoAlert (stop, msg);
   }
} /* MenuPass */


/****************************************************************
*
* MenuSelfPlay - Change the current playing mode
*
****************************************************************/
void MenuSelfPlay (void)
{
selfPlay = ! selfPlay;
if (selfPlay)
   SetMItem (computerPlayStr, options_SelfPlay);
else
   SetMItem (selfPlayStr, options_SelfPlay);
} /* MenuSelfPlay */


/****************************************************************
*
* MenuSetPly - Change the current playing level
*
* Input:
*      newPly - menu number of playing level selected
*
****************************************************************/
void MenuSetPly (int newPly)
{
CheckMItem (false, ply + level_1Ply - 1);		 /* uncheck old ply   */
CheckMItem (true, newPly);				 /* check new ply     */
ply = newPly - level_1Ply + 1;				 /* set the ply level */
} /* MenuSetPly */


/****************************************************************
*
* HandleMenu - Handle a menu event
*
* Input:
*      menuNum - menu number of menu to handle
*
****************************************************************/
void HandleMenu (int menuNum)
{
switch (menuNum) {					   /* handle the menu */
   case apple_AboutReversi:
       MenuAbout ();
       break;

   case file_NewGame:
       NewGame ();
       DrawBoard ();
       break;

   case file_Quit:
       done = true;
       break;

   case level_1Ply: case level_2Ply: case level_3Ply: case level_4Ply:
   case level_5Ply: case level_6Ply: case level_7Ply: case level_8Ply:
       MenuSetPly (menuNum);
       break;

   case options_SelfPlay:
       MenuSelfPlay ();
       break;

   case options_ComputerPlaysWhite:
       MenuColor ();
       break;

   case options_Pass:
       MenuPass ();
       break;

   case options_ShowScoreWindow:
       MenuShowScoreWindow ();
       break;

   case options_ShowMovesWindow:
       MenuShowMovesWindow ();
       break;

   default:
       break;
   } /* switch */

HiliteMenu (false, (int) (lastEvent.wmTaskData >> 16));
} /* HandleMenu */


/****************************************************************
*
* HideAWindow - Hide the front window
*
****************************************************************/
void HideAWindow (void)
{
if (FrontWindow () == scoreWindow)
   MenuShowScoreWindow ();
else /* if FrontWindow == movesWindow */
   MenuShowMovesWindow ();
} /* HideAWindow */


/****************************************************************
*
* LegalMove - Check if a move is legal
*
* Input:
*      index - move to make
*      color - color of player making the move
*
****************************************************************/
BOOL LegalMove (int index, int color)
{
struct moveListType moveList;			   /* for list of legal moves */
int i;						   /* loop variable	      */

GetMoves (board, color, &moveList);
for (i = 0; i < moveList.num; i++)
   if (index == moveList.moves[i])
       return true;
return false;
} /* LegalMove */


/****************************************************************
*
* GrowMoves - Grow the Moves window (the only window that can grow)
*
****************************************************************/
void GrowMoves (void)
{
Rect rt; 			      /* for creating scroll bar 	      */
int  movesInWindow;		      /* # moves the Moves window can display */
union longShort { long isLong;	      /* for converting between int and long  */
		  int  lsw, msw; } r, s;

s.isLong = GetMaxGrow (movesWindow);			      /* get max size */
					   /* track the growing of the window */
r.isLong = GrowWindow (s.msw, 64, lastEvent.where.h, lastEvent.where.v,
		     movesWindow);
if (r.isLong) {					 /* if the size changed then... */
   SizeWindow (s.msw, r.lsw, movesWindow);	  /* change the window's size */
   MoveControl (73, r.lsw - 12, growHandle);	  /* move the grow box	      */
   DisposeControl (vScrollHandle);		  /* resize the scroll bar    */
   rt.h1 = 73;	   rt.h2 = 89;
   rt.v1 = 0;	   rt.v2 = r.lsw - 11;

   vScrollHandle =				  /* update the thumb size    */
      NewControl (movesWindow, &rt, NULL, 3, 0, 112, 25, (void *) 0x06000000,
		  0L, NULL);
					  /* position thumb of the scroll bar */
   SetCtlParams (Even (movesMade) / 2 * charHeight, r.lsw - 25, vScrollHandle);
   SetCtlValue (topMove / 2 * charHeight, vScrollHandle);

   if (r.lsw > moveHeight) {			/* if the window grew then... */
						/* dispose of trailing blanks */
       movesInWindow = (r.lsw - 25) / charHeight * 2 + 2;
       if ((Even(topMove) + movesInWindow + 1) / 2 > (Even (movesMade) + 1) / 2)
	 {
	   topMove = Even (movesMade) - movesInWindow;
	   if (!(topMove & 0x0001))
	       topMove++;
	   if (topMove < 1)
	       topMove = 1;
	   }

       updateMoves = true;				 /* redraw moves list */
       moveHeight  = r.lsw;
       DrawMoves ();
       }

   moveHeight = r.lsw;				    /* update the window size */
   }
} /* GrowMoves */


/****************************************************************
*
* Scroll - Handle vertical scrolls in the Moves window
*
****************************************************************/
void Scroll (void)
{
int part;			      /* part # from TrackControl	      */
int movesInWindow;		      /* # moves the Moves window can display */

part = TrackControl (lastEvent.where.h, lastEvent.where.v, (void *) -1,
		     vScrollHandle);
movesInWindow = (moveHeight - 25) / charHeight * 2 + 2;

if ((part > 4) && (part < 9)) {	    /* if the part is not the slide switch... */
   switch (part) {
       case 5:						   /* handle up arrow */
	   if (topMove > 1)
	       topMove -= 2;
	   break;

       case 6:						 /* handle down arrow */
	   if (Even (topMove) + movesInWindow < Even (movesMade) + 1)
	       topMove += 2;
	   break;

       case 7:						    /* handle up page */
	   if (topMove > 1) {
	       topMove -= movesInWindow;
	       if (topMove < 1)
		   topMove = 1;
	     }
	   break;

       case 8:						  /* handle down page */
	   if (Even(topMove) + movesInWindow < Even(movesMade) + 1) {
	       topMove += movesInWindow;
	       if ( ((Even(topMove) + movesInWindow + 1) / 2)  >
		    (Even(movesMade) + 1) / 2 ) {
		   topMove = Even (movesMade) - movesInWindow;
		   if (! (topMove >> 15) & 0x0001)
		       topMove++;
		   }
	       }
       } /* switch */

   updateMoves = true;					 /* redraw the window */
   DrawMoves ();
					  /* position thumb of the scroll bar */
   SetCtlValue (topMove / 2 * charHeight, vScrollHandle);
   }

else if (part == 129) {			/* reposition based on new thumb loc. */
   topMove = GetCtlValue (vScrollHandle) * 2 / charHeight +1;
   if (! (topMove >> 15) & 0x0001)
       topMove++;
   updateMoves = true;
   DrawMoves ();
   }
} /* Scroll */


/****************************************************************
*
* TryMove - If there is a legal move at the indicated coordinates,
*	    make it
*
****************************************************************/
void TryMove (void)
{
Point p; 					    /* location of mouse      */
int   row, col;					    /* position on board      */
int   index;					    /* index into board array */

if (movesLeft) { 			       /* make sure game is not over  */
   StartDrawing (boardWindow);		       /* easy way to set port	      */
   p.h = lastEvent.where.h;		       /* find out where the mouse is */
   p.v = lastEvent.where.v;
   GlobalToLocal (&p);
   col = p.h / squareWidth + 1;			 /* convert to board index    */
   row = p.v / squareHeight + 1;
   index = row * 10 + col;

   if (LegalMove( index, currentColor)) {	 /* if move is legal, make it */
       MakeAMove (index, currentColor);
       currentColor ^= 3;			      /* switch color to move */
       }

   else {					      /* flag a bad move      */
       strcpy (msg, "\pIllegal move -\rtry again.");
       DoAlert (stop, msg);
       }
   CheckForDone ();
   DrawScore (); 				      /* update the score     */
   DrawMoves (); 				      /* update the move list */
   }
} /* TryMove */


/****************************************************************
*
* DoContent - Handle a mouse-down event in the content region
*
****************************************************************/
void DoContent (void)
{
int part;				    /* part # returned by FindControl */
CtlRecHndl ctl;				    /* control handle		      */

if (FrontWindow () == (GrafPortPtr) lastEvent.wmTaskData) {
   if ((GrafPortPtr) lastEvent.wmTaskData == boardWindow)
       TryMove ();					 /* try making a move */

   else if ((GrafPortPtr) lastEvent.wmTaskData == movesWindow) {
       part = FindControl (&ctl, lastEvent.where.h, lastEvent.where.v,
			  movesWindow);
       if (part == 10)
	   GrowMoves (); 				 /* handle grow box   */
       else if (part)
	   Scroll ();					 /* handle scroll bar */
       }
   }
} /* DoContent */


/****************************************************************
*
* Update - Handle an update event
*
****************************************************************/
void Update (void)
{
if (lastEvent.message == (long) boardWindow) {
   BeginUpdate (boardWindow);			   /* update the board window */
   DrawBoard (); 				   /* redraw the board	      */
   EndUpdate (boardWindow);			   /* complete the update     */
   }

else if (lastEvent.message == (long) scoreWindow) {
   BeginUpdate (scoreWindow);			   /* update the score window */
   DrawScore (); 				   /* redraw the score window */
   EndUpdate (scoreWindow);			   /* complete the update     */
   }

else if (lastEvent.message == (long) movesWindow) {
   BeginUpdate (movesWindow);			   /* update the Moves window */
   updateMoves = true;				   /* redraw the Moves window */
   DrawMoves ();
   EndUpdate (movesWindow);			   /* complete the update     */
   DrawControls (movesWindow);			   /* redraw the controls     */
   }
} /* Update */


/****************************************************************
*
* Main program starts here
*
****************************************************************/

int main (void)

{
startdesk (640); 			/* initialize the dekstop environment */
QDAuxStartUp ();
SetPenMode (0);				     /* set pen mode to copy	      */
InitMenus ();				     /* set up the menu bar	      */
InitWindow ();				     /* draw the board's window       */
InitVariables ();			     /* initialize global variables   */
lastEvent.wmTaskMask = 0x13FFL;		     /* let Task Master do most stuff */
ShowCursor ();				     /* show the cursor		      */

done = false;						   /* main event loop */
do {
   event = TaskMaster (0x074E, &lastEvent);
   switch (event) {			      /* handle the events we need to */
       case wInMenuBar: HandleMenu ((int) lastEvent.wmTaskData);
			break;

       case inUpdate:	Update ();
			break;

       case wInContent: DoContent ();
			break;

       case wInGoAway : HideAWindow ();
			break;

       default:		break;
       }


   /* If the Moves window has been brought to front, draw its controls. */

   if (FrontWindow () == movesWindow) {
       if (movesNotFront) {
	   movesNotFront = false;
	   HiliteControl (0, vScrollHandle);
	   HiliteControl (0, growHandle);
	   DrawControls (movesWindow);
	   }
       }
   else if (! movesNotFront) {
       movesNotFront = true;
       HiliteControl (255, vScrollHandle);
       HiliteControl (255, growHandle);
       }

   if (movesLeft) {				     /* let the computer move */
       if (selfPlay) {
	   FindMove (currentColor);
	   currentColor ^= 3;
	   DrawScore ();
	   DrawMoves ();
	   }
       else if (color == currentColor) {
	   FindMove (color);
	   currentColor ^= 3;
	   DrawScore ();
	   DrawMoves ();
	   }
       } /* if */
   }
while (!done);

QDAuxShutDown ();			/* shut down the desktop environment */
enddesk ();
} /* Reversi */
