
/* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 * 
 * Program: Vanilla Chess V2.6
 * Author: Shaun Press
 * Date: February 1997
 * 
 * Contributors: Jim Ablett, Dann Corbit, Roland Chastain
 * 
 * %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */

#ifdef _MSC_VER
#define inline
#define CDECL __cdecl
#else
#define CDECL
#endif

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <time.h>
#include <sys/timeb.h>

struct piecetype
{
  int pieceno;
  int indexno;
};

struct squaretype
{
  struct piecetype piece;
  int colour;
};

struct flagtype
{
  int kingcastle[3];
  int queencastle[3];
  int enpas;
  int move50;
  int moveno;
  int transindex[2];
  int staticval[3];
  int incrementval[3];
};

struct boardtype
{
  struct flagtype boardflag;
  struct squaretype square[0x80];
}
board;

struct piecetabletype
{
  int pieceentry[16];
};

struct movetype
{
  struct piecetype piece;
  int startsq;
  int endsq;
  struct piecetype capture;
  int special;
  int movevalue;
};

struct movelisttype
{
  int moveno;
  struct movetype move[207];
};

struct pvtype
{
  int pvlength;
  struct movetype pvmove[50];
};

struct transvaluetype
{
  long checksum;
  int transval;
  short depth;
  char mover;
  char bound;
};

struct stabletype
{
  int stable[0x80];
};

struct attacktabtype
{
  int pieceset;
  int direction;
};

struct svtype
{
  int squarevalue[3][8][0x80];
}
sv, oldsv;
extern int attacks(int player, int asquare, int vsquare);
extern int CDECL capcompare(const void *i, const void *j);
extern int evalgame(int mover);
extern int evalmove(int mover);
extern int firstlevel(int player);
extern int get_ms(void);
extern int incheck(int player, int nsquare);
extern int CDECL intcompare(const void *i, const void *j);
extern int matesearch(int player);
#undef max
extern int max(int a, int b);
#undef min
extern int min(int a, int b);
extern int repetition(void);
extern int search(int player, int depth, int alpha, int beta, struct pvtype * prevpv);
extern struct movetype playermove(int mover);
extern void addmove(int player, struct movetype * pmove, struct movelisttype * movearray);
extern void bishopmoves(int mover, struct movelisttype * movelist, int nsquare);
extern void displayboard(void);
extern void findbestmove(int player);
extern void gencaptures(int mover, struct movelisttype * movelist);
extern void genmoves(int mover, struct movelisttype * movelist);
extern void initattacktab(void);
extern void initboard(void);
extern void initsquaretable(void);
extern void inittranstable(void);
extern void kingmoves(int mover, struct movelisttype * movelist, int nsquare);
extern void knightmoves(int mover, struct movelisttype * movelist, int nsquare);
extern void pawnattacks(int mover, struct movelisttype * movelist, int nsquare);
extern void pawnmoves(int mover, struct movelisttype * movelist, int nsquare);
extern void playmove(int player, struct movetype pmove);
extern void rookmoves(int mover, struct movelisttype * movelist, int nsquare);
extern void unplaymove(int player, struct movetype pmove);
extern void updatesquaretable(void);
static void CDECL catch_sigint(int s);

#define BISHOP 3
#define BLACK 2
#define BOOL int
#define DRAW 3
#define EMPTY 0
#define ENDGAME 2
#define FALSE 0
#define INVALID 99
#define KING 6
#define KNIGHT 2
#define LOSS 2
#define LOWER 2
#define MATING 3
#define MIDDLEGAME 1
#define OPENING 0
#define PAWN 1
#define PLAY 4
#define QUEEN 5
#define RESIGNTHRESHOLD (800)
#define TIMEALLOC (55000)
#define ROOK 4
#define TRUE 1
#define UPPER 1
#define VALID 0
#define WHITE 1
#define WIN 1

/* apparently uses 12 bytes per entry */

#define TSIZE (200000*10)

BOOL ftime_ok = FALSE;
BOOL promote = FALSE;
BOOL stop_search = FALSE;
BOOL xboard = FALSE;
BOOL end_game = FALSE;
BOOL no_go = FALSE;
BOOL draw_claim = TRUE;
BOOL do_resign = TRUE;

static int c,
       compplayer,
       dispboard,
       disppv,
       et,
       ft,
       gamestate,
       howdeep,
       lst,
       maxdepth,
       maxtime,
       maxval,
       mresult,
       nocomp,
       nodes,
       nps,
       player,
       playing,
       resigncounter,
       max_moves,
       selfplay,
       start_time,
       stop_time,
       timeleft,
       transadds,
       transhits;

static int opponent[] = {EMPTY, BLACK, WHITE};
static int pawnfield[3][8];
static int piecevalue[] = {0, 125, 340, 340, 500, 900, 10000};
static int minefield[3][0x80];
static int transtindex[2][16][0x80];

struct attacktabtype attacktab[0x100];
struct flagtype flaglist[400];
struct movetype bmove;
struct movetype emptymove;
struct movetype oldmoves[400];
struct piecetabletype piecetable[3];
struct piecetype nocapture;
struct squaretype emptysquare;
struct transvaluetype transtable[TSIZE];

unsigned movehist[4096];

inline int get_ms(void)
{
  struct timeb timebuffer;
  ftime(&timebuffer);
  if (timebuffer.millitm != 0)
    ftime_ok = TRUE;
  return (timebuffer.time * 1000) + timebuffer.millitm;
}

static void CDECL
catch_sigint(int s)
{
  signal(s, catch_sigint);
}

int CDECL main(int argc, char *argv[])
{

  char figure[] = " PNBRQK";
  setbuf(stdout, NULL);
  setbuf(stdin, NULL);
  setvbuf(stdout, NULL, _IONBF, 0);
  setvbuf(stdin, NULL, _IONBF, 0);
  maxtime = 1 << 25;
  maxdepth = 4;
  compplayer = BLACK;
  player = WHITE;
  signal(SIGINT, catch_sigint);
  printf("Vanilla Chess 2.6 by Shaun Press\n");
  dispboard = TRUE;
  disppv = TRUE;

  while (--argc > 0 && (*++argv)[0] == '-')
  {
    c = *++argv[0];
    switch (c)
    {
    case 't':
      maxtime = atoi(++argv[0]);
      break;
    case 'p':
      if (*++argv[0] == 'W')
        compplayer = WHITE;
      if (*argv[0] == 'C')
        selfplay = TRUE;
      if (*argv[0] == 'S')
        nocomp = TRUE;
      break;

    case 's':
      dispboard = TRUE;
      break;
    case 'S':
      dispboard = TRUE;
      disppv = TRUE;
      break;
    case 'x':
      signal(SIGINT, SIG_IGN);
      break;
    case 'd':

      draw_claim = FALSE, printf("SCP draw claim de-activated\n");
      break;
    case 'r':

      do_resign = FALSE, printf("SCP resign de-activated\n");
      break;

    }
  }
  inittranstable();
  initboard();
  initsquaretable();
  initattacktab();
  playing = TRUE;
  player = WHITE;
  while (playing)
  {
    do
    {
      nodes = 0;
      transhits = 0;
      transadds = 0;
      lst = time(0);
      if (selfplay)
        compplayer = player;
      if (nocomp)
        compplayer = opponent[player];
      if (player == compplayer)
      {
        displayboard();
        findbestmove(player);
        printf("\nmove ");
        /*
        printf("%c%d%c%d\n", bmove.startsq % 16 + 97, bmove.startsq / 16 + 1, bmove.endsq % 16 + 97, bmove.endsq / 16 + 1);
        if (bmove.special > 1)
          printf("%c", figure[bmove.special]);
        */
        printf("%c%d%c%d", bmove.startsq % 16 + 97, bmove.startsq / 16 + 1, bmove.endsq % 16 + 97, bmove.endsq / 16 + 1);
        if (bmove.special > 1)
          printf("%c", figure[bmove.special]);
        putchar('\n');
      }
      else
      {
        bmove = playermove(player);
      }
      if (bmove.startsq == -2)
      {
        compplayer = player;
        nocomp = FALSE;
      }
      else if (bmove.startsq == -3)
      {
        compplayer = opponent[player];
        nocomp = TRUE;
      }
      else if (bmove.startsq == -4)
      {
        unplaymove(opponent[player], oldmoves[board.boardflag.moveno - 1]);
        board.boardflag = flaglist[board.boardflag.moveno - 1];
        player = opponent[player];
        nocomp = TRUE;
        displayboard();
      }
    }
    while (bmove.startsq < 0);
    ft = time(0);
    et = ft - lst;
    if (et == 0)
      et = 1;
    if (disppv && player == compplayer)
      printf("Nodes = %d Hits = %d Adds = %d\n", nodes, transhits, transadds);
    nodes += transhits;
    nps = nodes / et;
    if (disppv && player == compplayer)
      printf("Nodes per second = %d\n", nps);
    oldmoves[board.boardflag.moveno] = bmove;
    flaglist[board.boardflag.moveno] = board.boardflag;
    playmove(player, bmove);
    if (dispboard)
      displayboard();

    mresult = evalgame(player);
    if (mresult != PLAY)
      playing = FALSE;
    if (player == WHITE)
      player = BLACK;
    else
      player = WHITE;
  }
}

void initboard()
{
  int i, k;
  int offset[3] = {0, 0, 6};
  int startrow[8] = {ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK};
  int indexrow[8] = {2, 6, 4, 1, 0, 5, 7, 3};
  emptysquare.piece.pieceno = EMPTY;
  emptysquare.piece.indexno = -1;
  emptysquare.colour = EMPTY;
  emptymove.startsq = -1;
  emptymove.endsq = -1;
  nocapture.pieceno = EMPTY;
  nocapture.indexno = -1;
  board.boardflag.transindex[0] = 0;
  board.boardflag.transindex[1] = 0;
  gamestate = OPENING;
  for (i = 0; i < 0x80; i++)
  {
    board.square[i] = emptysquare;
  }
  for (i = 0; i < 8; i++)
  {
    board.square[i].piece.pieceno = startrow[i];
    board.square[i].piece.indexno = indexrow[i];
    piecetable[WHITE].pieceentry[indexrow[i]] = i;
    board.square[i + 0x70].piece.pieceno = startrow[i];
    board.square[i + 0x70].piece.indexno = indexrow[i];
    piecetable[BLACK].pieceentry[indexrow[i]] = i + 0x70;
    board.square[i].colour = WHITE;
    board.square[i + 0x70].colour = BLACK;
    pawnfield[WHITE][i] = 1;
    pawnfield[BLACK][i] = 1;
  }
  for (i = 0; i < 8; i++)
  {
    board.square[i + 0x10].piece.pieceno = PAWN;
    board.square[i + 0x10].piece.indexno = i + 8;
    piecetable[WHITE].pieceentry[i + 8] = i + 0x10;
    board.square[i + 0x10].colour = WHITE;
    board.square[i + 0x60].piece.pieceno = PAWN;
    board.square[i + 0x60].piece.indexno = i + 8;
    piecetable[BLACK].pieceentry[i + 8] = i + 0x60;
    board.square[i + 0x60].colour = BLACK;
  }
  board.boardflag.staticval[WHITE] = 3900;
  board.boardflag.staticval[BLACK] = 3900;
  board.boardflag.move50 = 1;
  board.boardflag.kingcastle[WHITE] = TRUE;
  board.boardflag.kingcastle[BLACK] = TRUE;
  board.boardflag.queencastle[WHITE] = TRUE;
  board.boardflag.queencastle[BLACK] = TRUE;
  board.boardflag.enpas = EMPTY;
  for (k = 0; k < 2; k++)
  {
    for (i = 0; i < 0x80; i++)
    {
      if (!(i & 0x88))
      {
        if (board.square[i].piece.pieceno == 0)
          board.boardflag.transindex[k] += transtindex[k][0][i];
        else
          board.boardflag.transindex[k] += transtindex[k][board.square[i].piece.pieceno + offset[board.square[i].colour]][i];
      }
    }
    board.boardflag.transindex[k] = board.boardflag.transindex[k] % TSIZE;
  }
}

void initsquaretable()
{
  int loop, loop1, loop2;
  int centreval[8] = {1, 2, 3, 5, 5, 3, 2, 1};
  int piecesval[6][8] =
  {
    {0, 0, 1, 2, 4, 6,10,20},
    {0, 1, 3, 3, 5, 7, 5, 2},
    {0, 1, 1, 3, 4, 4, 3, 1},
    {1, 1, 2, 3, 4, 5, 6, 7},
    {0, 0, 1, 1, 2, 2, 3, 4},
    {3, 2, 1, 1, 1, 1, 2, 3}
  };
  for (loop = 0; loop < 4096; loop++)
    movehist[loop] = 0;
  for (loop = 0; loop < 8; loop++)
  {
    for (loop1 = 0; loop1 < 8; loop1++)
    {
      for (loop2 = PAWN; loop2 < KING; loop2++)
      {
        oldsv.squarevalue[WHITE][loop2][loop * 16 + loop1] = piecesval[loop2 - 1][loop] * centreval[loop1];
        oldsv.squarevalue[BLACK][loop2][0x77 - (loop * 16 + loop1)] = piecesval[loop2 - 1][loop] * centreval[loop1];
      }
    }
  }
  for (loop = 0; loop < 8; loop++)
  {
    for (loop1 = 0; loop1 < 8; loop1++)
    {
      oldsv.squarevalue[WHITE][KING][loop * 16 + loop1] = piecesval[KING - 1][loop] * (5 - centreval[loop1]);
      oldsv.squarevalue[BLACK][KING][0x77 - (loop * 16 + loop1)] = piecesval[KING - 1][loop] * (5 - centreval[loop1]);
    }
  }
}

#undef max
int max(int a, int b)
{
  return (a > b) ? a : b;
}

#undef min
int min(int a, int b)
{
  return (a < b) ? a : b;
}

void updatesquaretable()
{
  int loop, loop1, loop2;
  int centreval[8] = {1, 2, 3, 5, 5, 3, 2, 1};
  int piecesval[8] = {1, 2, 3, 4, 4, 3, 2, 1};
  int pawndir[3] = {0, 0x10, -0x10};
  int attval[7] = {0, 0, 5, 5, 2, 1, 0};
  struct movelisttype whitelist, blacklist;
  for (loop = 0; loop < 4096; loop++)
    movehist[loop] = (movehist[loop] >> 4);
  if ((board.boardflag.moveno > 20) && (gamestate < MIDDLEGAME))
  {
    for (loop = 0; loop < 8; loop++)
    {
      for (loop1 = 0; loop1 < 8; loop1++)
      {
        oldsv.squarevalue[WHITE][QUEEN][loop * 16 + loop1] *= 2;
        oldsv.squarevalue[BLACK][QUEEN][0x77 - (loop * 16 + loop1)] *= 2;
      }
    }
    gamestate = MIDDLEGAME;
  }
  if ((board.boardflag.staticval[WHITE] < 1500) && (board.boardflag.staticval[BLACK] < 1500) && (gamestate < ENDGAME))
  {
    for (loop = 0; loop < 8; loop++)
    {
      for (loop1 = 0; loop1 < 8; loop1++)
      {
        oldsv.squarevalue[WHITE][KING][loop * 16 + loop1] = piecesval[loop] * centreval[loop1];
        oldsv.squarevalue[BLACK][KING][0x77 - (loop * 16 + loop1)] = piecesval[loop] * centreval[loop1];
      }
    }
    gamestate = ENDGAME;
    {
      size_t index;
      int pv2[] = {0, 200, 300, 330, 510, 900, 10000};
      int pv[] = {0, 130, 350, 370, 530, 1200, 1000};
      for (index = 0; index < sizeof piecevalue / sizeof piecevalue[0]; index++)
        piecevalue[index] = pv[index];
    }
  }
  if ((board.boardflag.staticval[compplayer] >= 500) && (board.boardflag.staticval[opponent[compplayer]] < 300))
    gamestate = MATING;
  sv = oldsv;
  if (gamestate == OPENING)
  {
    sv.squarevalue[WHITE][BISHOP][0x2] -= 5;
    sv.squarevalue[WHITE][BISHOP][0x5] -= 5;
    sv.squarevalue[WHITE][KNIGHT][0x1] -= 5;
    sv.squarevalue[WHITE][KNIGHT][0x6] -= 5;
    sv.squarevalue[BLACK][BISHOP][0x72] -= 5;
    sv.squarevalue[BLACK][BISHOP][0x75] -= 5;
    sv.squarevalue[BLACK][KNIGHT][0x71] -= 5;
    sv.squarevalue[BLACK][KNIGHT][0x76] -= 5;
  }
  for (loop = 0; loop < 0x80; loop++)
  {
    minefield[WHITE][loop] = max(0, 8 - max((loop - piecetable[BLACK].pieceentry[0]) % 16, (loop - piecetable[BLACK].pieceentry[0]) / 16));
    minefield[BLACK][loop] = max(0, 8 - max((loop - piecetable[WHITE].pieceentry[0]) % 16, (loop - piecetable[WHITE].pieceentry[0]) / 16));
  }
  for (loop = 0; loop < 0x80; loop++)
  {
    if (board.square[loop].piece.pieceno == PAWN)
    {
      for (loop1 = -1; loop1 <= 1; loop1 += 2)
      {
        if (!((loop + loop1) & 0x88))
          minefield[opponent[board.square[loop].colour]][loop + pawndir[board.square[loop].colour] + loop1] -= 10;
      }
    }
  }
  whitelist.moveno = -1;
  genmoves(WHITE, &whitelist);
  for (loop = 0; loop < whitelist.moveno; loop++)
  {
    minefield[BLACK][whitelist.move[loop].endsq] -= attval[whitelist.move[loop].piece.pieceno];
  }
  blacklist.moveno = -1;
  genmoves(BLACK, &blacklist);
  for (loop = 0; loop < blacklist.moveno; loop++)
  {
    minefield[WHITE][blacklist.move[loop].endsq] -= attval[blacklist.move[loop].piece.pieceno];
  }
  for (loop = 0; loop < 0x80; loop++)
  {
    for (loop1 = KNIGHT; loop1 < KING; loop1++)
    {
      for (loop2 = WHITE; loop2 <= BLACK; loop2++)
      {
        sv.squarevalue[loop2][loop1][loop] += minefield[loop2][loop];
      }
    }
  }
}

void inittranstable()
{
  int i, j, k;
  srand(time(0));
  for (i = 0; i < TSIZE; i++)
  {
    transtable[i].depth = -100;
    transtable[i].bound = INVALID;
  }
  for (k = 0; k < 2; k++)
    for (i = 0; i < 14; i++)
    {
      for (j = 0; j < 0x80; j++)
      {
        if (!(j & 0x88))
          transtindex[k][i][j] = rand() % 32768;
      }
    }
}

struct movetype playermove(int mover)
{
  struct movetype pmove = {0};
  struct movelisttype pmovelist;
  int loop, pstartsq, pfinsq, moveind;
  char cmove[256];
  char line[256];
  pmovelist.moveno = -1;
  moveind = -1;
  genmoves(mover, &pmovelist);

  while (moveind == -1)
  {
    if (!xboard)
    {
      printf(">\n");
    }
    else
    {
      putchar('\n');
    }
    if (!fgets(line, 256, stdin))
      return pmove;
    if (line[0] == '\n')
      continue;
    sscanf(line, "%s", cmove);
    if (!strcmp(cmove, "list"))
    {
      putchar('\n');
      for (loop = 0; loop <= pmovelist.moveno; loop++)
      {
        struct movetype bmove = pmovelist.move[loop];
        printf("%c%d%c%d ", bmove.startsq % 16 + 97, bmove.startsq / 16 + 1, bmove.endsq % 16 + 97, bmove.endsq / 16 + 1);
      }
      putchar('\n');
      continue;
    }

    if (!strcmp(cmove, "go"))
    {
      pmove = emptymove;
      pmove.startsq = -2;
      return (pmove);
      continue;
    }

    if (!strcmp(cmove, "self"))
    {
      pmove = emptymove;
      pmove.startsq = -3;
      return (pmove);
      continue;
    }
    if (!strcmp(cmove, "back"))
    {
      pmove = emptymove;
      pmove.startsq = -4;
      return (pmove);
      continue;
    }
    if (!strcmp(cmove, "undo"))
    {
      pmove = emptymove;
      pmove.startsq = -4;
      return (pmove);
      continue;
    }
    if (!strcmp(cmove, "black"))
    {
      compplayer = BLACK;
      selfplay = FALSE;
      nocomp = FALSE;
      no_go = TRUE;
      continue;
    }
    if (!strcmp(cmove, "white"))
    {
      compplayer = WHITE;
      selfplay = FALSE;
      nocomp = FALSE;
      no_go = FALSE;
      continue;
    }
    if (!strcmp(cmove, "new"))
    {
      compplayer = BLACK;
      selfplay = FALSE;
      nocomp = FALSE;
      inittranstable();
      initboard();
      initsquaretable();
      initattacktab();
      playing = TRUE;
      player = WHITE;
      continue;
    }

    if (!strcmp(cmove, "protover"))
    {
      printf("feature colors=1 myname=\"Vanilla Chess 2.6h\" time=1 pause=0 ping=1 sigint=0 sigterm=0 name=1 reuse=0 done=1\n");
      continue;
    }
    
    if (!strcmp(cmove, "force"))
    {
      nocomp = TRUE;
      continue;
    }
    
    if (!strcmp(cmove, "quit"))
    {
      exit(0);
    }

    if (!strcmp(cmove, "easy"))
    {
      printf("easy (ponder off)\n");
      continue;
    }
    
    if (!strcmp(cmove, "hard"))
    {
      printf("hard (ponder not implemented)\n");
      continue;
    }

    if (!strcmp(cmove, "ping"))
    {
      int ping;
      sscanf(line, "%*s %d", &ping);
      printf("pong %d\n", ping);
      continue;
    }
    /*
    if (!strcmp(cmove, "set_depth"))
    {
      sscanf(line, "set_depth %d", &maxdepth);
      maxtime = 1 << 25;
      maxdepth = max(1, min(maxdepth, 25));
      printf("maximum search depth is %d plies\n", maxdepth);
      continue;
    }
    */
    if (!strcmp(cmove, "st"))
    {
      scanf(line, "st %d", &maxtime);
      maxtime = (maxtime * 1000);
      maxdepth = 32;
      continue;
    };

    if (!strcmp(cmove, "time"))
    {
      sscanf(line, "time %d", &maxtime);
      maxtime *= 14;
      maxtime /= (TIMEALLOC);
      maxdepth = 32;
      continue;
    };

    if (!strcmp(cmove, "level"))
    {
      sscanf(line, "level %d %d", &max_moves, &maxtime);
      if (max_moves == 1);
      max_moves = (TIMEALLOC / 1000);
      maxtime *= 14;
      maxtime /= (max_moves * 1000);
      maxdepth = 32;
      continue;
    };

    if (!strcmp(cmove, "sd"))
    {
      sscanf(line, "sd %d", &maxdepth);
      maxtime = 1 << 25;
      continue;
    }

    if (!strcmp(cmove, "otim"))
    {
      continue;
    }

    if (!strcmp(cmove, "result"))
    {
      char result[256];
      sscanf(line, "result %s", result);
      nocomp = TRUE;
      continue;
    }

    if (!strcmp(cmove, "xboard"))
    {
      xboard = TRUE;
      printf("feature done=0\n");
      continue;
    }
    
    pstartsq = (cmove[0] - 97) + (cmove[1] - 49) * 16;
    pfinsq = (cmove[2] - 97) + (cmove[3] - 49) * 16;
    for (loop = 0; loop <= pmovelist.moveno; loop++)
    {
      if ((pstartsq == pmovelist.move[loop].startsq) && (pfinsq == pmovelist.move[loop].endsq))
        if (pmovelist.move[loop].special > 1)
        {
          if ((cmove[4] - 48) == pmovelist.move[loop].special)
            cmove[4] = EMPTY;
          moveind = loop;
        }
        else
          moveind = loop;
    }
    if (xboard == FALSE && moveind == -1)
      printf("Error (unknown command): %s\n", cmove);
  }
  return (pmovelist.move[moveind]);
}

int evalgame(int mover)
{
  struct movelisttype movelist;
  int otherp;

  otherp = opponent[mover];

  movelist.moveno = -1;
  genmoves(otherp, &movelist);
  if (movelist.moveno == -1)
  {
    if (incheck(otherp, piecetable[otherp].pieceentry[0]))
    {
      printf("computer mates\n");
      end_game = TRUE;
      nocomp = TRUE;
    }
    else if (draw_claim) printf("Draw\n");
    end_game = TRUE;
    nocomp = TRUE;
  }
  if (draw_claim)
  {
    if (((board.boardflag.moveno - board.boardflag.move50) >= 100))
    {
      printf("Claim a draw! - 50 moves rule\n");
      printf("Draw\n");
      end_game = TRUE;
      nocomp = TRUE;
    }
    else if (repetition())
    {
      printf("Claim a draw! - 3 fold repetition\n");
      printf("Draw\n");
      end_game = TRUE;
      nocomp = TRUE;
    }
  }

  return (PLAY);
}

int matesearch(int player)
{
  int otherp, otherx, othery;
  int myx, myy;
  int edgedist, proxdist, mateval;
  otherp = opponent[player];
  otherx = piecetable[otherp].pieceentry[0] % 16;
  othery = piecetable[otherp].pieceentry[0] / 16;
  edgedist = min(min(otherx, othery), min(7 - otherx, 7 - othery));
  myx = piecetable[player].pieceentry[0] % 16;
  myy = piecetable[player].pieceentry[0] / 16;
  proxdist = max(abs(myx - otherx), abs(myy - othery));
  mateval = 80 - (edgedist * 10) - (proxdist * 5);
  return (mateval);
}

int evalmove(int mover)
{
  int moveval, otherp;
  int loop, loop1, loop2, offset, attackcount, pawnsq;
  int pawndir[3] = {0, 0x10, -0x10};
  otherp = opponent[mover];
  moveval = board.boardflag.staticval[mover] - board.boardflag.staticval[otherp];
  if (gamestate < ENDGAME)
  {
    for (loop = WHITE; loop <= BLACK; loop++)
    {
      for (loop1 = 4; loop1 <= 5; loop1++)
      {
        if (piecetable[loop].pieceentry[loop1] != -1)
        {
          attackcount = 0;
          for (loop2 = 0; loop2 <= 3; loop2++)
          {
            if (piecetable[opponent[loop]].pieceentry[loop2] != -1)
            {
              offset = piecetable[loop].pieceentry[loop1] - piecetable[opponent[loop]].pieceentry[loop2] + 0x80;
              if ((attacktab[offset].pieceset & 8) > 0)
                attackcount++;
            }
          }
          board.boardflag.incrementval[loop] += (attackcount * 5);
        }
      }
    }
    if (gamestate > OPENING)
    {
      for (loop = WHITE; loop <= BLACK; loop++)
      {
        if (pawnfield[loop][piecetable[loop].pieceentry[0] % 16] == 0)
          board.boardflag.incrementval[loop] -= 10;
        if (pawnfield[opponent[loop]][piecetable[loop].pieceentry[0] % 16] == 0)
        {
          board.boardflag.incrementval[loop] -= 10;
          if (pawnfield[loop][piecetable[loop].pieceentry[0] % 16] == 0)
            board.boardflag.incrementval[loop] -= 30;
        }
      }
    }
  }
  if (gamestate <= MIDDLEGAME)
  {
    /* King safety stuff will go here */
    for (loop = WHITE; loop <= BLACK; loop++)
    {
      for (loop1 = piecetable[loop].pieceentry[0] - 1; loop1 <= piecetable[loop].pieceentry[0] + 1; loop1++)
      {
        if (!(loop1 & 0x88))
          for (loop2 = 1; loop2 <= 2; loop2++)
          {
            pawnsq = loop1 + (loop2 * pawndir[loop]);
            if (!(pawnsq & 0x88))
            {
              if ((board.square[pawnsq].piece.pieceno == PAWN) && (board.square[pawnsq].colour == loop))
              {
                board.boardflag.incrementval[loop] += (6 - (loop2 * 2));
              }
            }
          }
      }
    }
  }
  if (gamestate < MATING)
  {
    for (loop = WHITE; loop <= BLACK; loop++)
    {
      for (loop1 = 0; loop1 < 8; loop1++)
      {
        if (pawnfield[loop][loop1] > 1)
          board.boardflag.incrementval[loop] -= (5 * pawnfield[loop][loop1]);
      }
      for (loop1 = 1; loop1 < 7; loop1++)
      {
        if (pawnfield[loop][loop1] > 0)
        {
          if ((pawnfield[loop][loop1 - 1] == 0) && (pawnfield[loop][loop1 + 1] == 0))
          {
            board.boardflag.incrementval[loop] -= (20 * pawnfield[loop][loop1]);
            loop1++;
          }
        }
      }
    }
    moveval += board.boardflag.incrementval[mover] - board.boardflag.incrementval[otherp];
    moveval += (rand() % 5);
  }
  else
    moveval += matesearch(mover);
  if (repetition() > FALSE)
    moveval = 0;
  return (moveval);
}

void displayboard()
{
  if (!xboard)
  {
    int i, j;
    int figindex;
    char figure[] = " PNBRQKpnbrqk";
    int offset[3] =
    {0, 0, 6};
    printf("Move No:%d\n", (board.boardflag.moveno + 1) / 2);
    printf("Trans Table = %d Board Hash = %ld\n", board.boardflag.transindex[0], board.boardflag.transindex[1]);
    printf("-----------------\n");
    for (i = 7; i >= 0; i--)
    {
      for (j = 0; j < 8; j++)
      {
        figindex = offset[board.square[i * 16 + j].colour] + board.square[i * 16 + j].piece.pieceno;
        printf("|%c", figure[figindex]);
      }
      printf("|\n");
      printf("-----------------\n");
    }
  }
}

void genmoves(int mover, struct movelisttype * movelist)
{
  int loop, fsquare;
  for (loop = 0; loop < 16; loop++)
  {
    fsquare = piecetable[mover].pieceentry[loop];
    if (fsquare > -1)
    {
      switch (board.square[fsquare].piece.pieceno)
      {
      case PAWN:
        pawnmoves(mover, movelist, fsquare);
        break;
      case KNIGHT:
        knightmoves(mover, movelist, fsquare);
        break;
      case BISHOP:
        bishopmoves(mover, movelist, fsquare);
        break;
      case ROOK:
        rookmoves(mover, movelist, fsquare);
        break;
      case QUEEN:
        bishopmoves(mover, movelist, fsquare);
        rookmoves(mover, movelist, fsquare);
        break;
      case KING:
        kingmoves(mover, movelist, fsquare);
        break;
      }
    }
  }
  qsort(movelist->move, movelist->moveno + 1, sizeof(movelist->move[0]), capcompare);
}

void gencaptures(int mover, struct movelisttype * movelist)
{
  int loop, loop1;
  int fsquare, otherp;
  struct movetype pmove;
  otherp = opponent[mover];
  for (loop = 0; loop < 16; loop++)
  {
    fsquare = piecetable[mover].pieceentry[loop];
    if (fsquare > -1)
    {
      if (board.square[fsquare].piece.pieceno == PAWN)
        pawnattacks(mover, movelist, fsquare);
      else
      {
        for (loop1 = 1; loop1 < 16; loop1++)
        {
          if (piecetable[otherp].pieceentry[loop1] > -1)
          {
            if (attacks(mover, fsquare, piecetable[otherp].pieceentry[loop1]))
            {
              pmove.startsq = fsquare;
              pmove.endsq = piecetable[otherp].pieceentry[loop1];
              pmove.capture = board.square[pmove.endsq].piece;
              pmove.special = EMPTY;
              pmove.piece = board.square[fsquare].piece;
              addmove(mover, &pmove, movelist);
            }
          }
        }
      }
    }
  }
  qsort(movelist->move, movelist->moveno + 1, sizeof(movelist->move[0]), capcompare);
}

void pawnattacks(int mover, struct movelisttype * movelist, int nsquare)
{
  int loop;
  int pawndir[3] = {0, 0x10, -0x10};
  int promrow[3] = {0, 7, 0};
  struct movetype pmove;
  int newsquare, otherp;
  otherp = opponent[mover];
  pmove.startsq = nsquare;
  pmove.piece = board.square[nsquare].piece;
  for (loop = -1; loop <= 1; loop += 2)
  {
    newsquare = nsquare + pawndir[mover] + loop;
    if (!(newsquare & 0x88) && (board.square[newsquare].colour == otherp))
    {
      pmove.capture = board.square[newsquare].piece;
      pmove.special = EMPTY;
      pmove.endsq = newsquare;
      if ((newsquare / 0x10) == promrow[mover])
      {
        for (loop = KNIGHT; loop <= QUEEN; loop++)
        {
          pmove.special = loop;
          addmove(mover, &pmove, movelist);
        }
      }
      else
      {
        addmove(mover, &pmove, movelist);
      }
    }
  }
  if (((nsquare - 1) == board.boardflag.enpas) && (board.square[board.boardflag.enpas].colour == otherp))
  {
    pmove.endsq = nsquare + pawndir[mover] - 1;
    pmove.special = -1;
    pmove.capture = board.square[nsquare - 1].piece;
    addmove(mover, &pmove, movelist);
  }
  else if (((nsquare + 1) == board.boardflag.enpas) && (board.square[board.boardflag.enpas].colour == otherp))
  {
    pmove.endsq = nsquare + pawndir[mover] + 1;
    pmove.special = -1;
    pmove.capture = board.square[nsquare + 1].piece;
    addmove(mover, &pmove, movelist);
  }
}

void pawnmoves(int mover, struct movelisttype * movelist, int nsquare)
{
  int loop;
  int pawndir[3] = {0, 0x10, -0x10};
  int promrow[3] = {0, 7, 0};
  int startrow[3] = {0, 1, 6};
  struct movetype pmove;
  int newsquare, otherp;
  otherp = opponent[mover];
  pmove.piece = board.square[nsquare].piece;
  pmove.startsq = nsquare;
  pmove.capture = nocapture;
  pmove.special = EMPTY;
  newsquare = nsquare + pawndir[mover];
  if (board.square[newsquare].colour == EMPTY)
  {
    pmove.endsq = newsquare;
    if ((newsquare / 0x10) == promrow[mover])
    {
      for (loop = KNIGHT; loop <= QUEEN; loop++)
      {
        pmove.special = loop;
        addmove(mover, &pmove, movelist);
      }
    }
    else
    {
      pmove.special = EMPTY;
      addmove(mover, &pmove, movelist);
      if ((nsquare / 0x10) == startrow[mover])
      {
        newsquare += pawndir[mover];
        if (board.square[newsquare].colour == EMPTY)
        {
          pmove.endsq = newsquare;
          addmove(mover, &pmove, movelist);
        }
      }
    }
  }
  for (loop = -1; loop <= 1; loop += 2)
  {
    newsquare = nsquare + pawndir[mover] + loop;
    if (!(newsquare & 0x88) && (board.square[newsquare].colour == otherp))
    {
      pmove.capture = board.square[newsquare].piece;
      pmove.special = EMPTY;
      pmove.endsq = newsquare;
      if ((newsquare / 0x10) == promrow[mover])
      {
        for (loop = KNIGHT; loop <= QUEEN; loop++)
        {
          pmove.special = loop;
          addmove(mover, &pmove, movelist);
        }
      }
      else
      {
        addmove(mover, &pmove, movelist);
      }
    }
  }
  if (((nsquare - 1) == board.boardflag.enpas) && (board.square[board.boardflag.enpas].colour == otherp))
  {
    pmove.endsq = nsquare + pawndir[mover] - 1;
    pmove.special = -1;
    pmove.capture = board.square[nsquare - 1].piece;
    addmove(mover, &pmove, movelist);
  }
  else if (((nsquare + 1) == board.boardflag.enpas) && (board.square[board.boardflag.enpas].colour == otherp))
  {
    pmove.endsq = nsquare + pawndir[mover] + 1;
    pmove.special = -1;
    pmove.capture = board.square[nsquare + 1].piece;
    addmove(mover, &pmove, movelist);
  }
}

void knightmoves(int mover, struct movelisttype * movelist, int nsquare)
{
  int loop;
  int knightdir[8] = {0x1f, 0x21, 0x12, -0xe, -0x1f, -0x21, -0x12, 0xe};
  struct movetype pmove;
  pmove.piece = board.square[nsquare].piece;
  pmove.startsq = nsquare;
  pmove.special = EMPTY;
  for (loop = 0; loop < 8; loop++)
  {
    pmove.endsq = nsquare + knightdir[loop];
    if (!(pmove.endsq & 0x88))
    {
      if (!(board.square[pmove.endsq].colour == mover))
      {
        pmove.capture = board.square[pmove.endsq].piece;
        addmove(mover, &pmove, movelist);
      }
    }
  }
}

void bishopmoves(int mover, struct movelisttype * movelist, int nsquare)
{
  int loop, otherp;
  int bishopdir[4] = {0xf, 0x11, -0x11, -0xf};
  struct movetype pmove;
  otherp = opponent[mover];
  pmove.startsq = nsquare;
  pmove.piece = board.square[nsquare].piece;
  pmove.special = EMPTY;
  for (loop = 0; loop < 4; loop++)
  {
    pmove.endsq = nsquare + bishopdir[loop];
    pmove.capture = nocapture;
    while (!(pmove.endsq & 0x88) && (board.square[pmove.endsq].colour == EMPTY))
    {
      addmove(mover, &pmove, movelist);
      pmove.endsq += bishopdir[loop];
    }
    if (!(pmove.endsq & 0x88) && (board.square[pmove.endsq].colour == otherp))
    {
      pmove.capture = board.square[pmove.endsq].piece;
      addmove(mover, &pmove, movelist);
    }
  }
}

void rookmoves(int mover, struct movelisttype * movelist, int nsquare)
{
  int loop, otherp;
  int rookdir[4] = {0x10, 0x1, -0x10, -0x1};
  struct movetype pmove;
  otherp = opponent[mover];
  pmove.piece = board.square[nsquare].piece;
  pmove.startsq = nsquare;
  pmove.special = EMPTY;
  for (loop = 0; loop < 4; loop++)
  {
    pmove.capture = nocapture;
    pmove.endsq = nsquare + rookdir[loop];
    while ((!(pmove.endsq & 0x88)) && (board.square[pmove.endsq].colour == EMPTY))
    {
      addmove(mover, &pmove, movelist);
      pmove.endsq += rookdir[loop];
    }
    if ((!(pmove.endsq & 0x88)) && (board.square[pmove.endsq].colour == otherp))
    {
      pmove.capture = board.square[pmove.endsq].piece;
      addmove(mover, &pmove, movelist);
    }
  }
}

void kingmoves(int mover, struct movelisttype * movelist, int nsquare)
{
  int loop;
  int kingdir[8] = {0x10, 0x11, 0x1, -0x11, -0x10, -0xf, -0x1, 0xf};
  struct movetype pmove;
  pmove.piece = board.square[nsquare].piece;
  pmove.special = EMPTY;
  pmove.startsq = nsquare;
  for (loop = 0; loop < 8; loop++)
  {
    pmove.endsq = nsquare + kingdir[loop];
    if (!(pmove.endsq & 0x88))
    {
      if (!(board.square[pmove.endsq].colour == mover))
      {
        pmove.capture = board.square[pmove.endsq].piece;
        addmove(mover, &pmove, movelist);
      }
    }
  }
  if (board.boardflag.kingcastle[mover])
  {
    if ((board.square[piecetable[mover].pieceentry[0] + 1].piece.pieceno == EMPTY) && (board.square[piecetable[mover].pieceentry[0] + 2].piece.pieceno == EMPTY))
    {
      if ((!incheck(mover, piecetable[mover].pieceentry[0])) && (!incheck(mover, piecetable[mover].pieceentry[0] + 1)) && (!incheck(mover, piecetable[mover].pieceentry[0] + 2)))
      {
        pmove.endsq = piecetable[mover].pieceentry[0] + 2;
        pmove.capture = nocapture;
        addmove(mover, &pmove, movelist);
      }
    }
  }
  if (board.boardflag.queencastle[mover])
  {
    if ((board.square[piecetable[mover].pieceentry[0] - 1].piece.pieceno == EMPTY) && (board.square[piecetable[mover].pieceentry[0] - 2].piece.pieceno == EMPTY) && (board.square[piecetable[mover].pieceentry[0] - 3].piece.pieceno == EMPTY))
    {
      if ((!incheck(mover, piecetable[mover].pieceentry[0])) && (!incheck(mover, piecetable[mover].pieceentry[0] - 1)) && (!incheck(mover, piecetable[mover].pieceentry[0] - 2)))
      {
        pmove.endsq = piecetable[mover].pieceentry[0] - 2;
        pmove.capture = nocapture;
        addmove(mover, &pmove, movelist);
      }
    }
  }
}

void addmove(int player, struct movetype * pmove, struct movelisttype * movearray)
{
  struct flagtype tflag;
  tflag = board.boardflag;
  playmove(player, *pmove);
  if (!(incheck(player, piecetable[player].pieceentry[0])))
  {
    pmove->movevalue = movehist[(pmove->startsq & 7) + ((pmove->startsq & 0x70) >> 1) + (((pmove->endsq & 7) + ((pmove->endsq & 0x70) >> 1)) << 6)];
    movearray->moveno++;
    movearray->move[movearray->moveno] = *pmove;
  }
  unplaymove(player, *pmove);
  board.boardflag = tflag;
}

void initattacktab()
{
  int loop, square, loop1;
  int rookdir[4] = {0x10, 0x1, -0x10, -0x1};
  int kingdir[8] = {0x10, 0x11, 0x1, -0x11, -0x10, -0xf, -0x1, 0xf};
  int bishopdir[4] = {0xf, 0x11, -0x11, -0xf};
  int knightdir[8] = {0x1F, 0x21, 0x12, -0xE, -0x1F, -0x21, -0x12, 0xE};
  for (loop = 0; loop < 0x100; loop++)
  {
    attacktab[loop].pieceset = 0;
    attacktab[loop].direction = 0;
  }
  for (loop = 0; loop < 8; loop++)
  {
    square = 0x80 + knightdir[loop];
    attacktab[square].pieceset += 4;
    attacktab[square].direction = knightdir[loop];
  }
  for (loop = 0; loop < 8; loop++)
  {
    square = 0x80 + kingdir[loop];
    attacktab[square].pieceset += 64;
    attacktab[square].direction = kingdir[loop];
  }
  for (loop = 0; loop < 4; loop++)
  {
    square = 0x80;
    for (loop1 = 0; loop1 < 7; loop1++)
    {
      square += bishopdir[loop];
      attacktab[square].pieceset += 40;
      attacktab[square].direction = bishopdir[loop];
    }
  }
  for (loop = 0; loop < 4; loop++)
  {
    square = 0x80;
    for (loop1 = 0; loop1 < 7; loop1++)
    {
      square += rookdir[loop];
      attacktab[square].pieceset += 48;
      attacktab[square].direction = rookdir[loop];
    }
  }
}

int attacks(int player, int asquare, int vsquare)
{
  int offset, nsquare;
  int piecemask[7] = {1, 2, 4, 8, 16, 32, 64};
  offset = asquare - vsquare + 0x80;
  if ((attacktab[offset].pieceset & piecemask[board.square[asquare].piece.pieceno]) > 0)
  {
    if ((board.square[asquare].piece.pieceno > KNIGHT) && (board.square[asquare].piece.pieceno < KING))
    {
      nsquare = vsquare + attacktab[offset].direction;
      while ((board.square[nsquare].colour == EMPTY) && !(nsquare & 0x88))
      {
        nsquare += attacktab[offset].direction;
      }
      if (nsquare == asquare)
        return (TRUE);
    }
    else
      return (TRUE);
  }
  return (FALSE);
}

int repetition()
{
  int loop, repcount;

  repcount = 0;
  for (loop = board.boardflag.moveno; loop >= board.boardflag.move50; loop -= 2)
  {
    if (board.boardflag.transindex[0] == flaglist[loop].transindex[0])
      repcount++;
  }
  if (repcount > 2) return (TRUE);
  return (FALSE);
}

int search(int player, int depth, int alpha, int beta, struct pvtype * prevpv)
{
  int validmove;
  int maxval;
  struct movelisttype movelist;
  int loop,
      checkflag,
      histval;
  struct flagtype tflag;
  struct pvtype mypv =
  {0};
  player = opponent[player];
  if (alpha >= beta)
    abort();
  maxval = -10000;
  if (depth > 0)
    histval = (1 << depth);
  else
    histval = 1;
  if (depth >= 0 && incheck(player, piecetable[player].pieceentry[0]))
  {
    depth++;
    checkflag = TRUE;
  }
  else
    checkflag = FALSE;
  if (depth <= 0)
  {
    nodes++;
    maxval = evalmove(player);
    prevpv->pvlength = 0;
    if (alpha < maxval)
    {
      alpha = maxval;
      if (maxval >= beta)
      {
        return (maxval);
      }

      if (et >= maxtime)
      {
        return (maxval);
      }

    }
  }
  if (depth <= 0)
  {
    movelist.moveno = -1;
    gencaptures(player, &movelist);
  }
  else
  {
    movelist.moveno = -1;
    genmoves(player, &movelist);
  }
  if (depth > 0 && movelist.moveno == -1)
  {
    prevpv->pvlength = 0;
    if (checkflag)
      maxval = -10000;
    else
      maxval = 0;
  }
  for (loop = 0; loop <= movelist.moveno; loop++)
  {
    register struct transvaluetype *ti;
    int mval = 0,
        tbeta = beta;
    tflag = board.boardflag;
    playmove(player, movelist.move[loop]);
    ti = &(transtable[board.boardflag.transindex[0]]);
    if (repetition() > FALSE || ((board.boardflag.moveno - board.boardflag.move50) > 99))
    {
      mval = 0;
    }
    else
    {
      if (depth < howdeep)
        howdeep = depth;
      validmove = FALSE;
      if (ti->depth >= depth
          && ti->checksum == board.boardflag.transindex[1]
          && ti->mover == player)
      {
        mval = ti->transval;
        if (ti->bound == LOWER && mval > alpha)
          alpha = mval;
        else if (ti->bound == UPPER && tbeta > mval)
          tbeta = mval;
        else if (ti->bound == VALID)
          validmove = TRUE;
        mypv.pvlength = 0;
        transhits++;
      }
      if (alpha >= tbeta)
        validmove = TRUE;
      if (validmove == FALSE)
      {
        mval = -search(player, depth - 1, -tbeta, -alpha, &mypv);
        transadds++;
        ti->depth = depth;
        ti->transval = mval;
        ti->mover = player;
        ti->checksum = board.boardflag.transindex[1];
        if (mval <= alpha)
        {
          ti->bound = UPPER;
          ti->transval++;
        }
        else if (mval >= beta)
        {
          ti->bound = LOWER;
          ti->transval--;
        }
        else
          ti->bound = VALID;
      }
    }
    unplaymove(player, movelist.move[loop]);
    board.boardflag = tflag;
    if (mval > maxval)
    {
      *prevpv = mypv;
      prevpv->pvlength++;
      prevpv->pvmove[prevpv->pvlength] = movelist.move[loop];
      movehist[(movelist.move[loop].startsq & 7) + ((movelist.move[loop].startsq & 0x70) >> 1) + (((movelist.move[loop].endsq & 7) + ((movelist.move[loop].endsq & 0x70) >> 1)) << 6)] += histval;
      maxval = mval;
    }
    if (alpha < maxval)
    {
      alpha = maxval;
      if (maxval >= beta)
      {
        movehist[(movelist.move[loop].startsq & 7) + ((movelist.move[loop].startsq & 0x70) >> 1) + (((movelist.move[loop].endsq & 7) + ((movelist.move[loop].endsq & 0x70) >> 1)) << 6)] += histval;
        break;
      }
    }
  }
  return (maxval);
}

int firstlevel(int player)
{
  /* Handles moves at the top of the tree */
  struct movelisttype movelist;
  struct flagtype tflag;
  struct movetype bestmove =
  {0};
  struct pvtype mypv,
           bestpv =
  {0};
  int loop,
      et,
      st,
      osc = 0,
      research;
  int mval,
      maxval = -10000,
      alpha,
      beta,
      oldalpha,
      oldbestval = 30000,
      exitmove = 0;
  st = time(0);
  et = 0;
  movelist.moveno = -1;
  maxdepth = 1;
  research = FALSE;
  alpha = -900;
  beta = 10000;
  genmoves(player, &movelist);
  while ((timeleft) && (maxdepth < 32))
  {
    board.boardflag.incrementval[WHITE] = 0;
    board.boardflag.incrementval[BLACK] = 0;
    maxval = -10000;
    oldalpha = alpha;
    howdeep = 99;
    for (loop = 0; (loop <= movelist.moveno) && timeleft; loop++)
    {
      tflag = board.boardflag;
      playmove(player, movelist.move[loop]);
      mval = -search(player, maxdepth - 1, -beta, -alpha, &mypv);
      /* printf("Depth %d Alpha %d Beta %d Move %d Value
      * %d\n",maxdepth,alpha,beta,loop,mval); */
#if 0
      if ((mval < beta) && (mval > alpha))
      {
        mval = -search(player, maxdepth - 1, -beta, -mval, &mypv);
      }
#endif
      movelist.move[loop].movevalue = mval;
      if (mval > maxval)
      {
        maxval = mval;
        bestmove = movelist.move[loop];
        bestpv = mypv;
        bestpv.pvlength++;
        bestpv.pvmove[bestpv.pvlength] = movelist.move[loop];
        if (mval > alpha)
        {
          alpha = mval;
          if (alpha >= beta)
            alpha = beta - 1;
        }
      }
      board.boardflag = tflag;
      unplaymove(player, movelist.move[loop]);
      et = time(0) - st;
      if ((et >= maxtime) && (maxdepth > 2) && (maxval >= (oldbestval - 10)) && !research)
        timeleft = FALSE;
    }
    exitmove = loop;
    qsort((char *) movelist.move, movelist.moveno + 1, sizeof(movelist.move[0]), intcompare);
    if (disppv)
    {
      printf("%d %d %d %d ", maxdepth, maxval, et, nodes);

      for (loop = bestpv.pvlength; loop >= 1; loop--)
      {
        printf("%c%d", (bestpv.pvmove[loop].startsq % 16) + 97, (bestpv.pvmove[loop].startsq / 16) + 1);
        printf("%c%d ", (bestpv.pvmove[loop].endsq % 16) + 97, (bestpv.pvmove[loop].endsq / 16) + 1);
      }
      putchar('\n');
    }
    oldbestval = maxval;
    if (maxval <= oldalpha && osc == 0)
    {
      alpha = -10000;
      beta = maxval + 2;
      osc++;
      timeleft = TRUE;
      research = TRUE;
    }
    else if (maxval >= beta && osc == 0)
    {
      alpha = maxval - 2;
      beta = 10000;
      osc++;
    }
    else
    {
      alpha = maxval - 50;
      beta = maxval + 50;
      maxdepth++;
      osc = 0;
      research = FALSE;
    }
    if (beta <= -900)
      beta = -890;
    if (alpha >= 10000)
      alpha = 9990;
    if (!research && et >= maxtime)
      timeleft = FALSE;
    if (maxval == 10000)
      timeleft = FALSE;
  }
  if (disppv)
    printf("Exit move = %d.%d\n", maxdepth, exitmove);

  if (do_resign)
  {

    if (maxval > -RESIGNTHRESHOLD)
    {
      resigncounter = 0;
    }
    else
    {
      printf("# VanillaChess thinking about resigning\n");
      resigncounter++;
    }
    if (resigncounter > 3)
    {
      printf("# VanillaChess resigns\n");
      printf("resign\n");
      end_game = TRUE;

    }
  }

  if (!end_game)
  {
    bmove = bestmove;
    return (0);
  }

}

int CDECL
capcompare(const void *ii, const void *jj)
{
  struct movetype *i = (struct movetype *) ii;
  struct movetype *j = (struct movetype *) jj;
  if (i->capture.pieceno < j->capture.pieceno)
    return (1);
  if (i->capture.pieceno > j->capture.pieceno)
    return (-1);
  if (i->movevalue < j->movevalue)
    return (1);
  if (i->movevalue > j->movevalue)
    return (-1);
  return (0);
}

int CDECL
intcompare(const void *ii, const void *jj)
{
  struct movetype *i = (struct movetype *) ii;
  struct movetype *j = (struct movetype *) jj;
  if (i->movevalue < j->movevalue)
    return (1);
  if (i->movevalue > j->movevalue)
    return (-1);
  return (0);
}

void findbestmove(int player)
{
  if (gamestate < MATING)
    updatesquaretable();
  timeleft = TRUE;
  /* signal(SIGALRM,onalarm); */
  firstlevel(player);
}

void playmove(int player, struct movetype pmove)
{
  int otherp,
      pindex,
      oindex,
      piecehit,
      pawnsquare,
      loop,
      k;
  int offset[3] =
  {0, 0, 6};
  int pawndir[3] =
  {0, 0x10, -0x10};
  int pawnatt[3] =
  {0, 10, 50};
  otherp = opponent[player];
  board.boardflag.moveno++;
  board.boardflag.staticval[otherp] -= piecevalue[board.square[pmove.endsq].piece.pieceno];
  board.square[pmove.endsq] = board.square[pmove.startsq];
  board.square[pmove.startsq] = emptysquare;
  board.boardflag.incrementval[player] += (sv.squarevalue[player][pmove.piece.pieceno][pmove.endsq] - sv.squarevalue[player][pmove.piece.pieceno][pmove.startsq]);
  pindex = offset[player] + pmove.piece.pieceno;
  for (k = 0; k < 2; k++)
  {
    board.boardflag.transindex[k] += (transtindex[k][pindex][pmove.endsq] - transtindex[k][pindex][pmove.startsq] + transtindex[k][0][pmove.startsq]);
  }
  if (pmove.capture.pieceno > 0)
  {
    oindex = offset[otherp] + pmove.capture.pieceno;
    board.boardflag.incrementval[otherp] -= sv.squarevalue[otherp][pmove.capture.pieceno][pmove.endsq];
    for (k = 0; k < 2; k++)
      board.boardflag.transindex[k] -= transtindex[k][oindex][pmove.endsq];
    piecetable[otherp].pieceentry[pmove.capture.indexno] = -1;
    if (pmove.capture.pieceno == PAWN)
    {
      pawnfield[otherp][pmove.endsq % 16]--;
    }
    if (pmove.piece.pieceno == PAWN)
    {
      pawnfield[player][pmove.endsq % 16]++;
      pawnfield[player][pmove.startsq % 16]--;
    }
  }
  else
  {
    oindex = 0;
    for (k = 0; k < 2; k++)
      board.boardflag.transindex[k] -= transtindex[k][0][pmove.endsq];
  }
  piecetable[player].pieceentry[pmove.piece.indexno] = pmove.endsq;
  if (pmove.special == -1)
  {
    board.square[board.boardflag.enpas] = emptysquare;
    board.boardflag.staticval[otherp] -= 100;
    piecetable[otherp].pieceentry[pmove.capture.indexno] = -1;
  }
  board.boardflag.enpas = -1;
  if (pmove.piece.pieceno == KING)
  {
    if (abs(pmove.endsq - pmove.startsq) == 2)
    {
      if (pmove.startsq < pmove.endsq)
      {
        board.square[pmove.startsq + 1] = board.square[pmove.endsq + 1];
        board.square[pmove.endsq + 1] = emptysquare;
        piecetable[player].pieceentry[board.square[pmove.startsq + 1].piece.indexno] = pmove.startsq + 1;
      }
      else
      {
        board.square[pmove.startsq - 1] = board.square[pmove.endsq - 2];
        board.square[pmove.endsq - 2] = emptysquare;
        piecetable[player].pieceentry[board.square[pmove.startsq - 1].piece.indexno] = pmove.startsq - 1;
      }
      board.boardflag.incrementval[player] += 20;
    }
    board.boardflag.kingcastle[player] = FALSE;
    board.boardflag.queencastle[player] = FALSE;
  }
  if (pmove.piece.pieceno == PAWN)
  {
    if (pmove.special > 0)
    {
      pawnfield[player][pmove.endsq % 16]--;
      board.square[pmove.endsq].piece.pieceno = pmove.special;
      board.boardflag.staticval[player] += piecevalue[pmove.special] - 100;
      for (k = 0; k < 2; k++)
        board.boardflag.transindex[k] += (transtindex[k][offset[player] + pmove.special][pmove.endsq] - transtindex[k][offset[player] + PAWN][pmove.endsq]);
    }
    if (abs(pmove.endsq - pmove.startsq) == 0x20)
    {
      board.boardflag.enpas = pmove.endsq;
    }
    piecehit = 0;
    for (loop = -1; loop <= 1; loop += 2)
    {
      pawnsquare = pmove.endsq + pawndir[player] + loop;
      if (!(pawnsquare & 0x88) && (board.square[pawnsquare].colour == otherp) && (board.square[pawnsquare].piece.pieceno > PAWN))
      {
        piecehit++;
      }
    }
    board.boardflag.incrementval[player] += pawnatt[piecehit];
    board.boardflag.move50 = board.boardflag.moveno;
  }
  if (pmove.piece.pieceno == ROOK)
  {
    if (pmove.startsq % 16 == 0)
      board.boardflag.queencastle[player] = FALSE;
    if (pmove.startsq % 16 == 7)
      board.boardflag.kingcastle[player] = FALSE;
  }
  if (pmove.capture.pieceno != EMPTY)
  {
    board.boardflag.move50 = board.boardflag.moveno;
    if (pmove.endsq == 0x70)
      board.boardflag.queencastle[BLACK] = FALSE;
    if (pmove.endsq == 0x77)
      board.boardflag.kingcastle[BLACK] = FALSE;
    if (pmove.endsq == 0x0)
      board.boardflag.queencastle[WHITE] = FALSE;
    if (pmove.endsq == 0x7)
      board.boardflag.kingcastle[WHITE] = FALSE;
  }
  for (k = 0; k < 2; k++)
  {
    while (board.boardflag.transindex[k] < 0)
      board.boardflag.transindex[k] += TSIZE;
    board.boardflag.transindex[k] %= TSIZE;
  }
  flaglist[board.boardflag.moveno] = board.boardflag;
}

void unplaymove(int player, struct movetype pmove)
{
  int otherp;
  int pawndir[3] =
  {0, 0x10, -0x10};
  otherp = opponent[player];
  piecetable[player].pieceentry[pmove.piece.indexno] = pmove.startsq;
  board.square[pmove.startsq] = board.square[pmove.endsq];
  board.square[pmove.endsq] = emptysquare;
  if (pmove.capture.pieceno > 0)
  {
    piecetable[otherp].pieceentry[pmove.capture.indexno] = pmove.endsq;
    board.square[pmove.endsq].piece = pmove.capture;
    board.square[pmove.endsq].colour = otherp;
    if (pmove.capture.pieceno == PAWN)
      pawnfield[otherp][pmove.endsq % 16]++;
    if (pmove.piece.pieceno == PAWN)
    {
      pawnfield[player][pmove.endsq % 16]--;
      pawnfield[player][pmove.startsq % 16]++;
    }
  }
  if (pmove.piece.pieceno == KING)
  {
    if (abs(pmove.endsq - pmove.startsq) == 2)
    {
      if (pmove.startsq < pmove.endsq)
      {
        piecetable[player].pieceentry[board.square[pmove.endsq - 1].piece.indexno] = pmove.endsq + 1;
        board.square[pmove.endsq + 1] = board.square[pmove.endsq - 1];
        board.square[pmove.endsq - 1] = emptysquare;
      }
      else
      {
        piecetable[player].pieceentry[board.square[pmove.endsq + 1].piece.indexno] = pmove.endsq - 2;
        board.square[pmove.endsq - 2] = board.square[pmove.endsq + 1];
        board.square[pmove.endsq + 1] = emptysquare;
      }
    }
  }
  if (pmove.piece.pieceno == PAWN)
  {
    if (pmove.special > 0)
    {
      board.square[pmove.startsq].piece.pieceno = PAWN;
      pawnfield[player][pmove.endsq % 16]++;
    }
    if (pmove.special == -1)
    {
      board.square[pmove.endsq - pawndir[player]].piece = pmove.capture;
      board.square[pmove.endsq - pawndir[player]].colour = otherp;
      board.square[pmove.endsq] = emptysquare;
      piecetable[otherp].pieceentry[pmove.capture.indexno] = pmove.endsq - pawndir[player];
    }
  }
}

int incheck(int player, int nsquare)
{
  int loop,
      checksquare,
      otherp;
  int pawndir[3] =
  {0, 0x10, -0x10};
  otherp = opponent[player];
  for (loop = -1; loop <= 1; loop += 2)
  {
    checksquare = nsquare + pawndir[player] + loop;
    if (!(checksquare & 0x88) && (board.square[checksquare].colour == otherp) && (board.square[checksquare].piece.pieceno == PAWN))
      return (TRUE);
  }
  for (loop = 0; loop < 16; loop++)
  {
    if (piecetable[otherp].pieceentry[loop] > -1)
      if (attacks(player, piecetable[otherp].pieceentry[loop], nsquare))
        return (TRUE);
  }
  return (FALSE);
}
