From 91522721f4a6f4449e14e1b3ccb9f6f2add5d814 Mon Sep 17 00:00:00 2001 From: Hristo Kovachev Date: Wed, 22 Feb 2006 14:24:54 +0000 Subject: New chessbox plugin by Miguel A. ArГ©valo, based on GNU Chess v2 Not built yet because of a missing dependancy with the pieces' bitmaps. Someone with Makefile knowledge, please, look at it! MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8778 a1c6a512-1295-4272-9138-f99709370657 --- apps/plugins/chessbox/gnuchess.c | 2405 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 2405 insertions(+) create mode 100644 apps/plugins/chessbox/gnuchess.c (limited to 'apps/plugins/chessbox/gnuchess.c') diff --git a/apps/plugins/chessbox/gnuchess.c b/apps/plugins/chessbox/gnuchess.c new file mode 100644 index 0000000000..ed4a7f2a0f --- /dev/null +++ b/apps/plugins/chessbox/gnuchess.c @@ -0,0 +1,2405 @@ +/* + C source for CHESS. + + Revision: 5-23-88 + + Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc. + Copyright (c) 1988 John Stanback + + This file is part of CHESS. + + CHESS is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. No author or distributor + accepts responsibility to anyone for the consequences of using it + or for whether it serves any particular purpose or works at all, + unless he says so in writing. Refer to the CHESS General Public + License for full details. + + Everyone is granted permission to copy, modify and redistribute + CHESS, but only under the conditions described in the + CHESS General Public License. A copy of this license is + supposed to have been given to you along with CHESS so you + can know your rights and responsibilities. It should be in a + file named COPYING. Among other things, the copyright notice + and this notice must be preserved on all copies. +*/ + +#include "plugin.h" + +#include "gnuchess.h" + +#include + +#define ttblsz 4096 + +/*#define ttblsz 16384*/ +#define huge + +#define ctlP 0x4000 +#define ctlN 0x2800 +#define ctlB 0x1800 +#define ctlR 0x0400 +#define ctlQ 0x0200 +#define ctlK 0x0100 +#define ctlBQ 0x1200 +#define ctlRQ 0x0600 +#define ctlNN 0x2000 +#define pxx " PNBRQK" +#define qxx " pnbrqk" +#define rxx "12345678" +#define cxx "abcdefgh" +#define check 0x0001 +#define capture 0x0002 +#define draw 0x0004 +#define promote 0x0008 +#define cstlmask 0x0010 +#define epmask 0x0020 +#define exact 0x0040 +#define pwnthrt 0x0080 +#define truescore 0x0001 +#define lowerbound 0x0002 +#define upperbound 0x0004 +#define maxdepth 30 +#define true 1 +#define false 0 +#define absv(x) ((x) < 0 ? -(x) : (x)) +#define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b])) + +/* ---- RockBox datatypes and variables */ +static struct plugin_api* rb; + +/* ---- Chess datatypes and variables ---- */ +struct leaf + { + short f,t,score,reply; + unsigned short flags; + }; +struct GameRec + { + unsigned short gmove; + short score,depth,time,piece,color; + long nodes; + }; +struct TimeControlRec + { + short moves[2]; + long clock[2]; + }; +struct BookEntry + { + struct BookEntry *next; + unsigned short *mv; + }; +struct hashval + { + unsigned long bd; + unsigned short key; + }; +struct hashentry + { + unsigned long hashbd; + unsigned short mv,flags; + short score,depth; + }; + +char mvstr1[5],mvstr2[5],mvstr3[6]; +struct leaf Tree[1500],*root; +short TrPnt[maxdepth],board[64],color[64]; +short row[64],column[64],locn[8][8],Pindex[64],svalue[64]; +short PieceList[2][16],PieceCnt[2],atak[2][64],PawnCnt[2][8]; +short castld[2],kingmoved[2],mtl[2],pmtl[2],emtl[2],hung[2]; +short c1,c2,*atk1,*atk2,*PC1,*PC2,EnemyKing; +short mate,post,opponent,computer,Sdepth,Awindow,Bwindow,dither; +long ResponseTime,ExtraTime,Level,et,et0,time0,cputimer,ft; +long NodeCnt,evrate,ETnodes,EvalNodes,HashCnt; +short quit,reverse,bothsides,hashflag,InChk,player,force,easy,beep; +short wking,bking,FROMsquare,TOsquare,timeout,Zscore,zwndw,xwndw,slk; +short INCscore; +short HasPawn[2],HasKnight[2],HasBishop[2],HasRook[2],HasQueen[2]; +short ChkFlag[maxdepth],CptrFlag[maxdepth],PawnThreat[maxdepth]; +short Pscore[maxdepth],Tscore[maxdepth],Threat[maxdepth]; +struct GameRec GameList[240]; +short GameCnt,Game50,epsquare,lpost,rcptr,contempt; +short MaxSearchDepth,Xscore; +struct BookEntry *Book; +struct TimeControlRec TimeControl; +short TCflag,TCmoves,TCminutes,OperatorTime; +short otherside[3]={1,0,2}; +short rank7[3]={6,1,0}; +short map[64]= + {0,1,2,3,4,5,6,7, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77}; +short unmap[120]= + {0,1,2,3,4,5,6,7,-1,-1,-1,-1,-1,-1,-1,-1, + 8,9,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1, + 16,17,18,19,20,21,22,23,-1,-1,-1,-1,-1,-1,-1,-1, + 24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1, + 32,33,34,35,36,37,38,39,-1,-1,-1,-1,-1,-1,-1,-1, + 40,41,42,43,44,45,46,47,-1,-1,-1,-1,-1,-1,-1,-1, + 48,49,50,51,52,53,54,55,-1,-1,-1,-1,-1,-1,-1,-1, + 56,57,58,59,60,61,62,63}; +short Dcode[120]= + {0,1,1,1,1,1,1,1,0,0,0,0,0,0,0x0E,0x0F, + 0x10,0x11,0x12,0,0,0,0,0,0,0,0,0,0,0,0x0F,0x1F, + 0x10,0x21,0x11,0,0,0,0,0,0,0,0,0,0,0x0F,0,0, + 0x10,0,0,0x11,0,0,0,0,0,0,0,0,0x0F,0,0,0, + 0x10,0,0,0,0x11,0,0,0,0,0,0,0x0F,0,0,0,0, + 0x10,0,0,0,0,0x11,0,0,0,0,0x0F,0,0,0,0,0, + 0x10,0,0,0,0,0,0x11,0,0,0x0F,0,0,0,0,0,0, + 0x10,0,0,0,0,0,0,0x11}; +short Stboard[64]= + {rook,knight,bishop,queen,king,bishop,knight,rook, + pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn, + rook,knight,bishop,queen,king,bishop,knight,rook}; +short Stcolor[64]= + {white,white,white,white,white,white,white,white, + white,white,white,white,white,white,white,white, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + black,black,black,black,black,black,black,black, + black,black,black,black,black,black,black,black}; +short sweep[7]= {false,false,false,true,true,true,false}; +short Dpwn[3]={4,6,0}; +short Dstart[7]={6,4,8,4,0,0,0}; +short Dstop[7]={7,5,15,7,3,7,7}; +short Dir[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11, + 0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21}; +short Pdir[34]={0,0x38,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x35, + 0x38,0x35,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x02, + 0,0x02}; +short pbit[7]={0,0x01,0x02,0x04,0x08,0x10,0x20}; +unsigned short killr0[maxdepth],killr1[maxdepth],killr2[maxdepth]; +unsigned short killr3[maxdepth],PrVar[maxdepth]; +unsigned short PV,hint,Swag0,Swag1,Swag2,Swag3,Swag4; +unsigned short hashkey; +unsigned long hashbd; +struct hashval hashcode[2][7][64]; +struct hashentry huge *ttable,*ptbl; +unsigned char history[8192]; + +short Mwpawn[64],Mbpawn[64],Mknight[2][64],Mbishop[2][64]; +short Mking[2][64],Kfield[2][64]; +short value[7]={0,valueP,valueN,valueB,valueR,valueQ,valueK}; +short control[7]={0,ctlP,ctlN,ctlB,ctlR,ctlQ,ctlK}; +short PassedPawn0[8]={0,60,80,120,200,360,600,800}; +short PassedPawn1[8]={0,30,40,60,100,180,300,800}; +short PassedPawn2[8]={0,15,25,35,50,90,140,800}; +short PassedPawn3[8]={0,5,10,15,20,30,140,800}; +short ISOLANI[8] = {-12,-16,-20,-24,-24,-20,-16,-12}; +short BACKWARD[8] = {-6,-10,-15,-21,-28,-28,-28,-28}; +short BMBLTY[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16}; +short RMBLTY[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14}; +short Kthreat[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80, + -80,-80,-80,-80}; +short KNIGHTPOST,KNIGHTSTRONG,BISHOPSTRONG,KATAK,KBNKsq; +short PEDRNK2B,PWEAKH,PADVNCM,PADVNCI,PAWNSHIELD,PDOUBLED,PBLOK; +short RHOPN,RHOPNX,KHOPN,KHOPNX,KSFTY; +short ATAKD,HUNGP,HUNGX,KCASTLD,KMOVD,XRAY,PINVAL; +short stage,stage2,Zwmtl,Zbmtl,Developed[2],PawnStorm; +short PawnBonus,BishopBonus,RookBonus; +short KingOpening[64]= + { 0, 0, -4,-10,-10, -4, 0, 0, + -4, -4, -8,-12,-12, -8, -4, -4, + -12,-16,-20,-20,-20,-20,-16,-12, + -16,-20,-24,-24,-24,-24,-20,-16, + -16,-20,-24,-24,-24,-24,-20,-16, + -12,-16,-20,-20,-20,-20,-16,-12, + -4, -4, -8,-12,-12, -8, -4, -4, + 0, 0, -4,-10,-10, -4, 0, 0}; +short KingEnding[64]= + { 0, 4, 8,12,12, 8, 4, 0, + 4,16,20,24,24,20,16, 4, + 8,20,28,32,32,28,20, 8, + 12,24,32,36,36,32,24,12, + 12,24,32,36,36,32,24,12, + 8,20,28,32,32,28,20, 8, + 4,16,20,24,24,20,16, 4, + 0, 4, 8,12,12, 8, 4, 0}; +short KBNK[64]= + {99,90,80,70,60,50,40,40, + 90,80,60,50,40,30,20,40, + 80,60,40,30,20,10,30,50, + 70,50,30,10, 0,20,40,60, + 60,40,20, 0,10,30,50,70, + 50,30,10,20,30,40,60,80, + 40,20,30,40,50,60,80,90, + 40,40,50,60,70,80,90,99}; +short pknight[64]= + { 0, 4, 8,10,10, 8, 4, 0, + 4, 8,16,20,20,16, 8, 4, + 8,16,24,28,28,24,16, 8, + 10,20,28,32,32,28,20,10, + 10,20,28,32,32,28,20,10, + 8,16,24,28,28,24,16, 8, + 4, 8,16,20,20,16, 8, 4, + 0, 4, 8,10,10, 8, 4, 0}; +short pbishop[64]= + {14,14,14,14,14,14,14,14, + 14,22,18,18,18,18,22,14, + 14,18,22,22,22,22,18,14, + 14,18,22,22,22,22,18,14, + 14,18,22,22,22,22,18,14, + 14,18,22,22,22,22,18,14, + 14,22,18,18,18,18,22,14, + 14,14,14,14,14,14,14,14}; +short PawnAdvance[64]= + { 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 0, 0, 4, 4, 4, + 6, 8, 2,10,10, 2, 8, 6, + 6, 8,12,16,16,12, 8, 6, + 8,12,16,24,24,16,12, 8, + 12,16,24,32,32,24,16,12, + 12,16,24,32,32,24,16,12, + 0, 0, 0, 0, 0, 0, 0, 0}; + +/* ............ prototypes ............ */ +void ScorePosition( short side, short *score ); +void ScoreLoneKing( short side, short *score ); +int ScoreKPK( short side, short winner, short loser, + short king1, short king2, short sq ); +int ScoreKBNK( short winner, short king1, short king2 ); +int SqValue( short sq, short side ); +void KingScan( short sq, short *s ); +void BRscan( short sq, short *s, short *mob ); +int trapped( short sq, short piece ); +void ExaminePosition( void ); +void UpdateWeights( void ); +int distance( short a, short b ); +void BlendBoard( short a[64] , short b[64] , short c[64] ); +void CopyBoard( short a[64] , short b[64] ); + +void OpeningBook ( void ); +int search ( short side, short ply, short depth, + short alpha, short beta, + unsigned short bstline[], short *rpt ); +int evaluate ( short side, short xside, short ply, short depth, + short alpha, short beta ); +int ProbeTTable ( short side, short depth, + short *alpha, short *beta, short *score); +void PutInTTable ( short side, short score, short depth, + short alpha, short beta, unsigned short mv ); +void ZeroTTable ( void ); +void MoveList ( short side, short ply ); + +void GenMoves ( short ply, short sq, short side, short xside ); +void LinkMove ( short ply, short f, short t, short xside ); +void CaptureList ( short side, short xside, short ply ); +int castle ( short side, short kf, short kt, short iop ); +void EnPassant ( short xside, short f, short t, short iop ); +void MakeMove ( short side, struct leaf *node, + short *tempb, short *tempc, short *tempsf, short *tempst ); +void UnmakeMove ( short side, struct leaf *node, + short *tempb, short *tempc, short *tempsf, short *tempst ); +void UpdateHashbd ( short side, short piece, short f, short t ); +void UpdatePieceList ( short side, short sq, short iop ); +void InitializeStats ( void ); +void pick ( short p1, short p2 ); +void repetition ( short *cnt ); +int SqAtakd ( short sq, short side ); +void ataks ( short side, short *a ); + +void algbr ( short f, short t, short flag ); +void ElapsedTime( short iop); + +void NewGame(void); + + +/* ............ POSITIONAL EVALUATION ROUTINES ............ */ + + +void ScorePosition(side,score) +short side,*score; + +/* + Perform normal static evaluation of board position. A score is + generated for each piece and these are summed to get a score for each + side. +*/ + +{ +register short sq,s,i,xside; +short pscore[3]; + + wking = PieceList[white][0]; bking = PieceList[black][0]; + UpdateWeights(); + xside = otherside[side]; + pscore[white] = pscore[black] = 0; + + /* ok, I will yield here although this function will be called much more + many times than needed I think */ + rb->yield(); + + for (c1 = white; c1 <= black; c1++) + { + c2 = otherside[c1]; + if (c1 == white) EnemyKing = bking; else EnemyKing = wking; + atk1 = atak[c1]; atk2 = atak[c2]; + PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2]; + for (i = 0; i <= PieceCnt[c1]; i++) + { + sq = PieceList[c1][i]; + s = SqValue(sq,side); + pscore[c1] += s; + svalue[sq] = s; + } + } + if (hung[side] > 1) pscore[side] += HUNGX; + if (hung[xside] > 1) pscore[xside] += HUNGX; + + *score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] + 10; + if (dither) *score += rb->rand() % dither; + + if (*score > 0 && pmtl[side] == 0) { + if (emtl[side] < valueR) { + *score = 0; + } else { + if (*score < valueR) *score /= 2; + } + } + if (*score < 0 && pmtl[xside] == 0) { + if (emtl[xside] < valueR) { + *score = 0; + } else { + if (-*score < valueR) *score /= 2; + } + } + + if (mtl[xside] == valueK && emtl[side] > valueB) *score += 200; + if (mtl[side] == valueK && emtl[xside] > valueB) *score -= 200; +} + + +void ScoreLoneKing(side,score) +short side,*score; + +/* + Static evaluation when loser has only a king and winner has no pawns + or no pieces. +*/ + +{ +register short winner,loser,king1,king2,s,i; + + UpdateWeights(); + if (mtl[white] > mtl[black]) winner = white; else winner = black; + loser = otherside[winner]; + king1 = PieceList[winner][0]; king2 = PieceList[loser][0]; + + s = 0; + + if (pmtl[winner] > 0) + for (i = 1; i <= PieceCnt[winner]; i++) + s += ScoreKPK(side,winner,loser,king1,king2,PieceList[winner][i]); + + else if (emtl[winner] == valueB+valueN) + s = ScoreKBNK(winner,king1,king2); + + else if (emtl[winner] > valueB) + s = 500 + emtl[winner] - 2*KingEnding[king2] - 2*distance(king1,king2); + + if (side == winner) *score = s; else *score = -s; +} + + +int ScoreKPK(side,winner,loser,king1,king2,sq) +short side,winner,loser,king1,king2,sq; + +/* + Score King and Pawns versus King endings. +*/ + +{ +register short s,r; + + if (PieceCnt[winner] == 1) s = 50; else s = 120; + if (winner == white) + { + if (side == loser) r = row[sq]-1; else r = row[sq]; + if (row[king2] >= r && distance(sq,king2) < 8-r) s += 10*row[sq]; + else s = 500+50*row[sq]; + if (row[sq] < 6) sq += 16; else sq += 8; + } + else + { + if (side == loser) r = row[sq]+1; else r = row[sq]; + if (row[king2] <= r && distance(sq,king2) < r+1) s += 10*(7-row[sq]); + else s = 500+50*(7-row[sq]); + if (row[sq] > 1) sq -= 16; else sq -= 8; + } + s += 8*(taxicab(king2,sq) - taxicab(king1,sq)); + return(s); +} + + +int ScoreKBNK(winner,king1,king2) +short winner,king1,king2; + +/* + Score King+Bishop+Knight versus King endings. + This doesn't work all that well but it's better than nothing. +*/ + +{ +register short s; + s = emtl[winner] - 300; + if (KBNKsq == 0) s += KBNK[king2]; + else s += KBNK[locn[row[king2]][7-column[king2]]]; + s -= taxicab(king1,king2); + s -= distance(PieceList[winner][1],king2); + s -= distance(PieceList[winner][2],king2); + return(s); +} + + +int SqValue(sq,side) +short sq,side; + +/* + Calculate the positional value for the piece on 'sq'. +*/ + +{ +register short j,fyle,rank,a1,a2; +short s,piece,in_square,r,mob,e,c; + + piece = board[sq]; + a1 = (atk1[sq] & 0x4FFF); a2 = (atk2[sq] & 0x4FFF); + rank = row[sq]; fyle = column[sq]; + s = 0; + if (piece == pawn && c1 == white) + { + s = Mwpawn[sq]; + if (sq == 11 || sq == 12) + if (color[sq+8] != neutral) s += PEDRNK2B; + if ((fyle == 0 || PC1[fyle-1] == 0) && + (fyle == 7 || PC1[fyle+1] == 0)) + s += ISOLANI[fyle]; + else if (PC1[fyle] > 1) s += PDOUBLED; + if (a1 < ctlP && atk1[sq+8] < ctlP) + { + s += BACKWARD[a2 & 0xFF]; + if (PC2[fyle] == 0) s += PWEAKH; + if (color[sq+8] != neutral) s += PBLOK; + } + if (PC2[fyle] == 0) + { + if (side == black) r = rank-1; else r = rank; + in_square = (row[bking] >= r && distance(sq,bking) < 8-r); + if (a2 == 0 || side == white) e = 0; else e = 1; + for (j = sq+8; j < 64; j += 8) + if (atk2[j] >= ctlP) { e = 2; break; } + else if (atk2[j] > 0 || color[j] != neutral) e = 1; + if (e == 2) s += (stage*PassedPawn3[rank]) / 10; + else if (in_square || e == 1) s += (stage*PassedPawn2[rank]) / 10; + else if (emtl[black] > 0) s += (stage*PassedPawn1[rank]) / 10; + else s += PassedPawn0[rank]; + } + } + else if (piece == pawn && c1 == black) + { + s = Mbpawn[sq]; + if (sq == 51 || sq == 52) + if (color[sq-8] != neutral) s += PEDRNK2B; + if ((fyle == 0 || PC1[fyle-1] == 0) && + (fyle == 7 || PC1[fyle+1] == 0)) + s += ISOLANI[fyle]; + else if (PC1[fyle] > 1) s += PDOUBLED; + if (a1 < ctlP && atk1[sq-8] < ctlP) + { + s += BACKWARD[a2 & 0xFF]; + if (PC2[fyle] == 0) s += PWEAKH; + if (color[sq-8] != neutral) s += PBLOK; + } + if (PC2[fyle] == 0) + { + if (side == white) r = rank+1; else r = rank; + in_square = (row[wking] <= r && distance(sq,wking) < r+1); + if (a2 == 0 || side == black) e = 0; else e = 1; + for (j = sq-8; j >= 0; j -= 8) + if (atk2[j] >= ctlP) { e = 2; break; } + else if (atk2[j] > 0 || color[j] != neutral) e = 1; + if (e == 2) s += (stage*PassedPawn3[7-rank]) / 10; + else if (in_square || e == 1) s += (stage*PassedPawn2[7-rank]) / 10; + else if (emtl[white] > 0) s += (stage*PassedPawn1[7-rank]) / 10; + else s += PassedPawn0[7-rank]; + } + } + else if (piece == knight) + { + s = Mknight[c1][sq]; + } + else if (piece == bishop) + { + s = Mbishop[c1][sq]; + BRscan(sq,&s,&mob); + s += BMBLTY[mob]; + } + else if (piece == rook) + { + s += RookBonus; + BRscan(sq,&s,&mob); + s += RMBLTY[mob]; + if (PC1[fyle] == 0) s += RHOPN; + if (PC2[fyle] == 0) s += RHOPNX; + if (rank == rank7[c1] && pmtl[c2] > 100) s += 10; + if (stage > 2) s += 14 - taxicab(sq,EnemyKing); + } + else if (piece == queen) + { + if (stage > 2) s += 14 - taxicab(sq,EnemyKing); + if (distance(sq,EnemyKing) < 3) s += 12; + } + else if (piece == king) + { + s = Mking[c1][sq]; + if (KSFTY > 0) + if (Developed[c2] || stage > 0) KingScan(sq,&s); + if (castld[c1]) s += KCASTLD; + else if (kingmoved[c1]) s += KMOVD; + + if (PC1[fyle] == 0) s += KHOPN; + if (PC2[fyle] == 0) s += KHOPNX; + if (fyle == 1 || fyle == 2 || fyle == 3 || fyle == 7) + { + if (PC1[fyle-1] == 0) s += KHOPN; + if (PC2[fyle-1] == 0) s += KHOPNX; + } + if (fyle == 4 || fyle == 5 || fyle == 6 || fyle == 0) + { + if (PC1[fyle+1] == 0) s += KHOPN; + if (PC2[fyle+1] == 0) s += KHOPNX; + } + if (fyle == 2) + { + if (PC1[0] == 0) s += KHOPN; + if (PC2[0] == 0) s += KHOPNX; + } + if (fyle == 5) + { + if (PC1[7] == 0) s += KHOPN; + if (PC2[7] == 0) s += KHOPNX; + } + } + + if (a2 > 0) + { + c = (control[piece] & 0x4FFF); + if (a1 == 0 || a2 > c+1) + { + s += HUNGP; + ++hung[c1]; + if (piece != king && trapped(sq,piece)) ++hung[c1]; + } + else if (piece != pawn || a2 > a1) + if (a2 >= c || a1 < ctlP) s += ATAKD; + } + return(s); +} + + +void KingScan(sq,s) +short sq,*s; + +/* + Assign penalties if king can be threatened by checks, if squares + near the king are controlled by the enemy (especially the queen), + or if there are no pawns near the king. +*/ + +#define ScoreThreat\ + if (color[u] != c2) {\ + if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) {\ + ++cnt;\ + } else {\ + *s -= 3; \ + }\ + } + +{ +register short m,u,d,i,m0,cnt,ok; + + cnt = 0; + m0 = map[sq]; + if (HasBishop[c2] || HasQueen[c2]) + for (i = Dstart[bishop]; i <= Dstop[bishop]; i++) + { + d = Dir[i]; m = m0+d; + while (!(m & 0x88)) + { + u = unmap[m]; + if (atk2[u] & ctlBQ) ScoreThreat + if (color[u] != neutral) break; + m += d; + } + } + if (HasRook[c2] || HasQueen[c2]) + for (i = Dstart[rook]; i <= Dstop[rook]; i++) + { + d = Dir[i]; m = m0+d; + while (!(m & 0x88)) + { + u = unmap[m]; + if (atk2[u] & ctlRQ) ScoreThreat + if (color[u] != neutral) break; + m += d; + } + } + if (HasKnight[c2]) + for (i = Dstart[knight]; i <= Dstop[knight]; i++) + if (!((m = m0+Dir[i]) & 0x88)) + { + u = unmap[m]; + if (atk2[u] & ctlNN) ScoreThreat + } + *s += (KSFTY*Kthreat[cnt]) / 16; + + cnt = 0; ok = false; + m0 = map[sq]; + for (i = Dstart[king]; i <= Dstop[king]; i++) + if (!((m = m0+Dir[i]) & 0x88)) + { + u = unmap[m]; + if (board[u] == pawn) ok = true; + if (atk2[u] > atk1[u]) + { + ++cnt; + if (atk2[u] & ctlQ) + if (atk2[u] > ctlQ+1 && atk1[u] < ctlQ) *s -= 4*KSFTY; + } + } + if (!ok) *s -= KSFTY; + if (cnt > 1) *s -= KSFTY; +} + + +void BRscan(sq,s,mob) +short sq,*s,*mob; + +/* + Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the + hung[] array if a pin is found. +*/ + +{ +register short m,u,d,m0,j,piece,pin; +short *Kf; + + Kf = Kfield[c1]; + *mob = 0; + m0 = map[sq]; piece = board[sq]; + for (j = Dstart[piece]; j <= Dstop[piece]; j++) + { + pin = -1; + d = Dir[j]; m = m0+d; + while (!(m & 0x88)) + { + u = unmap[m]; *s += Kf[u]; + if (color[u] == neutral) + { + (*mob)++; + m += d; + } + else if (pin < 0) + { + if (board[u] == pawn || board[u] == king) break; + pin = u; + m += d; + } + else if (color[u] == c2 && (board[u] > piece || atk2[u] == 0)) + { + if (color[pin] == c2) + { + *s += PINVAL; + if (atk2[pin] == 0 || + atk1[pin] > control[board[pin]]+1) + ++hung[c2]; + } + else *s += XRAY; + break; + } + else break; + } + } +} + + +int trapped(sq,piece) +short sq,piece; + +/* + See if the attacked piece has unattacked squares to move to. +*/ + +{ +register short u,m,d,i,m0; + + m0 = map[sq]; + if (sweep[piece]) + for (i = Dstart[piece]; i <= Dstop[piece]; i++) + { + d = Dir[i]; m = m0+d; + while (!(m & 0x88)) + { + u = unmap[m]; + if (color[u] == c1) break; + if (atk2[u] == 0 || board[u] >= piece) return(false); + if (color[u] == c2) break; + m += d; + } + } + else if (piece == pawn) + { + if (c1 == white) u = sq+8; else u = sq-8; + if (color[u] == neutral && atk1[u] >= atk2[u]) + return(false); + if (!((m = m0+Dir[Dpwn[c1]]) & 0x88)) + if (color[unmap[m]] == c2) return(false); + if (!((m = m0+Dir[Dpwn[c1]+1]) & 0x88)) + if (color[unmap[m]] == c2) return(false); + } + else + { + for (i = Dstart[piece]; i <= Dstop[piece]; i++) + if (!((m = m0+Dir[i]) & 0x88)) + { + u = unmap[m]; + if (color[u] != c1) + if (atk2[u] == 0 || board[u] >= piece) return(false); + } + } + return(true); +} + + +void ExaminePosition() + +/* + This is done one time before the search is started. Set up arrays + Mwpawn, Mbpawn, Mknight, Mbishop, Mking which are used in the + SqValue() function to determine the positional value of each piece. +*/ + +{ +register short i,sq; +short wpadv,bpadv,wstrong,bstrong,z,side,pp,j,val,Pd,fyle,rank; + + wking = PieceList[white][0]; bking = PieceList[black][0]; + ataks(white,atak[white]); ataks(black,atak[black]); + Zwmtl = Zbmtl = 0; + UpdateWeights(); + HasPawn[white] = HasPawn[black] = 0; + HasKnight[white] = HasKnight[black] = 0; + HasBishop[white] = HasBishop[black] = 0; + HasRook[white] = HasRook[black] = 0; + HasQueen[white] = HasQueen[black] = 0; + for (side = white; side <= black; side++) + for (i = 0; i <= PieceCnt[side]; i++) + switch (board[PieceList[side][i]]) + { + case pawn : ++HasPawn[side]; break; + case knight : ++HasKnight[side]; break; + case bishop : ++HasBishop[side]; break; + case rook : ++HasRook[side]; break; + case queen : ++HasQueen[side]; break; + } + if (!Developed[white]) + Developed[white] = (board[1] != knight && board[2] != bishop && + board[5] != bishop && board[6] != knight); + if (!Developed[black]) + Developed[black] = (board[57] != knight && board[58] != bishop && + board[61] != bishop && board[62] != knight); + if (!PawnStorm && stage < 5) + PawnStorm = ((column[wking] < 3 && column[bking] > 4) || + (column[wking] > 4 && column[bking] < 3)); + + CopyBoard(pknight,Mknight[white]); + CopyBoard(pknight,Mknight[black]); + CopyBoard(pbishop,Mbishop[white]); + CopyBoard(pbishop,Mbishop[black]); + BlendBoard(KingOpening,KingEnding,Mking[white]); + BlendBoard(KingOpening,KingEnding,Mking[black]); + + for (sq = 0; sq < 64; sq++) + { + fyle = column[sq]; rank = row[sq]; + wstrong = bstrong = true; + for (i = sq; i < 64; i += 8) + if (atak[black][i] >= ctlP) wstrong = false; + for (i = sq; i >= 0; i -= 8) + if (atak[white][i] >= ctlP) bstrong = false; + wpadv = bpadv = PADVNCM; + if ((fyle == 0 || PawnCnt[white][fyle-1] == 0) && + (fyle == 7 || PawnCnt[white][fyle+1] == 0)) wpadv = PADVNCI; + if ((fyle == 0 || PawnCnt[black][fyle-1] == 0) && + (fyle == 7 || PawnCnt[black][fyle+1] == 0)) bpadv = PADVNCI; + Mwpawn[sq] = (wpadv*PawnAdvance[sq]) / 10; + Mbpawn[sq] = (bpadv*PawnAdvance[63-sq]) / 10; + Mwpawn[sq] += PawnBonus; Mbpawn[sq] += PawnBonus; + if (castld[white] || kingmoved[white]) + { + if ((fyle < 3 || fyle > 4) && distance(sq,wking) < 3) + Mwpawn[sq] += PAWNSHIELD; + } + else if (rank < 3 && (fyle < 2 || fyle > 5)) + Mwpawn[sq] += PAWNSHIELD / 2; + if (castld[black] || kingmoved[black]) + { + if ((fyle < 3 || fyle > 4) && distance(sq,bking) < 3) + Mbpawn[sq] += PAWNSHIELD; + } + else if (rank > 4 && (fyle < 2 || fyle > 5)) + Mbpawn[sq] += PAWNSHIELD / 2; + if (PawnStorm) + { + if ((column[wking] < 4 && fyle > 4) || + (column[wking] > 3 && fyle < 3)) Mwpawn[sq] += 3*rank - 21; + if ((column[bking] < 4 && fyle > 4) || + (column[bking] > 3 && fyle < 3)) Mbpawn[sq] -= 3*rank; + } + + Mknight[white][sq] += 5 - distance(sq,bking); + Mknight[white][sq] += 5 - distance(sq,wking); + Mknight[black][sq] += 5 - distance(sq,wking); + Mknight[black][sq] += 5 - distance(sq,bking); + Mbishop[white][sq] += BishopBonus; + Mbishop[black][sq] += BishopBonus; + for (i = 0; i <= PieceCnt[black]; i++) + if (distance(sq,PieceList[black][i]) < 3) + Mknight[white][sq] += KNIGHTPOST; + for (i = 0; i <= PieceCnt[white]; i++) + if (distance(sq,PieceList[white][i]) < 3) + Mknight[black][sq] += KNIGHTPOST; + if (wstrong) Mknight[white][sq] += KNIGHTSTRONG; + if (bstrong) Mknight[black][sq] += KNIGHTSTRONG; + if (wstrong) Mbishop[white][sq] += BISHOPSTRONG; + if (bstrong) Mbishop[black][sq] += BISHOPSTRONG; + + if (HasBishop[white] == 2) Mbishop[white][sq] += 8; + if (HasBishop[black] == 2) Mbishop[black][sq] += 8; + if (HasKnight[white] == 2) Mknight[white][sq] += 5; + if (HasKnight[black] == 2) Mknight[black][sq] += 5; + + if (board[sq] == bishop) { + if (rank % 2 == fyle % 2) { + KBNKsq = 0; + } else { + KBNKsq = 7; + } + } + + Kfield[white][sq] = Kfield[black][sq] = 0; + if (distance(sq,wking) == 1) Kfield[black][sq] = KATAK; + if (distance(sq,bking) == 1) Kfield[white][sq] = KATAK; + + Pd = 0; + for (i = 0; i < 64; i++) + if (board[i] == pawn) + { + if (color[i] == white) + { + pp = true; + if (row[i] == 6) z = i+8; else z = i+16; + for (j = i+8; j < 64; j += 8) + if (atak[black][j] > ctlP || board[j] == pawn) pp = false; + } + else + { + pp = true; + if (row[i] == 1) z = i-8; else z = i-16; + for (j = i-8; j >= 0; j -= 8) + if (atak[white][j] > ctlP || board[j] == pawn) pp = false; + } + if (pp) Pd += 5*taxicab(sq,z); else Pd += taxicab(sq,z); + } + if (Pd != 0) + { + val = (Pd*stage2) / 10; + Mking[white][sq] -= val; + Mking[black][sq] -= val; + } + } +} + + +void UpdateWeights() + +/* + If material balance has changed, determine the values for the + positional evaluation terms. +*/ + +{ +register short tmtl; + + if (mtl[white] != Zwmtl || mtl[black] != Zbmtl) + { + Zwmtl = mtl[white]; Zbmtl = mtl[black]; + emtl[white] = Zwmtl - pmtl[white] - valueK; + emtl[black] = Zbmtl - pmtl[black] - valueK; + tmtl = emtl[white] + emtl[black]; + if (tmtl > 6600) stage = 0; + else if (tmtl < 1400) stage = 10; + else stage = (6600-tmtl) / 520; + if (tmtl > 3600) stage2 = 0; + else if (tmtl < 1400) stage2 = 10; + else stage2 = (3600-tmtl) / 220; + + PEDRNK2B = -15; /* centre pawn on 2nd rank & blocked */ + PBLOK = -4; /* blocked backward pawn */ + PDOUBLED = -14; /* doubled pawn */ + PWEAKH = -4; /* weak pawn on half open file */ + PAWNSHIELD = 10-stage; /* pawn near friendly king */ + PADVNCM = 10; /* advanced pawn multiplier */ + PADVNCI = 7; /* muliplier for isolated pawn */ + PawnBonus = stage; + + KNIGHTPOST = (stage+2)/3; /* knight near enemy pieces */ + KNIGHTSTRONG = (stage+6)/2; /* occupies pawn hole */ + + BISHOPSTRONG = (stage+6)/2; /* occupies pawn hole */ + BishopBonus = 2*stage; + + RHOPN = 10; /* rook on half open file */ + RHOPNX = 4; + RookBonus = 6*stage; + + XRAY = 8; /* Xray attack on piece */ + PINVAL = 10; /* Pin */ + + KHOPN = (3*stage-30) / 2; /* king on half open file */ + KHOPNX = KHOPN / 2; + KCASTLD = 10 - stage; + KMOVD = -40 / (stage+1); /* king moved before castling */ + KATAK = (10-stage) / 2; /* B,R attacks near enemy king */ + if (stage < 8) KSFTY = 16-2*stage; else KSFTY = 0; + + ATAKD = -6; /* defender > attacker */ + HUNGP = -8; /* each hung piece */ + HUNGX = -12; /* extra for >1 hung piece */ + } +} + + +int distance(a,b) +short a,b; +{ +register short d1,d2; + + d1 = abs(column[a]-column[b]); + d2 = abs(row[a]-row[b]); + if (d1 > d2) return(d1); else return(d2); +} + + +void BlendBoard(a,b,c) +short a[64],b[64],c[64]; +{ +register int sq; + for (sq = 0; sq < 64; sq++) + c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10; +} + + +void CopyBoard(a,b) +short a[64],b[64]; +{ +register int sq; + for (sq = 0; sq < 64; sq++) + b[sq] = a[sq]; +} + +/* ............ MOVE GENERATION & SEARCH ROUTINES .............. */ + + +int SelectMove(side,iop) +short side,iop; + +/* + Select a move by calling function search() at progressively deeper + ply until time is up or a mate or draw is reached. An alpha-beta + window of -90 to +90 points is set around the score returned from the + previous iteration. If Sdepth != 0 then the program has correctly + predicted the opponents move and the search will start at a depth of + Sdepth+1 rather than a depth of 1. +*/ + +{ +static short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt; + + timeout = false; + xside = otherside[side]; + if (iop != 2) player = side; + if (TCflag) + { + ResponseTime = (TimeControl.clock[side]) / + (TimeControl.moves[side] + 3) - + OperatorTime; + ResponseTime += (ResponseTime*TimeControl.moves[side])/(2*TCmoves+1); + } + else ResponseTime = Level; + if (iop == 2) ResponseTime = 999; + if (Sdepth > 0 && root->score > Zscore-zwndw) ResponseTime -= ft; + else if (ResponseTime < 1) ResponseTime = 1; + ExtraTime = 0; + ExaminePosition(); + ScorePosition(side,&score); + Pscore[0] = -score; + + if (Sdepth == 0) + { + ZeroTTable(); + /*SearchStartStuff(side);*/ + for (i = 0; i < 8192; i++) history[i] = 0; + FROMsquare = TOsquare = -1; + PV = 0; + if (iop != 2) hint = 0; + for (i = 0; i < maxdepth; i++) + PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0; + + alpha = -9000; beta = 9000; + rpt = 0; + TrPnt[1] = 0; root = &Tree[0]; + MoveList(side,1); + for (i = TrPnt[1]; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1); + /*if (Book != NULL) OpeningBook();*/ + if (Book != NULL) timeout = true; + NodeCnt = ETnodes = EvalNodes = HashCnt = 0; + Zscore = 0; zwndw = 20; + } + + while (!timeout && Sdepth < MaxSearchDepth) + { + Sdepth++; + /*ShowDepth(' ');*/ + score = search(side,1,Sdepth,alpha,beta,PrVar,&rpt); + for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i]; + if (score < alpha && !timeout) + { + /*ShowDepth('-');*/ + ExtraTime = 10*ResponseTime; + ZeroTTable(); + score = search(side,1,Sdepth,-9000,beta,PrVar,&rpt); + } + if (score > beta && !timeout && !(root->flags & exact)) + { + /*ShowDepth('+');*/ + ExtraTime = 0; + ZeroTTable(); + score = search(side,1,Sdepth,alpha,9000,PrVar,&rpt); + } + score = root->score; + if (!timeout) + for (i = TrPnt[1]+1; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1); + /*ShowResults(score,PrVar,'.');*/ + for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i]; + if (score > Zscore-zwndw && score > Tree[1].score+250) ExtraTime = 0; + else if (score > Zscore-3*zwndw) ExtraTime = ResponseTime; + else ExtraTime = 3*ResponseTime; + if (root->flags & exact) timeout = true; + if (Tree[1].score < -9000) timeout = true; + if (4*et > 2*ResponseTime + ExtraTime) timeout = true; + if (!timeout) + { + Tscore[0] = score; + if (Zscore == 0) Zscore = score; + else Zscore = (Zscore+score)/2; + } + zwndw = 20+abs(Zscore/12); + beta = score + Bwindow; + if (Zscore < score) alpha = Zscore - Awindow - zwndw; + else alpha = score - Awindow - zwndw; + } + + score = root->score; + if (rpt >= 2 || score < -12000) root->flags |= draw; + if (iop == 2) return(0); + if (Book == NULL) hint = PrVar[2]; + ElapsedTime(1); + + if (score > -9999 && rpt <= 2) + { + MakeMove(side,root,&tempb,&tempc,&tempsf,&tempst); + algbr(root->f,root->t,root->flags & cstlmask); + } + else mvstr1[0] = '\0'; + /*OutputMove();*/ + if (score == -9999 || score == 9998) mate = true; + if (mate) hint = 0; + if (root->flags & cstlmask) Game50 = GameCnt; + else if (board[root->t] == pawn || (root->flags & capture)) + Game50 = GameCnt; + GameList[GameCnt].score = score; + GameList[GameCnt].nodes = NodeCnt; + GameList[GameCnt].time = (short)et; + GameList[GameCnt].depth = Sdepth; + if (TCflag) + { + TimeControl.clock[side] -= (et + OperatorTime); + if (--TimeControl.moves[side] == 0) SetTimeControl(); + } + if ((root->flags & draw) && bothsides) quit = true; + if (GameCnt > 238) quit = true; + player = xside; + Sdepth = 0; + return(0); +} + + +void OpeningBook() + +/* + Go thru each of the opening lines of play and check for a match with + the current game listing. If a match occurs, generate a random number. + If this number is the largest generated so far then the next move in + this line becomes the current "candidate". After all lines are + checked, the candidate move is put at the top of the Tree[] array and + will be played by the program. Note that the program does not handle + book transpositions. +*/ + +{ +short j,pnt; +unsigned short m,*mp; +unsigned r,r0; +struct BookEntry *p; + + rb->srand((unsigned)time0); + r0 = m = 0; + p = Book; + while (p != NULL) + { + mp = p->mv; + for (j = 0; j <= GameCnt; j++) + if (GameList[j].gmove != *(mp++)) break; + if (j > GameCnt) + if ((r=rb->rand()) > r0) + { + r0 = r; m = *mp; + hint = *(++mp); + } + p = p->next; + } + + for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++) + if ((Tree[pnt].f<<8) + Tree[pnt].t == m) Tree[pnt].score = 0; + pick(TrPnt[1],TrPnt[2]-1); + if (Tree[TrPnt[1]].score < 0) Book = NULL; +} + + + /*if (post) ShowCurrentMove(pnt,node->f,node->t);\*/ +#define UpdateSearchStatus \ +{\ + if (pnt > TrPnt[1])\ + {\ + d = best-Zscore; e = best-node->score;\ + if (best < alpha) ExtraTime = 10*ResponseTime;\ + else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\ + else if (d > -zwndw) ExtraTime = 0;\ + else if (d > -3*zwndw) ExtraTime = ResponseTime;\ + else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\ + else ExtraTime = 5*ResponseTime;\ + }\ +} + +int search(side,ply,depth,alpha,beta,bstline,rpt) +short side,ply,depth,alpha,beta,*rpt; +unsigned short bstline[]; + +/* + Perform an alpha-beta search to determine the score for the current + board position. If depth <= 0 only capturing moves, pawn promotions + and responses to check are generated and searched, otherwise all + moves are processed. The search depth is modified for check evasions, + certain re-captures and threats. Extensions may continue for up to 11 + ply beyond the nominal search depth. +*/ + +#define prune (cf && score+node->score < alpha) +#define ReCapture (rcptr && score > alpha && score < beta &&\ + ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2] &&\ + depth == Sdepth-ply+1) +#define Parry (hung[side] > 1 && ply == Sdepth+1) +#define MateThreat (ply < Sdepth+4 && ply > 4 &&\ + ChkFlag[ply-2] && ChkFlag[ply-4] &&\ + ChkFlag[ply-2] != ChkFlag[ply-4]) + +{ +register short j,pnt; +short best,tempb,tempc,tempsf,tempst; +short xside,pbst,d,e,cf,score,rcnt; +unsigned short mv,nxtline[maxdepth]; +struct leaf *node,tmp; + + NodeCnt++; + xside = otherside[side]; + + if (ply <= Sdepth+3) repetition(rpt); else *rpt = 0; + if (*rpt >= 2) return(0); + + score = evaluate(side,xside,ply,depth,alpha,beta); + if (score > 9000) return(score); + + if (depth > 0) + { + if (InChk || PawnThreat[ply-1] || ReCapture) ++depth; + } + else + { + if (score >= alpha && + (InChk || PawnThreat[ply-1] || Parry)) depth = 1; + else if (score <= beta && MateThreat) depth = 1; + } + + PV = 0; + if (depth > 0 && hashflag && ply > 1) + { + ProbeTTable(side,depth,&alpha,&beta,&score); + bstline[ply] = PV; + bstline[ply+1] = 0; + if (beta == -20000) return(score); + if (alpha > beta) return(alpha); + } + + if (Sdepth == 1) d = 7; else d = 11; + if (ply > Sdepth+d || (depth <= 0 && score > beta)) return(score); + + if (ply > 1) { + if (depth > 0) { + MoveList(side,ply); + } else { + CaptureList(side,xside,ply); + } + } + + if (TrPnt[ply] == TrPnt[ply+1]) return(score); + + cf = (depth < 1 && ply > Sdepth+1 && !ChkFlag[ply-2] && !slk); + + if (depth > 0) best = -12000; else best = score; + if (best > alpha) alpha = best; + + for (pnt = pbst = TrPnt[ply]; + pnt < TrPnt[ply+1] && best <= beta; + pnt++) + { + if (ply > 1) pick(pnt,TrPnt[ply+1]-1); + node = &Tree[pnt]; + mv = (node->f << 8) + node->t; + nxtline[ply+1] = 0; + + if (prune) break; + if (ply == 1) UpdateSearchStatus; + + if (!(node->flags & exact)) + { + MakeMove(side,node,&tempb,&tempc,&tempsf,&tempst); + CptrFlag[ply] = (node->flags & capture); + PawnThreat[ply] = (node->flags & pwnthrt); + Tscore[ply] = node->score; + node->score = -search(xside,ply+1,depth-1,-beta,-alpha, + nxtline,&rcnt); + if (abs(node->score) > 9000) node->flags |= exact; + else if (rcnt == 1) node->score /= 2; + if (rcnt >= 2 || GameCnt-Game50 > 99 || + (node->score == 9999-ply && !ChkFlag[ply])) + { + node->flags |= draw; node->flags |= exact; + if (side == computer) node->score = contempt; + else node->score = -contempt; + } + UnmakeMove(side,node,&tempb,&tempc,&tempsf,&tempst); + } + if (node->score > best && !timeout) + { + if (depth > 0) + if (node->score > alpha && !(node->flags & exact)) + node->score += depth; + best = node->score; pbst = pnt; + if (best > alpha) alpha = best; + for (j = ply+1; nxtline[j] > 0; j++) bstline[j] = nxtline[j]; + bstline[j] = 0; + bstline[ply] = mv; + if (ply == 1) + { + if (best == alpha) + { + tmp = Tree[pnt]; + for (j = pnt-1; j >= 0; j--) Tree[j+1] = Tree[j]; + Tree[0] = tmp; + pbst = 0; + } + /*if (Sdepth > 2) + if (best > beta) ShowResults(best,bstline,'+'); + else if (best < alpha) ShowResults(best,bstline,'-'); + else ShowResults(best,bstline,'&');*/ + } + } + if (NodeCnt > ETnodes) ElapsedTime(0); + if (timeout) return(-Tscore[ply-1]); + } + + node = &Tree[pbst]; + mv = (node->f<<8) + node->t; + if (hashflag && ply <= Sdepth && *rpt == 0 && best == alpha) + PutInTTable(side,best,depth,alpha,beta,mv); + if (depth > 0) + { + j = (node->f<<6) + node->t; if (side == black) j |= 0x1000; + if (history[j] < 150) history[j] += 2*depth; + if (node->t != (GameList[GameCnt].gmove & 0xFF)) { + if (best <= beta) { + killr3[ply] = mv; + } else { + if (mv != killr1[ply]) { + killr2[ply] = killr1[ply]; + killr1[ply] = mv; + } + } + } + if (best > 9000) killr0[ply] = mv; else killr0[ply] = 0; + } + return(best); +} + + +int evaluate(side,xside,ply,depth,alpha,beta) +short side,xside,ply,depth,alpha,beta; + +/* + Compute an estimate of the score by adding the positional score from + the previous ply to the material difference. If this score falls + inside a window which is 180 points wider than the alpha-beta window + (or within a 50 point window during quiescence search) call + ScorePosition() to determine a score, otherwise return the estimated + score. If one side has only a king and the other either has no pawns + or no pieces then the function ScoreLoneKing() is called. +*/ + +{ +register short evflag; + + Xscore = -Pscore[ply-1] - INCscore + mtl[side] - mtl[xside]; + hung[white] = hung[black] = 0; + slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) || + (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0))); + + if (slk) evflag = false; + else evflag = + (ply == 1 || ply < Sdepth || + (depth == 0 && Xscore > alpha-xwndw && Xscore < beta+xwndw) || + (depth < 0 && Xscore > alpha-25 && Xscore < beta+25)); + + if (evflag) + { + EvalNodes++; + ataks(side,atak[side]); + if (atak[side][PieceList[xside][0]] > 0) return(10001-ply); + ataks(xside,atak[xside]); + InChk = (atak[xside][PieceList[side][0]] > 0); + ScorePosition(side,&Xscore); + } + else + { + if (SqAtakd(PieceList[xside][0],side)) return(10001-ply); + InChk = SqAtakd(PieceList[side][0],xside); + if (slk) ScoreLoneKing(side,&Xscore); + } + + Pscore[ply] = Xscore - mtl[side] + mtl[xside]; + if (InChk) ChkFlag[ply-1] = Pindex[TOsquare]; + else ChkFlag[ply-1] = 0; + return(Xscore); +} + + +int ProbeTTable(side,depth,alpha,beta,score) +short side,depth,*alpha,*beta,*score; + +/* + Look for the current board position in the transposition table. +*/ + +{ +short hindx; + if (side == white) hashkey |= 1; else hashkey &= 0xFFFE; + hindx = (hashkey & (ttblsz-1)); + ptbl = (ttable + hindx); + if (ptbl->depth >= depth && ptbl->hashbd == hashbd) + { + HashCnt++; + PV = ptbl->mv; + if (ptbl->flags & truescore) + { + *score = ptbl->score; + *beta = -20000; + return(true); + } +/* + else if (ptbl->flags & upperbound) + { + if (ptbl->score < *beta) *beta = ptbl->score+1; + } +*/ + else if (ptbl->flags & lowerbound) + { + if (ptbl->score > *alpha) *alpha = ptbl->score-1; + } + } + return(false); +} + + +void PutInTTable(side,score,depth,alpha,beta,mv) +short side,score,depth,alpha,beta; +unsigned short mv; + +/* + Store the current board position in the transposition table. +*/ + +{ +short hindx; + if (side == white) hashkey |= 1; else hashkey &= 0xFFFE; + hindx = (hashkey & (ttblsz-1)); + ptbl = (ttable + hindx); + ptbl->hashbd = hashbd; + ptbl->depth = depth; + ptbl->score = score; + ptbl->mv = mv; + ptbl->flags = 0; + if (score < alpha) ptbl->flags |= upperbound; + else if (score > beta) ptbl->flags |= lowerbound; + else ptbl->flags |= truescore; +} + + +void ZeroTTable() +{ +int i; + if (hashflag) + for (i = 0; i < ttblsz; i++) + { + ptbl = (ttable + i); + ptbl->depth = 0; + } +} + + +void MoveList(side,ply) +short side,ply; + +/* + Fill the array Tree[] with all available moves for side to play. Array + TrPnt[ply] contains the index into Tree[] of the first move at a ply. +*/ + +{ +register short i,xside,f; + + xside = otherside[side]; + if (PV == 0) Swag0 = killr0[ply]; else Swag0 = PV; + Swag1 = killr1[ply]; Swag2 = killr2[ply]; + Swag3 = killr3[ply]; Swag4 = 0; + if (ply > 2) Swag4 = killr1[ply-2]; + TrPnt[ply+1] = TrPnt[ply]; + Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1; + for (i = PieceCnt[side]; i >= 0; i--) + GenMoves(ply,PieceList[side][i],side,xside); + if (kingmoved[side] == 0 && !castld[side]) + { + f = PieceList[side][0]; + if (castle(side,f,f+2,0)) + { + LinkMove(ply,f,f+2,xside); + Tree[TrPnt[ply+1]-1].flags |= cstlmask; + } + if (castle(side,f,f-2,0)) + { + LinkMove(ply,f,f-2,xside); + Tree[TrPnt[ply+1]-1].flags |= cstlmask; + } + } +} + + +void GenMoves(ply,sq,side,xside) +short ply,sq,side,xside; + +/* + Generate moves for a piece. The from square is mapped onto a special + board and offsets (taken from array Dir[]) are added to the mapped + location. The newly generated square is tested to see if it falls off + the board by ANDing the square with 88 HEX. Legal moves are linked + into the tree. +*/ + +{ +register short m,u,d,i,m0,piece; + + piece = board[sq]; m0 = map[sq]; + if (sweep[piece]) + for (i = Dstart[piece]; i <= Dstop[piece]; i++) + { + d = Dir[i]; m = m0+d; + while (!(m & 0x88)) + { + u = unmap[m]; + if (color[u] == neutral) + { + LinkMove(ply,sq,u,xside); + m += d; + } + else if (color[u] == xside) + { + LinkMove(ply,sq,u,xside); + break; + } + else break; + } + } + else if (piece == pawn) + { + if (side == white && color[sq+8] == neutral) + { + LinkMove(ply,sq,sq+8,xside); + if (row[sq] == 1) + if (color[sq+16] == neutral) + LinkMove(ply,sq,sq+16,xside); + } + else if (side == black && color[sq-8] == neutral) + { + LinkMove(ply,sq,sq-8,xside); + if (row[sq] == 6) + if (color[sq-16] == neutral) + LinkMove(ply,sq,sq-16,xside); + } + for (i = Dstart[piece]; i <= Dstop[piece]; i++) + if (!((m = m0+Dir[i]) & 0x88)) + { + u = unmap[m]; + if (color[u] == xside || u == epsquare) + LinkMove(ply,sq,u,xside); + } + } + else + { + for (i = Dstart[piece]; i <= Dstop[piece]; i++) + if (!((m = m0+Dir[i]) & 0x88)) + { + u = unmap[m]; + if (color[u] != side) LinkMove(ply,sq,u,xside); + } + } +} + + +void LinkMove(ply,f,t,xside) +short ply,f,t,xside; + +/* + Add a move to the tree. Assign a bonus to order the moves + as follows: + 1. Principle variation + 2. Capture of last moved piece + 3. Other captures (major pieces first) + 4. Killer moves + 5. "history" killers +*/ + +{ +register short s,z; +register unsigned short mv; +struct leaf *node; + + node = &Tree[TrPnt[ply+1]]; + ++TrPnt[ply+1]; + node->flags = 0; + node->f = f; node->t = t; + mv = (f<<8) + t; + s = 0; + if (mv == Swag0) s = 2000; + else if (mv == Swag1) s = 60; + else if (mv == Swag2) s = 50; + else if (mv == Swag3) s = 40; + else if (mv == Swag4) s = 30; + if (color[t] != neutral) + { + node->flags |= capture; + if (t == TOsquare) s += 500; + s += value[board[t]] - board[f]; + } + if (board[f] == pawn) { + if (row[t] == 0 || row[t] == 7) { + node->flags |= promote; + s += 800; + } else { + if (row[t] == 1 || row[t] == 6) { + node->flags |= pwnthrt; + s += 600; + } else { + if (t == epsquare) node->flags |= epmask; + } + } + } + z = (f<<6) + t; if (xside == white) z |= 0x1000; + s += history[z]; + node->score = s - 20000; +} + + +void CaptureList(side,xside,ply) +short side,xside,ply; + +/* + Generate captures and Pawn promotions only. +*/ + +#define LinkCapture \ +{\ + node->f = sq; node->t = u;\ + node->flags = capture;\ + node->score = value[board[u]] + svalue[board[u]] - piece;\ + if (piece == pawn && (u < 8 || u > 55))\ + {\ + node->flags |= promote;\ + node->score = valueQ;\ + }\ + ++node;\ + ++TrPnt[ply+1];\ +} + +{ +register short m,u,d,sq,m0; +short i,j,j1,j2,r7,d0,piece,*PL; +struct leaf *node; + + TrPnt[ply+1] = TrPnt[ply]; + node = &Tree[TrPnt[ply]]; + Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1; + if (side == white) + { + r7 = 6; d0 = 8; + } + else + { + r7 = 1; d0 = -8; + } + PL = PieceList[side]; + for (i = 0; i <= PieceCnt[side]; i++) + { + sq = PL[i]; + m0 = map[sq]; piece = board[sq]; + j1 = Dstart[piece]; j2 = Dstop[piece]; + if (sweep[piece]) + for (j = j1; j <= j2; j++) + { + d = Dir[j]; m = m0+d; + while (!(m & 0x88)) + { + u = unmap[m]; + if (color[u] == neutral) m += d; + else + { + if (color[u] == xside) LinkCapture; + break; + } + } + } + else + { + for (j = j1; j <= j2; j++) + if (!((m = m0+Dir[j]) & 0x88)) + { + u = unmap[m]; + if (color[u] == xside) LinkCapture; + } + if (piece == pawn && row[sq] == r7) + { + u = sq+d0; + if (color[u] == neutral) LinkCapture; + } + } + } +} + + +int castle(side,kf,kt,iop) +short side,kf,kt,iop; + +/* + Make or Unmake a castling move. +*/ + +{ +register short rf,rt,d,t0,xside; + + xside = otherside[side]; + if (kt > kf) + { + rf = kf+3; rt = kt-1; d = 1; + } + else + { + rf = kf-4; rt = kt+1; d = -1; + } + if (iop == 0) + { + if (board[kf] != king || board[rf] != rook || color[rf] != side) + return(false); + if (color[kt] != neutral || color[rt] != neutral) return(false); + if (d == -1 && color[kt+d] != neutral) return(false); + if (SqAtakd(kf,xside)) return(false); + if (SqAtakd(kt,xside)) return(false); + if (SqAtakd(kf+d,xside)) return(false); + } + else + { + if (iop == 1) castld[side] = true; else castld[side] = false; + if (iop == 2) + { + t0 = kt; kt = kf; kf = t0; + t0 = rt; rt = rf; rf = t0; + } + board[kt] = king; color[kt] = side; Pindex[kt] = 0; + board[kf] = no_piece; color[kf] = neutral; + board[rt] = rook; color[rt] = side; Pindex[rt] = Pindex[rf]; + board[rf] = no_piece; color[rf] = neutral; + PieceList[side][Pindex[kt]] = kt; + PieceList[side][Pindex[rt]] = rt; + if (hashflag) + { + UpdateHashbd(side,king,kf,kt); + UpdateHashbd(side,rook,rf,rt); + } + } + return(true); +} + + +void EnPassant(xside,f,t,iop) +short xside,f,t,iop; + +/* + Make or unmake an en passant move. +*/ + +{ +register short l; + if (t > f) l = t-8; else l = t+8; + if (iop == 1) + { + board[l] = no_piece; color[l] = neutral; + } + else + { + board[l] = pawn; color[l] = xside; + } + InitializeStats(); +} + + +void MakeMove(side,node,tempb,tempc,tempsf,tempst) +short side,*tempc,*tempb,*tempsf,*tempst; +struct leaf *node; + +/* + Update Arrays board[], color[], and Pindex[] to reflect the new board + position obtained after making the move pointed to by node. Also + update miscellaneous stuff that changes when a move is made. +*/ + +{ +register short f,t,xside,ct,cf; + + xside = otherside[side]; + f = node->f; t = node->t; epsquare = -1; + FROMsquare = f; TOsquare = t; + INCscore = 0; + GameList[++GameCnt].gmove = (f<<8) + t; + if (node->flags & cstlmask) + { + GameList[GameCnt].piece = no_piece; + GameList[GameCnt].color = side; + castle(side,f,t,1); + } + else + { + *tempc = color[t]; *tempb = board[t]; + *tempsf = svalue[f]; *tempst = svalue[t]; + GameList[GameCnt].piece = *tempb; + GameList[GameCnt].color = *tempc; + if (*tempc != neutral) + { + UpdatePieceList(*tempc,t,1); + if (*tempb == pawn) --PawnCnt[*tempc][column[t]]; + if (board[f] == pawn) + { + --PawnCnt[side][column[f]]; + ++PawnCnt[side][column[t]]; + cf = column[f]; ct = column[t]; + if (PawnCnt[side][ct] > 1+PawnCnt[side][cf]) + INCscore -= 15; + else if (PawnCnt[side][ct] < 1+PawnCnt[side][cf]) + INCscore += 15; + else if (ct == 0 || ct == 7 || PawnCnt[side][ct+ct-cf] == 0) + INCscore -= 15; + } + mtl[xside] -= value[*tempb]; + if (*tempb == pawn) pmtl[xside] -= valueP; + if (hashflag) UpdateHashbd(xside,*tempb,-1,t); + INCscore += *tempst; + } + color[t] = color[f]; board[t] = board[f]; svalue[t] = svalue[f]; + Pindex[t] = Pindex[f]; PieceList[side][Pindex[t]] = t; + color[f] = neutral; board[f] = no_piece; + if (board[t] == pawn) { + if (t-f == 16) { + epsquare = f+8; + } else { + if (f-t == 16) epsquare = f-8; + } + } + if (node->flags & promote) + { + board[t] = queen; + --PawnCnt[side][column[t]]; + mtl[side] += valueQ - valueP; + pmtl[side] -= valueP; + HasQueen[side] = true; + if (hashflag) + { + UpdateHashbd(side,pawn,f,-1); + UpdateHashbd(side,queen,f,-1); + } + INCscore -= *tempsf; + } + if (board[t] == king) ++kingmoved[side]; + if (node->flags & epmask) EnPassant(xside,f,t,1); + else if (hashflag) UpdateHashbd(side,board[t],f,t); + } +} + + +void UnmakeMove(side,node,tempb,tempc,tempsf,tempst) +short side,*tempc,*tempb,*tempsf,*tempst; +struct leaf *node; + +/* + Take back a move. +*/ + +{ +register short f,t,xside; + + xside = otherside[side]; + f = node->f; t = node->t; epsquare = -1; + GameCnt--; + if (node->flags & cstlmask) castle(side,f,t,2); + else + { + color[f] = color[t]; board[f] = board[t]; svalue[f] = *tempsf; + Pindex[f] = Pindex[t]; PieceList[side][Pindex[f]] = f; + color[t] = *tempc; board[t] = *tempb; svalue[t] = *tempst; + if (node->flags & promote) + { + board[f] = pawn; + ++PawnCnt[side][column[t]]; + mtl[side] += valueP - valueQ; + pmtl[side] += valueP; + if (hashflag) + { + UpdateHashbd(side,queen,-1,t); + UpdateHashbd(side,pawn,-1,t); + } + } + if (*tempc != neutral) + { + UpdatePieceList(*tempc,t,2); + if (*tempb == pawn) ++PawnCnt[*tempc][column[t]]; + if (board[f] == pawn) + { + --PawnCnt[side][column[t]]; + ++PawnCnt[side][column[f]]; + } + mtl[xside] += value[*tempb]; + if (*tempb == pawn) pmtl[xside] += valueP; + if (hashflag) UpdateHashbd(xside,*tempb,-1,t); + } + if (board[f] == king) --kingmoved[side]; + if (node->flags & epmask) EnPassant(xside,f,t,2); + else if (hashflag) UpdateHashbd(side,board[f],f,t); + } +} + + +void UpdateHashbd(side,piece,f,t) +short side,piece,f,t; + +/* + hashbd contains a 32 bit "signature" of the board position. hashkey + contains a 16 bit code used to address the hash table. When a move is + made, XOR'ing the hashcode of moved piece on the from and to squares + with the hashbd and hashkey values keeps things current. +*/ + +{ + if (f >= 0) + { + hashbd ^= hashcode[side][piece][f].bd; + hashkey ^= hashcode[side][piece][f].key; + } + if (t >= 0) + { + hashbd ^= hashcode[side][piece][t].bd; + hashkey ^= hashcode[side][piece][t].key; + } +} + + +void UpdatePieceList(side,sq,iop) +short side,sq,iop; + +/* + Update the PieceList and Pindex arrays when a piece is captured or + when a capture is unmade. +*/ + +{ +register short i; + if (iop == 1) + { + PieceCnt[side]--; + for (i = Pindex[sq]; i <= PieceCnt[side]; i++) + { + PieceList[side][i] = PieceList[side][i+1]; + Pindex[PieceList[side][i]] = i; + } + } + else + { + PieceCnt[side]++; + PieceList[side][PieceCnt[side]] = sq; + Pindex[sq] = PieceCnt[side]; + } +} + + +void InitializeStats() + +/* + Scan thru the board seeing what's on each square. If a piece is found, + update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also + determine the material for each side and set the hashkey and hashbd + variables to represent the current board position. Array + PieceList[side][indx] contains the location of all the pieces of + either side. Array Pindex[sq] contains the indx into PieceList for a + given square. +*/ + +{ +register short i,sq; + epsquare = -1; + for (i = 0; i < 8; i++) + PawnCnt[white][i] = PawnCnt[black][i] = 0; + mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0; + PieceCnt[white] = PieceCnt[black] = 0; + hashbd = hashkey = 0; + for (sq = 0; sq < 64; sq++) + if (color[sq] != neutral) + { + mtl[color[sq]] += value[board[sq]]; + if (board[sq] == pawn) + { + pmtl[color[sq]] += valueP; + ++PawnCnt[color[sq]][column[sq]]; + } + if (board[sq] == king) Pindex[sq] = 0; + else Pindex[sq] = ++PieceCnt[color[sq]]; + PieceList[color[sq]][Pindex[sq]] = sq; + hashbd ^= hashcode[color[sq]][board[sq]][sq].bd; + hashkey ^= hashcode[color[sq]][board[sq]][sq].key; + } +} + + +void pick(p1,p2) +short p1,p2; + +/* + Find the best move in the tree between indexes p1 and p2. Swap the + best move into the p1 element. +*/ + +{ +register short p,s,p0,s0; +struct leaf temp; + + s0 = Tree[p1].score; p0 = p1; + for (p = p1+1; p <= p2; p++) + if ((s = Tree[p].score) > s0) + { + s0 = s; p0 = p; + } + if (p0 != p1) + { + temp = Tree[p1]; Tree[p1] = Tree[p0]; Tree[p0] = temp; + } +} + + +void repetition(cnt) +short *cnt; + +/* + Check for draw by threefold repetition. +*/ + +{ +register short i,c,f,t; +short b[64]; +unsigned short m; + *cnt = c = 0; + if (GameCnt > Game50+3) + { + for (i = 0; i < 64; b[i++] = 0); + for (i = GameCnt; i > Game50; i--) + { + m = GameList[i].gmove; f = m>>8; t = m & 0xFF; + if (++b[f] == 0) c--; else c++; + if (--b[t] == 0) c--; else c++; + if (c == 0) (*cnt)++; + } + } +} + + +int SqAtakd(sq,side) +short sq,side; + +/* + See if any piece with color 'side' ataks sq. First check for pawns + or king, then try other pieces. Array Dcode is used to check for + knight attacks or R,B,Q co-linearity. +*/ + +{ +register short m,d,m0,m1,i,loc,piece,*PL; + + m1 = map[sq]; + if (side == white) m = m1-0x0F; else m = m1+0x0F; + if (!(m & 0x88)) + if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true); + if (side == white) m = m1-0x11; else m = m1+0x11; + if (!(m & 0x88)) + if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true); + if (distance(sq,PieceList[side][0]) == 1) return(true); + + PL = PieceList[side]; + for (i = 1; i <= PieceCnt[side]; i++) + { + loc = PL[i]; piece = board[loc]; + if (piece == pawn) continue; + m0 = map[loc]; d = Dcode[abs(m1-m0)]; + if (d == 0 || (Pdir[d] & pbit[piece]) == 0) continue; + if (piece == knight) return(true); + else + { + if (m1 < m0) d = -d; + for (m = m0+d; m != m1; m += d) + if (color[unmap[m]] != neutral) break; + if (m == m1) return(true); + } + } + return(false); +} + + +void ataks(side,a) +short side,*a; + +/* + Fill array atak[][] with info about ataks to a square. Bits 8-15 + are set if the piece (king..pawn) ataks the square. Bits 0-7 + contain a count of total ataks to the square. +*/ + +{ +register short u,m,d,c,m0; +short j,j1,j2,piece,i,sq,*PL; + + for (u = 0; u < 64; a[u++] = 0); + Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1; + PL = PieceList[side]; + for (i = 0; i <= PieceCnt[side]; i++) + { + sq = PL[i]; + m0 = map[sq]; + piece = board[sq]; + c = control[piece]; j1 = Dstart[piece]; j2 = Dstop[piece]; + if (sweep[piece]) + for (j = j1; j <= j2; j++) + { + d = Dir[j]; m = m0+d; + while (!(m & 0x88)) + { + u = unmap[m]; + a[u] = ++a[u] | c; + if (color[u] == neutral) m += d; + else break; + } + } + else + for (j = j1; j <= j2; j++) + if (!((m = m0+Dir[j]) & 0x88)) + { + u = unmap[m]; + a[u] = ++a[u] | c; + } + } +} + + + +void ElapsedTime(iop) + +/* + Determine the time that has passed since the search was started. If + the elapsed time exceeds the target (ResponseTime+ExtraTime) then set + timeout to true which will terminate the search. +*/ + +short iop; +{ + /*et = time((long *)0) - time0;*/ + et = *(rb->current_tick) / HZ - time0; + if (et < 0) et = 0; + ETnodes += 50; + if (et > et0 || iop == 1) + { + if (et > ResponseTime+ExtraTime && Sdepth > 1) timeout = true; + et0 = et; + if (iop == 1) + { + /*time0 = time((long *)0);*/ + time0 = *(rb->current_tick) / HZ ; + et0 = 0; + } + /*(void) times(&tmbuf2); + cputimer = 100*(tmbuf2.tms_utime - tmbuf1.tms_utime) / HZ; + if (cputimer > 0) evrate = (100*NodeCnt)/(cputimer+100*ft); + else evrate = 0;*/ + ETnodes = NodeCnt + 50; + /*UpdateClocks();*/ + } +} + + + +void SetTimeControl( void ) +{ + if (TCflag) + { + TimeControl.moves[white] = TimeControl.moves[black] = TCmoves; + TimeControl.clock[white] = TimeControl.clock[black] = 60*(long)TCminutes; + } + else + { + TimeControl.moves[white] = TimeControl.moves[black] = 0; + TimeControl.clock[white] = TimeControl.clock[black] = 0; + Level = 60*(long)TCminutes; + } + et = 0; + ElapsedTime(1); +} + + + +/* ............ INTERFACE ROUTINES ........................... */ + +/*static void VoidFunction ( void ) { + while (!(quit)) + { + if (bothsides && !mate) SelectMove(opponent,1); else InputCommand(); + if (!(quit || mate || force)) SelectMove(computer,1); + } + ExitChess(); +}*/ + +int VerifyMove(char s[],short iop,unsigned short *mv) + +/* + Compare the string 's' to the list of legal moves available for the + opponent. If a match is found, make the move on the board. +*/ + +{ +static short pnt,tempb,tempc,tempsf,tempst,cnt; +static struct leaf xnode; +struct leaf *node; + + *mv = 0; + if (iop == 2) + { + UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst); + return(false); + } + cnt = 0; + MoveList(opponent,2); + pnt = TrPnt[2]; + while (pnt < TrPnt[3]) + { + node = &Tree[pnt++]; + algbr(node->f,node->t,node->flags & cstlmask); + if (rb->strcmp(s,mvstr1) == 0 || rb->strcmp(s,mvstr2) == 0 || + rb->strcmp(s,mvstr3) == 0) + { + cnt++; xnode = *node; + } + } + if (cnt == 1) + { + MakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst); + if (SqAtakd(PieceList[opponent][0],computer)) + { + UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst); + /*ShowMessage("Illegal Move!!");*/ + return(false); + } + else + { + if (iop == 1) return(true); + /*if (xnode.flags & epmask) UpdateDisplay(0,0,1,0); + else UpdateDisplay(xnode.f,xnode.t,0,xnode.flags & cstlmask);*/ + if (xnode.flags & cstlmask) Game50 = GameCnt; + else if (board[xnode.t] == pawn || (xnode.flags & capture)) + Game50 = GameCnt; + GameList[GameCnt].depth = GameList[GameCnt].score = 0; + GameList[GameCnt].nodes = 0; + ElapsedTime(1); + GameList[GameCnt].time = (short)et; + TimeControl.clock[opponent] -= et; + --TimeControl.moves[opponent]; + *mv = (xnode.f << 8) + xnode.t; + algbr(xnode.f,xnode.t,false); + return(true); + } + } + /*if (cnt > 1) ShowMessage("Ambiguous Move!");*/ + return(false); +} + + +/* ---- Reset the board and other variables to start a new game. ---- */ +void NewGame() { + short l,r,c,p; + + mate = quit = reverse = bothsides = post = false; + hashflag = force = PawnStorm = false; + easy = beep = rcptr = true; + lpost = NodeCnt = epsquare = et0 = 0; + dither = 0; + Awindow = 90; + Bwindow = 90; + xwndw = 90; + MaxSearchDepth = 29; + contempt = 0; + GameCnt = -1; Game50 = 0; + Zwmtl = Zbmtl = 0; + Developed[white] = Developed[black] = false; + castld[white] = castld[black] = false; + kingmoved[white] = kingmoved[black] = 0; + PawnThreat[0] = CptrFlag[0] = Threat[0] = false; + Pscore[0] = 12000; Tscore[0] = 12000; + opponent = white; computer = black; + for (r = 0; r < 8; r++) + for (c = 0; c < 8; c++) + { + l = 8*r+c; locn[r][c] = l; + row[l] = r; column[l] = c; + board[l] = Stboard[l]; color[l] = Stcolor[l]; + } + for (c = white; c <= black; c++) + for (p = pawn; p <= king; p++) + for (l = 0; l < 64; l++) + { + hashcode[c][p][l].key = (unsigned short)rb->rand(); + hashcode[c][p][l].bd = ((unsigned long)rb->rand() << 16) + + (unsigned long)rb->rand(); + } + if (TCflag) SetTimeControl(); + /*else if (Level == 0) SelectLevel();*/ + /*UpdateDisplay(0,0,1,0);*/ + InitializeStats(); + /*time0 = time((long *)0);*/ + time0 = *(rb->current_tick) / HZ ; + ElapsedTime(1); + /*GetOpenings();*/ +} + +/* ---- Initialize variables and reset board ---- */ +void GNUChess_Initialize ( void ) { + int buffer_size; + /* no malloc sir, 64K should be enough for now */ + /*char ttablearray[65536];*/ + /*ttable = (struct hashentry *)ttablearray;*/ + /*ttable = (struct hashentry *)malloc(ttblsz * + (unsigned long)sizeof(struct hashentry));*/ + buffer_size = ttblsz * sizeof(struct hashentry); + ttable = rb->plugin_get_buffer( &buffer_size ); + Level = 1; + OperatorTime = 0; + TCmoves = 60; + TCminutes = 5; + TCflag = true; + NewGame(); + MaxSearchDepth = 29 ; + /* remember to GetOpenings */ +} + +void algbr(f,t,flag) +short f,t,flag; +{ + mvstr1[0] = cxx[column[f]]; mvstr1[1] = rxx[row[f]]; + mvstr1[2] = cxx[column[t]]; mvstr1[3] = rxx[row[t]]; + mvstr2[0] = qxx[board[f]]; + mvstr2[1] = mvstr1[2]; mvstr2[2] = mvstr1[3]; + mvstr1[4] = '\0'; mvstr2[3] = '\0'; + if (flag) { + if (t > f) { + rb->strcpy(mvstr2,"o-o"); + } else { + rb->strcpy(mvstr2,"o-o-o"); + } + } + + if (board[f] == pawn) mvstr3[0] = mvstr1[0]; + else mvstr3[0] = qxx[board[f]]; + if (color[t] != neutral) + { + mvstr3[1] = ':'; + mvstr3[2] = mvstr1[2]; + mvstr3[3] = mvstr1[3]; + mvstr3[4] = '\0'; + } + else if (board[f] == pawn) + { + mvstr3[1] = mvstr1[3]; + mvstr3[2] = '\0'; + } + else + { + mvstr3[1] = mvstr1[0]; + mvstr3[2] = mvstr1[1]; + mvstr3[3] = mvstr1[2]; + mvstr3[4] = mvstr1[3]; + mvstr3[5] = '\0'; + } +} -- cgit v1.2.3