#include <ctype.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <functions.h>
#include <exec/exec.h>
#include <fcntl.h>
#include <stdio.h>

/******************************************** NOW FOLLOWING PARAGON DOOR */
#define CAR if(doormsg->carrier==1) return;
#define DROP if(doormsg->carrier==1) end();

struct DoorMsg {
	struct Message Door_Msg;
	short command;
	short data;
	char string[80];
	short carrier;
	};

struct DoorMsg *doormsg,*garbage;
struct MsgPort *MyPort,*replyport;

extern void getsvar();
extern void sendmessage();
extern void hotkey();
extern void prompt();
extern void sprompt();
extern void showfile();
extern void end();

struct Task *mytask; /* Pointer to this task so we can name it */

/******************************************** NOW FOLLOWING CHESS        */

int err;

char version[] = "Paragon chess door... by Sven Sauter";

#define neutral 0
#define white 1
#define black 2 
#define no_piece 0
#define pawn 1
#define knight 2
#define bishop 3
#define rook 4
#define queen 5
#define king 6
#define px " PNBRQK"
#define qx " pnbrqk"
#define rx "12345678"
#define cx "abcdefgh"
#define check 0x0001
#define capture 0x0002
#define draw 0x0004
#define promote 0x0010
#define incheck 0x0020
#define epmask 0x0040
#define exact 0x0100
#define pwnthrt 0x0200
#define true 1
#define false 0
#undef TRUE
#undef FALSE

struct leaf
  {
    short f,t,score,reply;
    unsigned short flags;
  };

int feldtop[10];
char userntop[10][30];
int feldbad[10];
char usernbad[10][30];
int scr_row, scr_col, top=0, bad=0, position;
BPTR lockptr;
char filename[20],username[30],line_number;
int flag, counting;
char tt;
char mvstr1[5],mvstr2[5];
struct leaf Tree[2000],*root;
short TrPnt[30];
short row[64],col[64],locn[8][8],indx[64],svalue[64];
short PieceList[3][16],PieceCnt[3];
short castld[3],kingmoved[3],mtl[3],pmtl[3],emtl[3],hung[3];
short mate,post,xkillr,ykillr,opponent,computer,Sdepth;
long time();
long time0 = 0;
int response_time,extra_time,timeout,et,et0;
short quit,reverse,bothsides,InChk,player;
int NodeCnt,srate;
short atak[3][64],PawnCnt[3][8];
short ChkFlag[30],CptrFlag[30],PawnThreat[30],PPscore[30];
short BookSize,BookDepth;
short GameCnt,Game50,epsquare,lpost;
unsigned short GameList[240],Book[80][24];
short GameScore[240],GamePc[240],GameClr[240];
short value[8]={0,100,330,330,500,950,999};
short otherside[3]={0,2,1};
short passed_pawn1[8]={0,3,4,8,14,24,40,80};
short passed_pawn2[8]={0,2,3,4,6,9,13,80};
short passed_pawn3[8]={0,1,2,3,4,5,6,80};
short map[64]=
   {26,27,28,29,30,31,32,33,38,39,40,41,42,43,44,45,
    50,51,52,53,54,55,56,57,62,63,64,65,66,67,68,69,
    74,75,76,77,78,79,80,81,86,87,88,89,90,91,92,93,
    98,99,100,101,102,103,104,105,110,111,112,113,114,115,116,117};
short unmap[144]=
   {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,0,1,2,3,4,5,6,7,-1,-1,-1,-1,8,9,10,11,12,13,14,15,-1,-1,
    -1,-1,16,17,18,19,20,21,22,23,-1,-1,-1,-1,24,25,26,27,28,29,30,31,-1,-1,
    -1,-1,32,33,34,35,36,37,38,39,-1,-1,-1,-1,40,41,42,43,44,45,46,47,-1,-1,
    -1,-1,48,49,50,51,52,53,54,55,-1,-1,-1,-1,56,57,58,59,60,61,62,63,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
short edge[64]=
   {0,1,2,3,3,2,1,0,1,2,3,4,4,3,2,1,2,3,4,5,5,4,3,2,3,4,5,6,6,5,4,3,
    3,4,5,6,6,5,4,3,2,3,4,5,5,4,3,2,1,2,3,4,4,3,2,1,0,1,2,3,3,2,1,0};
short pknight[64]=
   {0,6,11,14,14,11,6,0,6,12,22,25,25,22,12,6,
    11,20,30,36,36,30,20,11,14,25,36,44,44,36,25,14,
    14,25,36,44,44,36,25,14,11,20,30,36,36,30,20,11,
    6,12,22,25,25,22,12,6,0,6,11,14,14,11,6,0};
short pbishop[64]=
   {14,14,14,14,14,14,14,14,14,18,18,18,18,18,18,14,
    14,18,22,22,22,22,18,14,14,18,22,22,22,22,18,14,
    14,18,22,22,22,22,18,14,14,18,22,22,22,22,18,14,
    14,18,18,18,18,18,18,14,14,14,14,14,14,14,14,14};
short board[64]=
   {rook,knight,bishop,queen,king,bishop,knight,rook,
    pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
    rook,knight,bishop,queen,king,bishop,knight,rook};
short piece_color[64]=
   {white,white,white,white,white,white,white,white,
    white,white,white,white,white,white,white,white,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    black,black,black,black,black,black,black,black,
    black,black,black,black,black,black,black,black};
short color[64]=
   {0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0,
    0,1,0,1,0,1,0,1,
    1,0,1,0,1,0,1,0};
short sweep[7]= {false,false,false,true,true,true,false};
short Dstpwn[3]={0,4,6};
short Dstart[7]={6,4,8,4,0,0,0};
short Dstop[7]={7,5,15,7,3,7,7};
short Dir[16]={1,12,-1,-12,11,13,-11,-13,10,-10,14,-14,23,-23,25,-25};
unsigned short PV,Swag1,Swag2,killr1[30],killr2[30],killr3[30],Qkillr[30];
unsigned short Ckillr[3],prvar[30];


main(argc,argv)
int argc;
char *argv[];
{
char yesno[20];
/******************************************** NOW FOLLOWING PARAGON DOOR */
	char rportname[10],cportname[12];	/* ReplyPort and Control Port names */
	char line_number;
	line_number=argv[1][0];
	mytask=FindTask(0L);
	mytask->tc_Node.ln_Name = "Chess 2.0";
	
	/* Create the Reply port, with the name based on the number...

	   Attempts at doing this with a simple "sprintf" failed, causing
	   the creation of garbled portnames.  This works fine.  Stick with
           it.  */

	switch(line_number){
		case '0':	replyport=CreatePort("DoorReply0",0L); break;
		case '1':	replyport=CreatePort("DoorReply1",0L); break;
		case '2':	replyport=CreatePort("DoorReply2",0L); break;
		case '3':	replyport=CreatePort("DoorReply3",0L); break;
		case '4':	replyport=CreatePort("DoorReply4",0L); break;
		case '5':	replyport=CreatePort("DoorReply5",0L); break;
		case '6':	replyport=CreatePort("DoorReply6",0L); break;
		case '7':	replyport=CreatePort("DoorReply7",0L); break;
		case '8':	replyport=CreatePort("DoorReply8",0L); break;
		case '9':	replyport=CreatePort("DoorReply9",0L); break;
	}
	
	doormsg=(struct DoorMsg *)AllocMem((long)sizeof(*doormsg),MEMF_PUBLIC);
	
	if(doormsg==0)
	{
		puts("Couldn't allocate DoorMsg!");
		return;
	}
	
	doormsg->Door_Msg.mn_Node.ln_Type = NT_MESSAGE;
	doormsg->Door_Msg.mn_ReplyPort = replyport;
	doormsg->Door_Msg.mn_Length = (UWORD)sizeof(*doormsg);
	
	/* Locate the correct DoorControl port based on the line number */
	
	sprintf(cportname,"DoorControl%c",line_number);
   	MyPort=FindPort(cportname);
   	if(MyPort==0L) 
	{
		puts("DoorControl port not located!");
		FreeMem(doormsg,(long)sizeof(*doormsg));
		return;
	}
	
/******************************************** main of chess              */

	getsvar (1, username);
	open10();
	sprintf(filename,"ch.%s",username);
	if ((lockptr=Lock(filename, ACCESS_READ))!=DOSFALSE)
	{
 	 close (lockptr);
	 clear();
	 gotoXY(10,5);  printw("\33[33mHello %s\33[37m", username);
	 gotoXY(10,10); printw("I have a saved game of you.");
	 gotoXY(10,12); printw("Do you want to reload it? (y/n)");
LOOP:
	 hotkey("",yesno);
	 if (strcmp(yesno,"y")==0 || strcmp(yesno,"Y")==0)
	  {
 	  close (lockptr);
	  NewGame();
          GetGame(filename);
          InitializeStats();
          PrintBoard(white,0,0,1);
	  play();
	  }
	 if (strcmp(yesno,"n")==0 || strcmp(yesno,"N")==0)
	  {
	  close (lockptr);
	  NewGame();
	  PrintBoard(white,0,0,1);
	  play();
	  }
	 goto LOOP;
	}
NewGame();
PrintBoard(white,0,0,1);
play();
}

play()
{
 char temp[20];
 while (!(quit))
  {
   if (bothsides && !mate) select_move(opponent); else input_command();
   if (!quit && !mate) select_move(computer);
  }
  clear();
  gotoXY(10,10);
  printw("\33[33mThank you for playing, %s...\33[37m",username);
  gotoXY(1,20);
  end();
}

OpeningBook(side)
short side;
{
short i,j,r0,pnt;
unsigned m,r;
  srand(time(NULL));
  r0 = m = 0;
  for (i = 0; i < BookSize; i++)
    {
      for (j = 0; j <= GameCnt; j++)
        if (GameList[j] != Book[i][j]) break;
      if (j > GameCnt)
        if ((r=rand()) > r0)
          {
            r0 = r; m = Book[i][GameCnt+1];
          }
    }
  for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
    if ((Tree[pnt].f<<8) + Tree[pnt].t == m) Tree[pnt].score = 0;
  sort(TrPnt[1],TrPnt[2]-1);
  if (Tree[TrPnt[1]].score < 0) BookDepth = -1;
}


select_move(side)
short side;

/*
     Select a move by calling function search() at progressively deeper
     ply until time is up or a mate or draw is reached. An alpha-beta 
     window of -0, +75 points is set around the score returned from the
     previous iteration. 
*/

{
short i,alpha,beta,tempb,tempc;
char usertemp[50], nothing;
int feldd;

int loop;

  timeout = false; player = side;
  for (i = 0; i < 30; i++)
    prvar[i] = killr1[i] = killr2[i] = killr3[i] = 0;
  PPscore[0] = -5000;
  alpha = -9999; beta = 9999;
  NodeCnt = Sdepth = extra_time = 0;
  ataks(white,atak[white]); ataks(black,atak[black]);
  TrPnt[1] = 0; root = &Tree[0];
  MoveList(side,1);
  if (GameCnt < BookDepth) OpeningBook(side); else BookDepth = -1;
  if (BookDepth > 0) timeout = true;
  counting++;
  gotoXY(50,16); printw("My move is: %s     ",mvstr1); ClrEoln();
  while (!timeout && Sdepth<30)
    {
      Sdepth++;
      search(side,1,Sdepth,alpha,beta,prvar);
      if (root->score < alpha)
        search(side,1,Sdepth,-12000,alpha,prvar);
      if (root->score > beta && !(root->flags & exact))
        {
          search(side,1,Sdepth,beta,12000,prvar);
        }
      beta = root->score+75;
      if (root->flags & exact) timeout = true;
    }
  if (root->score > -9999)
    {
      MakeMove(side,root,&tempb,&tempc);
      algbrnot(root->f,root->t);
      PrintBoard(side,root->f,root->t,0);
    }
  ElapsedTime(1);
  if (root->flags & draw)
	{
		gotoXY(50,13);
		printw("\33[33mdraw game!\33[37m              ");
	}
  if (root->score < -9000)
	{
		gotoXY(50,13);
		printw("\33[33myou will soon mate!\33[37m     ");
	}
  if (root->score > 9000)
	{
		gotoXY(50,13);
		printw("\33[33mcomputer will soon mate!\33[37m");
	}
  if (root->score == -9999)
    {
	gotoXY(50,13);
	position=sortup();
	clear();
	gotoXY(5,2); printw("\33[33mComputer is mate!!\33[37m");
	showfinal();
	save10();
	gotoXY(31,20);hotkey("\33[32mPress any key...\33[37m",nothing);
	end();
     }
  if (root->score == 9998)
    {
	gotoXY(50,13);
	position=sortdown();
	clear();
	gotoXY(5,2); printw("\33[33mYou are mate!!\33[37m");
	showfinal();
	save10();
	gotoXY(31,20);hotkey("\33[32mPress any key...\33[37m",nothing);
	end();
    }
  ClrEoln();
  if (post) post_move(root);
  if (root->f == 255 || root->t == 255) Game50 = GameCnt;
  else if (board[root->t] == pawn || (root->flags & capture)) 
    Game50 = GameCnt;
  GameScore[GameCnt] = root->score;
  if (GameCnt > 238) quit = true;
  player = otherside[side];
}


VerifyMove(s,ok)
char s[];
short *ok;

/*
    See if the opponents move is legal, if so, make it.
*/

{
short x,pnt,cnt,tempb,tempc;
unsigned short nxtline[30];
struct leaf *node,*xnode;

  *ok = false; cnt = 0;
  MoveList(opponent,2);
  pnt = TrPnt[2];
  while (pnt < TrPnt[3])
    {
      node = &Tree[pnt]; pnt++;
      algbrnot(node->f,node->t);
      if (strcmp(s,mvstr1) == 0 || strcmp(s,mvstr2) == 0)
        {
          xnode = node; cnt++;
        }
    }
  if (cnt == 1)
    {
      MakeMove(opponent,xnode,&tempb,&tempc);
      CaptureSearch(computer,opponent,3,1,-9999,9999,0,&x,nxtline);
      if (x == 10000) UnmakeMove(opponent,xnode,&tempb,&tempc);
      else
        {
          *ok = true; PrintBoard(opponent,xnode->f,xnode->t,0);
          if (xnode->f == 255 || xnode->t == 255) Game50 = GameCnt;
          else if (board[xnode->t] == pawn || (xnode->flags & capture)) 
            Game50 = GameCnt;
        } 
    }
}

 
input_command()
{
short ok,i,f,t;
char s[20],temp[20];
FILE *fd;

  ok=quit=false;
  while (!(ok || quit))
    {
      gotoXY(50,21); printw("Your move is? "); ClrtoEL();
      scanw("%s",s);
      player = opponent;
      VerifyMove(s,&ok);
      if (strcmp(s,"prt") == 0)
        {
          ClrScreen();  PrintBoard(white,0,0,1);
        }
      if (strcmp(s,"quit") == 0) quit = true;
      if (strcmp(s,"go") == 0) ok = true;
      if (strcmp(s,"help") == 0) help();
      if (strcmp(s,"rev") == 0)
        {
          reverse = !reverse;
          ClrScreen();
          PrintBoard(white,0,0,1);
        }
      if (strcmp(s,"save") == 0)
        {
	  sprintf(temp, "ch.%s", username);
          SaveGame(temp);
	  quit = true;
        }
    }
  if (!(quit)) ElapsedTime(1);
}


gotoXY(x,y)
short x,y;
{
  move(y-1,x-1);
}


ClrScreen()
{
clear();
getsvar (1, username);
gotoXY(50,2); printw("Player:");
gotoXY(58,2); printw(username);
gotoXY(50,4); printw("HELP  help");
gotoXY(50,5); printw("GO    skip your move");
gotoXY(50,6); printw("PRT   redraw board");
gotoXY(50,7); printw("REV   reverse board display");
gotoXY(50,8); printw("SAVE  save and quit");
gotoXY(50,9); printw("QUIT  quit without save");
gotoXY(50,11); printw("o-o   castle king side");
gotoXY(50,12); printw("o-o-o castle queen side");
}


ClrEoln()
{
  clrtoeol();
}

algbrnot(f,t)
short f,t;
{
  if (f == 255)
    { strcpy(mvstr1,"o-o"); strcpy(mvstr2,"o-o"); }
  else if (t == 255)
    { strcpy(mvstr1,"o-o-o"); strcpy(mvstr2,"o-o"); }
  else
    {
      mvstr1[0] = cx[col[f]]; mvstr1[1] = rx[row[f]];
      mvstr1[2] = cx[col[t]]; mvstr1[3] = rx[row[t]];
      mvstr2[0] = qx[board[f]];
      mvstr2[1] = mvstr1[2]; mvstr2[2] = mvstr1[3];
      mvstr1[4] = '\0'; mvstr2[3] = '\0';
    }
}


parse(s,m)
unsigned short *m; char s[];
{
short r1,r2,c1,c2;
  if (s[4] == 'o') *m = 0x00FF;
  else if (s[0] == 'o') *m = 0xFF00;
  else
    {
      c1 = s[0] - 'a'; r1 = s[1] - '1';
      c2 = s[2] - 'a'; r2 = s[3] - '1';
      *m = (locn[r1][c1]<<8) + locn[r2][c2];
    }
}


GetOpenings()
{
FILE *fd;
int c,j;
char s[80],*p;
  fd = fopen("chess.opn","r");
  BookSize = 0; BookDepth = 24; j = -1; c = '?';
  while (c != EOF)
    {
      p = s;
      while ((c=getc(fd)) != EOF)
        if (c == '\n') break; else *(p++) = c;
      *p = '\0';
      if (c != EOF)
        if (s[0] == '!')
          {
            while (j < BookDepth) Book[BookSize][j++] = 0; 
            BookSize++; j = -1;
          }
        else if (j < 0) j++;
        else
          {
            parse(&s[0],&Book[BookSize][j]); j++;
            parse(&s[6],&Book[BookSize][j]); j++;
          } 
    }
  fclose(fd);
}


GetGame(fname)
char fname[20];
{
FILE *fd;
int c;
short loc;
unsigned short m;

  if (fname[0] == '\0') strcpy(fname,"chess.000");
  if ((fd = fopen(fname,"r")) != NULL)
    {
      fscanf(fd,"%hd",&castld[white]);
      fscanf(fd,"%hd",&castld[black]);
      fscanf(fd,"%hd",&kingmoved[white]);
      fscanf(fd,"%hd",&kingmoved[black]);
      fscanf(fd,"%hd",&counting);
      for (loc = 0; loc < 64; loc++)
        {
          fscanf(fd,"%hd",&m); board[loc] = (m >> 8); piece_color[loc] = (m & 0xFF);
        }
      GameCnt = -1; c = '?';
      while (c != EOF)
        c = fscanf(fd,"%hd%hd%hd%hd",&GameList[++GameCnt],&GameScore[GameCnt],
                   &GamePc[GameCnt],&GameClr[GameCnt]);
    }
  fclose(fd);
}


SaveGame(fname)
char fname[20];
{
FILE *fd;
short loc,i;

  if (fname[0] == '\0') strcpy(fname,"chess.000");
  fd = fopen(fname,"w");
  fprintf(fd,"%d\n",castld[white]);
  fprintf(fd,"%d\n",castld[black]);
  fprintf(fd,"%d\n",kingmoved[white]);
  fprintf(fd,"%d\n",kingmoved[black]);
  fprintf(fd,"%d\n",counting);
  for (loc = 0; loc < 64; loc++)
    fprintf(fd,"%d\n",256*board[loc] + piece_color[loc]);
  for (i = 0; i <= GameCnt; i++)
    fprintf(fd,"%d %d %d %d\n",GameList[i],GameScore[i],GamePc[i],GameClr[i]);
  fclose(fd);
}


ElapsedTime(iop)
short iop;
{
int minute,second;
  et = time(NULL) - time0;
  if (et < et0) et0 = 0;
  if (et > et0 || iop == 1)
    {
      if (et > response_time+extra_time) timeout = true;
      et0 = et;
      if (iop == 1)
        {
          et0 = 0; time0 = time(NULL);
        }
      minute = et/60; second = (et - 60*minute);
      if (player == computer) gotoXY(50,18); else gotoXY(50,23);
      if (flag==1) 
	{
	printw("%d:%02d",minute,second); ClrEoln();
	}
      if (flag==0)
	{
	flag=1;
	}
    }
}


post_move(node)
struct leaf *node;
{
short d,e,ply;
  d = 4; ply = 1;
  gotoXY(60,d); printw("%6d  ",node->score);
  while (prvar[ply] > 0)
    {
      algbrnot(prvar[ply]>>8,prvar[ply] & 0x00FF);
      gotoXY(50,d); printw("%5s",mvstr1);
      ply++; d++;
    }
  e = d;
  while (d < lpost)
    {
      gotoXY(50,d++); ClrEoln();
    }
  lpost = e;
}


DrawPiece(loc)
short loc;
{
short r,c; char x[10];
char temp[10];
  if (reverse) r = 7-row[loc]; else r = row[loc];
  if (reverse) c = 7-col[loc]; else c = col[loc];
  if (piece_color[loc] == black) sprintf (x,"\33[31m"); else sprintf (x,"\33[32m");
  if (color[loc] == 1) 
    strcpy (temp,"\33[47m");
  else
    strcpy (temp,"\33[40m");
  gotoXY(7+5*c,1+3*(7-r)); printw("%s%s%c\33[37;40m",temp,x,px[board[loc]]," ");
}


PrintBoard(side,f,t,flag)
short side,f,t,flag;
{
short i,l,c,z=0; 
int q,w;

  if (side == white) c = 0; else c = 56;
  if (flag)
    {
      i = -1;

      for (w=0;w<4;w++)
	{
	  gotoXY(3,++i);
	  printw ("  \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     ");
	  gotoXY(3,++i);
	  z++;
	  if (reverse) z = 9-z;
	  printw("%d \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     ",z);
	  gotoXY(3,++i);
	  printw ("  \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     ");
	  gotoXY(3,++i);
	  printw ("  \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m");
	  gotoXY(3,++i);
	  z++;
	  if (reverse) z = 9-z;
	  printw("%d \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m",z);
	  gotoXY(3,++i);
	  printw ("  \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m     \33[47m     \33[40m");
        }
      gotoXY(3,26);
      if (reverse) printw("    h    g    f    e    d    c    b    a");
              else printw("    a    b    c    d    e    f    g    h");
      for (l = 0; l < 64; l++) DrawPiece(l);
    }
  else if (f == 255)
    {
      DrawPiece(c+4); DrawPiece(c+6);
      DrawPiece(c+7); DrawPiece(c+5);
    }
  else if (t == 255)
    {
      DrawPiece(c+4); DrawPiece(c+2);
      DrawPiece(c); DrawPiece(c+3);
    }
  else
    {
      DrawPiece(f); DrawPiece(t);
    }
}

NewGame()
{
short l,r,c;

  mate = quit = reverse = bothsides = post = false;
  lpost =  NodeCnt = epsquare = xkillr = 0;
  GameCnt = Game50 = -1;
  castld[white] = castld[black] = false;
  kingmoved[white] = kingmoved[black] = 0;
  opponent = white; computer = black;
  for (r = 0; r < 8; r++)
    for (c = 0; c < 8; c++)
      {
        l = 8*r+c; locn[r][c] = l;
        row[l] = r; col[l] = c;
      }
  ClrScreen(); 
  response_time=1;
  ClrScreen(); 
  
  InitializeStats();
  ElapsedTime(1);
  GetOpenings();
}


help()
{
char c;

sendmessage ("\14",0);
showfile ("chess.hlp"); 
hotkey ("",tt);
ClrScreen();
PrintBoard(white,0,0,1);
}


UpdatePieceList(side,loc,iop)
short side,loc,iop;

/*
    Array PieceList[side][indx] contains the location of all the pieces of
    either side. Array indx[loc] contains the indx into PieceList for a
    given square.
*/

{
register short i;
  if (iop == 1)
    {
      PieceCnt[side]--;
      for (i = indx[loc]; i <= PieceCnt[side]; i++)
        {
          PieceList[side][i] = PieceList[side][i+1];
          indx[PieceList[side][i]] = i;
        }
    }
  else
    {
      PieceCnt[side]++;
      PieceList[side][PieceCnt[side]] = loc;
      indx[loc] = PieceCnt[side];
    }
}


InitializeStats()
{
register short i,loc;
  for (i = 0; i < 8; i++)
    PawnCnt[white][i] = PawnCnt[black][i] = 0;
  mtl[white] = mtl[black] = pmtl[white] = pmtl[black]=0;
  PieceCnt[white] = PieceCnt[black] = 0;
  for (loc = 0; loc < 64; loc++)
    if (piece_color[loc] != neutral)
      {
        mtl[piece_color[loc]] += value[board[loc]];
        if (board[loc] == pawn)
          {
            pmtl[piece_color[loc]] += value[pawn];
            ++PawnCnt[piece_color[loc]][col[loc]];
          }
        if (board[loc] == king) indx[loc] = 0;
          else indx[loc] = ++PieceCnt[piece_color[loc]];
        PieceList[piece_color[loc]][indx[loc]] = loc;
      }
}


sort(p1,p2)
short p1,p2;
{
register short p,p0,s;
struct leaf temp;

  s = 32000;
  while (p1 < p2)
    if (Tree[p1].score >= s) p1++;
    else
      {
        s = Tree[p1].score; p0 = p1;
        for (p = p1+1; p <= p2; p++)
          if (Tree[p].score > s)
            {
              s = Tree[p].score; p0 = p;
            }
        temp = Tree[p1]; Tree[p1] = Tree[p0]; Tree[p0] = temp;
        p1++;
      }
}


repetition(node)
struct leaf *node;
/*
    Check for draw by threefold repetition or 50 move rule.
*/
{
register short i,f,t,c;
short r,b[64];
unsigned short m;
  r = c = 0;
  setmem(b, 64*sizeof(short), 0);
  for (i = GameCnt; i > Game50; i--)
    {
      m = GameList[i]; f = m>>8; t = m & 0xFF;
      if (t != 255 && f != 255)
        {
          b[f]++; b[t]--;
          if (b[f] == 0) c--; else c++;
          if (b[t] == 0) c--; else c++;
          if (c == 0) r++;
        }
    }
  if (r == 1)
    if (node->score > 0) node->score -= 20;
    else node->score += 20;
  if (GameCnt-Game50 > 99 || r == 2)
    {
      node->score = 0;
      node->flags |= exact;
      node->flags |= draw;
    }
}


ataks(side,a)
short side,a[];

/*
    Place the lowest value piece attacking a square into array atak[][].
*/

{
register short m,u,d,j;
short piece,i,m0,*aloc,*s;

  setmem(a, 64*sizeof(short),0);
  Dstart[pawn] = Dstpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
  aloc = &PieceList[side][0];
  for (i = 0; i <= PieceCnt[side]; i++)
    {
      piece = board[*aloc]; m0 = map[*aloc];
      s = &svalue[*aloc]; *s = 0;
      aloc++;
      if (sweep[piece])
        for (j = Dstart[piece]; j <= Dstop[piece]; j++)
          {
            d = Dir[j]; m = m0+d; u = unmap[m];
            while (u >= 0)
              {
                *s += 2;
                if (a[u] == 0 || piece < a[u]) a[u] = piece;
                if (piece_color[u] == neutral)
                  {
                    m += d; u = unmap[m];
                  }
                else u = -1;
              }
          }
      else
        {
          for (j = Dstart[piece]; j <= Dstop[piece]; j++)
            if ((u = unmap[m0+Dir[j]]) >= 0)
              if (a[u] == 0 || piece < a[u]) a[u] = piece;
        }
    }
}

  
castle(side,f,t,iop,ok)
short side,f,t,iop,*ok;
{
short i,e,k1,k2,r1,r2,c1,c2,t0,xside;

  xside = otherside[side];
  if (side == white) e = 0; else e = 56;
  if (f == 255)
    {
      k1 = e+4; k2 = e+6; r1 = e+7; r2 = e+5; c1 = k1; c2 = r1;
    }
  else
    {
      k1 = e+4; k2 = e+2; r1 = e; r2 = e+3; c1 = r1; c2 = k1;
    }
  if (iop == 0)
    {
      *ok = false;
      if (board[k1] == king && board[r1] == rook) *ok = true;
      for (i = c1; i <= c2; i++)
        if (atak[xside][i] > 0) *ok = false; 
      for (i = c1+1; i < c2; i++)
        if (piece_color[i] != neutral) *ok = false;
    }
  else
    {
      if (iop == 1) castld[side] = true; else castld[side] = false;
      if (iop == 2)
        {
          t0 = k1; k1 = k2; k2 = t0;
          t0 = r1; r1 = r2; r2 = t0;
        }
      board[k2] = king; piece_color[k2] = side; indx[k2] = 0;
      board[k1] = no_piece; piece_color[k1] = neutral;
      board[r2] = rook; piece_color[r2] = side; indx[r2] = indx[r1];
      board[r1] = no_piece; piece_color[r1] = neutral;
      PieceList[side][indx[k2]] = k2;
      PieceList[side][indx[r2]] = r2;
    }
}


en_passant(side,xside,f,t,iop)
short side,f,t,iop;
{
short l;
  if (t > f) l = t-8; else l = t+8;
  if (iop == 1)
    {
      board[l] = no_piece; piece_color[l] = neutral;
    }
  else 
    {
      board[l] = pawn; piece_color[l] = xside;
    }
  InitializeStats();
}


LinkMove(ply,f,t,side,xside)
short ply,f,t,side,xside;
{

/*
    Add a move to the tree.  Assign a bonus (in an attempt to
    improve move ordering) if move is a
    principle variation, "killer", or capturing move.
*/

register short s;
unsigned short mv;
struct leaf *node;

  node = &Tree[TrPnt[ply+1]];
  ++TrPnt[ply+1];
  node->flags = node->reply = 0;
  node->f = f; node->t = t; mv = (f<<8) + t;
  if (f == 255 || t == 255) s = 100;
  else
    {
      s = 0;
      if (mv == PV) s = 150;
      else if (mv == killr1[ply]) s = 90;
      else if (mv == killr2[ply]) s = 70;
      else if (mv == killr3[ply]) s = 50;
      else if (mv == Swag1) s = 30;
      else if (mv == Swag2) s = 20;
      if (piece_color[t] != neutral)
        {
          node->flags |= capture;
          if (t == xkillr) s += 400;
          if (atak[xside][t] == 0) s += value[board[t]]-board[f];
          else if (board[t] > board[f]) s += value[board[t]]-value[board[f]];
          else s += 15;
        }
      if (board[f] == pawn)
        {
          if (row[t] == 0 || row[t] == 7) node->flags |= promote;
          else if (row[t] == 1 || row[t] == 6) node->flags |= pwnthrt;
          else if (t == epsquare) node->flags |= epmask;
        }
      if (atak[xside][f] > 0) s += 15;
      if (atak[xside][t] > 0) s -= 20;
      if (InChk)
        {
          if (board[f] == king && atak[xside][t] == 0) s += 600;  
          if (mv == Qkillr[ply]) s += 100;
        }
    }
  node->score = s-20000;
}


GenMoves(ply,loc,side,xside)
short ply,loc,side,xside;

/*
     Generate moves for a piece. The from square is mapped onto a 12 by 
     12 board and offsets (taken from array Dir[]) are added to the 
     mapped location. Array unmap[] maps the move back onto array 
     board[] (yielding a value of -1 if the to square is off the board). 
     This process is repeated for bishops, rooks, and queens until a 
     piece is encountered or the the move falls off the board. Legal 
     moves are then linked into the tree. 
*/
    
{
register short m,u,d;
short i,m0,piece; 

  piece = board[loc]; m0 = map[loc];
  if (sweep[piece])
    {
      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
        {
          d = Dir[i]; m = m0+d; u = unmap[m];
          while (u >= 0)
            if (piece_color[u] == neutral)
              {
                LinkMove(ply,loc,u,side,xside);
                m += d; u = unmap[m];
              }
            else if (piece_color[u] == xside)
              {
                LinkMove(ply,loc,u,side,xside);
                u = -1;
              }
            else u = -1;
        }
    }
  else if (piece == pawn)
    {
      if (side == white && piece_color[loc+8] == neutral)
        {
          LinkMove(ply,loc,loc+8,side,xside);
          if (row[loc] == 1)
            if (piece_color[loc+16] == neutral)
              LinkMove(ply,loc,loc+16,side,xside);
        }
      else if (side == black && piece_color[loc-8] == neutral)
        {
          LinkMove(ply,loc,loc-8,side,xside);
          if (row[loc] == 6)
            if (piece_color[loc-16] == neutral)
              LinkMove(ply,loc,loc-16,side,xside);
        }
      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
        if ((u = unmap[m0+Dir[i]]) >= 0)
          if (piece_color[u] == xside || u == epsquare)
            LinkMove(ply,loc,u,side,xside);
    }
  else
    {
      for (i = Dstart[piece]; i <= Dstop[piece]; i++)
        if ((u = unmap[m0+Dir[i]]) >= 0)
          if (piece_color[u] != side)
            LinkMove(ply,loc,u,side,xside);
    }
}



MoveList(side,ply)
short side,ply;

/*
    Fill the array Tree[] with all available moves for side to
    play. Array TrPnt[ply] contains the index into Tree[]
    of the first move at a ply.
*/
    
{
register short i;
short ok,xside;

  xside = otherside[side];
  TrPnt[ply+1] = TrPnt[ply];
  Dstart[pawn] = Dstpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
  for (i = 0; i <= PieceCnt[side]; i++)
    GenMoves(ply,PieceList[side][i],side,xside);
  if (kingmoved[side] == 0)
    {
      castle(side,255,0,0,&ok);
      if (ok) LinkMove(ply,255,0,side,xside);
      castle(side,0,255,0,&ok);
      if (ok) LinkMove(ply,0,255,side,xside);
    }
  sort(TrPnt[ply],TrPnt[ply+1]-1);
}


MakeMove(side,node,tempb,tempc)
short side,*tempc,*tempb;
struct leaf *node;

/*
    Update Arrays board[], piece_color[], and indx[] to reflect the new
    board position obtained after making the move pointed to by
    node.  Also update miscellaneous stuff that changes when a move
    is made.
*/
    
{
register short f,t;
short ok,xside;

  xside = otherside[side];
  f = node->f; t = node->t; epsquare = -1; xkillr = t;
  GameList[++GameCnt] = (f<<8) + t;
  if (f == 255 || t == 255)
    {
      GamePc[GameCnt] = no_piece; GameClr[GameCnt] = neutral;
      castle(side,f,t,1,&ok);
    }
  else
    {
      *tempc = piece_color[t]; *tempb = board[t];
      GamePc[GameCnt] = *tempb; GameClr[GameCnt] = *tempc;
      if (*tempc != neutral)
        {
          UpdatePieceList(*tempc,t,1);
          if (*tempb == pawn) --PawnCnt[*tempc][col[t]];
          if (board[f] == pawn)
            {
              --PawnCnt[side][col[f]];
              ++PawnCnt[side][col[t]];
            }
          mtl[xside] -= value[*tempb];
          if (*tempb == pawn) pmtl[xside] -= value[pawn];
        }
      piece_color[t] = piece_color[f]; board[t] = board[f];
      indx[t] = indx[f]; PieceList[side][indx[t]] = t;
      piece_color[f] = neutral; board[f] = no_piece;
      if (board[t] == pawn)
        if (t-f == 16) epsquare = f+8;
        else if (f-t == 16) epsquare = f-8;
      if (node->flags & promote)
        {
          board[t] = queen;
          mtl[side] += value[queen] - value[pawn];
          pmtl[side] -= value[pawn];
        } 
      if (board[t] == king) ++kingmoved[side];
      if (node->flags & epmask) en_passant(side,xside,f,t,1);
    }
}


UnmakeMove(side,node,tempb,tempc)
short side,*tempc,*tempb;
struct leaf *node;

/*
    Take back the move pointed to by node.
*/

{
register short f,t;
short ok,xside;

  xside = otherside[side];
  f = node->f; t = node->t; epsquare = -1;
  GameCnt--;
  if (f == 255 || t == 255) castle(side,f,t,2,&ok);
  else
    {
      piece_color[f] = piece_color[t]; board[f] = board[t];
      indx[f] = indx[t]; PieceList[side][indx[f]] = f;
      piece_color[t] = *tempc; board[t] = *tempb;
      if (*tempc != neutral)
        {
          UpdatePieceList(*tempc,t,2);
          if (*tempb == pawn) ++PawnCnt[*tempc][col[t]];
          if (board[f] == pawn)
            {
              --PawnCnt[side][col[t]];
              ++PawnCnt[side][col[f]];
            }
          mtl[xside] += value[*tempb];
          if (*tempb == pawn) pmtl[xside] += value[pawn];
        }
      if (node->flags & promote)
        {
          board[f] = pawn;
          mtl[side] += value[pawn] - value[queen];
          pmtl[side] += value[pawn];
        } 
      if (board[f] == king) --kingmoved[side];
      if (node->flags & epmask) en_passant(side,xside,f,t,2);
    }
}


LinkCapture(ply,f,t,ck)
short ply,f,t,ck;
{
struct leaf *node;

  node = &Tree[TrPnt[ply+1]];
  ++TrPnt[ply+1];
  node->flags = node->reply = 0;
  node->f = f; node->t = t;
  if (t == ykillr || t == ck) node->score = value[board[t]]-board[f];
  else node->score = value[board[t]]-value[board[f]];
}


CaptureList(side,xside,ply)
short side,xside,ply;

/*
    Generate a list of captures similiarly to GenMoves.
*/

{
register short m,u,d;
short i,j,m0,piece,ck,*aloc;

  ck = Ckillr[side] & 0x00FF;
  TrPnt[ply+1] = TrPnt[ply];
  Dstart[pawn] = Dstpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
  aloc = &PieceList[side][0];
  for (i = 0; i <= PieceCnt[side]; i++)
    { 
      piece = board[*aloc]; m0 = map[*aloc];
      if (sweep[piece])
        for (j = Dstart[piece]; j <= Dstop[piece]; j++)
          {
            d = Dir[j]; m = m0+d; u = unmap[m];
            while (u >= 0)
              if (piece_color[u] == neutral)
                {
                  m += d; u = unmap[m];
                }
              else
                {
                  if (piece_color[u] == xside) LinkCapture(ply,*aloc,u,ck);
                  u = -1;
                }
          }
      else
        for (j = Dstart[piece]; j <= Dstop[piece]; j++)
          if ((u = unmap[m0+Dir[j]]) >= 0)
            if (piece_color[u] == xside) LinkCapture(ply,*aloc,u,ck);
      aloc++;
    }
  sort(TrPnt[ply],TrPnt[ply+1]-1);
}


distance(a,b)
short a,b;
{
short d1,d2;

  d1 = col[a]-col[b]; if (d1 < 0) d1 = -d1;
  d2 = row[a]-row[b]; if (d2 < 0) d2 = -d2;
  if (d1 > d2) return(d1); else return(d2);
}


ScorePosition(side,score)
short side,*score;

/*
  Calculate a positional score for each piece as follows:
    pawns:
      material value     : 100 pts
      d,e file, not moved: -10 pts
           & also blocked: -10 pts
      doubled            : -12 pts (each pawn)
      isolated           : -24 pts
      backward           : -8  pts
         & attacked      : -6  pts
      passed             : depends on rank, material balance,
                           position of opponents king, blocked
    knights:
      material value     : 330 pts
      centre proximity   : array pknight 
    bishops:
      material value     : 330 pts
      discourage edges   : array pbishop
      mobility           : +2 pts per move  
    rooks:
      material value     : 500 pts
      mobility           : +2 pts per move
      open file          : +12 pts
      half open          : +6 pts
    queen:
      material value     : 950 pts
    king:
      castled            : ~ +10 pts (depends on material)
      king moved         : ~ -15 pts (depends on material)
      adjacent pawn      : +5 pts before endgame
      attacks to         : -5 pts each if more than 1 attack
      adjacent square        before endgame
      pawn missing from  : -10 pts before endgame
      adjacent column
      centre proximity   : -2 pts before endgame, during endgame
                           switches to a bonus for center proximity
                           dependent on opponents control of adjacent
                           squares
                           
    "hung" pieces        : -8  (1 hung piece)
                           -24 (more than 1)
*/

{
register short i,j,a;
short loc,e,m0,u,piece,wking,bking,cwking,cbking;
short r,db,dw,s,stage1,stage2,c1,c2,a1,a2;
short pscore[3],xside,rank,column,in_square;

  xside = otherside[side];
  pscore[white] = pscore[black] = 0;
  emtl[white] = mtl[white] - pmtl[white] - value[king];
  emtl[black] = mtl[black] - pmtl[black] - value[king];
  wking = PieceList[white][0]; bking = PieceList[black][0];
  cwking = col[wking]; cbking = col[bking];
  stage1 = 10 - (emtl[white]+emtl[black]) / 670;
  stage2 = (stage1*stage1) / 10;

  for (c1 = white; c1 <= black; c1++)
  {
    c2 = otherside[c1];
    for (i = 0; i <= PieceCnt[c1]; i++)
      {
        loc = PieceList[c1][i]; piece = board[loc];
        a1 = atak[c1][loc]; a2 = atak[c2][loc];
        rank = row[loc]; column = col[loc];
        s = svalue[loc];

        if (piece == pawn && c1 == white)
          {
            if (column == 3 || column == 4)
              if (rank == 1)
                {
                  s -= 10;
                  if (piece_color[loc+8] == white) s -=10;
                }
              else if (rank == 4 && a1 == pawn) s += 8;
            if (column-cwking > 1 || cwking-column > 1) s += stage1*rank;
            if (PawnCnt[white][column] > 1) s -= 12;
            if (column > 0 && PawnCnt[white][column-1] == 0 &&
                column < 7 && PawnCnt[white][column+1] == 0) s -= 24;
            if (a1 != pawn && atak[c1][loc+8] != pawn)
              {
                s -= 8;
                if (a2 > 0) s -= 6;
              }
            if (PawnCnt[black][column] == 0)
              {
                dw = distance(loc,wking);
                db = distance(loc,bking);
                s += stage2*(db-dw);
                if (side == white) r = rank-1; else r = rank;
                if (row[bking] >= r && db < 8-r) in_square = true;
                  else in_square = false;
                e = 0; 
                for (a = loc+8; a < 64; a += 8)
                  if (atak[black][a] == pawn) a = 99;
                  else if (atak[black][a] > 0 || piece_color[a] != neutral) e = 1; 
                if (a == 99) s += stage1*passed_pawn3[rank];
                else if (in_square || e == 1) s += stage1*passed_pawn2[rank];
                else s += stage1*passed_pawn1[rank];
              }
          }
        else if (piece == pawn && c1 == black)
          {
            if (column == 3 || column == 4)
              if (rank == 6)
                {
                  s -= 10;
                  if (piece_color[loc-8] == black) s -= 10;
                }
              else if (rank == 3 && a1 == pawn) s += 8;
            if (column-cbking > 1 || cbking-column > 1) s += stage1*(7-rank);
            if (PawnCnt[black][column] > 1) s -= 12;
            if (column > 0 && PawnCnt[black][column-1] == 0 &&
                column < 7 && PawnCnt[black][column+1] == 0) s -= 24;
            if (a1 != pawn && atak[c1][loc-8] != pawn)
              {
                s -= 8;
                if (a2 > 0) s -= 6;
              }
            if (PawnCnt[white][column] == 0)
              {
                dw = distance(loc,wking);
                db = distance(loc,bking);
                s += stage2*(dw-db);
                if (side == black) r = rank+1; else r = rank;
                if (row[wking] <= r && dw < r+1) in_square = true;
                  else in_square = false;
                e = 0; 
                for (a = loc-8; a >= 0 ; a -= 8)
                  if (atak[white][a] == pawn) a = -99;
                  else if (atak[white][a] > 0 || piece_color[a] != neutral) e = 1; 
                if (a == -99) s += stage1*passed_pawn3[7-rank];
                else if (in_square || e == 1) s += stage1*passed_pawn2[7-rank];
                else s += stage1*passed_pawn1[7-rank];
              }
          }
        else if (piece == knight)
          {
            s = pknight[loc];
          }
        else if (piece == bishop)
          {
            s += pbishop[loc];
          }
        else if (piece == rook)
          {
            if (PawnCnt[white][column] == 0) s += 6;
            if (PawnCnt[black][column] == 0) s += 6;
          }
        else if (piece == queen)
          {
            s = s/3;
          }
        else if (piece == king)
          {
            m0 = map[loc];
            if (castld[c1]) s += (20/(stage1+1));
            else if (kingmoved[c1] > 0) s -= (30/(stage1+1));
            if (emtl[c1] > 1300)
              {
                s -= 2*edge[loc]; a = 0;
                for (j = Dstart[king]; j <= Dstop[king]; j++)
                  if ((u = unmap[m0+Dir[j]]) >= 0)
                    {
                      if (atak[c2][u] > 0) a++;
                      if (board[u] == pawn) s += 5;
                    }
                if (a > 1) s -= 5*a; 
                if (column > 0 && PawnCnt[c1][column-1] == 0) s -= 10;
                if (column < 7 && PawnCnt[c1][column+1] == 0) s -= 10;
                if (PawnCnt[c1][column] == 0) s -= 12;
              }
            else
              {
                e = edge[loc];
                for (j = Dstart[king]; j <= Dstop[king]; j++)
                  if ((u=unmap[m0+Dir[j]]) >= 0)
                    if (atak[c2][u] == 0) e += edge[u];
                s += (e*((1300-emtl[c1])/100))/8;
              }
            if (mtl[c1]<1000 && mtl[c2]<1990 && distance(wking,bking)==2
                && e<12) s -= 30;
          }
        if (a2 > 0 && (a1 == 0 || a2 < piece)) ++hung[c1];
        if (a2 > 0) s -= 3;
        pscore[c1] += s; svalue[loc] = s;
      }
  }
  if (hung[side] > 1) pscore[side] -= 12;
  if (hung[xside] == 1) pscore[xside] -= 8;
  if (hung[xside] > 1) pscore[xside] -= 24;
  *score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] - 5;
  if (*score > 0 && pmtl[side] == 0 && emtl[side] <= value[bishop])
    *score = 0;
  if (*score < 0 && pmtl[xside] == 0 && emtl[xside] <= value[bishop])
    *score = 0;
}


CaptureSearch(side,xside,ply,depth,alpha,beta,qscore,best,bstline)
short side,xside,ply,depth,alpha,beta,qscore,*best;
unsigned short bstline[];

/*
    Perform alpha-beta search on captures up to 9 ply past
    nominal search depth.
*/

{
register short j,f,t;
short v,q,pnt,tempb,tempc,pbst,sv;
unsigned short nxtline[30];
struct leaf *node;

  *best = -qscore; bstline[ply] = 0;
  CaptureList(side,xside,ply);
  pnt = TrPnt[ply]; pbst = 0;
  while (pnt < TrPnt[ply+1] && *best <= beta)
    {
      node = &Tree[pnt]; pnt++;
      f = node->f; t = node->t;
      v = value[board[t]]-qscore+svalue[t]; 
      if (v > alpha)
        {
          if (board[t] == king) node->score = 10000;
          else if (depth == 1) node->score = v;
          else
            {
              ykillr = t; NodeCnt++;
              sv = svalue[t]; svalue[t] = svalue[f];
              tempb = board[t]; tempc = piece_color[t];
              UpdatePieceList(tempc,t,1);
              board[t] = board[f]; piece_color[t] = piece_color[f];
              indx[t] = indx[f]; PieceList[side][indx[t]] = t;
              board[f] = no_piece; piece_color[f] = neutral;
              CaptureSearch(xside,side,ply+1,depth-1,-beta,-alpha,v,
                            &q,nxtline);
              node->score = -q;
              board[f] = board[t]; piece_color[f] = piece_color[t];
              indx[f] = indx[t]; PieceList[side][indx[f]] = f;
              board[t] = tempb; piece_color[t] = tempc;
              UpdatePieceList(xside,t,2);
              svalue[f] = svalue[t]; svalue[t] = sv;
            }
        if (node->score > *best)
          {
            pbst = pnt;
            *best = node->score;
            if (*best > alpha) alpha = *best;
            for (j = ply; j < 30; j++) bstline[j] = nxtline[j];
            bstline[ply] = (f<<8) + t;
          } 
        }
    }
  if (pbst == 0) Ckillr[side] = -1;
    else Ckillr[side] = (Tree[pbst].f<<8) + Tree[pbst].t;
}


expand(side,node,depth,ply,alpha,beta,nxtline)
short side,depth,alpha,beta,ply;
unsigned short nxtline[];
struct leaf *node;

/*
    Generate a score for current position by calling search routine
    to generate opponents best response.
*/

{
short s,xside;
struct leaf *reply;

  xside = otherside[side];
  nxtline[ply] = (node->f<<8) + node->t;
  nxtline[ply+1] = node->reply;
  search(xside,ply+1,depth-1,-beta,-alpha,nxtline);
  if (!timeout)
    {
      reply = &Tree[TrPnt[ply+1]];
      s = -reply->score;
      if (s >= alpha && s <= beta) node->score = s;
      else if (s < alpha && s < node->score) node->score = s;
      else if (s > beta && s > node->score) node->score = s;
      if ((reply->flags & incheck) && !(node->flags & check))
        {
          node->flags |= draw; node->score = 0;
        }
      if ((node->flags & draw) || (node->score <= -9000) ||
          (node->score >= 9000)) node->flags |= exact;
      node->reply = nxtline[ply+1];
    }
}


evaluate(side,node,ply,depth,alpha,beta,nxtline)
short side,ply,alpha,beta;
unsigned short nxtline[];
struct leaf *node;

/*
    See if either king is in check.  If positional score estimate
    passed forward from previous ply warrants, score the position.
    If positional score is greater than alpha, perform CaptureSearch
    to modify score based on ensuing capture sequence.
*/

{
short xside,s,x,t;

  hung[white] = hung[black] = 0;
  xside = otherside[side];
  ataks(xside,atak[xside]);
  if (atak[xside][PieceList[side][0]] > 0)
    {
      node->score = ply-10000;
      node->flags |= incheck;
      node->flags |= exact;
    }
  else
    {
      ataks(side,atak[side]);
      if (atak[side][PieceList[xside][0]]) node->flags |= check;
      if (ply > Sdepth) t = 0; else t = 90;
      s = -PPscore[ply-1]+mtl[side]-mtl[xside];
      if (s+t > alpha || (node->flags & check) ||
        (node->flags & pwnthrt)) ScorePosition(side,&s);
      PPscore[ply] = s-mtl[side]+mtl[xside];
      if (s < alpha || depth > 1)
        {
          if (node->score < -12000) node->score = s;
        }
      else
        {
          ykillr = xkillr;
          CaptureSearch(xside,side,ply+1,9,-s-1,-alpha,s,&x,nxtline);
          node->score = -x;
          node->reply = nxtline[ply+1];
        }
      repetition(node);
    }
}


search(side,ply,depth,alpha,beta,bstline)
short side,ply,depth,alpha,beta;
unsigned short bstline[];

/*
    Perform the main alpha-beta search.  Extensions up to 3 ply
    beyond the nominal iterative search depth MAY occur for checks,
    check evasions, pawn promotion threats, and threats to multiple
    pieces.  
*/

{
register short j;
short best,tempb,tempc,xside,pnt,pbst,hhh,d;
unsigned short mv,nxtline[30];
struct leaf *node;

  xside = otherside[side];
  if (ply == 1) InChk = false; else InChk = ChkFlag[ply-1];
  PV = bstline[ply];
  if (ply < 3)
    {
      Swag1 = Swag2 = 0;
    }
  else
    {
      Swag1 = (Tree[TrPnt[ply-2]].f<<8) + Tree[TrPnt[ply-2]].t;
      Swag2 = (Tree[TrPnt[ply-2]+1].f<<8) + Tree[TrPnt[ply-2]+1].t;
    }
  if (ply > 1) MoveList(side,ply);
  best = -12000; PPscore[ply] = -PPscore[ply-1];
  pnt = TrPnt[ply]; pbst = pnt;
  while (pnt < TrPnt[ply+1] && best<=beta && !timeout)
    {
      node = &Tree[pnt]; NodeCnt++;
      nxtline[ply+1] = 0;
      if (ply == 1)
        {
          d = node->score-best;
          if (pnt == TrPnt[ply]) extra_time = 0;
          else if (d < -50) extra_time = -response_time/3;
          else if (d < 20) extra_time = 0;
          else if (d < 60) extra_time = response_time/3;
          else if (d < 200) extra_time = response_time;
          else extra_time = 2*response_time;
        }
      if (node->flags & capture) CptrFlag[ply] = true;
        else CptrFlag[ply] = false;
      if (node->flags & pwnthrt) PawnThreat[ply] = true;
        else PawnThreat[ply] = false;
      if (ply == 1 && post)
        {
          algbrnot(node->f,node->t);
          gotoXY(50,2); printw("%5s",mvstr1,' '); ClrEoln();
        }
      if ((node->flags & exact) == 0)
      {
        MakeMove(side,node,&tempb,&tempc);
        evaluate(side,node,ply,depth,alpha,beta,nxtline);
        if (hung[xside] > 1 && ply <= Sdepth) hhh = true;
          else hhh = false;
        if (node->flags & check) ChkFlag[ply] = true; 
          else ChkFlag[ply] = false;
        if ((node->flags & exact) == 0)
          {
            if (depth > 1) expand(side,node,depth,ply,alpha,beta,nxtline);
            if (node->score <= beta && (PawnThreat[ply] ||
               ((ChkFlag[ply] || hhh) && depth == 1)))
              expand(side,node,depth+1,ply,alpha,beta,nxtline);
            else if ((ChkFlag[ply-1] || PawnThreat[ply-1]) &&
                     ply<=Sdepth+2 && Sdepth>1 &&
                     (ply>Sdepth || CptrFlag[ply-1] ||
                     (ply>3 && (ChkFlag[ply-3] || CptrFlag[ply-3])) ||
                     (hung[side] > 1)))
              expand(side,node,depth+1,ply,alpha,beta,nxtline);
          }
        UnmakeMove(side,node,&tempb,&tempc);
      }
      if (node->score > best && !timeout)
        {
          if (ply == 1 && depth > 1 && node->score>alpha &&
            (node->flags & exact) == 0) node->score += 5;
          best = node->score; pbst = pnt;
          if (best > alpha) alpha = best;
          for (j = ply; j < 30; j++) bstline[j] = nxtline[j];
          bstline[ply] = (node->f<<8) + node->t;
          if (ply == 1 && post) post_move(node);
        }
      if ((pnt % 5) == 0) ElapsedTime(0);
      pnt++;
      if (best > 9000) beta = 0;
    }
  if (timeout) pnt--;
  if (ply == 1) sort(TrPnt[ply],pnt-1);
  else Tree[TrPnt[ply]] = Tree[pbst];
  node = &Tree[TrPnt[ply]];
  mv = (node->f<<8) + node->t;
  if (node->t != (GameList[GameCnt] & 0x00FF))
    if (best > beta) killr1[ply] = mv;
    else if (mv != killr2[ply])
      {
        killr3[ply] = killr2[ply];
        killr2[ply] = mv;
      }
  if (InChk && best > -9000) Qkillr[ply] = mv;
}



/************************************************************************
 *									*
 *	 Here starts the standard Paragon Door Protocol functions.	*
 *									*
 ************************************************************************/
 
/*
 * end() -  Notifies Paragon that we are done and ready to continue with
 *		the BBS.  ALWAYS use this to exit from your program, or
 *		the BBS will go to never-never land.
 */

void end()
{
	doormsg->command = 20;
	PutMsg(MyPort,(struct Message *)doormsg);
	(void)WaitPort(replyport);
	(void)GetMsg(replyport);
	FreeMem(doormsg,(long)sizeof(*doormsg));
	DeletePort(replyport);
	exit(0);
}

/*
 * getsvar(typ,mstring) - Gets certain string variables from Paragon.
 * "mstring" is a pointer to a string to dump the string into.  "typ" tells
 * it what you want: 1=Name, 2=Password, 3=Address, 4=City, 5=State
 * 6=Postal code, 7=Door pathname, 8=Default BBS pathname.
 */

void getsvar(typ,mstring)
int typ;
char *mstring;
{
	doormsg->data = typ;
	doormsg->command = 14;
	PutMsg(MyPort,(struct Message *)doormsg);
	(void)WaitPort(replyport);
	strcpy(mstring,doormsg->string);
	(void)GetMsg(replyport);
}

/*
 * sendmessage(mstring,nl) - Sends a message to the local window and to
 * the modem (if applicable).  "mstring" is the output string you want to
 * send, "nl" is and integer which is 1 if you want it to send the
 * c/r+l/f combination, or 0 if not.
 */

void sendmessage(mstring,nl)
char mstring[];
int nl;
{
	doormsg->data = nl;
	doormsg->command = 1;
	strcpy(doormsg->string,mstring);
	PutMsg(MyPort,(struct Message *)doormsg);
	(void)WaitPort(replyport);
	(void)GetMsg(replyport);
}

/*
 * hotkey(mstring,ostring) - outputs the string "mstring" and waits
 * for one key which it will place in element [0] of "ostring".
 * "mstring" may be a null string, in which case it will only wait for
 * the key, and not output any prompt.
 */

void hotkey(mstring,ostring)
char mstring[];
char *ostring;
{
	strcpy(doormsg->string,mstring);
	doormsg->command = 8;
	PutMsg(MyPort,(struct Message *)doormsg);
	(void)WaitPort(replyport);
	(void)GetMsg(replyport);
	strcpy(ostring,doormsg->string);
}

/*
 * prompt(mstring,ostring,len) - outputs the string "mstring" and inputs
 * a string which is placed in ostring.  'len' is the maximum number of
 * characters which will be accepted.
 */

void prompt(mstring,ostring,len)
char mstring[];
char *ostring;
int len;
{
	strcpy(doormsg->string,mstring);
	doormsg->data=len;
	doormsg->command = 6;
	PutMsg(MyPort,(struct Message *)doormsg);
	(void)WaitPort(replyport);
	(void)GetMsg(replyport);
	strcpy(ostring,doormsg->string);
}

/* sprompt is the same as prompt, except it will accept stacked commands
 * (with the '/' key) and will send back any stacked command which is
 * currently in the command buffer instead of waiting for input from the
 * user.  It will even accept stacked commands which bridged over from the
 * BBS.
 */

void sprompt(mstring,ostring,len)
char mstring[];
char *ostring;
int len;
{
	strcpy(doormsg->string,mstring);
	doormsg->data=len;
	doormsg->command = 7;
	PutMsg(MyPort,(struct Message *)doormsg);
	(void)WaitPort(replyport);
	(void)GetMsg(replyport);
	strcpy(ostring,doormsg->string);
}

/* showfile(mstring) shows the text file which mstring is the path to.
   It handles ^C aborting, and ^S/^Q pausing. */

void showfile(mstring)
char mstring[];
{
	strcpy(doormsg->string,mstring);
	doormsg->command = 10;
	PutMsg(MyPort,(struct Message *)doormsg);
	(void)WaitPort(replyport);
	(void)GetMsg(replyport);
}


/*----------------------------------------------------------*/

move(x,y)
{
	char buf[32];
	sprintf(buf, "\33[%d;%dH", x+1, y+1);
	sendmessage(buf,0);
	scr_row = x;
	scr_col = y;
}

clrtoeol() {}


clear()
{
	sendmessage ("\14",0);
	scr_row=0;
	scr_col=0;
}

printw(a,b,c,d,e)
char *a;
char *b;
{
	char buf[132];
	sprintf(buf, a,b,c,d,e);
	sendmessage(buf,0);
	scr_col=scr_col+strlen(buf);
}

scanw(fmt, buf)
char *fmt;
char *buf;
{
   char temp[32];
   prompt ("",buf,32);
   strcpy (temp,buf);
   sscanf(temp, fmt, buf);
}

ClrtoEL()
{
	int rest, i;
	rest=79-scr_col;
	for (i=0; i<rest; i++)	sendmessage (" ",0);
	for (i=0; i<rest; i++)  sendmessage ("\b",0);
}

sortup()
{
	int i , j , temp=12;
	top=1;
	for (i=0 ; i<10 ; i++)
	{
		if (counting <= feldtop[i])
		{
			for (j=9 ; j>i ; j--)
			{
				feldtop[j]=feldtop[j-1];
				strcpy(userntop[j],userntop[j-1]);
			}
			feldtop[i]=counting;
			strcpy (userntop[i],username);
			temp=i;
			i=11;
		}
	}
return (temp);
}

sortdown()
{
	int i , j , temp=12;
	bad=1;
	for (i=0 ; i<10 ; i++)
	{
		if (counting <= feldbad[i])
		{
			for (j=9 ; j>i ; j--)
			{
				feldbad[j]=feldbad[j-1];
				strcpy(usernbad[j],usernbad[j-1]);
			}
			feldbad[i]=counting;
			strcpy (usernbad[i],username);
			temp=i;
			i=11;
		}
	}
return (temp);
}

open10()
{
FILE *fd;
int loop;

      if ((fd = fopen("top10","r")) != NULL)
	{
	for (loop=0;loop<10;loop++)
	  {
	    fscanf(fd,"%d",&feldtop[loop]);
	    fscanf(fd,"%s",userntop[loop]);
	  }
	}
        fclose(fd);
      if ((fd = fopen("bad10","r")) != NULL)
	{
	for (loop=0;loop<10;loop++)
	  {
	    fscanf(fd,"%d",&feldbad[loop]);
	    fscanf(fd,"%s",usernbad[loop]);
	  }
	}
        fclose(fd);
}

save10()
{
FILE *fd;
int loop;

      if ((fd = fopen("top10","w")) != NULL)
	{
	for (loop=0;loop<10;loop++)
	  {
	    fprintf(fd,"%d\n",feldtop[loop]);
	    fprintf(fd,"%s\n",userntop[loop]);
	  }
	}
        fclose(fd);
      if ((fd = fopen("bad10","w")) != NULL)
	{
	for (loop=0;loop<10;loop++)
	  {
	    fprintf(fd,"%d\n",feldbad[loop]);
	    fprintf(fd,"%s\n",usernbad[loop]);
	  }
	}
        fclose(fd);
}

showfinal()
{
int loop;
	gotoXY(5,4); printw("BEST CHESS-PLAYERS");
	gotoXY(45,4); printw("WORST CHESS-PLAYERS");
	for (loop=0;loop<10;loop++)
	{
		if (loop==position && top==1) printw("\33[31m");
		gotoXY(5,loop+6);printw("%d",loop+1);
		gotoXY(8,loop+6);printw("%d",feldtop[loop]);
		gotoXY(15,loop+6);printw("%s",userntop[loop]);
		if (loop==position && top==1) printw("\33[37m");

		if (loop==position && bad==1) printw("\33[31m");
		gotoXY(45,loop+6);printw("%d",loop+1);
		gotoXY(48,loop+6);printw("%d",feldbad[loop]);
		gotoXY(55,loop+6);printw("%s",usernbad[loop]);
		if (loop==position && bad==1) printw("\33[37m");
        }
}
