Saturday, May 4, 2019

main.cpp

#include "stdafx.h"
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include <iostream>

#include <sys/timeb.h>

#include "globals.h"

void ShowHelp();
void SetUp();

bool ftime_ok = false;  /* does ftime return milliseconds? */
//
void xboard();

//diagram stuff
int LoadDiagram(char* file,int);
int GetSquare(char file,char rank);
int GetPiece(char b);

int pos[100][3][16][3];
int startpos[100];
int diag_number;

int ponder;

FILE *diagram_file;
char fen_name[256];

int flip = 0;

int number=0;

int computer_side;
int player[2];

int fixed_time;
int fixed_depth;
int max_time;
int start_time;
int stop_time;
int max_depth;
int turn = 0;

void print_result();
void NewGame();

void SetMaterial();

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

char *move_str(int start,int dest,int bits,int promote)
{
static char str[6];

char c;

if (bits & 32) {
switch (promote) {
case N:
c = 'n';
break;
case B:
c = 'b';
break;
case R:
c = 'r';
break;
default:
c = 'q';
break;
}
sprintf_s(str, "%c%d%c%d%c",
col[start] + 'a',
row[start] + 1,
col[dest] + 'a',
row[dest] + 1,
c);
}
else
sprintf_s(str, "%c%d%c%d",
col[start] + 'a',
row[start] + 1,
col[dest] + 'a',
row[dest] + 1);
return str;
}

int main()
{
printf("\n");
printf("Bills bare bones chess engine\n");
printf("bv 8, 18/7/18\n");
printf("Copyright 2018 Bill Jordan \n");
printf("\n");
printf("\"help\" displays a list of commands.\n");
printf("\n");

char s[256];
char sFen[256];
char sText[256];
int m;
int turns=0;
int editmode=0;
int analyze=0;
int np=0;
int edit_color=0;
int sq=0;
int t;
int lookup;

double nps;

fixed_time = 0;

SetUp();

while(true)
{
diag_number=0;
if (side == computer_side)

player[side] = 1;
think();
turns++;

currentkey = GetKey();
currentlock = GetLock();
lookup = LookUp(side);
if(lookup != 0)
{
   printf("\n lookup %d ",lookup);
   Alg(hash_start,hash_dest);printf("\n");
}
else
{
printf("(no legal moves)\n");
computer_side = EMPTY;
print_board();
Gen();
continue;
}       

printf("\n hash %d ",hashpositions[0]);
printf(" hash %d ",hashpositions[1]);
printf(" collisions %d ",collisions);
printf("\n");
collisions = 0;

printf("Computer's move: %s\n", move_str(hash_start,hash_dest,0,0));printf("\n");
MakeMove(hash_start,hash_dest);

SetMaterial();

t = get_ms() - start_time;
printf("\nTime: %d ms\n", t);
    if(t>0)
      nps = (double)nodes / (double)t;
    else
      nps=0;
nps *= 1000.0;

printf("\nNodes per second: %d\n", (int)nps);
ply = 0;

first_move[0] = 0;//11/12/12
Gen();
print_result();

    printf(" turn "); printf("%d",turn++);
print_board();
continue;
}
printf("Enter move or command> ");
if (scanf("%s", s) == EOF)
return 0;
if (!strcmp(s, "quit"))
    {
printf("Program exiting\n");
break;
}
if (!strcmp(s, "go"))
    {
computer_side = side;
continue;
}
   if (!strcmp(s, "sb"))
   {
sFen[0] = 0;
strcat_s(sFen,"c:\\bscp\\");//
        scanf("%s", sText);
strcat_s(sFen,sText);
        strcat_s(sFen,".fen");
LoadDiagram(sFen,1);
continue;
}
if (!strcmp(s, "on") || !strcmp(s, "p")) {
computer_side = side;
continue;
}
if (!strcmp(s, "off")) {
computer_side = EMPTY;
continue;
}
        if (!strcmp(s, "random")) {
continue;
}
if (!strcmp(s, "st")) {
scanf("%d", &max_time);
max_time *= 1000;
max_depth = MAX_PLY;
fixed_time = 1;
continue;
}
if (!strcmp(s, "sd")) {
scanf("%d", &max_depth);
max_time = 1 << 25;
fixed_depth = 1;
continue;
}
if (!strcmp(s, "undo")) {
if (!hply)
continue;
computer_side = EMPTY;
TakeBack();
ply = 0;
if(first_move[0] != 0)
first_move[0] = 0;
Gen();
continue;
}
if (!strcmp(s, "new"))
{
NewGame();
computer_side = EMPTY;
continue;
}
if (!strcmp(s, "d")) {
print_board();
printf("\n key %d ",currentkey);
printf("\n lock %d ",currentlock);
continue;
}
        if (!strcmp(s, "f")) {
flip = 1 - flip;
            print_board();
continue;
}
        if (!strcmp(s, "sw")) {
        side = 1-side;
            xside = 1-xside;
continue;
}
        if (!strcmp(s, "moves")) {   
printf("Moves \n");
            move *g;
            for (int i = 0; i < first_move[1]; ++i)
            {
g = &move_list[i];
printf("%s",move_str(move_list[i].start,move_list[i].dest,0,move_list[i].promote));
printf("\n");
            }
continue;
}
if (!strcmp(s, "sb")) {
sFen[0] = 0;
strcat_s(sFen,"c:\\bscp\\");//
            scanf("%s", sText);
strcat_s(sFen,sText);//
            strcat_s(sFen,".fen");
LoadDiagram(sFen,1);
continue;
}
if (!strcmp(s, "bye")) {
printf("Share and enjoy!\n");
break;
}
if (!strcmp(s, "xboard")) {
xboard();
break;
}     
if (!strcmp(s, "help")) {
ShowHelp();
continue;
}

/* maybe the user entered a move? */
ply = 0;
  if(first_move[0] != 0)
      first_move[0] = 0;
Gen();
  m = parse_move(s);
if (m == -1 || !MakeMove(move_list[m].start,move_list[m].dest))
{
printf("Illegal move. \n");
printf(s);printf(" \n");
move_str(move_list[m].start,move_list[m].dest,0,move_list[m].promote);
if (m == -1)printf(" m = -1 \n");
}
if(game_list[hply].promote >0 && (row[move_list[m].dest]==0 || row[move_list[m].dest]==7))
{
RemovePiece(xside,Q,move_list[m].dest);
if(s[4]=='n' || s[4]=='N')
AddPiece(xside,N,move_list[m].dest);
else if(s[4]=='b' || s[4]=='B')
AddPiece(xside,B,move_list[m].dest);
else if(s[4]=='r' || s[4]=='r')
AddPiece(xside,R,move_list[m].dest);
else AddPiece(xside,Q,move_list[m].dest);
}
}
    Free();
return 0;
}

/* parse the move s (in coordinate notation) and return the move's
   indx in move_list, or -1 if the move is illegal */

int parse_move(char *s)
{
int start, dest, i;

if (s[0] < 'a' || s[0] > 'h' ||
s[1] < '0' || s[1] > '9' ||
s[2] < 'a' || s[2] > 'h' ||
s[3] < '0' || s[3] > '9')
return -1;

    start = s[0] - 'a';
    start += ((s[1] - '0') - 1)*8;
    dest = s[2] - 'a';
    dest += ((s[3] - '0') - 1)*8;

for (i = 0; i < first_move[1]; ++i)
if (move_list[i].start == start && move_list[i].dest == dest)
        {
return i;
    }
return -1;
}
/* print_board() prints the board */

void print_board()
{
int flip = 0;
int i, x=0;

printf("\n8 ");
    if(flip==0)
    {
for (int j = 0; j < 64; ++j)
    {
        i = Flip[j];
        {
    switch (color[i])
        {
case EMPTY:
                if(x==0)
printf(" .");
                else
                printf(". ");
break;
case 0:
            if(x==0)
printf(" %c", piece_char[board[i]]);
                else
                printf("%c ", piece_char[board[i]]);
break;
case 1:
            if(x==0)
printf(" %c", piece_char[board[i]] + ('a' - 'A'));
                else
                printf("%c ", piece_char[board[i]] + ('a' - 'A'));
break;
default:
if(x==0)
printf(" %d.",color[i]);
                else
                printf(".%d ",color[i]);
break;
}
if((color[i]==0 || color[i]==1) && board[i]==6)
if(x==0)
printf(" %d",color[i]);
        else
            printf("%d ",color[i]);
if(board[i]<0 || board[i]>6)
if(x==0)
printf(" %d.",board[i]);
        else
            printf("%d ",board[i]);
        }
if ((j + 1) % 8 == 0 && j != 63)
printf("\n%d ", row[i]);
}
printf("\n\n   a b c d e f g h\n\n");
    }

     if(flip==1)
    {
  for (int j = 0; j < 64; ++j) {
        i = 63-Flip[j];
switch (color[i])
{
case EMPTY:
printf(" .");
break;
case 0:
printf(" %c", piece_char[board[i]]);
break;
case 1:
printf(" %c", piece_char[board[i]] + ('a' - 'A'));
break;
}
if ((j + 1) % 8 == 0 && row[i] != 7)
printf("\n%d ",  row[j]+2);//7-
}
printf("\n\n   h g f e d c b a\n\n");
    }
}

/* xboard() is a substitute for main() that is XBoard
   and WinBoard compatible. See the following page for details:
   http://www.research.digital.com/SRC/personal/mann/xboard/engine-intf.html */

void xboard()
{
int computer_side;
char line[256], command[256];
int m;
int post = 0;
int analyze = 0;
int lookup;

signal(SIGINT, SIG_IGN);
printf("\n");
NewGame();
fixed_time = 0;
computer_side = EMPTY;
   
while(true)
{
fflush(stdout);
if (side == computer_side)
{
think();
SetMaterial();
Gen();
currentkey = GetKey();
currentlock = GetLock();
lookup = LookUp(side);

move_list[0].start = hash_start;
            move_list[0].dest = hash_dest;
     
printf("move %s\n", move_str(hash_start,hash_dest,0,0));

MakeMove(hash_start,hash_dest);
 
ply = 0;
Gen();
print_result();
continue;
}
if (!fgets(line, 256, stdin))
return;
if (line[0] == '\n')
continue;
sscanf(line, "%s", command);
if (!strcmp(command, "xboard"))
continue;
if (!strcmp(command, "new"))
{
NewGame();
computer_side = 1;
continue;
}
if (!strcmp(command, "quit"))
return;
if (!strcmp(command, "force"))
{
computer_side = EMPTY;
continue;
}
if (!strcmp(command, "white"))
{
side = 0;
xside = 1;
Gen();
computer_side = 1;
continue;
}
if (!strcmp(command, "black"))
{
side = 1;
xside = 0;
Gen();
computer_side = 0;
continue;
}
if (!strcmp(command, "st"))
{
sscanf(line, "st %d", &max_time);
max_time *= 1000;
max_depth = MAX_PLY;
fixed_time = 1;
continue;
}
if (!strcmp(command, "sd"))
{
sscanf(line, "sd %d", &max_depth);
max_time = 1 << 25;
continue;
}
if (!strcmp(command, "time"))
{
sscanf(line, "time %d", &max_time);
if(max_time < 200)
  max_depth = 1;
else
{
max_time /= 2;
max_depth = MAX_PLY;
}
continue;
}
if (!strcmp(command, "otim"))
{
continue;
}
if (!strcmp(command, "go"))
{
computer_side = side;
continue;
}
if (!strcmp(command, "random"))
continue;
if (!strcmp(command, "level"))
continue;
if (!strcmp(command, "hard"))
continue;
if (!strcmp(command, "easy"))
continue;
if (!strcmp(command, "hint"))
{
think();
currentkey = GetKey();
currentlock = GetLock();
lookup = LookUp(side);
if(hash_start==0 && hash_dest==0)
continue;
printf("Hint: %s\n", move_str(hash_start,hash_dest,0,0));
continue;
}
if (!strcmp(command, "undo"))
{
if (!hply)
continue;
TakeBack();
ply = 0;
Gen();
continue;
}
if (!strcmp(command, "remove"))
{
if (hply < 2)
continue;
TakeBack();
TakeBack();
ply = 0;
Gen();
continue;
}
if (!strcmp(command, "post"))
{
post = 2;
continue;
}
if (!strcmp(command, "nopost"))
{
post = 0;
continue;
}
first_move[0] = 0;
Gen();

m = parse_move(line);
if (m == -1 || !MakeMove(move_list[m].start,move_list[m].dest))
printf("Error (unknown command): %s\n", command);
else
{
ply = 0;
  Gen();
print_result();
}
}
}

void NewGame()
{
InitBoard();
    first_move[0] = 0;
turn = 0;
fifty = 0;
ply = 0;
hply = 0;
Gen();
}

void print_result()
{
int i;
    int flag=0;

SetMaterial();
Gen();
for (i = 0; i < first_move[1]; ++i)
if (MakeMove(move_list[i].start,move_list[i].dest))
        {
TakeBack();
            flag=1;
break;
}

    if(pawn_mat[0]==0 && pawn_mat[1]==0 && piece_mat[0]<=300 && piece_mat[1]<=300)
    {
printf("1/2-1/2 {Stalemate}\n");
NewGame();
computer_side = EMPTY;
return;
    }
if (i == first_move[1] && flag==0)
    {
Gen();
        printf(" end of game ");

if (Attack(xside,kingloc[side]))
        {
if (side == 0)
{
printf("0-1 {Black mates}\n");
}
else
{
printf("1-0 {White mates}\n");
}
}
else
{
printf("1/2-1/2 {Stalemate}\n");
}
NewGame();
computer_side = EMPTY;
}
else if (reps() >= 3)
{
printf("1/2-1/2 {Draw by repetition}\n");
NewGame();
computer_side = EMPTY;
}
else if (fifty >= 100)
{
printf("1/2-1/2 {Draw by fifty move rule}\n");
NewGame();
computer_side = EMPTY;
}
if(turn>300)
{
printf("1/2-1/2 {>300 moves}\n");
NewGame();
computer_side = EMPTY;
return;
}
}

void SetMaterial()
{
pawn_mat[0]=0;
pawn_mat[1]=0;
piece_mat[0]=0;
piece_mat[1]=0;
for(int x=0;x<64;x++)
{
if(board[x]<6)
{
if(board[x]==5)
kingloc[color[x]] = x;
if(board[x]==0)
pawn_mat[color[x]] += 100;
else
piece_mat[color[x]] += piece_value[board[x]];
}
}
}

int reps()
{
int r = 0;

for (int i = hply - 1; i >= hply-fifty; i-=2)
if (game_list[i].hash == currentkey && game_list[i].lock == currentlock)
++r;
return r;
}

void CloseDiagram()
{
if (diagram_file)
    fclose(diagram_file);
diagram_file = NULL;
}

int LoadDiagram(char* file,int num)
{
int x,n=0;
static int count=1;
char ts[200];

diagram_file = fopen(file, "r");
if (!diagram_file)
{
printf("Diagram missing.\n");
return -1;
}

strcpy_s(fen_name,file);

for(x=0;x<num;x++)
{
fgets(ts, 256, diagram_file);
if(!ts) break;
}

for(x=0;x<64;x++)
{
board[x]=EMPTY;
color[x]=EMPTY;
}
int c=0,i=0,j;

while(ts)
{
if(ts[c]>='0' && ts[c]<='8')
i += ts[c]-48;
if(ts[c]=='\\')
continue;
j=Flip[i];

switch(ts[c])
{
case 'K': board[j]=K; color[j]=0;i++;
kingloc[0]=j;break;
case 'Q': board[j]=Q;color[j]=0;i++;break;
case 'R': board[j]=R; color[j]=0;i++;break;
case 'B': board[j]=B; color[j]=0;i++;break;
case 'N': board[j]=N; color[j]=0;i++;break;
case 'P': board[j]=P; color[j]=0;i++;break;
case 'k': board[j]=K; color[j]=1;i++;

  kingloc[1]=j;break;
case 'q': board[j]=Q;color[j]=1;i++;break;
case 'r': board[j]=R; color[j]=1;i++;break;
case 'b': board[j]=B; color[j]=1;i++;break;
case 'n': board[j]=N; color[j]=1;i++;break;
case 'p': board[j]=P; color[j]=1;i++;break;
}
c++;
if(ts[c]==' ')
  break;
if(i>63)
  break;
}
if(ts[c]==' ' && ts[c+2]==' ')
{
if(ts[c+1]=='w')
{
side=0;xside=1;
}
if(ts[c+1]=='b')
{
side=1;xside=0;
}
}

game_list[0].castle_q[0] = 0;
game_list[0].castle_q[1] = 0;
game_list[0].castle_k[0] = 0;
game_list[0].castle_k[1] = 0;

while(ts[c])
{
switch(ts[c])
{
case '-': break;
case 'K':if(board[E1]==5 && color[E1]==0) game_list[0].castle_q[0] = 1;break;
case 'Q':if(board[E1]==5 && color[E1]==0) game_list[0].castle_q[1] = 1;break;
case 'k':if(board[E8]==5 && color[E8]==1) game_list[0].castle_k[0] = 1;break;
case 'q':if(board[E8]==5 && color[E8]==1) game_list[0].castle_k[1] = 1;break;
default:break;
}
c++;
}

CloseDiagram();
print_board();
NewPosition();
Gen();
printf(" diagram # %d \n",num+count);
count++;
if(side==0)
  printf("White to move\n");
else
  printf("Black to move\n");
printf(" %s \n",ts);
return 0;
}

void ShowHelp()
{

}

void SetUp()
{
RandomizeHash();
FreeAllHash();
SetTables();
SetMoves();
InitBoard();
Gen();
computer_side = EMPTY;
player[0] =0;
player[1] = 0;
max_time = 1 << 25;
max_depth = 4;
}

search.cpp

#include <setjmp.h>

#include "globals.h"

void SetHashMove();
void DisplayPV(int i);

jmp_buf env;
bool stop_search;

int currentmax;

/*

think() iterates until the maximum depth for the move is reached or until the allotted time
has run out.
After each iteration the principal variation is then displayed.

*/
void think()
{
int x;

stop_search = false;

setjmp(env);
if (stop_search)
{
while (ply)
TakeBack();
return;
}
if(fixed_time==0)
{
if(game_list[hply-1].capture < 6 && game_list[hply-1].capture == board[game_list[hply-1].dest])
{
max_time = max_time/2;
}

else if (Attack(xside,kingloc[side]))
{
max_time = max_time/2;
}
}
start_time = get_ms();
stop_time = start_time + max_time;

ply = 0;
nodes = 0;
 
NewPosition();
memset(history, 0, sizeof(history));
printf("ply      nodes  score  pv\n");

for (int i = 1; i <= max_depth; ++i)
{
currentmax = i;
if(fixed_depth==0)
if(fixed_time==1)
{
if(get_ms() >= start_time + max_time)
{
stop_search = true;
    return;
}
}
else if(get_ms() >= start_time + max_time/4)
    {
stop_search = true;
  return;
    }

    x = Search(-10000, 10000, i);

printf("%d %d %d %d ", i, x, (get_ms() - start_time) / 10, nodes);

if(LookUp(side))
{
DisplayPV(i);
}
printf("\n");
fflush(stdout);

if (x > 9000 || x < -9000)
{
break;
}
}
}
/*

search is the main part of the search.
If the position is repeated we don't need to look any further.
If depth has run out, the capture search is done.
Every 4,000 positions approx the time is checked.
Moves are generated.
The moves are looped through in order of their score.
If a move is illegal (for example, if it attempts to move a pinned piece)
then it is skipped over.
If the move is check, we extend by one ply. This is done by not changing depth in the call to search.
If it has a score greater than zero, ply is one or the move number is less than 12
a normal search is done. This is done by subtracting 1 from depth.
Otherwise we reduce by one ply. This is done by subtracting 2 from depth.
The move is taken back.

If the score from search is greater than beta, a beta cutoff happens. No need to
search any moves at this depth.
Otherwise, if it is greater than alpha, alpha is changed.

If there were no legal moves it is either checkmate or stalemate.

*/
int Search(int alpha, int beta, int depth)
{
if (ply && reps2())
{
return 0;
}

if (depth < 1)
return CaptureSearch(alpha,beta);

nodes++;

if ((nodes & 4095) == 0)
{
CheckUp();
}

if (ply > MAX_PLY-2)
return Eval();

move bestmove;

int bestscore = -10001;

int check = 0;

if (Attack(xside,kingloc[side]))
{
check = 1;
}
Gen();

if(LookUp(side))
  SetHashMove();

int c = 0;
int x;
int d;

int top = move_list[first_move[ply]].score;//

for (int i = first_move[ply]; i < first_move[ply + 1]; ++i)
{
    if(top>0)
top = Sort(i);

if (!MakeMove(move_list[i].start,move_list[i].dest))
{
continue;
}
c++;

if (Attack(xside,kingloc[side]))
{
d = depth;
}
else
{
   d = depth - 2;
if(move_list[i].score > CAPTURE_SCORE || c==1 || check==1)
{
   d = depth - 1;
}
else if(move_list[i].score > 0)
{
d = depth - 2;
}
}
x = -Search(-beta, -alpha, d);

TakeBack();

if(x > bestscore)
{
bestscore = x;
bestmove = move_list[i];
}
if (x > alpha)
{
if (x >= beta)
{
if(board[move_list[i].dest]==6)  
history[move_list[i].start][move_list[i].dest] += depth;
AddHash(side, move_list[i]);
return beta;
}
alpha = x;
}
}
if (c == 0)
{
if (Attack(xside,kingloc[side]))
{
return -10000 + ply;
}
else
return 0;
    }

if (fifty >= 100)
return 0;
AddHash(side, bestmove);
return alpha;
}
/*

CaptureSearch evaluates the position. If the position is more than a queen less than
alpha (the best score that side can do) it doesn't search.
It generates all captures and does a recapture search to see if material is won.
If so, the material gain is added to the score.

*/
int CaptureSearch(int alpha,int beta)
{
nodes++;

int x = Eval();

if (x > alpha)
{
if(x >= beta)
{
return beta;
}
alpha = x;
}
else if(x + 900 < alpha)
return alpha;

int score = 0, bestmove = 0;
int best = 0;

GenCaptures();

for (int i = first_move[ply]; i < first_move[ply + 1]; ++i)
{
Sort(i);

if(x + piece_value[board[move_list[i].dest]] < alpha)
{
continue;
}

    score = ReCaptureSearch(move_list[i].start, move_list[i].dest);

if(score>best)
{
best = score;
bestmove = i;
}
}

if(best>0)
{
x += best;
}
if (x > alpha)
{
if (x >= beta)
{
if(best>0)
AddHash(side, move_list[bestmove]);
return beta;
}
return x;
}

return alpha;
}
/*

ReCaptureSearch searches the outcome of capturing and recapturing on the same square.
It stops searching if the value of the capturing piece is more than that of the
captured piece and the next attacker. For example, a White queen could take a rook, but a
bishop could take the queen. Even if White could take the bishop, its not worth exchanging a
queen for rook and bishop.

*/
int ReCaptureSearch(int a,const int sq)
{
int b;
int c = 0;
int t = 0;
int score[12];

memset(score,0,sizeof(score));
score[0] = piece_value[board[sq]];
score[1] = piece_value[board[a]];

int total_score = 0;

while(c < 10)
{
if(!MakeRecapture(a,sq))
break;
t++;
nodes++;
c++;

b = LowestAttacker(side,sq);

if(b>-1)
{
score[c + 1] = piece_value[board[b]];
if(score[c] > score[c - 1] + score[c + 1])
{
c--;
break;
}
}
else
{
break;
}
a = b;
}

while(c>1)
{
if(score[c-1] >= score[c-2])
c -= 2;
else
break;
}

for(int x=0; x < c; x++)
{
if(x%2 == 0)
total_score += score[x];
else
total_score -= score[x];
}

while(t)
{
UnMakeRecapture();
t--;
}

return total_score;
}
/*

reps2() searches backwards for an identical position.
A positions are identical if the key and lock are the same.
'fifty' represents the number of moves made since the last pawn move or capture.

*/
int reps2()
{
for (int i = hply-4; i >= hply-fifty; i-=2)
{
if (game_list[i].hash == currentkey && game_list[i].lock == currentlock)
{
return 1;
}
}
return 0;
}
/*

Sort searches the move list for the move with the highest score.
It is moved to the top of the list so that it will be played next.

*/
int Sort(const int from)
{
move g;

int bs = move_list[from].score;
int bi = from;
for (int i = from + 1; i < first_move[ply + 1]; ++i)
if (move_list[i].score > bs)
{
bs = move_list[i].score;
bi = i;
}

g = move_list[from];
move_list[from] = move_list[bi];
move_list[bi] = g;

return move_list[bi].score;
}
/*

checkup checks to see if the time has run out.
If so, the search ends.

*/
void CheckUp()
{
if( (get_ms() >= stop_time || (max_time<50 && ply>1)) && fixed_depth==0)
{
stop_search = true;
longjmp(env, 0);
}
}
/*

SetHashMove searches the move list for the move from the Hash Table.
If it finds it, it sets the move a high score so that it will be played first.

*/
void SetHashMove()
{

for(int x=first_move[ply];x < first_move[ply+1];x++)
{
 if(move_list[x].start == hash_start && move_list[x].dest == hash_dest)
 {
move_list[x].score = HASH_SCORE;
return;
  }
}

}
/*

DisplayPV displays the principal variation(PV). This is the best line of play by both sides.
Firstly it displays the best move at the root.
It plays this move so that the current hash key and lock will be correct.
It looks up the Hash Table and finds the best move at the greater depth and
continues until no more best moves can be found.
Lastly, it takes back the moves, returning to the original position.

*/
void DisplayPV(int i)
{
Alg(hash_start,hash_dest);
for(int x=0;x < i;x++)
{
if(LookUp(side)==false)
break;
printf(" ");
Alg(hash_start,hash_dest);
MakeMove(hash_start,hash_dest);
}
while (ply)
TakeBack();
}

hash.cpp

#include "globals.h"

U64 hash[2][6][64];
U64 lock[2][6][64];

U64 currentkey,currentlock;
U64 collisions;

const U64 MAXHASH =  5000000;
const U64 HASHSIZE = 5000000;

int hash_start,hash_dest;
/*

A hash table entry includes a lock and start and dest squares.

*/
struct hashp
{
U64 hashlock;
int start;
int dest;
int num;
};

hashp *hashpos[2];
unsigned int  hashpositions[2];
/*

RandomizeHash is called when the engine is started.
The whitehash, blackhash, whitelock and blacklock tables
are filled with random numbers.

*/
void RandomizeHash()
{
int p,x;
for(p=0;p<6;p++)
for(x=0;x<64;x++)
{
hash[0][p][x] = Random(HASHSIZE);
hash[1][p][x]= Random(HASHSIZE);
lock[0][p][x]= Random(HASHSIZE);
lock[1][p][x]= Random(HASHSIZE);
}
hashpos[0] = new hashp[MAXHASH];
hashpos[1] = new hashp[MAXHASH];
}
/*

Random() generates a random number up to the size of x.

*/
int Random(const int x)
{
return rand() % x;
}
/*

Free() Frees memory that was allocated to the hashpos pointers

with new.

*/
void Free()
{
delete hashpos[0];
delete hashpos[1];
}
/*

FreeAllHash() empties the Hash Tables.

*/
void FreeAllHash()
{
hashpositions[0]=0;
hashpositions[1]=0;
}
/*
Adds an entry into the HashTable.
If that index is already being used, it simply overwrites it.

*/
void AddHash(const int s, const move m)
{
hashp* ptr = &hashpos[s][currentkey];
ptr->hashlock = currentlock;
ptr->start=m.start;
ptr->dest=m.dest;
}
/*

AddKey updates the current key and lock.
The key is a single number representing a position.
Different positions may map to the same key.
The lock is very similar to the key (its a second key), which

is a different number
because it was seeded with different random numbers.
While the odds of several positions having the same key are
very high, the odds of
two positions having the same key and same lock are very very
low.

*/
void AddKey(const int s,const int p,const int x)
{
  currentkey ^= hash[s][p][x];
  currentlock ^= lock[s][p][x];
}
/*

GetLock gets the current lock from a position.

*/
U64 GetLock()
{
U64 loc=0;
for(int x=0;x<64;x++)
{
if(board[x]!=6)
    loc ^= lock[color[x]][board[x]][x];
}
return loc;
}
/*

GetKey gets the current key from a position.

*/
U64 GetKey()
{
U64 key=0;
for(int x=0;x<64;x++)
{
if(board[x]!=6)
    key ^= hash[color[x]][board[x]][x];
}
return key;
}
/*

Looks up the current position to see if it is in the HashTable.
If so, it fetches the move stored there.

*/
bool LookUp(const int s)
{
if(hashpos[s][currentkey].hashlock != currentlock)
{
  return false;
}

hash_start = hashpos[s][currentkey].start;
hash_dest = hashpos[s][currentkey].dest;
return true;
}

eval.cpp

#include "globals.h"

#define ISOLATED 20

int EvalPawn(const int x);
int EvalRook(const int s,const int x);
bool Pawns(const int s,const int file);
bool Pawns2(const int s,const int xs,const int start);

int queenside_pawns[2],kingside_pawns[2];

const int queenside_defence[2][64]=
{
{
0, 0, 0, 0, 0, 0, 0, 0,
8,10, 8, 0, 0, 0, 0, 0,
8, 6, 8, 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, 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, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
8, 6, 8, 0, 0, 0, 0, 0,
8,10, 8, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
}};

const int kingside_defence[2][64]=
{
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 8,10, 8,
0, 0, 0, 0, 0, 8, 6, 8,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
8, 6, 8, 0, 0, 8, 8, 8,
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,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 8, 6, 8,
0, 0, 0, 0, 0, 8,10, 8,
0, 0, 0, 0, 0, 0, 0, 0
}};
/*

Eval() is simple. Firstly it fetches the table scores which were updated whenever moves were
updated.

It then looks up the pawn hash table. If the pawn position is not
already stored it evaluates the pawns and adds the scores to the pawn hash table.
It adds the pawn scores for each side.

It then adds a score for the king position depending on how much material the opponent has.
It adds a bonus for a pawn or piece in front of the King. (A very simple King defence score).

It turn returns the side to moves score minus the opponent's score.

There are plenty of things that could be added to the eval function.

*/
int Eval()
{
int score[2] = {0,0};
int queens[2] = {0,0};

queenside_pawns[0] = 0;
queenside_pawns[1] = 0;
kingside_pawns[0] = 0;
kingside_pawns[1] = 0;

for(int x = 0;x < 64;x++)
{
if(color[x] != EMPTY)
{
score[color[x]] += square_score[color[x]][board[x]][x];
if(board[x] == P)
{
score[color[x]] += EvalPawn(x);
}
else if(board[x] == R)
{
score[color[x]] += EvalRook(color[x],x);
}
else if(board[x] == Q)
{
queens[color[x]] = 1;
}
}
}
  if(queens[1]==0)
    score[0] += king_endgame[0][kingloc[0]];
  else
  {
if(col[kingloc[0]]>3)
score[0] += kingside_pawns[0];
else
score[0] += queenside_pawns[0];
  }

  if(queens[0]==0)
    score[1] += king_endgame[1][kingloc[1]];
   else
  {
if(col[kingloc[0]]>3)
score[1] += kingside_pawns[0];
else
score[1] += queenside_pawns[0];
  }

  return score[side] - score[xside];
}
/*

EvalPawn() evaluates each pawn and gives a bonus for passed pawns
and a minus for isolated pawns.

*/
int EvalPawn(const int x)
{
int score = 0;
int s = color[x];
int xs = OtherSide[s];

if(!Pawns2(s,xs,x))
{
score += passed[s][x];
}
if( (col[x]==0 || !Pawns(s,col[x]-1)) && (col[x]==7 || !Pawns(s,col[x]+1)) )
score -= ISOLATED;
kingside_pawns[s] += kingside_defence[s][x];
queenside_pawns[s] += queenside_defence[s][x];

return score;
}
/*

EvalRook() evaluates each rook and gives a bonus for being
on an open file or half-open file.
*/
int EvalRook(const int s,const int x)
{
int score = 0;
if(!Pawns(s,col[x]))
{
score = 10;
if(!Pawns(OtherSide[s],col[x]))
score += 10;
}
return score;
}
/*

Pawns() searches for pawns on a file.
It is used to detect isolated pawns.

*/
bool Pawns(const int s,const int file)
{
for(int x = file + 8;x < A8; x += 8)
{
if(board[x]==P && color[x]==s)
return true;
}
return false;
}
/*

Pawns2() searches for pawns on a file beyond a square.
It is used to detect passed pawns.

*/
bool Pawns2(const int s,const int xs,const int start)
{
int x = start + ForwardSquare[s];
while(x>H2 && x<A7)
{
if(board[x]==P && color[x]==xs)
return true;
if(col[x]>0 && board[x-1]==P && color[x-1]==xs)
return true;
if(col[x]<7 && board[x+1]==P && color[x+1]==xs)
return true;
x += ForwardSquare[s];
}
return false;
}

update.cpp

#include "globals.h"

int ReverseSquare[2] = {-8,8};

game* g;
/*

UpdatePiece updates the Hash Table key, the board and the table_score (the incremental
evaluation) whenever a piece moves.

*/
void UpdatePiece(const int s,const int p,const int start,const int dest)
{
AddKey(s,p,start);
AddKey(s,p,dest);
board[dest]=p;
color[dest]=s;
board[start]=EMPTY;
color[start]=EMPTY;
if(p==K)
kingloc[s] = dest;
}
/*

RemovePiece updates the Hash Table key, the board and the table_score (the incremental
evaluation) whenever a piece is removed.

*/
void RemovePiece(const int s,const int p,const int sq)
{
AddKey(s,p,sq);
board[sq]=EMPTY;
color[sq]=EMPTY;
}
/*

AddPiece updates the Hash Table key, the board and the table_score (the incremental
evaluation) whenever a piece is added.

*/
void AddPiece(const int s,const int p,const int sq)
{
AddKey(s,p,sq);
board[sq]=p;
color[sq]=s;
}
/*

MakeMove updates the board whenever a move is made.
If the King moves two squares then it sees if castling is legal.
If a pawn moves and changes file s without making a capture, then its an en passant capture
and the captured pawn is removed.
If the move is a capture then the captured piece is removed from the board.
If castling permissions are effected then they are updated.
If a pawn moves to the last rank then its promoted. The pawn is removed and a queen is added.
If the move leaves the King in check (for example, if a pinned piece moved), then the move is taken back.

*/
int MakeMove(const int start,const int dest)
{
g = &game_list[hply];

if (abs(start - dest) ==2 && board[start] == K)
{
if (Attack(xside,start))
return false;
if(dest==G1)
{
if (Attack(xside,F1))
return false;
UpdatePiece(side,R,H1,F1);
}
else if(dest==C1)
{
if (Attack(xside,D1))
return false;
UpdatePiece(side,R,A1,D1);
}
else if(dest==G8)
{
if (Attack(xside,F8))
return false;
UpdatePiece(side,R,H8,F8);
}
else if(dest==C8)
{
if (Attack(xside,D8))
return false;
UpdatePiece(side,R,A8,D8);
}
}

g->start = start;
g->dest = dest;
g->capture = board[dest];
g->fifty = fifty;
g->hash = currentkey;
g->lock = currentlock;

++ply;
++hply;

game_list[hply].castle_q[0] = game_list[hply-1].castle_q[0];
game_list[hply].castle_q[1] = game_list[hply-1].castle_q[1];
game_list[hply].castle_k[0] = game_list[hply-1].castle_k[0];
game_list[hply].castle_k[1] = game_list[hply-1].castle_k[1];

fifty++;

if (board[start] == P)
{
fifty = 0;
if (board[dest] == EMPTY && col[start] != col[dest])
{
RemovePiece(xside,P,dest + ReverseSquare[side]);
}
}

if(board[dest]<6)
{
fifty = 0;
    RemovePiece(xside,board[dest],dest);
}

if (board[start]==P && (row[dest]==0 || row[dest]==7))//promotion
{
    RemovePiece(side,P,start);
    AddPiece(side,Q,dest);
game_list[hply].promote = Q;
}
else
{
game_list[hply].promote = 0;
    UpdatePiece(side,board[start],start,dest);
}

if(dest == A1 || start == A1)
game_list[hply].castle_q[0] = 0;
else if(dest == H1 || start == H1)
game_list[hply].castle_k[0] = 0;
else if(start == E1)
{
game_list[hply].castle_q[0] = 0;
game_list[hply].castle_k[0] = 0;
}

if(dest == A8 || start == A8)
game_list[hply].castle_q[1] = 0;
else if(dest == H8 || start == H8)
game_list[hply].castle_k[1] = 0;
else if(start == E8)
{
game_list[hply].castle_q[1] = 0;
game_list[hply].castle_k[1] = 0;
}

side ^= 1;
xside ^= 1;
if (Attack(side,kingloc[xside]))
{
TakeBack();
return false;
}
return true;
}
/*

TakeBack is the opposite of MakeMove.

*/
void TakeBack()
{
side ^= 1;
xside ^= 1;
ply--;
hply--;

game* m = &game_list[hply];
int start = m->start;
int dest = m->dest;

fifty = m->fifty;

if (board[dest]==P && m->capture == EMPTY && col[start] != col[dest])
    {
        AddPiece(xside,P,dest + ReverseSquare[side]);
}
if(game_list[hply+1].promote == Q)
    {
       AddPiece(side,P,start);
       RemovePiece(side,board[dest],dest);
    }
else
    {
       UpdatePiece(side,board[dest],dest,start);
    }
    if (m->capture != EMPTY)
    {
      AddPiece(xside,m->capture,dest);
    }
if (abs(start - dest) == 2 && board[start] == K)
    {
if(dest==G1)
UpdatePiece(side,R,F1,H1);
else if(dest==C1)
UpdatePiece(side,R,D1,A1);
else if(dest==G8)
UpdatePiece(side,R,F8,H8);
else if(dest==C8)
UpdatePiece(side,R,D8,A8);
  }
}
/*

MakeRecapture is simpler than MakeMove because there is no castling involved and it
doesn't include en passant capture and promotion.
It the capture is illegal it is taken back.

*/
int MakeRecapture(const int start,const int dest)
{
game_list[hply].start = start;
game_list[hply].dest = dest;
game_list[hply].capture = board[dest];
ply ++;
hply ++;

board[dest] = board[start];
color[dest] = color[start];
board[start] = EMPTY;
color[start] = EMPTY;

if(board[dest]==K)
kingloc[side] = dest;
 
side ^= 1;
xside ^= 1;
if (Attack(side,kingloc[xside]))
{
UnMakeRecapture();
return false;
}
return true;
}
/*

UnMakeRecapture is very similar to MakeRecapture.

*/
void UnMakeRecapture()
{
side ^= 1;
xside ^= 1;
ply--;
hply--;

int start = game_list[hply].start;
int dest = game_list[hply].dest;

board[start] = board[dest];
color[start] = color[dest];
board[dest] = game_list[hply].capture;
color[dest] = xside;

if(board[start]==K)
kingloc[side] = start;
}
/*

GetHistoryStart returns the start square for the move in the game list.

*/
int GetHistoryStart(const int n)
{
return game_list[n].start;
}
/*

GetHistoryDest returns the dest square for the move in the game list.

*/
int GetHistoryDest(const int n)
{
return game_list[n].dest;
}

gen.cpp

#include "globals.h"

move *g;

int px[6] = {0,10,20,30,40,0};
int nx[6] = {-3,7,17,27,37,0};
int bx[6] = {-3,7,17,27,37,0};
int rx[6] = {-5,5,15,25,35,0};
int qx[6] = {-9,1,11,21,31,0};
int kx[6] = {0,10,20,30,40,0};

int ForwardSquare[2] = {8,-8};
int Double[2] = {16,-16};
int Left[2] = {7,-9};
int Right[2] = {9,-7};
int OtherSide[2] = {1,0};

/*

Gen sees if an en passant capture or castling is possible.
It then loops through the board searching for pieces of one
side and generates
moves for them.

*/
void Gen()
{
first_move[ply + 1] = first_move[ply];

GenEp();

GenCastle();

for(int x = 0;x < 64;x++)
{
if(color[x] == side)
{
switch(board[x])
{
case P:
GenPawn(x);
break;
case N:
GenKnight(x);
break;
case B:
GenBishop(x,NE);
GenBishop(x,SE);
GenBishop(x,SW);
GenBishop(x,NW);
break;
case R:
GenRook(x,NORTH);
GenRook(x,EAST);
GenRook(x,SOUTH);
GenRook(x,WEST);
break;
case Q:
GenQueen(x,NE);
GenQueen(x,SE);
GenQueen(x,SW);
GenQueen(x,NW);
GenQueen(x,NORTH);
GenQueen(x,EAST);
GenQueen(x,SOUTH);
GenQueen(x,WEST);
break;
case K:
GenKing(x);
break;
default:
break;
}
}
}
}
/*

GenEp looks at the last move played and sees if it is a double pawn move.
If so, it sees if there is an opponent pawn next to it.
If there is, it adds the en passant capture to the move list.
Note that sometimes two en passant captures may be possible.

*/
void GenEp()
{
int ep = GetHistoryDest(hply - 1);

if(board[ep] == 0 && abs(GetHistoryStart(hply - 1) - ep) == 16)
{
if(col[ep] > 0 && color[ep-1]==side && board[ep-1]==P)
{
AddCapture(ep-1,ep+ForwardSquare[side],10);
}
if(col[ep] < 7 && color[ep+1]==side && board[ep+1]==P)
{
AddCapture(ep+1,ep+ForwardSquare[side],10);
}
}
}
/*

GenCastle generates a castling move if the King and Rook haven't moved and
there are no pieces in the way. Attacked squares are looked at in MakeMove.

*/
void GenCastle()
{
if(side==0)
{
if(game_list[hply].castle_k[side])
{
if(board[F1] == EMPTY && board[G1] == EMPTY)
{
AddMove(E1,G1);
}
}
if(game_list[hply].castle_q[side])
{
if(board[B1] == EMPTY && board[C1] == EMPTY && board[D1] == EMPTY)
{
AddMove(E1,C1);
}
}
}
else
{

if(game_list[hply].castle_k[side])
{
if(board[F8] == EMPTY && board[G8] == EMPTY)
{
AddMove(E8,G8);
}
}
if(game_list[hply].castle_q[side])
{
if(board[B8] == EMPTY && board[C8] == EMPTY && board[D8] == EMPTY)
{
AddMove(E8,C8);
}
}
}
}
/*

GenPawn generates single and double pawn moves and pawn
captures for a pawn.

*/
void GenPawn(const int x)
{
if(board[x+ForwardSquare[side]] == EMPTY)
{
AddMove(x,x + ForwardSquare[side]);
if(rank[side][x]==1 && board[x + Double[side]] == EMPTY)
{
AddMove(x,x + Double[side]);
}
}
if(col[x] > 0 && color[x + Left[side]] == OtherSide[side])
{
AddCapture(x,x + Left[side],px[board[x + Left[side]]]);
}
if(col[x] < 7 && color[x + Right[side]] == OtherSide[side])
{
AddCapture(x,x + Right[side],px[board[x + Right[side]]]);
}
}
/*

GenKnight generates knight moves and captures by using the
knight_moves look up
table created in init.cpp.

*/
void GenKnight(const int sq)
{
int k = 0;
int sq2 = knight_moves[sq][k++];
while(sq2 > -1)
{
if(color[sq2] == EMPTY)
AddMove(sq,sq2);
else if(color[sq2] == xside)
AddCapture(sq,sq2,nx[board[sq2]]);
sq2 = knight_moves[sq][k++];
}
}
/*

GenBishop generates bishop moves and
captures for each diagonal.

*/
void GenBishop(const int x,const int dir)
{
int sq = qrb_moves[x][dir];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(color[sq] == xside)
AddCapture(x,sq,bx[board[sq]]);
break;
}
AddMove(x,sq);
sq = qrb_moves[sq][dir];
}

}
/*

GenRook generates straight moves and captures
for each rank and file.

*/
void GenRook(const int x,const int dir)
{
int sq = qrb_moves[x][dir];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(color[sq] == xside)
{
AddCapture(x,sq,rx[board[sq]]);
}
break;
}
AddMove(x,sq);
sq = qrb_moves[sq][dir];
}

}
/*

GenQueen generates queen moves and captures
for line.

*/
void GenQueen(const int x,const int dir)
{
int sq = qrb_moves[x][dir];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(color[sq] == xside)
{
AddCapture(x,sq,qx[board[sq]]);
}
break;
}
AddMove(x,sq);
sq = qrb_moves[sq][dir];
}

}
/*

GenKing generates king moves and captures by using the
king_moves look up table created in init.cpp.

*/
void GenKing(const int x)
{
int k = 0;
int sq = king_moves[x][k++];

while(sq > -1)
{
if(color[sq] == EMPTY)
AddMove(x,sq);
else if(color[sq] == xside)
AddCapture(x,sq,kx[board[sq]]);
sq = king_moves[x][k++];
}

}
/*

AddMove adds the start and dest squares of a move to the movelist.
The score is the history value.

*/
void AddMove(const int x,const int sq)
{
g = &move_list[first_move[ply + 1]++];
g->start = x;
g->dest = sq;
g->score = history[x][sq];
}
/*

AddCapture adds the start and dest squares of a move to the
movelist.
CAPTURE_SCORE is added to the score so that captures will be
looked at first.
The score is also added and will be used in move ordering.

*/
void AddCapture(const int x,const int sq,const int score)
{
g = &move_list[first_move[ply + 1]++];
g->start = x;
g->dest = sq;
g->score = score + CAPTURE_SCORE;
}
/*

GenCaptures is very similar to Gen, except that only captures
are being generated instead of all moves.

*/
void GenCaptures()
{
first_move[ply + 1] = first_move[ply];

for(int x = 0;x < 64;x++)
{
if(color[x] == side)
{
switch(board[x])
{
case P:
CapPawn(x);
break;
case N:
CapKnight(x);
break;
case B:
CapBishop(x,NE);
CapBishop(x,SE);
CapBishop(x,SW);
CapBishop(x,NW);
break;
case R:
CapRook(x,EAST);
CapRook(x,SOUTH);
CapRook(x,WEST);
CapRook(x,NORTH);
break;
case Q:
CapQueen(x,NE);
CapQueen(x,SE);
CapQueen(x,SW);
CapQueen(x,NW);
CapQueen(x,EAST);
CapQueen(x,SOUTH);
CapQueen(x,WEST);
CapQueen(x,NORTH);
break;
case K:
CapKing(x);
break;
default:
break;
}
}
}
}
/*

CapPawn generates pawn captures.

*/
void CapPawn(const int x)
{

if(col[x] > 0 && color[x + Left[side]] == OtherSide[side])
{
AddCapture(x,x + Left[side],px[board[x + Left[side]]]);
}
if(col[x] < 7 && color[x + Right[side]] == OtherSide[side])
{
AddCapture(x,x + Right[side],px[board[x + Right[side]]]);
}

}
/*

CapKnight generates knight captures.

*/
void CapKnight(const int x)
{
int k = 0;
int sq = knight_moves[x][k++];
while(sq > -1)
{
if(color[sq] == xside)
AddCapture(x,sq,nx[board[sq]]);
sq = knight_moves[x][k++];
}
}
/*

CapBishop generates bishop captures.

*/
void CapBishop(const int x,const int dir)
{

int sq = qrb_moves[x][dir];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(color[sq] == xside)
AddCapture(x,sq,bx[board[sq]]);
break;
}
sq = qrb_moves[sq][dir];
}

}
/*

CapRook generates rook captures.

*/
void CapRook(const int x,const int dir)
{
int sq = qrb_moves[x][dir];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(color[sq] == xside)
{
AddCapture(x,sq,rx[board[sq]]);
}
break;
}
sq = qrb_moves[sq][dir];
}

}
/*

CapQueen generates queen captures.

*/
void CapQueen(const int x,const int dir)
{
int sq = qrb_moves[x][dir];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(color[sq] == xside)
{
AddCapture(x,sq,qx[board[sq]]);
}
break;
}
sq = qrb_moves[sq][dir];
}

}
/*

CapKing generates king captures.

*/
void CapKing(const int x)
{
int k = 0;
int sq = king_moves[x][k++];

while(sq > -1)
{
if(color[sq] == xside)
AddCapture(x,sq,kx[board[sq]]);
sq = king_moves[x][k++];
}
}