/*
 * gnuan.c - Analysis interface for gnuchess.
 * 
 * Copyright (c) 1988,1989,1990 John Stanback Copyright (c) 1992 Free Software
 * Foundation
 * 
 * This file is part of GNU CHESS.
 * 
 * GNU Chess is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2, or (at your option) any later
 * version.
 * 
 * GNU Chess is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * GNU Chess; see the file COPYING.  If not, write to the Free Software
 * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * This is a front end for a chess analysis program.  It takes a file of
 * moves in algebraic notation and creates a file containing each move that
 * was made, the move it would have made, the score it would give itself
 * after making the move it recommended, and the depth it searched for the
 * move.
 * 
 * This is a modification of nondsp.c.  I have cut out code that was not needed
 * for this application such as the help and edit functions.  Most of the
 * modifications were done in InputCommand.
 */

/*
 * This file will generate two different analysis programs.  One is meant to
 * be run as a background process inwhich the in and out files are
 * predefined. The other is meant to be run in the foreground where it will
 * prompt you for the name of the file with the game in it, the maximum depth
 * the search should be conducted to and the time limit per move.  It would
 * be nice to be able to give these parameters on the command line, but that
 * would mean changing main which is in the gnuchess.c file.
 * 
 * For each move it will analyse the move until either it has run out of time or
 * it has reached the maximum depth.
 * 
 * To build the version for background processing define BACKGROUND_ANALYSIS
 * either at the top of this file, or in compilation.  The files and depth
 * used are defined below.  They are MAX_DEPTH, MAX_TIME, OUT_FILE, IN_FILE
 * and PROG_FILE.  The PROG_FILE is a file that will be updated as each move
 * is analysed so you can check its progress.  This is only updated when
 * running the BACKGROUND_ANALYSIS version.  In the version where the
 * filename and depth are entered at runtime, the output goes to stdout.
 */

/* #define BACKGROUND_ANALYSIS 0 */

#define MAX_DEPTH  MAXDEPTH
#define MAX_TIME   10
#define OUT_FILE   "gnuan.out"
#define IN_FILE    "gnuan.in"
#define PROG_FILE  "gnuan.prog"


#include <ctype.h>
#include <signal.h>
#include <fcntl.h>
#include <time.h>
#ifdef MSDOS
#include <dos.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#else
#include <sys/param.h>
#include <sys/types.h>
#include <sys/file.h>
#ifndef AMIGADOS
#include <sys/ioctl.h>
#endif
void TerminateSearch (int), Die (int);

#define O_BINARY 0

#endif /* MSDOS */

#include "gnuchess.h"
#include "ttable.h"
#include "ataks.h"
#undef rxx
#undef cxx
#undef scanz
#undef printz

#define rxx "12345678"
#define cxx "abcdefgh"
#define scanz scanf
#define printz printf
extern SHORT board[64], color[64], Mvboard[64];
extern CHAR *ColorStr[2];
SHORT debuglevel = 0;
int mycnt1, mycnt2;
char mvstr[5][7];

static FILE *fpin;
static FILE *fpout;
int samedepth = false;
CHAR *DRAW;
UTSHORT MV[MAXDEPTH+1];
enum
  {
      XBOARD, GNUCHESS, PGN, OTHER
  }
InFileType;
CHAR InBuf[256];

#ifdef BACKGROUND_ANALYSIS
static FILE *fpprog;

#endif
static CHAR white_actual_move[20];
static CHAR black_actual_move[20];
static CHAR suggest_move[20];
static CHAR suggest_move1[20];
static CHAR suggest_move2[20];
static CHAR suggest_move3[20];
    int total_moves[2];
    int same_moves[2];
static int sdw, sdb;
static int print_score;
int tmpscore;
static int current_depth;
static int current_score;
static int enable_update_display = 0;
static CHAR GNUANmove[400][16];	/* moves for this game strings */
static SHORT GNUANsd[400];	/* search depth for each move */
static SHORT GNUANnext;		/*                               */
static SHORT GNUANhint;		/*                               */
static SHORT GNUANdepth;	/*Search depth override         */
static SHORT GNUANcurrmove;	/* current move within base  */
static SHORT GNUANbasemove;	/* base for curr move set    */
static SHORT GNUANmovecnt;	/* movecnt within base frame                          */
static SHORT GNUANnextstop = 0;	/*loop control proceed to this move */
SHORT GNUANtop;			/* # movees in adjlist   */
SHORT GNUANtopLim = 0;			/* # movees in adjlist   */
static unsigned short GNUANadjlist[20];		/*moves to not use       */
static CHAR GNUANinbuf[256];	/* input buffer     */
struct
  {
      SHORT board[64];
      SHORT color[64];
      SHORT mvboard[64];
      SHORT currmove;
      SHORT movecnt;
      SHORT basemove;
      SHORT moveno;
  }
GNUANsave[20];
SHORT GNUANsavedepth;
static enum INenum
  {
      file, keyboard
  }
GNUANinput;
int move_number = 1;

#ifdef notdef
GNUANlist (SHORT mv[])
{
    SHORT B[64], C[64];
    SHORT from, to, i;
    SHORT plain = false;
    memcpy (B, board, sizeof (B));
    memcpy (C, color, sizeof (C));

    for (i = 1; mv[i] != 0; i++)
      {
	  from = mv[i] >> 8;
	  to = mv[i] & 0xff;
	  algbr (from, to, 0);
	  if(plain) fprintf (fpout, "%5s ", mvstr[0]);
	  else fprintf (fpout, "%5s ", mvstr[1]);
	  if (mv[i] == WHITECASTLE)
	    {
		/* castle short */ board[5] = board[7];
		board[7] = no_piece;
		color[5] = color[7];
		color[7] = neutral;
	    }
	  else if (mv[i] == LONGWHITECASTLE)
	    {
		/* castle short */ board[3] = board[0];
		board[0] = no_piece;
		color[3] = color[0];
		color[0] = neutral;
	    }
	  else if (mv[i] == BLACKCASTLE)
	    {
		/* castle short */ board[60] = board[63];
		board[63] = no_piece;
		color[60] = color[63];
		color[63] = neutral;
	    }
	  else if (mv[i] == LONGBLACKCASTLE)
	    {
		/* castle long */ board[59] = board[56];
		board[56] = no_piece;
		color[59] = color[56];
		color[56] = neutral;
	    }
/* could it be en-passant or promote */
	  else if (board[from] == pawn && color[from] == black)
	    {
		if (row (to) == 0)
		  {		/* promote */
    			 plain = true;
		  }
		else if ((row (from) == 3 && row(to) == 2) && 
			((column(to) == (column(from) -1)) || 
			 (column(to) == column(from) +1))
			&& board[to] == no_piece
			&& board[to + 8] == pawn
			&& color[to + 8] == white)
		  {		/* possible en-passant */
		     board[to+8] = no_piece;
		     color[to+8] = neutral;
		  }
	    }
	  else if (board[from] == pawn && color[from] == white)
	    {
		if (row (to) == 7)
		  {		/* promote */
    			 plain=true;
		  }
		else if ((row (from) == 4 && row(to) == 5) && 
			((column(to) == (column(from) -1)) || 
			 (column(to) == column(from) +1))
			&& board[to] == no_piece
			&& board[to - 8] == pawn
			&& color[to - 8] == black)
		  {		/* possible en-passant */
		     board[to+8] = no_piece;
		     color[to+8] = neutral;
		  }
	    }

	  board[to] = board[from];
	  color[to] = color[from];
	  board[from] = no_piece;
	  color[from] = neutral;
      }
    memcpy (board, B, sizeof (B));
    memcpy (color, C, sizeof (C));
    return(0);
}
#endif

void
GNUANadj ()
{
    int i, j, b;
    for (i = 0; i < GNUANtop; i++)
      {
	  for (b = TrPnt[1]; b < (unsigned) TrPnt[2]; b++)
	    {
		if (((Tree[b].f << 8) | Tree[b].t) == GNUANadjlist[i])
		  {
		      Tree[b].score = DONTUSE;
		      break;
		  }
	    }
      }
}
void
Initialize (void)
{
    mycnt1 = mycnt2 = 0;
}

void
ExitChess (void)
{
    ListGame ();
    exit (0);
}

#ifndef MSDOS			/* never called!!! */
void
Die (int sig)
{
    ExitChess ();
}

#endif /* MSDOS */

void
TerminateSearch (int sig)
{
#ifdef MSDOS
    sig++;			/* shut up the compiler */
#endif /* MSDOS */
    if (!flag.timeout)
	flag.musttimeout = true;
    flag.bothsides = false;
}

void
algbr (SHORT f, SHORT t, SHORT flag)


/*
 * Generate move strings in different formats.
 */

{
    int m3p;

    if (f != t)
      {
	  /* algebraic notation */
	  mvstr[0][0] = cxx[column (f)];
	  mvstr[0][1] = rxx[row (f)];
	  mvstr[0][2] = cxx[column (t)];
	  mvstr[0][3] = rxx[row (t)];
	  mvstr[4][0] = mvstr[0][4] = mvstr[3][0] = '\0';
	  if (((mvstr[1][0] = pxx[board[f]]) == CP[2][1]) || (flag & promote))
	    {
		if (mvstr[0][0] == mvstr[0][2])		/* pawn did not eat */
		  {
		      mvstr[2][0] = mvstr[1][0] = mvstr[0][2];	/* to column */
		      mvstr[2][1] = mvstr[1][1] = mvstr[0][3];	/* to row */
		      m3p = 2;
		  }
		else
		    /* pawn ate */
		  {
		      mvstr[2][0] = mvstr[1][0] = mvstr[0][0];	/* column */
		      mvstr[2][1] = mvstr[1][1] = mvstr[0][2];	/* to column */
		      mvstr[2][2] = mvstr[0][3];
		      m3p = 3;	/* to row */
		  }
		if (flag & promote)
		  {
		      mvstr[0][4] = mvstr[1][2] = mvstr[2][m3p] = qxx[flag & pmask];
		      mvstr[0][5] = mvstr[1][3] = mvstr[2][m3p + 1] = mvstr[3][0] = '\0';
#ifdef CHESSTOOL
		      mvstr[3][0] = mvstr[0][0];	/* Allow e7e8 for chesstool */
		      mvstr[3][1] = mvstr[0][1];
		      mvstr[3][2] = mvstr[0][2];
		      mvstr[3][3] = mvstr[0][3];
		      mvstr[3][4] = '\0';
#endif
		  }
		else
		    mvstr[2][m3p] = mvstr[1][2] = '\0';
	    }
	  else
	      /* not a pawn */
	    {
		mvstr[2][0] = mvstr[1][0];
		mvstr[2][1] = mvstr[0][1];
		mvstr[2][2] = mvstr[1][1] = mvstr[0][2];	/* to column */
		mvstr[2][3] = mvstr[1][2] = mvstr[0][3];	/* to row */
		mvstr[2][4] = mvstr[1][3] = '\0';
		strcpy (mvstr[3], mvstr[2]);
		mvstr[3][1] = mvstr[0][0];
		mvstr[4][0] = mvstr[1][0];
		strcpy (&mvstr[4][1], mvstr[0]);
		if (flag & cstlmask)
		  {
		      if (t > f)
			{
			    strcpy (mvstr[1], mvstr[0]);
			    strcpy (mvstr[0], CP[5]);
			    strcpy (mvstr[2], CP[7]);
			    strcpy (mvstr[3], "O-O");
			}
		      else
			{
			    strcpy (mvstr[1], mvstr[0]);
			    strcpy (mvstr[0], CP[6]);
			    strcpy (mvstr[2], CP[8]);
			    strcpy (mvstr[3], "O-O-O");
			}
		  }
	    }
      }
    else
	mvstr[0][0] = mvstr[1][0] = mvstr[2][0] = mvstr[3][0] = mvstr[4][0] = '\0';
}

int
strxcmp (char *sx, char *sbase)

/*
 * Compare strings sx and sbase, but ignore any 'x' characters found in sx.
 * This kludge lets gnuan parse notation with "x" for capture.
 */
{
    for (;;)
      {
	  if (*sx == 'x')
	      sx++;
	  if (*sx == '\0')
	    {
		if (*sbase == '\0')
		    return 0;
		else
		    return -1;
	    }
	  if (*sx < *sbase)
	      return -1;
	  else if (*sx > *sbase)
	      return 1;
	  sx++;
	  sbase++;
      }
}



int
VerifyMove (CHAR * s, SHORT iop, UTSHORT * mv)

/*
 * Compare the string 's' to the list of legal moves available for the
 * opponent. If a match is found, make the move on the board.
 */

{
    static SHORT pnt, tempb, tempc, tempsf, tempst, cnt;
    static struct leaf xnode;
    struct leaf *node;

    *mv = 0;
    if (iop == 2)
      {
	  UnmakeMove (computer, &xnode, &tempb, &tempc, &tempsf, &tempst);
	  return (false);
      }
    cnt = 0;
    MoveList (computer, 2);
    pnt = TrPnt[2];
    while (pnt < TrPnt[3])
      {
	  node = &Tree[pnt++];
	  algbr (node->f, node->t, (SHORT) node->flags);
	  if (strxcmp (s, mvstr[0]) == 0 || strxcmp (s, mvstr[1]) == 0 ||
	      strxcmp (s, mvstr[2]) == 0 || strxcmp (s, mvstr[3]) == 0)
	    {
		cnt++;
		xnode = *node;
	    }
      }
    if (cnt == 1)
      {
	  MakeMove (computer, &xnode, &tempb, &tempc, &tempsf, &tempst, &INCscore);
	  if (SqAtakd (PieceList[computer][0], opponent))
	    {
		UnmakeMove (opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
		printz ("Illegal move\n");
		return (false);
	    }
	  else
	    {
		if (iop == 1)
		    return (true);

		/*
		 * UpdateDisplay (xnode.f, xnode.t, 0, (SHORT) xnode.flags);
		 */
		if ((board[xnode.t] == pawn)
		    || (xnode.flags & capture)
		    || (xnode.flags & cstlmask))
		  {
		      Game50 = GameCnt;
		      ZeroRPT ();
		  }
		GameList[GameCnt].depth = GameList[GameCnt].score = 0;
		GameList[GameCnt].nodes = 0;
		ElapsedTime (1);
		GameList[GameCnt].time = (SHORT) et;
		TimeControl.clock[opponent] -= et;
		--TimeControl.moves[opponent];
		*mv = (xnode.f << 8) | xnode.t;
		algbr (xnode.f, xnode.t, false);
		return (true);
	    }
      }
#ifdef CHESSTOOL
    printz ("Illegal move\n");
#else
    if (cnt > 1)
	ShowMessage ("Ambiguous Move!");
#endif
    if (cnt == 0)
      {
	  pnt = TrPnt[2];
	  while (pnt < TrPnt[3])
	    {
		node = &Tree[pnt++];
		algbr (node->f, node->t, (SHORT) node->flags);
		printf ("%s -> %s %s %s %s\n", s, mvstr[0], mvstr[1], mvstr[2], mvstr[3]);
	    }
      }
    return (false);
}

void
help (void)
{
}

void
EditBoard (void)

/*
 * Set up a board position. Pieces are entered by typing the piece followed
 * by the location. For example, Nf3 will place a knight on square f3.
 */

{
}

void
SetupBoard (void)

/*
 * Compatibility with Unix chess and the nchesstool. Set up a board position.
 * Eight lines of eight characters are used to setup the board. a8-h8 is the
 * first line. Black pieces are  represented  by  uppercase characters.
 */

{
}

void
ShowDepth (CHAR ch)
{
#ifdef MSDOS
    ch++;			/* shut up the compiler */
#endif /* MSDOS */
}

void
ShowLine (UTSHORT * bstline)
{
    register int i;

    for (i = 1; bstline[i] > 0; i++)
      {
	  if ((i > 1) && (i % 8 == 1))
	      printf ("\n                          ");
	  algbr ((SHORT) (bstline[i] >> 8), (SHORT) (bstline[i] & 0xFF), false);
	  printf ("%5s ", mvstr[0]);
      }
    printf ("\n");
}


void
ShowResults (SHORT score, UTSHORT * bstline, CHAR ch)
{
    int i;

    if (flag.post)
      {
	  ElapsedTime (2);
	  printf ("%2d%c %6d %4ld %8ld  ", Sdepth, ch, score, et / 100, NodeCnt);
	  ShowLine (bstline);
      }
    current_score = score;
    current_depth = Sdepth;
    for (i = 1; bstline[i] > 0; i++)
      {
	  MV[i] = bstline[i];
      }
    MV[i] = 0;
}

void
SearchStartStuff (SHORT side)
{
    signal (SIGINT, TerminateSearch);
#ifndef MSDOS
    signal (SIGQUIT, TerminateSearch);
#endif /* MSDOS */
    if (flag.post)
      {
	  fprintf (stderr, "\nMove# %d    Target= %ld    Clock: %ld\n",
		   move_number,
		   ResponseTime, TimeControl.clock[side]);
      }
}

void
OutputMove (SHORT score)
{
    strcpy (suggest_move, mvstr[0]);
    strcpy (suggest_move1, mvstr[1]);
    strcpy (suggest_move2, mvstr[2]);
    strcpy (suggest_move3, mvstr[3]);
    print_score = current_score;
}


#ifdef HASGETTIMEOFDAY
#include <sys/time.h>
void
ElapsedTime (SHORT iop)


/*
 * Determine the time that has passed since the search was started. If the
 * elapsed time exceeds the target (ResponseTime+ExtraTime) then set timeout
 * to true which will terminate the search. iop = 0 calculate et bump ETnodes
 * iop = 1 calculate et set timeout if time exceeded, calculate et
 */

{
    struct timeval tv;

#ifndef MSDOS
    int nchar;
    extern int errno;
    int i;

#ifdef FIONREAD
    if (i = ioctl ((int) 0, FIONREAD, &nchar))
      {
	  perror ("FIONREAD");
	  fprintf (stderr,
	   "You probably have a non-ANSI <ioctl.h>; see README. %d %d %x\n",
		   i, errno, FIONREAD);
	  exit (1);
      }
    if (nchar)
      {
	  if (!flag.timeout)
	      flag.back = true;
	  flag.bothsides = false;
      }
#endif /* FIONREAD */
#else
    if (kbhit ())
      {
	  if (!flag.timeout)
	      flag.back = true;
	  flag.bothsides = false;
      }
#endif /* MSDOS */
    gettimeofday (&tv, NULL);
    et = (tv.tv_sec * 100 + (tv.tv_usec / 10000)) - time0;
    ETnodes = NodeCnt + ZNODES;
    if (et < 0)
	et = 0;
    if (iop == 1)
      {
	  if (et > ResponseTime + ExtraTime && Sdepth > MINDEPTH)
	      flag.timeout = true;
	  ETnodes = NodeCnt + ZNODES;
	  gettimeofday (&tv, NULL);
	  time0 = tv.tv_sec * 100 + tv.tv_usec / 10000;
      }
}

#else
void
ElapsedTime (SHORT iop)


/*
 * Determine the time that has passed since the search was started. If the
 * elapsed time exceeds the target (ResponseTime+ExtraTime) then set timeout
 * to true which will terminate the search. iop = 0 calculate et bump ETnodes
 * iop = 1 calculate et set timeout if time exceeded, calculate et
 */

{
#ifndef MSDOS
    int nchar;
    extern int errno;
    int i;

#ifdef FIONREAD
    if (i = ioctl ((int) 0, FIONREAD, &nchar))
      {
	  perror ("FIONREAD");
	  fprintf (stderr,
	   "You probably have a non-ANSI <ioctl.h>; see README. %d %d %x\n",
		   i, errno, FIONREAD);
	  exit (1);
      }
    if (nchar)
      {
	  if (!flag.timeout)
	      flag.back = true;
	  flag.bothsides = false;
      }
#endif /* FIONREAD */
#else
    if (kbhit ())
      {
	  if (!flag.timeout)
	      flag.back = true;
	  flag.bothsides = false;
      }
#endif /* MSDOS */
    et = (time ((long *) 0) - time0) * 100;
    ETnodes = NodeCnt + ZNODES;
    if (et < 0)
	et = 0;
    if (iop == 1)
      {
	  if (et > ResponseTime + ExtraTime && Sdepth > MINDEPTH)
	      flag.timeout = true;
	  ETnodes = NodeCnt + ZNODES;
	  time0 = time ((long *) 0);
      }
}

#endif
#ifdef notdef
void
ElapsedTime (SHORT iop)

/*
 * Determine the time that has passed since the search was started. If the
 * elapsed time exceeds the target (ResponseTime+ExtraTime) then set timeout
 * to true which will terminate the search.
 */
{
    et = (time ((long *) 0) - time0) * 100;
    /* et = (clock ()/CLOCKS_PER_SEC - time0) * 100; */
    if (et < 0)
	et = 0;
    ETnodes += ZNODES;
    if (iop == 1)
      {
	  if (et > ResponseTime + ExtraTime && Sdepth > 1)
	      flag.timeout = true;
	  time0 = time ((long *) 0);
	  /* time0 = clock () / CLOCKS_PER_SEC; */
	  ETnodes = NodeCnt + ZNODES;
      }
}

#endif

void
SetTimeControl (void)
{
    if (TCflag)
      {
	  TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
	  TimeControl.clock[white] = TimeControl.clock[black] = 6000L * TCminutes;
      }
    else
      {
	  TimeControl.moves[white] = TimeControl.moves[black] = 0;
	  TimeControl.clock[white] = TimeControl.clock[black] = 0;
	  MaxResponseTime = 6000L * TCminutes;
      }
    et = 0;
    ElapsedTime (1);
}

void
ClrScreen (void)
{
#ifndef CHESSTOOL
    printz ("\n");
#endif
}

void
UpdateDisplay (SHORT f, SHORT t, SHORT redraw, SHORT isspec)
{
#ifndef CHESSTOOL
    SHORT r, c, l;

    if (!enable_update_display)
	return;
    if (redraw)
      {
	  fprintf (fpout, "\n");
	  for (r = 7; r >= 0; r--)
	    {
		for (c = 0; c <= 7; c++)
		  {
		      l = locn (r, c);
		      if (color[l] == neutral)
			  fprintf (fpout, " -");
		      else if (color[l] == white)
			  fprintf (fpout, " %c", qxx[board[l]]);
		      else
			  fprintf (fpout, " %c", pxx[board[l]]);
		  }
		fprintf (fpout, "\n");
	    }
	  fprintf (fpout, "\n");
      }
#endif /* CHESSTOOL */
#ifdef MSDOS
    f++;
    t++;
    isspec++;			/* shut up the compiler */
#endif /* MSDOS */
}

void
GetGame (void)
{
}

void
SaveGame (void)
{
}

void
ListGame (void)
{
}

void
Undo (void)

/*
 * Undo the most recent half-move.
 */

{
    SHORT f, t;

    f = GameList[GameCnt].gmove >> 8;
    t = GameList[GameCnt].gmove & 0xFF;
    if (board[t] == king && distance (t, f) > 1)
	(void) castle (GameList[GameCnt].color, f, t, 2);
    else
      {
	  /* Check for promotion: */
	  if (GameList[GameCnt].flags & promote)
	    {
		board[t] = pawn;
	    }
	  board[f] = board[t];
	  color[f] = color[t];
	  board[t] = GameList[GameCnt].piece;
	  color[t] = GameList[GameCnt].color;
	  if (color[t] != neutral)
	      Mvboard[t]--;
	  Mvboard[f]--;
      }
    if (GameList[GameCnt].flags & epmask)
	EnPassant (otherside[color[f]], f, t, 2);
    else
	InitializeStats ();
    epsquare = GameList[GameCnt].epssq;
    if (TCflag && (TCmoves > 1))
	++TimeControl.moves[color[f]];
    hashkey = GameList[GameCnt].hashkey;
    hashbd = GameList[GameCnt].hashbd;
    GameCnt--;
    flag.mate = false;
    Sdepth = 0;

    /*
     * ShowSidetoMove (); UpdateDisplay (0, 0, 1, 0);
     */
    if (flag.regularstart)
	Book = BOOKFAIL;
}

#ifdef notdef
void
Undo (void)

/*
 * Undo the most recent half-move.
 */

{
    SHORT f, t;

    f = GameList[GameCnt].gmove >> 8;
    t = GameList[GameCnt].gmove & 0xFF;
    if (board[t] == king && distance (t, f) > 1)
	(void) castle (GameList[GameCnt].color, f, t, 2);
    else
      {
	  /* Check for promotion: */
	  if (GameList[GameCnt].flags & promote)
	    {
		board[t] = pawn;
	    }
	  board[f] = board[t];
	  color[f] = color[t];
	  board[t] = GameList[GameCnt].piece;
	  color[t] = GameList[GameCnt].color;
	  if (color[t] != neutral)
	      Mvboard[t]--;
	  Mvboard[f]--;
      }
    if (GameList[GameCnt].flags & epmask)
	EnPassant (color[t], f, t, 2);
    if (TCflag)
	++TimeControl.moves[color[f]];
    GameCnt--;
    computer = otherside[computer];
    opponent = otherside[opponent];
    flag.mate = false;
    Sdepth = 0;
    InitializeStats ();
}

#endif
void
ShowMessage (CHAR * s)
{
    fprintf (stderr, "%s\n", s);
}

void
ShowSidetoMove (void)
{
}

void
PromptForMove (void)
{
#ifndef CHESSTOOL
    printz ("\nYour move is? ");
#endif /* CHESSTOOL */
}


void
ShowCurrentMove (SHORT pnt, SHORT f, SHORT t)
{
#ifdef MSDOS
    f++;
    t++;
    pnt++;			/* shut up the compiler */
#endif /* MSDOS */
}

void
ChangeAlphaWindow (void)
{
    printz ("window: ");
}

void
ChangeBetaWindow (void)
{
    printz ("window: ");
}

void
GiveHint (void)
{
    algbr ((SHORT) (hint >> 8), (SHORT) (hint & 0xFF), false);
    fprintf (stderr, "Hint: %s\n", mvstr[0]);
}

void
SelectLevel (CHAR * sx)
{
}

void
ChangeSearchDepth (void)
{
    printz ("depth= ");
    scanz ("%hd", &MaxSearchDepth);
}

void
SetContempt (void)
{
    printz ("contempt= ");
    scanz ("%hd", &contempt);
}

void
ChangeXwindow (void)
{
    printz ("xwndw= ");
    scanz ("%hd", &xwndw);
}

void
TestSpeed (void (*f) (SHORT side, SHORT ply))
{
    SHORT i;
    long cnt, rate, t1, t2;

    t1 = time (0);
    for (i = 0; i < 10000; i++)
      {
	  f (opponent, 2);
      }
    t2 = time (0);
    cnt = 10000L * (TrPnt[3] - TrPnt[2]);
    rate = cnt / (t2 - t1);
    printz ("Nodes= %ld Nodes/sec= %ld\n", cnt, rate);
}

CHAR cbuf[256];
CHAR sdepth[128];
int sdindex;
SHORT GNCmode;
CHAR *GetNextPtr = (CHAR *) NULL;

GetNextChar ()
{
    GNCmode = false;
    while (true)
      {
	  if (GetNextPtr == NULL)
	    {
		if (fgets (cbuf, sizeof (cbuf), fpin) != NULL)
		  {
		      GetNextPtr = cbuf;
		  }
		else
		    return -1;
	    }
	  else
	      GetNextPtr++;
	  if (*GetNextPtr == '\n' || *GetNextPtr == '\0')
	    {
		GetNextPtr = NULL;
		return ' ';
	    }
	  if (GNCmode)
	      if (*GetNextPtr == '}')
		{
		    GNCmode = false;
		    continue;
		}
	      else
		  continue;
	  if (*GetNextPtr == '{')
	    {
		GNCmode = true;
		continue;
	    }
	  return (*GetNextPtr);

      }
}
int lastws = true;
static CHAR GNUANc;
int
GetNextMove (CHAR * buffer)
{
    CHAR *p, *q;

    sdw = sdb = 0;
    black_actual_move[0] = '\0';
    white_actual_move[0] = '\0';
    if (InFileType = PGN)
      {
	  lastws = true;
	  while (!isalpha (GNUANc))
	    {
		if (GNUANc == '0' && lastws)
		    break;
		if (GNUANc == ' ' || GNUANc == '.')
		    lastws = true;
		else
		    lastws = false;
		GNUANc = GetNextChar ();
		if (GNUANc == -1 && GetNextPtr == NULL)
		    return -1;
	    }
	  q = white_actual_move;
	  while (GNUANc != ' ' && GNUANc != -1)
	    {
		if (GNUANc != 'x' && GNUANc != '+')
		    *q++ = GNUANc;
		GNUANc = GetNextChar ();
	    }
	  *q = '\0';
	  lastws = true;
	  while (!isalpha (GNUANc))
	    {
		if (GNUANc == '0' && lastws)
		    break;
		if (GNUANc == ' ')
		    lastws = true;
		else
		    lastws = false;
		GNUANc = GetNextChar ();
		if (GetNextPtr == NULL)
		    return -1;
	    }
	  q = black_actual_move;
	  while (GNUANc != ' ' && GNUANc != -1)
	    {
		if (GNUANc != 'x' && GNUANc != '+')
		    *q++ = GNUANc;
		GNUANc = GetNextChar ();
	    }
	  *q = '\0';
	  return 1;

      }
    if (fgets (cbuf, sizeof (cbuf), fpin) != NULL)
      {
	  p = cbuf;
	  for (; *p; p++)
	    {
		if (isalpha (*p))
		  {
		      q = white_actual_move;
		      while (*p != ' ' && *p != '\n')
			  *q++ = *p++;
		      *q = '\0';
		      if (strcmp (white_actual_move, "Book") == 0)
			  continue;
		      else
			  break;
		      break;
		  }
	    }
	  if (*p == '\0' && white_actual_move[0] == '\0')
	      return 0;
	  if (InFileType == GNUCHESS)
	    {
		if (samedepth)
		  {
		      sdindex = 0;
		      while (*p == ' ' || *p == '\n')
			  p++;
		      while (*p != ' ' && *p != '\0')
			  p++;
		      while (*p == ' ' || *p == '\n')
			  p++;
		      while (*p != ' ' && *p != '\n')
			  sdepth[sdindex++] = *p++;
		      sdepth[sdindex] = '\0';
		      if (strcmp (sdepth, "Book") == 0)
			{
			    sdw = -99;
			    for (; *p != ' '; p++);
			}
		      else
			  sdw = atoi (sdepth);
		  }
	    }
	  for (; *p; p++)
	    {
		if (isalpha (*p))
		  {
		      q = black_actual_move;
		      while (*p != ' ' && *p != '\n')
			  *q++ = *p++;
		      *q = '\0';
		      if (strcmp (black_actual_move, "Book") == 0)
			  continue;
		      else
			  break;
		  }
	    }
	  if (*p == '\0' && black_actual_move[0] == '\0')
	      return 1;
	  if (InFileType == GNUCHESS)
	    {
		if (samedepth)
		  {
		      sdindex = 0;
		      while (*p == ' ' || *p == '\n')
			  p++;
		      while (*p != ' ' && *p != '\0')
			  p++;
		      while (*p == ' ' || *p == '\n')
			  p++;
		      while (*p != ' ' && *p != '\n')
			  sdepth[sdindex++] = *p++;
		      sdepth[sdindex] = '\0';
		      if (strcmp (sdepth, "Book") == 0)
			{
			    sdb = -99;
			    for (; *p != ' '; p++);
			}
		      else
			  sdb = atoi (sdepth);
		  }
	    }
	  return 1;
      }
    else			/* EOF */
	return -1;

}
UTSHORT mv;
UTSHORT GNUANmv;

DoIt (SHORT computer, CHAR * smove, SHORT inbook, CHAR * s)
{
    SHORT dok, i;

    dok = VerifyMove (smove, 0, &mv);
    if (!dok)
      {
	  fprintf (fpout, "\nBad move.  %s  Board position is: \n", s);
	  UpdateDisplay (0, 0, 1, 0);
	  flag.quit = 1;
	  return false;
      }
    if (inbook)
      {
	  if (computer == black)
	      fprintf (fpout, "            %-9s   -     -    book\n", smove);
	  else
	      fprintf (fpout, "%3d   %-9s         -     -    book\n", move_number, smove);

	  fflush (fpout);
	  Sdepth = 0;
	  ft = 0;
      }
    else
      {
	  CHAR x[8];

	  strcpy (x, smove);
	  if (strcmp (smove, suggest_move) == 0
	      || strcmp (smove, suggest_move1) == 0
	      || strcmp (smove, suggest_move2) == 0
	      || strcmp (smove, suggest_move3) == 0)
	    {
		same_moves[computer]++;
	    }
	  else
	      strcat (x, "*");
	  if (computer == white)
	    {
		if (sdw == -99)
		    fprintf (fpout, "%3d   %-9s      %5d   Book ", move_number, x, print_score, current_depth);
		else
		    fprintf (fpout, "%3d   %-9s      %5d%5d   ", move_number, x, print_score, current_depth);
	    }
	  else
	    {
		if (sdb == -99)
		    fprintf (fpout, "            %-9s%5d  Book  ", x, print_score, current_depth);
		else
		    fprintf (fpout, "            %-9s%5d%5d   ", x, print_score, current_depth);
	    }
	  for (i = 1; MV[i] > 0; i++)
	    {
		if(i == 1)fprintf (fpout, "%5s ", suggest_move1);
		else {algbr ((SHORT) (MV[i] >> 8), (SHORT) (MV[i] & 0xFF), false);
		fprintf (fpout, "%5s ", mvstr[0]);}
	    }
#ifdef notdef
	  GNUANlist (MV);
#endif
	  fprintf (fpout, "\n");
	  fflush (fpout);
	  Sdepth = 0;
	  ft = 0;
      }
    return true;
}

void
GNUANvarit ()
{
    memcpy (&GNUANsave[GNUANsavedepth].board, board, sizeof (board));
    memcpy (&GNUANsave[GNUANsavedepth].color, color, sizeof (color));
    memcpy (&GNUANsave[GNUANsavedepth].mvboard, Mvboard, sizeof (Mvboard));
    GNUANsave[GNUANsavedepth].currmove = GNUANcurrmove;
    GNUANsave[GNUANsavedepth].basemove = GNUANbasemove;
    GNUANsave[GNUANsavedepth].movecnt = GNUANmovecnt;
    GNUANcurrmove = GNUANmovecnt - 1;
    GNUANbasemove = GNUANmovecnt;
    GNUANmovecnt = 0;
    GNUANsave[GNUANsavedepth].moveno = move_number;
    GNUANsavedepth++;
}
void
GNUANravit ()
{
    GNUANsavedepth--;
    memcpy (board, &GNUANsave[GNUANsavedepth].board, sizeof (board));
    memcpy (color, &GNUANsave[GNUANsavedepth].color, sizeof (color));
    memcpy (Mvboard, &GNUANsave[GNUANsavedepth].mvboard, sizeof (Mvboard));
    GNUANcurrmove = GNUANsave[GNUANsavedepth].currmove;
    GNUANbasemove = GNUANsave[GNUANsavedepth].basemove;
    GNUANmovecnt = GNUANsave[GNUANsavedepth].movecnt;
    move_number = GNUANsave[GNUANsavedepth].moveno;
}

int Undid = false;

void
InputCommand (void)

/*
 * Open the file of moves to analyse.  Go through the file move by move and
 * do the following for each move.  See what gnuchess would have done in that
 * position.  Record the move it would have made along with the score it
 * would have given and the search depth.  Take back its move. Force the move
 * that was actually made.  Keep track of statistics such as how many moves
 * agreed.
 */

{
    int i;
    SHORT ok, inbook;
    UTSHORT mv;
    CHAR s[80];
    int search_depth;

#if !defined BACKGROUND_ANALYSIS
    int max_minutes;
    int max_seconds;
    CHAR inbuf[256];

#else
    CHAR outfilename[255];
    CHAR progfilename[255];

#endif
    CHAR infilename[255];
    long start_time, end_time, elapsed_time;
    float move_percent[2];
    CHAR GNUANinbuf1[128];
    CHAR *p, *q;

    /* Initialize necessary variables. */

    flag.quit = false;
    flag.beep = false;
    flag.post = true;
    enable_update_display = 1;
    ft = 0;
    Book = false;
    total_moves[0] = total_moves[1] = 0;
    same_moves[0] = same_moves[0] = 0;

#ifdef BACKGROUND_ANALYSIS

    /*
     * Set the in files to standard ones for analysis if background
     * processing selected.
     */

    strcpy (infilename, IN_FILE);
    strcpy (outfilename, OUT_FILE);
    strcpy (progfilename, PROG_FILE);
    fpout = fopen (outfilename, "w");
    if (fpout == NULL)
      {
	  fprintf (fpout, "This file does not exist : %s\n", outfilename);
	  flag.quit = 1;
	  return;
      }
    MaxSearchDepth = search_depth = MAX_DEPTH;
    TCminutes = MAX_TIME;

#else

    /* Request information on where the file is and the depth an time. */

    fpout = stderr;
    fprintf (fpout, "Input the file with the algebraic moves of the game.\n");
    fflush (fpout);
    gets (infilename);
    fprintf (fpout, "\n");
    do
      {
	  fprintf (fpout, "Input the search depth you want to use.  (1 to 29)(- for depth from file)\n");
	  gets (inbuf);
	  search_depth = atoi (inbuf);
	  if (search_depth < 0)
	    {
		samedepth = true;
		search_depth = -search_depth;
	    }
      }
    while (search_depth < 1 || search_depth > 29);
    MaxSearchDepth = search_depth;

    fprintf (fpout, "\n");
    max_minutes = max_seconds = 0;
    do
      {
	  fprintf (fpout, "Input the maximum number of minutes per move you want to use.\n");
	  gets (inbuf);
	  max_minutes = atoi (inbuf);
	  if (max_minutes < 0)
	    {
		max_seconds = -max_minutes;
		max_minutes = 0;
	    }
      }
    while ((max_minutes + max_seconds) < 1);
    fprintf (fpout, "Post the search results(y/n).\n");
    gets (inbuf);
    if (inbuf[0] == 'y')
	flag.post = true;
    else
	flag.post = false;
    printf ("\nYou will search to %d half moves\n", search_depth);
    printf ("\nWith no search taking more than %d minutes\n", max_minutes);
    TCminutes = max_minutes;

    fprintf (fpout, "\n\n");

#endif

    fpin = fopen (infilename, "r");
    if (fpin == NULL)
      {
	  fprintf (fpout, "This file does not exist : %s\n", infilename);
	  flag.quit = 1;
	  return;
      }
    /* lets find out about this file */
    fgets (InBuf, 256, fpin);
    InFileType = OTHER;
    if (!strncmp (InBuf, "xboard", 6) || !strncmp (InBuf, "# xboard", 8))
      {
	  InFileType = XBOARD;
	  fgets (InBuf, 256, fpin);
	  fgets (InBuf, 256, fpin);
      }
    else if (!strncmp (InBuf, "gnuchess", 6))
      {
	  InFileType = GNUCHESS;
	  fgets (InBuf, 256, fpin);
      }
    else if (InBuf[0] == '[')
      {
	  InFileType = PGN;
	  fprintf (fpout, "%s", InBuf);
	  while (InBuf[0] == '[')
	    {
		fprintf (fpout, "%s", InBuf);
		fgets (InBuf, 256, fpin);
	    }
	  fprintf (fpout, "\n");
      }
    else
	rewind (fpin);
    TCmoves = 1;
    TCflag = (TCmoves > 1);
    /* flag.onemove = true; */
    OperatorTime = 0;
    SetTimeControl ();


    fprintf (fpout, "Move White Black      Score Depth     Best Line\n");
    fprintf (fpout, "------------------------------------------------------------------\n");

#ifdef BACKGROUND_ANALYSIS

    /*
     * Update progress in the progress file if this is running in the
     * background.
     */

    fpprog = fopen (progfilename, "w");
    fprintf (fpprog, "Done with move #%d.\n", move_number - 1);
    fclose (fpprog);

#endif
    GNUANmovecnt = 0;
    GNUANbasemove = 0;
    while (GetNextMove (s) > 0)
      {
	  strcpy (GNUANmove[GNUANmovecnt], white_actual_move);
	  GNUANsd[GNUANmovecnt] = (sdw == -99) ? search_depth : (sdw) ? sdw : search_depth;
	  GNUANmovecnt++;
	  strcpy (GNUANmove[GNUANmovecnt], black_actual_move);
	  GNUANsd[GNUANmovecnt] = (sdb == -99) ? search_depth : (sdb) ? sdb : search_depth;
	  GNUANmovecnt++;
	  if (!strcmp (white_actual_move, "Black") || !strcmp (white_actual_move, "White") || !strcmp (white_actual_move, "draw"))
	      break;
      }
    printf ("Got %d moves\n", GNUANmovecnt);

    /* all the moves are stored now start */
    opponent = black;
    computer = white;
    GNUANinput = file;
    GNUANnext = false;
    GNUANnextstop = GNUANsavedepth = GNUANcurrmove = 0;
    time (&start_time);
    Undid = false;
    while (GNUANcurrmove < (GNUANbasemove + GNUANmovecnt))
      {

#ifdef IGNUAN
/************************************************************************/
	  /* gnuan interactive                                */
/************************************************************************/

	  /*
	   * Commands: var - initiate a variation - save current another - find
	   * next best move for this position top - always look at the top n
	   * moves comment - copy to output rav - return from variation go get
	   * next move from input
	   */
/************************************************************************/
#endif
	  if (GNUANdepth)
	      MaxSearchDepth = GNUANdepth;
	  else
	    {
		if (GNUANinput == file)
		    MaxSearchDepth = GNUANsd[GNUANcurrmove];
		else
		    MaxSearchDepth = 4;
	    }
	  if (GNUANnext)
	    {
		GNUANnext = false;
		inbook = false;
	    }
	  else
	    {
		VMoveList (computer, 1);
		inbook = GOpeningBook (&GNUANhint, computer, GNUANmove[GNUANcurrmove]);
	    }

	  if (!inbook)
	    {
		flag.force = 0;
		SelectMove (computer, 1);
		Undo ();
		SetTimeControl ();
		flag.force = 1;
	    }
	  if (GNUANinput == file)
	      ok = DoIt (computer, GNUANmove[GNUANcurrmove], inbook, s);
	  else
	      ok = DoIt (computer, GNUANinbuf, inbook, s);
	  if (!ok)
	    {
		if (GNUANinput == keyboard)
		    GNUANmovecnt--;
		GNUANcurrmove--;
	    }
#ifdef BACKGROUND_ANALYSIS

	  /*
	   * Update progress in the progress file if this is running in the
	   * background.
	   */

	  fpprog = fopen (progfilename, "w");
	  fprintf (fpprog, "Done with move #%d.\n", move_number - 1);
	  fclose (fpprog);
#else

	  /*
	   * fprintf(stderr, "Done with move #%d.\n", move_number-1);
	   */

#endif
#ifdef IGNUAN
	  /* we have done the move now any commands */
	  if(GNUANtopLim){
		if(GNUANtop < GNUANtopLim){
			 GNUANadjlist[GNUANtop++] = GNUANmv;
                          GNUANnext = true;
                          Undo ();
                          Undid = true;
			}
		else GNUANtop = 0;
		}
	  if (GNUANcurrmove >= GNUANnextstop) GNUANnextstop = 0;
	  if (GNUANnextstop == 0 && (GNUANtopLim == 0 || GNUANtop == 0))
	      while (true)
		{
		    printf (">");
		    gets (GNUANinbuf1);
		    p = GNUANinbuf1;
		    q = GNUANinbuf;
		    while (true)
		      {
			  while (true)
			    {
				if (*p == ' ')
				  {
				      p++;
				      continue;
				  }
				else
				    break;
			    }
			  while (true)
			    {
				if (*p != ' ')
				  {
				      if (*p == '\0')
					{
					    break;
					}
				      *q++ = *p++;
				      continue;
				  }
				else
				    break;
			    }
			  if (*p == '\0')
			      break;
			  else
			      *q++ = ' ';
		      }
		    *q = '\0';
		    if (strcmp ("var", GNUANinbuf) == 0)
		      {
			  GNUANvarit ();
			  GNUANinput = keyboard;
		      }
		    else if (strcmp ("rav", GNUANinbuf) == 0)
		      {
			  if (GNUANsavedepth == 0)
			    {
				printf ("Error not in Var\n");
				continue;
			    }
			  GNUANravit ();
			  InitializeStats ();
			  GNUANinput = (GNUANsavedepth ? keyboard : file);
		      }
		    else if (strcmp ("next", GNUANinbuf) == 0 || strcmp ("n", GNUANinbuf) == 0)
		      {
			  GNUANadjlist[GNUANtop++] = GNUANmv;
			  GNUANnext = true;
			  Undo ();
			  Undid = true;
			  break;
		      }
		    else if ((strncmp ("depth", GNUANinbuf, 5) == 0))
		      {
			  int i = strtol (&GNUANinbuf[5], NULL, 10);
			  if (i > 0)
			      GNUANdepth = i;
			  else
			    {
				printf ("Illegal depth %d\n", i);
				continue;
			    }
		      }
		    else if (strcmp ("wn", GNUANinbuf) == 0)
		      {
			  GNUANtop = 0;
		      }
		    else if (strncmp ("d", GNUANinbuf, 2) == 0)
		      {
			  int i = strtol (&GNUANinbuf[2], NULL, 10);
			  if (i > 0)
			      GNUANdepth = i;
			  else
			    {
				printf ("Illegal depth %d\n", i);
				continue;
			    }
		      }
		    else if (strncmp ("top", GNUANinbuf, 3) == 0)
		      {
			  int i = strtol (&GNUANinbuf[4], NULL, 10);
			  if (i > 1 && i < 6)
			      GNUANtopLim = i-1;
			  else
			      printf ("Illegal range for top %d\n", i);
		      }
		    else if (strncmp ("t", GNUANinbuf, 2) == 0)
		      {
			  int i = strtol (&GNUANinbuf[2], NULL, 10);
			  if (i > 0 && i < 99)
			      GNUANtop = i;
			  else
			      printf ("Illegal range for top %d\n", i);
		      }
		    else if (strcmp ("bd", GNUANinbuf) == 0)
		      {
			  UpdateDisplay (0, 0, 1, 0);
		      }
		    else if (strcmp ("quit", GNUANinbuf) == 0)
		      {
			  exit (1);
		      }
		    else if (strcmp ("go", GNUANinbuf) == 0 || strcmp ("g", GNUANinbuf) == 0)
		      {
			  if (!GNUANsavedepth)
			      break;
			  else
			      printf ("In variation need move or rav\n");
		      }
		    else if (isdigit (GNUANinbuf[0]))
		      {
			  /* means go to move nn */
			  GNUANnextstop = 2 * (strtol (GNUANinbuf, &p, 10) - 1) - 1;
			  if (GNUANnextstop <= GNUANcurrmove)
			    {
				printf ("already past that move\n");
				GNUANnextstop = 0;
				continue;
			    }
			  break;
		      }
		    else
		      {		/* none of above must be a move if in a var */
			  if (!GNUANsavedepth)
			    {
				printf ("Illegal input:must be in var to specify move\n");
				continue;
			    }
			  if (strlen (GNUANinbuf) < 2)
			    {
				printf ("Illegal input:%s\n", GNUANinbuf);
				continue;
			    }
			  else
			    {
				strcpy (GNUANmove[GNUANbasemove + GNUANmovecnt], GNUANinbuf);
				GNUANmovecnt++;
				GNUANinput = keyboard;
				break;
			    }
		      }

		}
#endif
	  if (!Undid)
	    {
		computer ^= 1;
		opponent ^= 1;
		GNUANcurrmove++;
	        if (computer == white) move_number++;
	    }
	  Undid = false;
      }

    move_percent[white] = ((float) same_moves[white]) * 100 / (float) GNUANmovecnt;
    move_percent[black] = ((float) same_moves[black]) * 100 / (float) GNUANmovecnt;
    fprintf (fpout, "\n           White's percentage was %5.2f%%.     Black's percentage was %5.2f%%.\n", move_percent[white], move_percent[black]);
    time (&end_time);
    elapsed_time = end_time - start_time;
    fprintf (fpout, "\n           Elapsed time was %d seconds.\n", elapsed_time);
    fclose (fpin);
    fclose (fpout);
    exit (0);
}

void
Ldisplay1 ()
{
};
void
Ldisplay2 ()
{
};
void
Ldisplay ()
{
};
void
Ldisplay3 ()
{
};
void
Ldisplay4 ()
{
};
int ecomove;
