📄 searchagent.cpp
字号:
/****************************************************
Author: S. Senthil kumar
File: SearchAgent.cpp
Purpose: Implementation of The Game Engine
******************************************************/
#include "Global.h"
#include "OneMove.h"
#include "Moves.h"
#include "TransTableEntry.h"
#include "TranspositionTable.h"
#include "SearchAgent.h"
extern int CheckCheck(int board[8][8],int target,int whilethinking=0);
extern CString GetMusicDirectory();
extern int computer_color;
extern int end_of_game;
extern int debug;
extern int movecount;
extern TranspositionTable table;
extern int whiteking_stalemate;
extern int blackking_stalemate;
extern int pondering;
extern int WHITEBASE;
extern int BLACKBASE;
extern CStatusBarCtrl statusbar;
extern int sndenable;
extern int BOARDSIZE;
SearchAgent::SearchAgent(int color,int board[8][8],int depth,int alpha,int beta,int chformate)
{
maxval=3950;
minval=0;
checkmate=0;
actualcolor=color;
checking_for_mate=chformate;
actualdepth=depth;
RetVal=RealSearch(color,board,depth,alpha,beta);
}
int SearchAgent::RealSearch(int currentcolor,int cboard[8][8],int depth,int alpha,int beta)
{
int currentboard[8][8];
int min,max;
min=13850;max=-13850;
static int count=0;
static int mincount=0;
OneMove tempbestwhitemove;
OneMove tempbestblackmove;
//Clone new board
memcpy(currentboard,cboard,BOARDSIZE);
if (depth==0)
{
//Evaluate current board
return eval(currentboard,currentcolor);
}
//Check for TransTable hit
if (!checking_for_mate)
{
TransTableEntry entry=table.LookUp(cboard);
if (entry.valid)
{
if (((entry.move.piece<10 && entry.move.piece>0 && currentcolor==1) || (entry.move.piece>10 && entry.move.piece<17 && currentcolor==0)) && entry.depth>=depth)
{
if (depth==actualdepth)
{
player_bestmove=entry.move;
}
return entry.value;
}
}
}
Moves moves;
int retval;
int newboard[8][8];
//Current color is WHITE
if (currentcolor==1)
{
int i;
int checkcount=0;
int currentalpha=alpha;
OneMove *temp;
//Generate moves for current board
moves.GenerateAllMoves(currentboard,(currentcolor==1?WHITE:BLACK),depth,checking_for_mate);
if (moves.size==0) {return (28000);}
temp=moves.head;
temp=temp->next;
currentmove=*temp;
//Iterate through moves generated
for (i=0;temp!=NULL;i++)
{
memcpy(newboard,currentboard,BOARDSIZE);
ApplyMove(newboard,temp);
if (CheckCheck(newboard,WHITE_KING,1)) //Skip if it leads to check
{
if (i!=(moves.size) && temp!=0)
{
temp=temp->next;
checkcount++;
}
else
break;
continue;
}
currentmove=*temp;
//Recursive call to next level. Return value indicates black's best move value for current white move
retval=RealSearch(!currentcolor,newboard,depth-1,currentalpha,beta);
//retval indicates move value for best black move. To prevent choosing that move, we choose the max since black's move evaluations are negative.(For white, more positive move eval the better and vice versa for black)
currentalpha=(currentalpha>retval?currentalpha:retval);
if (i==0 && actualcolor==0)
{
max=retval;
alpha=max;
}
//Value returned is greater than max so far. So must be good.
if (retval>max)
{
max=retval;
tempbestwhitemove=*temp;
//If this is top level, it is candidate for best move.
if (depth==actualdepth)
{
player_bestmove=*temp;
}
//If value reaches cutoff (means save in Transtable and return)
if (retval>=beta)
{
TransTableEntry t;
t.depth=depth;t.move=*temp;t.value=max;
table.AddEntry(cboard,t);
moves.destroy();
return max;
}
}
//Extra care to prevent going past end of linked list
if (i!=(moves.size-1) && temp!=0)
temp=temp->next;
else
break;
}
//Checking for stalemate and checkmate (If all moves are skipped as above)
if (checkcount==moves.size && !pondering)
{
if (!checking_for_mate)
{
if (!CheckCheck(currentboard,WHITE_KING,1)) //Avoid stalemate. If black moves such that white king is not in check
{
moves.destroy();
return 5000;
}
}
else
{
//Encourage mate in closest depth
if (depth==actualdepth-1)
{
return -7000;
}
else if(depth==actualdepth-2)
{
return -5000;
}
else if(depth==actualdepth-3)
{
return -3000;
}
else if(depth==actualdepth-4)
{
return -2000;
}
else
{
return -1000;
}
}
//If current level
if (depth==actualdepth)
{
//If whiteking not in check and still can't move, means Stalemate else Checkmate.(Win for black)
if (!whiteking_stalemate)
{
MessageBox(NULL,"Black Won",(computer_color==BLACK?"The Genius wins, as always":"The Genius is Defeated"),0);
checkmate=1;
if (sndenable)
{
if (computer_color==BLACK)
{
PlaySound(GetMusicDirectory()+"\\Wav\\Applause.Wav",NULL,0);
}
else
{
PlaySound(GetMusicDirectory()+"\\Wav\\Oooh.Wav",NULL,0);
}
}
statusbar.SetText("Game Over",0,0);
}
else
{
MessageBox(NULL,"Nobody wins","Stalemate",0);statusbar.SetText("Game Over",0,0);
}
end_of_game=1;
}
}
else
{
//No cutoff. Returns best value found so far though less than beta.
TransTableEntry t;
t.depth=depth;t.move=tempbestwhitemove;t.value=max;
table.AddEntry(cboard,t);
}
moves.destroy();
return max;
}
else
{
//If currentcolor is black
int i;
int currentbeta=beta;
int checkcount=0;
OneMove *temp;
//Generate Moves for current board
moves.GenerateAllMoves(currentboard,(currentcolor==1?WHITE:BLACK),depth,checking_for_mate);
if (moves.size==0) {return (-28000);}
temp=moves.head;
temp=temp->next;
currentmove=*temp;
//Iterate through loop
for (i=0;moves.size!=0 && temp!=NULL;i++)
{
//Clone new board
int newboard[8][8];
memcpy(newboard,currentboard,BOARDSIZE);
ApplyMove(newboard,temp);
if (CheckCheck(newboard,BLACK_KING,1)) //Skip if it leads to check
{
if (i!=(moves.size) && temp!=0)
{
temp=temp->next;
checkcount++;
}
else
break;
continue;
}
currentmove=*temp;
//Recursively goto next level (white's perspective)
retval=RealSearch(!currentcolor,newboard,depth-1,alpha,currentbeta);
//retval contains move value for best white move. So we shouldn't play that move and hence choose the minimum value(For white, more positive move eval the better and vice versa for black)
currentbeta=(retval<currentbeta?retval:currentbeta);
//
if (i==0 && actualcolor==1)
{
min=retval;
beta=min;
}
tempbestblackmove=*temp;
if (retval<min)
{
min=retval;
//Min of moves so far and so candidate for best move.
if (depth==actualdepth)
{
player_bestmove=*temp;
}
if (min<=alpha)
{
//retval less than what was wanted. So very good move. No need to search any more. Return eval
TransTableEntry t;
t.depth=depth;t.move=*temp;t.value=min;
table.AddEntry(cboard,t);
moves.destroy();
return min;
}
}
//Checking for end of linked list
if ((i!=moves.size) && temp!=NULL)
temp=temp->next;
}
//Checking for stalemate and checkmate
if (checkcount==moves.size && !pondering)
{
if (!checking_for_mate)
{
if (!CheckCheck(currentboard,BLACK_KING,1))
{
moves.destroy();
return -5000;
}
else
{
//Encourage mating moves by white by returning higher values for closer checkmates.
moves.destroy();
if (depth==actualdepth-1)
{
return 7000;
}
else if(depth==actualdepth-2)
{
return 5000;
}
else if(depth==actualdepth-3)
{
return 3000;
}
else if(depth==actualdepth-4)
{
return 2000;
}
else
{
return 1000;
}
}
}
if (depth==actualdepth)
{
if (!blackking_stalemate)
{
MessageBox(NULL,"White won",(computer_color==WHITE?"The Genius wins, as always":"The Genius is Defeated"),0);checkmate=1;statusbar.SetText("Game Over",0,0);
if (sndenable)
{
if (computer_color==WHITE)
{
PlaySound(GetMusicDirectory()+"\\Wav\\Applause.Wav",NULL,0);
}
else
{
PlaySound(GetMusicDirectory()+"\\Wav\\Oooh.Wav",NULL,0);
}
}
}
else
{
MessageBox(NULL,"Nobody wins","Stalemate",0);statusbar.SetText("Game Over",0,0);
}
end_of_game=1;
}
}
else
{
//No cutoff. Store value in TransTable and return
TransTableEntry t;
t.depth=depth;t.move=tempbestblackmove;t.value=min;
table.AddEntry(cboard,t);
}
moves.destroy();
return min;
}
}
void SearchAgent::ApplyMove(int currentboard[8][8],OneMove *temp)
{
currentboard[temp->desty][temp->destx]=currentboard[temp->sourcey][temp->sourcex];
currentboard[temp->sourcey][temp->sourcex]=0;
}
OneMove SearchAgent::getBestMove()
{
return player_bestmove;
}
int SearchAgent::eval(int currentboard[8][8],int color)
{
int value=0;
int oppplayer_value=0;
for (int i=0;i<8;i++)
{
for (int j=0;j<8;j++)
{
if (currentboard[i][j]<10 && currentboard[i][j]!=0)
{
switch (currentboard[i][j]%10)
{
case 1:
{
//Pawn promotion Considered as queen
if ((WHITEBASE==0 && i==7) || (WHITEBASE==7 && i==0))
{
value+=900;
}
else
{
value+=100;
}
}
break;
case 2:
{
value+=10000;
}
break;
case 3:
{
value+=900;
}
break;
case 4:
{
value+=325;
}
break;
case 5:
{
value+=300;
}break;
case 6:
{
value+=500;
}
break;
}
}
else
{
switch(currentboard[i][j]%10)
{
case 1:
{
if ((BLACKBASE==0 && i==7) || (BLACKBASE==7 && i==0))
{
oppplayer_value+=900;
}
else
{
oppplayer_value+=100;
}
}
break;
case 2:
{
oppplayer_value+=10000;
}break;
case 3:
{
oppplayer_value+=900;
}break;
case 4:
{
oppplayer_value+=325;
}
break;
case 5:
{
oppplayer_value+=300;
}break;
case 6:
{
oppplayer_value+=500;
}
}
}
}
}
//Statistical advantages.
int base=0;
if (actualcolor==1)
{
if (WHITEBASE==0)
{
base=0;
}
else
{
base=7;
}
}
else
{
if (BLACKBASE==0)
{
base=0;
}
else
{
base=7;
}
}
if (movecount<11) //Encourage horse movements in initial stages.
{
if (currentboard[base][1]==0 || currentboard[base][6]==0 || currentboard[base][2]==0 || currentboard[base][5]==0)
{
if (actualcolor==1)
{
value+=10;
}
else
{
oppplayer_value+=10;
}
}
}
if (color==1) return value-oppplayer_value; //For white, more positive the better
else return -((oppplayer_value-value)); //For black, more negative, the better.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -