/*==============================================================*\
 *  Svrpgame.c - game processing routine: processing of client
 *		 messages and game algorithm.
 *	Copyright 1992, IBM Corp.
 *
 *  DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
 *  sample code created by IBM Corporation. This sample code is not
 *  part of any standard or IBM product and is provided to you solely
 *  for	 the purpose of assisting you in the development of your
 *  applications.  The code is provided "AS IS", without
 *  warranty of any kind.  IBM shall not be liable for any damages
 *  arising out of your use of the sample code, even if they have been
 *  advised of the possibility of   such damages.						      *
 *
 *
\*==============================================================*/


#define INCL_DOSPROCESS
#define INCL_DOSNMPIPES
#define INCL_DOSMEMMGR
#define INCL_WINMESSAGEMGR
#define INCL_DOSERRORS
#define INCL_DOSFILEMGR

#include <os2.h>

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include "namepipe.h"
#include "svrpglbl.h"
#include "svrpmain.h"
#include "svrpxtrn.h"


VOID GameThread(VOID *hpTempPipe)
{
   HPIPE   hpGamePipe;
   BOOL	   fQuit=FALSE;
   PPIB	   dummy;
   PTIB	   ptibThrdInfo;
   ULONG   ulID;
   USHORT  usMsg, usData, GameBoard[DIVISIONS][DIVISIONS], usTotalMoves=0;

   /* save pipe handle in own memory */
   hpGamePipe = *(HPIPE *)hpTempPipe;

   /* get thread ID for use in displaying messages */
   if((BOOL)DosGetInfoBlocks(&ptibThrdInfo, &dummy))
   {
      ulID = 0;
   }

   else
   {
      ulID = ptibThrdInfo->tib_ptib2->tib2_ultid;
   }

   InitBoard(GameBoard);

   /* initialize random number generator */
   srand((unsigned) ulID);

   if(!(BOOL)DosConnectNPipe(hpGamePipe))
   {
      while (!fAppExit &&
	     !fQuit &&
	     !(BOOL)(Pipe_IO(CLIENT, hpGamePipe, &usMsg, &usData, ulID)) &&
	     !fAppExit)
      {
	 switch (usMsg)
	 {
	    case CLIENT_MOVE:
	       /* enter move from message */
	       *((USHORT *)GameBoard + usData) = CLIENT_NUM;
	       usTotalMoves++;

	       /* test for win if total moves >= DIVISIONS*2-1 */
	       if (usTotalMoves >= DIVISIONS*2-1 &&
		   ((BOOL)(usData=WinTest(GameBoard)) ||
		    usTotalMoves == DIVISIONS*DIVISIONS))
	       {
		  /* notify of win or draw, and break (switch) on return */
		  if (!usData)
		  {
		     usData = DIVISIONS*DIVISIONS;
		     usMsg = WIN_DRAW;
		  }

		  else
		  {
		     usMsg = WIN_CLIENT;
		  }

		  if ((BOOL)Pipe_IO(SERVER, hpGamePipe, &usMsg, &usData, ulID))
		  {
		     WinPostMsg(hwndMain, WM_MSG, MPFROMLONG(IDMSG_PIPE_WRITE_FAILED), MPVOID);
		     fQuit = TRUE;
		     break;
		  }

		  /* call InitBoard on win */
		  InitBoard(GameBoard);
		  usTotalMoves = 0;

		  break;  /* switch */
	       }

	       /* NO BREAK */

	    case YOU_FIRST:
	       /* get move if there are moves left */
	       usData = GetMove(GameBoard, usTotalMoves);
	       usTotalMoves++;

	       /* test for win if total moves >= DIVISIONS*2-1 */
	       if (usTotalMoves >= DIVISIONS*2-1 &&
		   ((BOOL)(usMsg=WinTest(GameBoard)) ||
		    usTotalMoves == DIVISIONS*DIVISIONS))
	       {
		  /* write game_won message with winning move */
		  if (!usMsg)
		  {
		     usMsg = WIN_DRAW;
		  }

		  else
		  {
		     usMsg = WIN_SERVER;
		  }

		  if ((BOOL)Pipe_IO(SERVER, hpGamePipe, &usMsg, &usData, ulID))
		  {
		     WinPostMsg(hwndMain, WM_MSG, MPFROMLONG(IDMSG_PIPE_WRITE_FAILED), MPVOID);
		     fQuit = TRUE;
		     break;
		  }

		  /* call InitBoard on win */
		  InitBoard(GameBoard);
		  usTotalMoves = 0;
	       }

	       /* else */
	       else
	       {
		  /* write move to client */
		  usMsg = SERVER_MOVE;
		  if ((BOOL)Pipe_IO(SERVER, hpGamePipe, &usMsg, &usData, ulID))
		  {
		     WinPostMsg(hwndMain, WM_MSG, MPFROMLONG(IDMSG_PIPE_WRITE_FAILED), MPVOID);
		     fQuit = TRUE;
		  }
	       }
	       break;

	    case ERROR_MSG:
	       /* post the error to message queue */
	       WinPostMsg(hwndMain, WM_MSG, MPFROMSHORT(usData), MPVOID);

	    case CLIENT_QUIT:
	       /* quit while */
	       fQuit = TRUE;
	 }
      }

      DosDisConnectNPipe(hpGamePipe);
   }

   DosClose(hpGamePipe);
}


/*
 *  Check for pieces owning entire row, column, or diagonal.
 */
USHORT WinTest(USHORT GameBoard[DIVISIONS][DIVISIONS])
{
   USHORT  usWinner=0, usTotal1=0, usTotal2=0, usTotal3=0, usTotal4=0;
   int	   i, j;

   for (i = 0; i < DIVISIONS && !(BOOL)usWinner; i++)
   {
      for (j = 0; j < DIVISIONS && !(BOOL)usWinner; j++)
      {
	 usTotal1 += GameBoard[i][j];
	 usTotal2 += GameBoard[j][i];
      }

      if (SERVER_NUM * DIVISIONS == usTotal1 || CLIENT_NUM * DIVISIONS == usTotal1)
      {
	 usWinner = usTotal1/(USHORT)DIVISIONS;
      }

      else if (SERVER_NUM * DIVISIONS == usTotal2 || CLIENT_NUM * DIVISIONS == usTotal2)
      {
	 usWinner = usTotal2/(USHORT)DIVISIONS;
      }

      else
      {
	 usTotal1 = usTotal2 = 0;
	 usTotal3 += GameBoard[i][i];
	 usTotal4 += GameBoard[i][DIVISIONS-i-1];
      }
   }

   if (SERVER_NUM * DIVISIONS == usTotal3 || CLIENT_NUM * DIVISIONS == usTotal3)
   {
      usWinner = usTotal3/(USHORT)DIVISIONS;
   }

   else if (SERVER_NUM * DIVISIONS == usTotal4 || CLIENT_NUM * DIVISIONS == usTotal4)
   {
      usWinner = usTotal4/(USHORT)DIVISIONS;
   }

   return(usWinner);
}


USHORT GetMove(USHORT GameBoard[DIVISIONS][DIVISIONS], USHORT usTotalMoves)
{
   USHORT  usMovesLeft;
   int	   i, j;

   usMovesLeft = (USHORT)((USHORT)DIVISIONS * (USHORT)DIVISIONS - usTotalMoves);

   /* a poor man's AI */
   usMovesLeft = (USHORT)((usMovesLeft * rand()) / (RAND_MAX + 1));

   for (i = 0; i < DIVISIONS; i++)
   {
      for (j = 0; j < DIVISIONS; j++)
      {
	 if (0 == GameBoard[i][j] && 0 == usMovesLeft--)
	 {
	    GameBoard[i][j] = SERVER_NUM;
	    return((USHORT)(i * DIVISIONS + j));
	 }
      }
   }
   return( 0 );
}


/*
 *  Reset game board.
 */
VOID InitBoard(USHORT GameBoard[DIVISIONS][DIVISIONS])
{
   int i, j;

   for (i = 0; i < DIVISIONS; i++)
      for (j = 0; j < DIVISIONS; j++)
	 GameBoard[i][j] = 0;
}
