#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();
}
Saturday, May 4, 2019
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;
}
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;
}
#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;
}
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++];
}
}
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++];
}
}
init.cpp
#include "globals.h"
int side,xside;
int fifty;
int ply,hply;
int nodes;
int board[64];
int color[64];
int kingloc[2];
int history[64][64];
int table_score[2] ;
int square_score[2][6][64];
int king_endgame[2][64];
int pawn_mat[2];
int piece_mat[2];
int passed[2][64];
int qrb_moves[64][9];
int knight_moves[64][9];
int king_moves[64][9];
move move_list[MOVE_STACK];
int first_move[MAX_PLY];
game game_list[GAME_STACK];
char piece_char[6] =
{
'P', 'N', 'B', 'R', 'Q', 'K'
};
int piece_value[6] =
{
100, 300, 300, 500, 900, 10000
};
int init_color[64] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
int init_board[64] =
{
3, 1, 2, 4, 5, 2, 1, 3,
0, 0, 0, 0, 0, 0, 0, 0,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
0, 0, 0, 0, 0, 0, 0, 0,
3, 1, 2, 4, 5, 2, 1, 3
};
const int col[64]=
{
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7
};
const int row[64]=
{
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7
};
int Flip[64] =
{
56, 57, 58, 59, 60, 61, 62, 63,
48, 49, 50, 51, 52, 53, 54, 55,
40, 41, 42, 43, 44, 45, 46, 47,
32, 33, 34, 35, 36, 37, 38, 39,
24, 25, 26, 27, 28, 29, 30, 31,
16, 17, 18, 19, 20, 21, 22, 23,
8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7
};
int pawn_score[64] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 4, -12, -12, 4, 2, 0,
0, 2, 4, 4, 4, 4, 2, 0,
0, 2, 4, 8, 8, 4, 2, 0,
0, 2, 4, 8, 8, 4, 2, 0,
4, 8, 10, 16, 16, 10, 8, 4,
100, 100, 100, 100, 100, 100, 100, 100,
0, 0, 0, 0, 0, 0, 0, 0
};
int knight_score[64] =
{
-30, -20, -10, -8, -8, -10, -20, -30,
-16, -6, -2, 0, 0, -2, -6, -16,
-8, -2, 4, 6, 6, 4, -2, -8,
-5, 0, 6, 8, 8, 6, 0, -5,
-5, 0, 6, 8, 8, 6, 0, -5,
-10, -2, 4, 6, 6, 4, -2, -10,
-20, -10, -2, 0, 0, -2, -10, -20,
-150, -20, -10, -5, -5, -10, -20, -150
};
int bishop_score[64] =
{
-10, -10, -12, -10, -10, -12, -10, -10,
0, 4, 4, 4, 4, 4, 4, 0,
2, 4, 6, 6, 6, 6, 4, 2,
2, 4, 6, 8, 8, 6, 4, 2,
2, 4, 6, 8, 8, 6, 4, 2,
2, 4, 6, 6, 6, 6, 4, 2,
-10, 4, 4, 4, 4, 4, 4, -10,
-10, -10, -10, -10, -10, -10, -10, -10
};
int rook_score[64] =
{
4, 4, 4, 6, 6, 4, 4, 4,
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,
20, 20, 20, 20, 20, 20, 20, 20,
10, 10, 10, 10, 10, 10, 10, 10
};
int queen_score[64] =
{
-10, -10, -6, -4, -4, -6, -10, -10,
-10, 2, 2, 2, 2, 2, 2, -10,
2, 2, 2, 3, 3, 2, 2, 2,
2, 2, 3, 4, 4, 3, 2, 2,
2, 2, 3, 4, 4, 3, 2, 2,
2, 2, 2, 3, 3, 2, 2, 2,
-10, 2, 2, 2, 2, 2, 2, -10,
-10, -10, 2, 2, 2, 2, -10, -10
};
int king_score[64] =
{
20, 20, 20, -40, 10, -60, 20, 20,
15, 20, -25, -30, -30, -45, 20, 15,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48
};
int king_endgame_score[64] =
{
0, 8, 16, 18, 18, 16, 8, 0,
8, 16, 24, 32, 32, 24, 16, 8,
16, 24, 32, 40, 40, 32, 24, 16,
25, 32, 40, 48, 48, 40, 32, 25,
25, 32, 40, 48, 48, 40, 32, 25,
16, 24, 32, 40, 40, 32, 24, 16,
8, 16, 24, 32, 32, 24, 16, 8,
0, 8, 16, 18, 18, 16, 8, 0
};
int passed_score[64] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
60, 60, 60, 60 ,60, 60, 60, 60,
30, 30, 30, 30, 30, 30, 30, 30,
15, 15, 15, 15,15, 15, 15, 15,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
0, 0, 0, 0, 0, 0, 0, 0
};
int rank[2][64];
/*
SetTables fills the square_score tables, king_endgame tables and passed tables with the individual piece tables.
The value of each piece is added to the score for each square.
The board is flipped for the Black scores.
*/
void SetTables()
{
for(int x=0;x<64;x++)
{
square_score[0][0][x] = pawn_score[x] + 100;
square_score[0][1][x] = knight_score[x] + 300;
square_score[0][2][x] = bishop_score[x] + 300;
square_score[0][3][x] = rook_score[x] + 500;
square_score[0][4][x] = queen_score[x] + 900;
square_score[0][5][x] = king_score[x];
square_score[1][0][x] = pawn_score[Flip[x]] + 100;
square_score[1][1][x] = knight_score[Flip[x]] + 300;
square_score[1][2][x] = bishop_score[Flip[x]] + 300;
square_score[1][3][x] = rook_score[Flip[x]] + 500;
square_score[1][4][x] = queen_score[Flip[x]] + 900;
square_score[1][5][x] = king_score[Flip[x]];
king_endgame[0][x] = king_endgame_score[x] - square_score[0][5][x];
king_endgame[1][x] = king_endgame_score[x] - square_score[1][5][x];
passed[0][x] = passed_score[Flip[x]];
passed[1][x] = passed_score[x];
}
}
/*
Sets up variables for a new game.
*/
void InitBoard()
{
int x;
for (x = 0; x < 64; ++x)
{
color[x] = init_color[x];
board[x] = init_board[x];
rank[0][x] = row[x];
rank[1][x] = 7 - row[x];
}
side = 0;
xside = 1;
fifty = 0;
ply = 0;
hply = 0;
first_move[0] = 0;
kingloc[0] = E1;
kingloc[1] = E8;
game_list[hply].castle_q[0] = 1;
game_list[hply].castle_q[1] = 1;
game_list[hply].castle_k[0] = 1;
game_list[hply].castle_k[1] = 1;
}
/*
NewPosition gets the board ready before the computer starts to think.
*/
void NewPosition()
{
piece_mat[0] = pawn_mat[0] = table_score[0] = 0;
piece_mat[1] = pawn_mat[1] = table_score[1] = 0;
for(int i=0;i<64;i++)
{
if(board[i] < 6)
{
AddPiece(color[i],board[i],i);
}
}
currentkey = GetKey();
currentlock = GetLock();
}
/*
Alg displays a move.
*/
void Alg(int a,int b)
{
Algebraic(a);
Algebraic(b);
}
/*
Algebraic displays a square.
e.g. 3 becomes col[3] + 96 which is ascii character 'd' and row[3]+1 which is '1'.
Passing 3 returns 'd1'.
*/
void Algebraic(int a)
{
if(a<0 || a>63) return;
char c[2]="a";
c[0] = 96+1+col[a];
printf("%s%d",c,row[a]+1);
}
/*
SetMoves creates the lookup tables for Knights, line-pieces and Kings.
These will later be used to generate moves, captures and attacks.
*/
void SetMoves()
{
int k=0;
int y;
nodes = 1;
for(int x=0;x<64;x++)
{
k = 0;
if(row[x]<6 && col[x]<7)
knight_moves[x][k++] = x+17;
if(row[x]<7 && col[x]<6)
knight_moves[x][k++] = x+10;
if(row[x]<6 && col[x]>0)
knight_moves[x][k++] = x+15;
if(row[x]<7 && col[x]>1)
knight_moves[x][k++] = x+6;
if(row[x]>1 && col[x]<7)
knight_moves[x][k++] = x-15;
if(row[x]>0 && col[x]<6)
knight_moves[x][k++] = x-6;
if(row[x]>1 && col[x]>0)
knight_moves[x][k++] = x-17;
if(row[x]>0 && col[x]>1)
knight_moves[x][k++] = x-10;
knight_moves[x][k] = -1;
if(x==47)
x=x;
}
for(int x=0;x<64;x++)
{
k = 0;
for(int z=0;z<8;z++)
{
qrb_moves[x][z] = -1;
}
if(col[x]>0) qrb_moves[x][WEST]=x-1;
if(col[x]<7) qrb_moves[x][EAST]=x+1;
if(row[x]>0) qrb_moves[x][SOUTH]=x-8;
if(row[x]<7) qrb_moves[x][NORTH]=x+8;
if(col[x]<7 && row[x]<7) qrb_moves[x][NE]=x+9;
if(col[x]>0 && row[x]<7) qrb_moves[x][NW]=x+7;
if(col[x]>0 && row[x]>0) qrb_moves[x][SW]=x-9;
if(col[x]<7 && row[x]>0) qrb_moves[x][SE]=x-7;
y=0;
if(col[x]>0)
king_moves[x][y++]=x-1;
if(col[x]<7)
king_moves[x][y++]=x+1;
if(row[x]>0)
king_moves[x][y++]=x-8;
if(row[x]<7)
king_moves[x][y++]=x+8;
if(col[x]<7 && row[x]<7)
king_moves[x][y++]=x+9;
if(col[x]>0 && row[x]<7)
king_moves[x][y++]=x+7;
if(col[x]>0 && row[x]>0)
king_moves[x][y++]=x-9;
if(col[x]<7 && row[x]>0)
king_moves[x][y++]=x-7;
king_moves[x][y] = -1;
}
nodes = 0;
}
/*dont need below here*/
int done[100];
int GetBest(int ply);//
void ShowAll(int ply)
{
move *g;
print_board();
memset(done, 0, sizeof(done));
printf(" ply ");
printf("%d",ply);
printf(" nodes ");
printf("%d",nodes);
printf(" side ");
printf("%d",side);
printf(" xside ");
printf("%d",xside);
printf("\n");
printf(" one %d ",first_move[ply]);
printf(" two %d ",first_move[ply+1]);
Alg(move_list[first_move[0]].start,move_list[first_move[0]].dest);
printf("\n");
int j;
for(int i=first_move[ply];i<first_move[ply+1];i++)
// for(int i=first_move[ply+1];i<first_move[ply + 2];i++)
{
j = GetBest(ply);
{
//how dest display current line?
g = &move_list[j];
printf("%s",move_str(move_list[j].start,move_list[j].dest,0,move_list[j].promote));
printf(" ");
printf(" score ");
printf("%d",g->score);
printf("\n");
}
}
printf("\n");
_getch();
}
int GetBest(int ply)
{
move *g;
int bestscore = -100000000;
int best = 0;
for(int i=0;i<first_move[ply+1]-first_move[ply];i++)
{
if(done[i] == 1) continue;
g = &move_list[first_move[ply] + i];
if(g->start == 0 && g->dest == 0)
continue;//
if(g->score > bestscore)
{
bestscore= g->score;
best = i;
}
}
if(best<1000) done[best]=1;//1000?
return first_move[ply]+best;
}
int side,xside;
int fifty;
int ply,hply;
int nodes;
int board[64];
int color[64];
int kingloc[2];
int history[64][64];
int table_score[2] ;
int square_score[2][6][64];
int king_endgame[2][64];
int pawn_mat[2];
int piece_mat[2];
int passed[2][64];
int qrb_moves[64][9];
int knight_moves[64][9];
int king_moves[64][9];
move move_list[MOVE_STACK];
int first_move[MAX_PLY];
game game_list[GAME_STACK];
char piece_char[6] =
{
'P', 'N', 'B', 'R', 'Q', 'K'
};
int piece_value[6] =
{
100, 300, 300, 500, 900, 10000
};
int init_color[64] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1
};
int init_board[64] =
{
3, 1, 2, 4, 5, 2, 1, 3,
0, 0, 0, 0, 0, 0, 0, 0,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6,
0, 0, 0, 0, 0, 0, 0, 0,
3, 1, 2, 4, 5, 2, 1, 3
};
const int col[64]=
{
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7,
0, 1, 2, 3, 4, 5, 6, 7
};
const int row[64]=
{
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
2, 2, 2, 2, 2, 2, 2, 2,
3, 3, 3, 3, 3, 3, 3, 3,
4, 4, 4, 4, 4, 4, 4, 4,
5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6,
7, 7, 7, 7, 7, 7, 7, 7
};
int Flip[64] =
{
56, 57, 58, 59, 60, 61, 62, 63,
48, 49, 50, 51, 52, 53, 54, 55,
40, 41, 42, 43, 44, 45, 46, 47,
32, 33, 34, 35, 36, 37, 38, 39,
24, 25, 26, 27, 28, 29, 30, 31,
16, 17, 18, 19, 20, 21, 22, 23,
8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7
};
int pawn_score[64] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 2, 4, -12, -12, 4, 2, 0,
0, 2, 4, 4, 4, 4, 2, 0,
0, 2, 4, 8, 8, 4, 2, 0,
0, 2, 4, 8, 8, 4, 2, 0,
4, 8, 10, 16, 16, 10, 8, 4,
100, 100, 100, 100, 100, 100, 100, 100,
0, 0, 0, 0, 0, 0, 0, 0
};
int knight_score[64] =
{
-30, -20, -10, -8, -8, -10, -20, -30,
-16, -6, -2, 0, 0, -2, -6, -16,
-8, -2, 4, 6, 6, 4, -2, -8,
-5, 0, 6, 8, 8, 6, 0, -5,
-5, 0, 6, 8, 8, 6, 0, -5,
-10, -2, 4, 6, 6, 4, -2, -10,
-20, -10, -2, 0, 0, -2, -10, -20,
-150, -20, -10, -5, -5, -10, -20, -150
};
int bishop_score[64] =
{
-10, -10, -12, -10, -10, -12, -10, -10,
0, 4, 4, 4, 4, 4, 4, 0,
2, 4, 6, 6, 6, 6, 4, 2,
2, 4, 6, 8, 8, 6, 4, 2,
2, 4, 6, 8, 8, 6, 4, 2,
2, 4, 6, 6, 6, 6, 4, 2,
-10, 4, 4, 4, 4, 4, 4, -10,
-10, -10, -10, -10, -10, -10, -10, -10
};
int rook_score[64] =
{
4, 4, 4, 6, 6, 4, 4, 4,
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,
20, 20, 20, 20, 20, 20, 20, 20,
10, 10, 10, 10, 10, 10, 10, 10
};
int queen_score[64] =
{
-10, -10, -6, -4, -4, -6, -10, -10,
-10, 2, 2, 2, 2, 2, 2, -10,
2, 2, 2, 3, 3, 2, 2, 2,
2, 2, 3, 4, 4, 3, 2, 2,
2, 2, 3, 4, 4, 3, 2, 2,
2, 2, 2, 3, 3, 2, 2, 2,
-10, 2, 2, 2, 2, 2, 2, -10,
-10, -10, 2, 2, 2, 2, -10, -10
};
int king_score[64] =
{
20, 20, 20, -40, 10, -60, 20, 20,
15, 20, -25, -30, -30, -45, 20, 15,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48,
-48, -48, -48, -48, -48, -48, -48, -48
};
int king_endgame_score[64] =
{
0, 8, 16, 18, 18, 16, 8, 0,
8, 16, 24, 32, 32, 24, 16, 8,
16, 24, 32, 40, 40, 32, 24, 16,
25, 32, 40, 48, 48, 40, 32, 25,
25, 32, 40, 48, 48, 40, 32, 25,
16, 24, 32, 40, 40, 32, 24, 16,
8, 16, 24, 32, 32, 24, 16, 8,
0, 8, 16, 18, 18, 16, 8, 0
};
int passed_score[64] =
{
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
60, 60, 60, 60 ,60, 60, 60, 60,
30, 30, 30, 30, 30, 30, 30, 30,
15, 15, 15, 15,15, 15, 15, 15,
8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8,
0, 0, 0, 0, 0, 0, 0, 0
};
int rank[2][64];
/*
SetTables fills the square_score tables, king_endgame tables and passed tables with the individual piece tables.
The value of each piece is added to the score for each square.
The board is flipped for the Black scores.
*/
void SetTables()
{
for(int x=0;x<64;x++)
{
square_score[0][0][x] = pawn_score[x] + 100;
square_score[0][1][x] = knight_score[x] + 300;
square_score[0][2][x] = bishop_score[x] + 300;
square_score[0][3][x] = rook_score[x] + 500;
square_score[0][4][x] = queen_score[x] + 900;
square_score[0][5][x] = king_score[x];
square_score[1][0][x] = pawn_score[Flip[x]] + 100;
square_score[1][1][x] = knight_score[Flip[x]] + 300;
square_score[1][2][x] = bishop_score[Flip[x]] + 300;
square_score[1][3][x] = rook_score[Flip[x]] + 500;
square_score[1][4][x] = queen_score[Flip[x]] + 900;
square_score[1][5][x] = king_score[Flip[x]];
king_endgame[0][x] = king_endgame_score[x] - square_score[0][5][x];
king_endgame[1][x] = king_endgame_score[x] - square_score[1][5][x];
passed[0][x] = passed_score[Flip[x]];
passed[1][x] = passed_score[x];
}
}
/*
Sets up variables for a new game.
*/
void InitBoard()
{
int x;
for (x = 0; x < 64; ++x)
{
color[x] = init_color[x];
board[x] = init_board[x];
rank[0][x] = row[x];
rank[1][x] = 7 - row[x];
}
side = 0;
xside = 1;
fifty = 0;
ply = 0;
hply = 0;
first_move[0] = 0;
kingloc[0] = E1;
kingloc[1] = E8;
game_list[hply].castle_q[0] = 1;
game_list[hply].castle_q[1] = 1;
game_list[hply].castle_k[0] = 1;
game_list[hply].castle_k[1] = 1;
}
/*
NewPosition gets the board ready before the computer starts to think.
*/
void NewPosition()
{
piece_mat[0] = pawn_mat[0] = table_score[0] = 0;
piece_mat[1] = pawn_mat[1] = table_score[1] = 0;
for(int i=0;i<64;i++)
{
if(board[i] < 6)
{
AddPiece(color[i],board[i],i);
}
}
currentkey = GetKey();
currentlock = GetLock();
}
/*
Alg displays a move.
*/
void Alg(int a,int b)
{
Algebraic(a);
Algebraic(b);
}
/*
Algebraic displays a square.
e.g. 3 becomes col[3] + 96 which is ascii character 'd' and row[3]+1 which is '1'.
Passing 3 returns 'd1'.
*/
void Algebraic(int a)
{
if(a<0 || a>63) return;
char c[2]="a";
c[0] = 96+1+col[a];
printf("%s%d",c,row[a]+1);
}
/*
SetMoves creates the lookup tables for Knights, line-pieces and Kings.
These will later be used to generate moves, captures and attacks.
*/
void SetMoves()
{
int k=0;
int y;
nodes = 1;
for(int x=0;x<64;x++)
{
k = 0;
if(row[x]<6 && col[x]<7)
knight_moves[x][k++] = x+17;
if(row[x]<7 && col[x]<6)
knight_moves[x][k++] = x+10;
if(row[x]<6 && col[x]>0)
knight_moves[x][k++] = x+15;
if(row[x]<7 && col[x]>1)
knight_moves[x][k++] = x+6;
if(row[x]>1 && col[x]<7)
knight_moves[x][k++] = x-15;
if(row[x]>0 && col[x]<6)
knight_moves[x][k++] = x-6;
if(row[x]>1 && col[x]>0)
knight_moves[x][k++] = x-17;
if(row[x]>0 && col[x]>1)
knight_moves[x][k++] = x-10;
knight_moves[x][k] = -1;
if(x==47)
x=x;
}
for(int x=0;x<64;x++)
{
k = 0;
for(int z=0;z<8;z++)
{
qrb_moves[x][z] = -1;
}
if(col[x]>0) qrb_moves[x][WEST]=x-1;
if(col[x]<7) qrb_moves[x][EAST]=x+1;
if(row[x]>0) qrb_moves[x][SOUTH]=x-8;
if(row[x]<7) qrb_moves[x][NORTH]=x+8;
if(col[x]<7 && row[x]<7) qrb_moves[x][NE]=x+9;
if(col[x]>0 && row[x]<7) qrb_moves[x][NW]=x+7;
if(col[x]>0 && row[x]>0) qrb_moves[x][SW]=x-9;
if(col[x]<7 && row[x]>0) qrb_moves[x][SE]=x-7;
y=0;
if(col[x]>0)
king_moves[x][y++]=x-1;
if(col[x]<7)
king_moves[x][y++]=x+1;
if(row[x]>0)
king_moves[x][y++]=x-8;
if(row[x]<7)
king_moves[x][y++]=x+8;
if(col[x]<7 && row[x]<7)
king_moves[x][y++]=x+9;
if(col[x]>0 && row[x]<7)
king_moves[x][y++]=x+7;
if(col[x]>0 && row[x]>0)
king_moves[x][y++]=x-9;
if(col[x]<7 && row[x]>0)
king_moves[x][y++]=x-7;
king_moves[x][y] = -1;
}
nodes = 0;
}
/*dont need below here*/
int done[100];
int GetBest(int ply);//
void ShowAll(int ply)
{
move *g;
print_board();
memset(done, 0, sizeof(done));
printf(" ply ");
printf("%d",ply);
printf(" nodes ");
printf("%d",nodes);
printf(" side ");
printf("%d",side);
printf(" xside ");
printf("%d",xside);
printf("\n");
printf(" one %d ",first_move[ply]);
printf(" two %d ",first_move[ply+1]);
Alg(move_list[first_move[0]].start,move_list[first_move[0]].dest);
printf("\n");
int j;
for(int i=first_move[ply];i<first_move[ply+1];i++)
// for(int i=first_move[ply+1];i<first_move[ply + 2];i++)
{
j = GetBest(ply);
{
//how dest display current line?
g = &move_list[j];
printf("%s",move_str(move_list[j].start,move_list[j].dest,0,move_list[j].promote));
printf(" ");
printf(" score ");
printf("%d",g->score);
printf("\n");
}
}
printf("\n");
_getch();
}
int GetBest(int ply)
{
move *g;
int bestscore = -100000000;
int best = 0;
for(int i=0;i<first_move[ply+1]-first_move[ply];i++)
{
if(done[i] == 1) continue;
g = &move_list[first_move[ply] + i];
if(g->start == 0 && g->dest == 0)
continue;//
if(g->score > bestscore)
{
bestscore= g->score;
best = i;
}
}
if(best<1000) done[best]=1;//1000?
return first_move[ply]+best;
}
attack.cpp
#include "globals.h"
int LineCheck(const int s,const int sq,const int d,const int p);
bool LineCheck2(const int s,const int sq,const int d,const int p1,const int p2);
/*
Attack returns true if one side attacks a given square and false if it doesn't.
It is used to tell if a King is in check, but can have other uses.
*/
bool Attack(const int s,const int x)
{
if(s==0)
{
if(row[x]>1)
{
if(col[x]<7 && color[x-7] == s && board[x-7] == 0)
{
return true;
}
if(col[x]>0 && color[x-9] == s && board[x-9] == 0)
{
return true;
}
}
}
else if(row[x]<6)
{
if(col[x]>0 && color[x+7] == s && board[x+7] == 0)
{
return true;
}
if(col[x]<7 && color[x+9] == s && board[x+9] == 0)
{
return true;
}
}
int k = 0;
int sq = knight_moves[x][k];
while(sq > -1)
{
if(color[sq] == s && board[sq]==N)
return true;
k++;
sq = knight_moves[x][k];
}
if(LineCheck2(s,x,NE,B,Q)) return true;
if(LineCheck2(s,x,NW,B,Q)) return true;
if(LineCheck2(s,x,SW,B,Q)) return true;
if(LineCheck2(s,x,SE,B,Q)) return true;
if(LineCheck2(s,x,NORTH,R,Q)) return true;
if(LineCheck2(s,x,SOUTH,R,Q)) return true;
if(LineCheck2(s,x,EAST,R,Q)) return true;
if(LineCheck2(s,x,WEST,R,Q)) return true;
if(abs(col[x] - col[kingloc[s]])<2 && abs(row[x] - row[kingloc[s]])<2)
{
return true;
}
return false;
}
/*
LowestAttacker is similar to Attack. It returns the square the weakest attacker of the given side and given square.
It returns -1 if there are no attackers.
It is used to find the next piece that will recapture, but can have other uses.
*/
int LowestAttacker(const int s,const int x)
{
if(s==0)
{
if(row[x]>1)
{
if(col[x]<7 && color[x-7] == s && board[x-7] == 0)
{
return x-7;
}
if(col[x]>0 && color[x-9] == s && board[x-9] == 0)
{
return x-9;
}
}
}
else if(row[x]<6)
{
if(col[x]>0 && color[x+7] == s && board[x+7] == 0)
{
return x+7;
}
if(col[x]<7 && color[x+9] == s && board[x+9] == 0)
{
return x+9;
}
}
int k = 0;
int sq = knight_moves[x][k];
while(sq > -1)
{
if(color[sq] == s && board[sq]==N)
return sq;
k++;
sq = knight_moves[x][k];
}
sq = LineCheck(s,x,NE,B); if(sq>-1) return sq;
sq = LineCheck(s,x,NW,B); if(sq>-1) return sq;
sq = LineCheck(s,x,SW,B); if(sq>-1) return sq;
sq = LineCheck(s,x,SE,B); if(sq>-1) return sq;
sq = LineCheck(s,x,NORTH,R); if(sq>-1) return sq;
sq = LineCheck(s,x,SOUTH,R); if(sq>-1) return sq;
sq = LineCheck(s,x,EAST,R); if(sq>-1) return sq;
sq = LineCheck(s,x,WEST,R); if(sq>-1) return sq;
sq = LineCheck(s,x,NORTH,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,SOUTH,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,EAST,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,WEST,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,NE,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,NW,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,SW,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,SE,Q); if(sq>-1) return sq;
if(abs(col[x] - col[kingloc[s]])<2 && abs(row[x] - row[kingloc[s]])<2)
{
return kingloc[s];
}
return -1;
}
/*
LineCheck searches a line in direction d for the given piece of the given side.
It returns -1 if there are none.
*/
int LineCheck(const int s,int sq,const int d,const int p)
{
sq = qrb_moves[sq][d];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(board[sq] == p && color[sq] == s)
return sq;
break;
}
sq = qrb_moves[sq][d];
}
return -1;
}
/*
LineCheck2 searches a line in direction d for the given pieces of the given side.
On diagonals it searches for bishops and queens, while on ranks or files it
searches for rooks and queens.
It returns -1 if there are none.
*/
bool LineCheck2(const int s,int sq,const int d,const int p1,const int p2)
{
sq = qrb_moves[sq][d];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if((board[sq] == p1 || board[sq] == p2) && color[sq] == s)
return true;
break;
}
sq = qrb_moves[sq][d];
}
return false;
}
int LineCheck(const int s,const int sq,const int d,const int p);
bool LineCheck2(const int s,const int sq,const int d,const int p1,const int p2);
/*
Attack returns true if one side attacks a given square and false if it doesn't.
It is used to tell if a King is in check, but can have other uses.
*/
bool Attack(const int s,const int x)
{
if(s==0)
{
if(row[x]>1)
{
if(col[x]<7 && color[x-7] == s && board[x-7] == 0)
{
return true;
}
if(col[x]>0 && color[x-9] == s && board[x-9] == 0)
{
return true;
}
}
}
else if(row[x]<6)
{
if(col[x]>0 && color[x+7] == s && board[x+7] == 0)
{
return true;
}
if(col[x]<7 && color[x+9] == s && board[x+9] == 0)
{
return true;
}
}
int k = 0;
int sq = knight_moves[x][k];
while(sq > -1)
{
if(color[sq] == s && board[sq]==N)
return true;
k++;
sq = knight_moves[x][k];
}
if(LineCheck2(s,x,NE,B,Q)) return true;
if(LineCheck2(s,x,NW,B,Q)) return true;
if(LineCheck2(s,x,SW,B,Q)) return true;
if(LineCheck2(s,x,SE,B,Q)) return true;
if(LineCheck2(s,x,NORTH,R,Q)) return true;
if(LineCheck2(s,x,SOUTH,R,Q)) return true;
if(LineCheck2(s,x,EAST,R,Q)) return true;
if(LineCheck2(s,x,WEST,R,Q)) return true;
if(abs(col[x] - col[kingloc[s]])<2 && abs(row[x] - row[kingloc[s]])<2)
{
return true;
}
return false;
}
/*
LowestAttacker is similar to Attack. It returns the square the weakest attacker of the given side and given square.
It returns -1 if there are no attackers.
It is used to find the next piece that will recapture, but can have other uses.
*/
int LowestAttacker(const int s,const int x)
{
if(s==0)
{
if(row[x]>1)
{
if(col[x]<7 && color[x-7] == s && board[x-7] == 0)
{
return x-7;
}
if(col[x]>0 && color[x-9] == s && board[x-9] == 0)
{
return x-9;
}
}
}
else if(row[x]<6)
{
if(col[x]>0 && color[x+7] == s && board[x+7] == 0)
{
return x+7;
}
if(col[x]<7 && color[x+9] == s && board[x+9] == 0)
{
return x+9;
}
}
int k = 0;
int sq = knight_moves[x][k];
while(sq > -1)
{
if(color[sq] == s && board[sq]==N)
return sq;
k++;
sq = knight_moves[x][k];
}
sq = LineCheck(s,x,NE,B); if(sq>-1) return sq;
sq = LineCheck(s,x,NW,B); if(sq>-1) return sq;
sq = LineCheck(s,x,SW,B); if(sq>-1) return sq;
sq = LineCheck(s,x,SE,B); if(sq>-1) return sq;
sq = LineCheck(s,x,NORTH,R); if(sq>-1) return sq;
sq = LineCheck(s,x,SOUTH,R); if(sq>-1) return sq;
sq = LineCheck(s,x,EAST,R); if(sq>-1) return sq;
sq = LineCheck(s,x,WEST,R); if(sq>-1) return sq;
sq = LineCheck(s,x,NORTH,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,SOUTH,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,EAST,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,WEST,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,NE,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,NW,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,SW,Q); if(sq>-1) return sq;
sq = LineCheck(s,x,SE,Q); if(sq>-1) return sq;
if(abs(col[x] - col[kingloc[s]])<2 && abs(row[x] - row[kingloc[s]])<2)
{
return kingloc[s];
}
return -1;
}
/*
LineCheck searches a line in direction d for the given piece of the given side.
It returns -1 if there are none.
*/
int LineCheck(const int s,int sq,const int d,const int p)
{
sq = qrb_moves[sq][d];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if(board[sq] == p && color[sq] == s)
return sq;
break;
}
sq = qrb_moves[sq][d];
}
return -1;
}
/*
LineCheck2 searches a line in direction d for the given pieces of the given side.
On diagonals it searches for bishops and queens, while on ranks or files it
searches for rooks and queens.
It returns -1 if there are none.
*/
bool LineCheck2(const int s,int sq,const int d,const int p1,const int p2)
{
sq = qrb_moves[sq][d];
while(sq > -1)
{
if(color[sq] != EMPTY)
{
if((board[sq] == p1 || board[sq] == p2) && color[sq] == s)
return true;
break;
}
sq = qrb_moves[sq][d];
}
return false;
}
Subscribe to:
Posts (Atom)