code police : fix some multiply defined variables
[kugel-rb.git] / apps / plugins / chessbox / gnuchess.c
blobb164e1f83f97c264ed5d5e51afb2ea9763eb16d0
1 /*
2 C source for CHESS.
4 Revision: 5-23-88
6 Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
7 Copyright (c) 1988 John Stanback
9 This file is part of CHESS.
11 CHESS is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY. No author or distributor
13 accepts responsibility to anyone for the consequences of using it
14 or for whether it serves any particular purpose or works at all,
15 unless he says so in writing. Refer to the CHESS General Public
16 License for full details.
18 Everyone is granted permission to copy, modify and redistribute
19 CHESS, but only under the conditions described in the
20 CHESS General Public License. A copy of this license is
21 supposed to have been given to you along with CHESS so you
22 can know your rights and responsibilities. It should be in a
23 file named COPYING. Among other things, the copyright notice
24 and this notice must be preserved on all copies.
27 #include "plugin.h"
29 #include "gnuchess.h"
30 #include "opening.h"
32 #include <ctype.h>
34 #define ttblsz 4096
36 #define ctlP 0x4000
37 #define ctlN 0x2800
38 #define ctlB 0x1800
39 #define ctlR 0x0400
40 #define ctlQ 0x0200
41 #define ctlK 0x0100
42 #define ctlBQ 0x1200
43 #define ctlRQ 0x0600
44 #define ctlNN 0x2000
45 #define pxx " PNBRQK"
46 #define qxx " pnbrqk"
47 #define rxx "12345678"
48 #define cxx "abcdefgh"
49 #define check 0x0001
50 #define capture 0x0002
51 #define draw 0x0004
52 #define promote 0x0008
53 #define cstlmask 0x0010
54 #define epmask 0x0020
55 #define exact 0x0040
56 #define pwnthrt 0x0080
57 #define truescore 0x0001
58 #define lowerbound 0x0002
59 #define upperbound 0x0004
60 #define maxdepth 30
61 #define true 1
62 #define false 0
63 #define absv(x) ((x) < 0 ? -(x) : (x))
64 #define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b]))
66 /* ---- RockBox datatypes and variables */
67 extern const struct plugin_api* rb;
69 /* ---- Chess datatypes and variables ---- */
70 struct leaf
72 short f,t,score,reply;
73 unsigned short flags;
75 struct BookEntry
77 struct BookEntry *next;
78 unsigned short *mv;
80 struct hashval
82 unsigned long bd;
83 unsigned short key;
85 struct hashentry
87 unsigned long hashbd;
88 unsigned short mv,flags;
89 short score,depth;
92 char mvstr1[5],mvstr2[5],mvstr3[6];
93 struct leaf Tree[1500],*root;
94 short TrPnt[maxdepth],board[64],color[64];
95 short row[64],column[64],locn[8][8],Pindex[64],svalue[64];
96 short PieceList[2][16],PieceCnt[2],atak[2][64],PawnCnt[2][8];
97 short castld[2],kingmoved[2],mtl[2],pmtl[2],emtl[2],hung[2];
98 short c1,c2,*atk1,*atk2,*PC1,*PC2,EnemyKing;
99 short mate,post,opponent,computer,Sdepth,Awindow,Bwindow,dither;
100 bool withbook ;
101 long ResponseTime,ExtraTime,Level,et,et0,time0,cputimer,ft;
102 long NodeCnt,evrate,ETnodes,EvalNodes,HashCnt;
103 short quit,reverse,bothsides,hashflag,InChk,player,force,easy,beep;
104 short wking,bking,FROMsquare,TOsquare,timeout,Zscore,zwndw,xwndw,slk;
105 short INCscore;
106 short HasPawn[2],HasKnight[2],HasBishop[2],HasRook[2],HasQueen[2];
107 short ChkFlag[maxdepth],CptrFlag[maxdepth],PawnThreat[maxdepth];
108 short Pscore[maxdepth],Tscore[maxdepth],Threat[maxdepth];
109 struct GameRec GameList[240];
110 short GameCnt,Game50,epsquare,lpost,rcptr,contempt;
111 short MaxSearchDepth,Xscore;
112 struct TimeControlRec TimeControl;
113 short TCflag,TCmoves,TCminutes,OperatorTime;
114 short otherside[3]={1,0,2};
115 short rank7[3]={6,1,0};
116 short map[64]=
117 {0,1,2,3,4,5,6,7,
118 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
119 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
120 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
121 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
122 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
123 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
124 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77};
125 short unmap[120]=
126 {0,1,2,3,4,5,6,7,-1,-1,-1,-1,-1,-1,-1,-1,
127 8,9,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,
128 16,17,18,19,20,21,22,23,-1,-1,-1,-1,-1,-1,-1,-1,
129 24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
130 32,33,34,35,36,37,38,39,-1,-1,-1,-1,-1,-1,-1,-1,
131 40,41,42,43,44,45,46,47,-1,-1,-1,-1,-1,-1,-1,-1,
132 48,49,50,51,52,53,54,55,-1,-1,-1,-1,-1,-1,-1,-1,
133 56,57,58,59,60,61,62,63};
134 short Dcode[120]=
135 {0,1,1,1,1,1,1,1,0,0,0,0,0,0,0x0E,0x0F,
136 0x10,0x11,0x12,0,0,0,0,0,0,0,0,0,0,0,0x0F,0x1F,
137 0x10,0x21,0x11,0,0,0,0,0,0,0,0,0,0,0x0F,0,0,
138 0x10,0,0,0x11,0,0,0,0,0,0,0,0,0x0F,0,0,0,
139 0x10,0,0,0,0x11,0,0,0,0,0,0,0x0F,0,0,0,0,
140 0x10,0,0,0,0,0x11,0,0,0,0,0x0F,0,0,0,0,0,
141 0x10,0,0,0,0,0,0x11,0,0,0x0F,0,0,0,0,0,0,
142 0x10,0,0,0,0,0,0,0x11};
143 short Stboard[64]=
144 {rook,knight,bishop,queen,king,bishop,knight,rook,
145 pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
146 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
147 pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
148 rook,knight,bishop,queen,king,bishop,knight,rook};
149 short Stcolor[64]=
150 {white,white,white,white,white,white,white,white,
151 white,white,white,white,white,white,white,white,
152 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,
153 black,black,black,black,black,black,black,black,
154 black,black,black,black,black,black,black,black};
155 short sweep[7]= {false,false,false,true,true,true,false};
156 short Dpwn[3]={4,6,0};
157 short Dstart[7]={6,4,8,4,0,0,0};
158 short Dstop[7]={7,5,15,7,3,7,7};
159 short Dir[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11,
160 0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21};
161 short Pdir[34]={0,0x38,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x35,
162 0x38,0x35,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x02,
163 0,0x02};
164 short pbit[7]={0,0x01,0x02,0x04,0x08,0x10,0x20};
165 unsigned short killr0[maxdepth],killr1[maxdepth],killr2[maxdepth];
166 unsigned short killr3[maxdepth],PrVar[maxdepth];
167 unsigned short PV,hint,Swag0,Swag1,Swag2,Swag3,Swag4;
168 unsigned short hashkey;
169 unsigned long hashbd;
170 struct hashval hashcode[2][7][64];
171 struct hashentry ttable[ttblsz];
172 struct hashentry *ptbl;
173 unsigned char history[8192];
175 short Mwpawn[64],Mbpawn[64],Mknight[2][64],Mbishop[2][64];
176 short Mking[2][64],Kfield[2][64];
177 short value[7]={0,valueP,valueN,valueB,valueR,valueQ,valueK};
178 short control[7]={0,ctlP,ctlN,ctlB,ctlR,ctlQ,ctlK};
179 short PassedPawn0[8]={0,60,80,120,200,360,600,800};
180 short PassedPawn1[8]={0,30,40,60,100,180,300,800};
181 short PassedPawn2[8]={0,15,25,35,50,90,140,800};
182 short PassedPawn3[8]={0,5,10,15,20,30,140,800};
183 short ISOLANI[8] = {-12,-16,-20,-24,-24,-20,-16,-12};
184 short BACKWARD[8] = {-6,-10,-15,-21,-28,-28,-28,-28};
185 short BMBLTY[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16};
186 short RMBLTY[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14};
187 short Kthreat[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80,
188 -80,-80,-80,-80};
189 short KNIGHTPOST,KNIGHTSTRONG,BISHOPSTRONG,KATAK,KBNKsq;
190 short PEDRNK2B,PWEAKH,PADVNCM,PADVNCI,PAWNSHIELD,PDOUBLED,PBLOK;
191 short RHOPN,RHOPNX,KHOPN,KHOPNX,KSFTY;
192 short ATAKD,HUNGP,HUNGX,KCASTLD,KMOVD,XRAY,PINVAL;
193 short stage,stage2,Zwmtl,Zbmtl,Developed[2],PawnStorm;
194 short PawnBonus,BishopBonus,RookBonus;
195 short KingOpening[64]=
196 { 0, 0, -4,-10,-10, -4, 0, 0,
197 -4, -4, -8,-12,-12, -8, -4, -4,
198 -12,-16,-20,-20,-20,-20,-16,-12,
199 -16,-20,-24,-24,-24,-24,-20,-16,
200 -16,-20,-24,-24,-24,-24,-20,-16,
201 -12,-16,-20,-20,-20,-20,-16,-12,
202 -4, -4, -8,-12,-12, -8, -4, -4,
203 0, 0, -4,-10,-10, -4, 0, 0};
204 short KingEnding[64]=
205 { 0, 4, 8,12,12, 8, 4, 0,
206 4,16,20,24,24,20,16, 4,
207 8,20,28,32,32,28,20, 8,
208 12,24,32,36,36,32,24,12,
209 12,24,32,36,36,32,24,12,
210 8,20,28,32,32,28,20, 8,
211 4,16,20,24,24,20,16, 4,
212 0, 4, 8,12,12, 8, 4, 0};
213 short KBNK[64]=
214 {99,90,80,70,60,50,40,40,
215 90,80,60,50,40,30,20,40,
216 80,60,40,30,20,10,30,50,
217 70,50,30,10, 0,20,40,60,
218 60,40,20, 0,10,30,50,70,
219 50,30,10,20,30,40,60,80,
220 40,20,30,40,50,60,80,90,
221 40,40,50,60,70,80,90,99};
222 short pknight[64]=
223 { 0, 4, 8,10,10, 8, 4, 0,
224 4, 8,16,20,20,16, 8, 4,
225 8,16,24,28,28,24,16, 8,
226 10,20,28,32,32,28,20,10,
227 10,20,28,32,32,28,20,10,
228 8,16,24,28,28,24,16, 8,
229 4, 8,16,20,20,16, 8, 4,
230 0, 4, 8,10,10, 8, 4, 0};
231 short pbishop[64]=
232 {14,14,14,14,14,14,14,14,
233 14,22,18,18,18,18,22,14,
234 14,18,22,22,22,22,18,14,
235 14,18,22,22,22,22,18,14,
236 14,18,22,22,22,22,18,14,
237 14,18,22,22,22,22,18,14,
238 14,22,18,18,18,18,22,14,
239 14,14,14,14,14,14,14,14};
240 short PawnAdvance[64]=
241 { 0, 0, 0, 0, 0, 0, 0, 0,
242 4, 4, 4, 0, 0, 4, 4, 4,
243 6, 8, 2,10,10, 2, 8, 6,
244 6, 8,12,16,16,12, 8, 6,
245 8,12,16,24,24,16,12, 8,
246 12,16,24,32,32,24,16,12,
247 12,16,24,32,32,24,16,12,
248 0, 0, 0, 0, 0, 0, 0, 0};
250 /* ............ prototypes ............ */
251 void ScorePosition( short side, short *score );
252 void ScoreLoneKing( short side, short *score );
253 int ScoreKPK( short side, short winner, short loser,
254 short king1, short king2, short sq );
255 int ScoreKBNK( short winner, short king1, short king2 );
256 int SqValue( short sq, short side );
257 void KingScan( short sq, short *s );
258 void BRscan( short sq, short *s, short *mob );
259 int trapped( short sq, short piece );
260 void ExaminePosition( void );
261 void UpdateWeights( void );
262 int distance( short a, short b );
263 void BlendBoard( short a[64] , short b[64] , short c[64] );
264 void CopyBoard( short a[64] , short b[64] );
266 void OpeningBook ( void );
267 int search ( short side, short ply, short depth,
268 short alpha, short beta,
269 unsigned short bstline[], short *rpt,
270 void (*callback)(void) );
271 int evaluate ( short side, short xside, short ply, short depth,
272 short alpha, short beta );
273 int ProbeTTable ( short side, short depth,
274 short *alpha, short *beta, short *score);
275 void PutInTTable ( short side, short score, short depth,
276 short alpha, short beta, unsigned short mv );
277 void ZeroTTable ( void );
278 void MoveList ( short side, short ply );
280 void GenMoves ( short ply, short sq, short side, short xside );
281 void LinkMove ( short ply, short f, short t, short xside );
282 void CaptureList ( short side, short xside, short ply );
283 int castle ( short side, short kf, short kt, short iop );
284 void EnPassant ( short xside, short f, short t, short iop );
285 void MakeMove ( short side, struct leaf *node,
286 short *tempb, short *tempc, short *tempsf, short *tempst );
287 void UnmakeMove ( short side, struct leaf *node,
288 short *tempb, short *tempc, short *tempsf, short *tempst );
289 void UpdateHashbd ( short side, short piece, short f, short t );
290 void UpdatePieceList ( short side, short sq, short iop );
291 void InitializeStats ( void );
292 void pick ( short p1, short p2 );
293 void repetition ( short *cnt );
294 int SqAtakd ( short sq, short side );
295 void ataks ( short side, short *a );
297 void algbr ( short f, short t, short flag );
298 void ElapsedTime( short iop);
300 void NewGame(void);
303 /* ............ POSITIONAL EVALUATION ROUTINES ............ */
306 void ScorePosition(side,score)
307 short side,*score;
310 Perform normal static evaluation of board position. A score is
311 generated for each piece and these are summed to get a score for each
312 side.
316 register short sq,s,i,xside;
317 short pscore[3];
319 wking = PieceList[white][0]; bking = PieceList[black][0];
320 UpdateWeights();
321 xside = otherside[side];
322 pscore[white] = pscore[black] = 0;
324 for (c1 = white; c1 <= black; c1++)
326 c2 = otherside[c1];
327 if (c1 == white) EnemyKing = bking; else EnemyKing = wking;
328 atk1 = atak[c1]; atk2 = atak[c2];
329 PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
330 for (i = 0; i <= PieceCnt[c1]; i++)
332 sq = PieceList[c1][i];
333 s = SqValue(sq,side);
334 pscore[c1] += s;
335 svalue[sq] = s;
338 if (hung[side] > 1) pscore[side] += HUNGX;
339 if (hung[xside] > 1) pscore[xside] += HUNGX;
341 *score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] + 10;
342 if (dither) *score += rb->rand() % dither;
344 if (*score > 0 && pmtl[side] == 0) {
345 if (emtl[side] < valueR) {
346 *score = 0;
347 } else {
348 if (*score < valueR) *score /= 2;
351 if (*score < 0 && pmtl[xside] == 0) {
352 if (emtl[xside] < valueR) {
353 *score = 0;
354 } else {
355 if (-*score < valueR) *score /= 2;
359 if (mtl[xside] == valueK && emtl[side] > valueB) *score += 200;
360 if (mtl[side] == valueK && emtl[xside] > valueB) *score -= 200;
364 void ScoreLoneKing(side,score)
365 short side,*score;
368 Static evaluation when loser has only a king and winner has no pawns
369 or no pieces.
373 register short winner,loser,king1,king2,s,i;
375 UpdateWeights();
376 if (mtl[white] > mtl[black]) winner = white; else winner = black;
377 loser = otherside[winner];
378 king1 = PieceList[winner][0]; king2 = PieceList[loser][0];
380 s = 0;
382 if (pmtl[winner] > 0)
383 for (i = 1; i <= PieceCnt[winner]; i++)
384 s += ScoreKPK(side,winner,loser,king1,king2,PieceList[winner][i]);
386 else if (emtl[winner] == valueB+valueN)
387 s = ScoreKBNK(winner,king1,king2);
389 else if (emtl[winner] > valueB)
390 s = 500 + emtl[winner] - 2*KingEnding[king2] - 2*distance(king1,king2);
392 if (side == winner) *score = s; else *score = -s;
396 int ScoreKPK(side,winner,loser,king1,king2,sq)
397 short side,winner,loser,king1,king2,sq;
400 Score King and Pawns versus King endings.
404 register short s,r;
406 if (PieceCnt[winner] == 1) s = 50; else s = 120;
407 if (winner == white)
409 if (side == loser) r = row[sq]-1; else r = row[sq];
410 if (row[king2] >= r && distance(sq,king2) < 8-r) s += 10*row[sq];
411 else s = 500+50*row[sq];
412 if (row[sq] < 6) sq += 16; else sq += 8;
414 else
416 if (side == loser) r = row[sq]+1; else r = row[sq];
417 if (row[king2] <= r && distance(sq,king2) < r+1) s += 10*(7-row[sq]);
418 else s = 500+50*(7-row[sq]);
419 if (row[sq] > 1) sq -= 16; else sq -= 8;
421 s += 8*(taxicab(king2,sq) - taxicab(king1,sq));
422 return(s);
426 int ScoreKBNK(winner,king1,king2)
427 short winner,king1,king2;
430 Score King+Bishop+Knight versus King endings.
431 This doesn't work all that well but it's better than nothing.
435 register short s;
436 s = emtl[winner] - 300;
437 if (KBNKsq == 0) s += KBNK[king2];
438 else s += KBNK[locn[row[king2]][7-column[king2]]];
439 s -= taxicab(king1,king2);
440 s -= distance(PieceList[winner][1],king2);
441 s -= distance(PieceList[winner][2],king2);
442 return(s);
446 int SqValue(sq,side)
447 short sq,side;
450 Calculate the positional value for the piece on 'sq'.
454 register short j,fyle,rank,a1,a2;
455 short s,piece,in_square,r,mob,e,c;
457 piece = board[sq];
458 a1 = (atk1[sq] & 0x4FFF); a2 = (atk2[sq] & 0x4FFF);
459 rank = row[sq]; fyle = column[sq];
460 s = 0;
461 if (piece == pawn && c1 == white)
463 s = Mwpawn[sq];
464 if (sq == 11 || sq == 12)
465 if (color[sq+8] != neutral) s += PEDRNK2B;
466 if ((fyle == 0 || PC1[fyle-1] == 0) &&
467 (fyle == 7 || PC1[fyle+1] == 0))
468 s += ISOLANI[fyle];
469 else if (PC1[fyle] > 1) s += PDOUBLED;
470 if (a1 < ctlP && atk1[sq+8] < ctlP)
472 s += BACKWARD[a2 & 0xFF];
473 if (PC2[fyle] == 0) s += PWEAKH;
474 if (color[sq+8] != neutral) s += PBLOK;
476 if (PC2[fyle] == 0)
478 if (side == black) r = rank-1; else r = rank;
479 in_square = (row[bking] >= r && distance(sq,bking) < 8-r);
480 if (a2 == 0 || side == white) e = 0; else e = 1;
481 for (j = sq+8; j < 64; j += 8)
482 if (atk2[j] >= ctlP) { e = 2; break; }
483 else if (atk2[j] > 0 || color[j] != neutral) e = 1;
484 if (e == 2) s += (stage*PassedPawn3[rank]) / 10;
485 else if (in_square || e == 1) s += (stage*PassedPawn2[rank]) / 10;
486 else if (emtl[black] > 0) s += (stage*PassedPawn1[rank]) / 10;
487 else s += PassedPawn0[rank];
490 else if (piece == pawn && c1 == black)
492 s = Mbpawn[sq];
493 if (sq == 51 || sq == 52)
494 if (color[sq-8] != neutral) s += PEDRNK2B;
495 if ((fyle == 0 || PC1[fyle-1] == 0) &&
496 (fyle == 7 || PC1[fyle+1] == 0))
497 s += ISOLANI[fyle];
498 else if (PC1[fyle] > 1) s += PDOUBLED;
499 if (a1 < ctlP && atk1[sq-8] < ctlP)
501 s += BACKWARD[a2 & 0xFF];
502 if (PC2[fyle] == 0) s += PWEAKH;
503 if (color[sq-8] != neutral) s += PBLOK;
505 if (PC2[fyle] == 0)
507 if (side == white) r = rank+1; else r = rank;
508 in_square = (row[wking] <= r && distance(sq,wking) < r+1);
509 if (a2 == 0 || side == black) e = 0; else e = 1;
510 for (j = sq-8; j >= 0; j -= 8)
511 if (atk2[j] >= ctlP) { e = 2; break; }
512 else if (atk2[j] > 0 || color[j] != neutral) e = 1;
513 if (e == 2) s += (stage*PassedPawn3[7-rank]) / 10;
514 else if (in_square || e == 1) s += (stage*PassedPawn2[7-rank]) / 10;
515 else if (emtl[white] > 0) s += (stage*PassedPawn1[7-rank]) / 10;
516 else s += PassedPawn0[7-rank];
519 else if (piece == knight)
521 s = Mknight[c1][sq];
523 else if (piece == bishop)
525 s = Mbishop[c1][sq];
526 BRscan(sq,&s,&mob);
527 s += BMBLTY[mob];
529 else if (piece == rook)
531 s += RookBonus;
532 BRscan(sq,&s,&mob);
533 s += RMBLTY[mob];
534 if (PC1[fyle] == 0) s += RHOPN;
535 if (PC2[fyle] == 0) s += RHOPNX;
536 if (rank == rank7[c1] && pmtl[c2] > 100) s += 10;
537 if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
539 else if (piece == queen)
541 if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
542 if (distance(sq,EnemyKing) < 3) s += 12;
544 else if (piece == king)
546 s = Mking[c1][sq];
547 if (KSFTY > 0)
548 if (Developed[c2] || stage > 0) KingScan(sq,&s);
549 if (castld[c1]) s += KCASTLD;
550 else if (kingmoved[c1]) s += KMOVD;
552 if (PC1[fyle] == 0) s += KHOPN;
553 if (PC2[fyle] == 0) s += KHOPNX;
554 if (fyle == 1 || fyle == 2 || fyle == 3 || fyle == 7)
556 if (PC1[fyle-1] == 0) s += KHOPN;
557 if (PC2[fyle-1] == 0) s += KHOPNX;
559 if (fyle == 4 || fyle == 5 || fyle == 6 || fyle == 0)
561 if (PC1[fyle+1] == 0) s += KHOPN;
562 if (PC2[fyle+1] == 0) s += KHOPNX;
564 if (fyle == 2)
566 if (PC1[0] == 0) s += KHOPN;
567 if (PC2[0] == 0) s += KHOPNX;
569 if (fyle == 5)
571 if (PC1[7] == 0) s += KHOPN;
572 if (PC2[7] == 0) s += KHOPNX;
576 if (a2 > 0)
578 c = (control[piece] & 0x4FFF);
579 if (a1 == 0 || a2 > c+1)
581 s += HUNGP;
582 ++hung[c1];
583 if (piece != king && trapped(sq,piece)) ++hung[c1];
585 else if (piece != pawn || a2 > a1)
586 if (a2 >= c || a1 < ctlP) s += ATAKD;
588 return(s);
592 void KingScan(sq,s)
593 short sq,*s;
596 Assign penalties if king can be threatened by checks, if squares
597 near the king are controlled by the enemy (especially the queen),
598 or if there are no pawns near the king.
601 #define ScoreThreat\
602 if (color[u] != c2) {\
603 if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) {\
604 ++cnt;\
605 } else {\
606 *s -= 3; \
611 register short m,u,d,i,m0,cnt,ok;
613 cnt = 0;
614 m0 = map[sq];
615 if (HasBishop[c2] || HasQueen[c2])
616 for (i = Dstart[bishop]; i <= Dstop[bishop]; i++)
618 d = Dir[i]; m = m0+d;
619 while (!(m & 0x88))
621 u = unmap[m];
622 if (atk2[u] & ctlBQ) ScoreThreat
623 if (color[u] != neutral) break;
624 m += d;
627 if (HasRook[c2] || HasQueen[c2])
628 for (i = Dstart[rook]; i <= Dstop[rook]; i++)
630 d = Dir[i]; m = m0+d;
631 while (!(m & 0x88))
633 u = unmap[m];
634 if (atk2[u] & ctlRQ) ScoreThreat
635 if (color[u] != neutral) break;
636 m += d;
639 if (HasKnight[c2])
640 for (i = Dstart[knight]; i <= Dstop[knight]; i++)
641 if (!((m = m0+Dir[i]) & 0x88))
643 u = unmap[m];
644 if (atk2[u] & ctlNN) ScoreThreat
646 *s += (KSFTY*Kthreat[cnt]) / 16;
648 cnt = 0; ok = false;
649 m0 = map[sq];
650 for (i = Dstart[king]; i <= Dstop[king]; i++)
651 if (!((m = m0+Dir[i]) & 0x88))
653 u = unmap[m];
654 if (board[u] == pawn) ok = true;
655 if (atk2[u] > atk1[u])
657 ++cnt;
658 if (atk2[u] & ctlQ)
659 if (atk2[u] > ctlQ+1 && atk1[u] < ctlQ) *s -= 4*KSFTY;
662 if (!ok) *s -= KSFTY;
663 if (cnt > 1) *s -= KSFTY;
667 void BRscan(sq,s,mob)
668 short sq,*s,*mob;
671 Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
672 hung[] array if a pin is found.
676 register short m,u,d,m0,j,piece,pin;
677 short *Kf;
679 Kf = Kfield[c1];
680 *mob = 0;
681 m0 = map[sq]; piece = board[sq];
682 for (j = Dstart[piece]; j <= Dstop[piece]; j++)
684 pin = -1;
685 d = Dir[j]; m = m0+d;
686 while (!(m & 0x88))
688 u = unmap[m]; *s += Kf[u];
689 if (color[u] == neutral)
691 (*mob)++;
692 m += d;
694 else if (pin < 0)
696 if (board[u] == pawn || board[u] == king) break;
697 pin = u;
698 m += d;
700 else if (color[u] == c2 && (board[u] > piece || atk2[u] == 0))
702 if (color[pin] == c2)
704 *s += PINVAL;
705 if (atk2[pin] == 0 ||
706 atk1[pin] > control[board[pin]]+1)
707 ++hung[c2];
709 else *s += XRAY;
710 break;
712 else break;
718 int trapped(sq,piece)
719 short sq,piece;
722 See if the attacked piece has unattacked squares to move to.
726 register short u,m,d,i,m0;
728 m0 = map[sq];
729 if (sweep[piece])
730 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
732 d = Dir[i]; m = m0+d;
733 while (!(m & 0x88))
735 u = unmap[m];
736 if (color[u] == c1) break;
737 if (atk2[u] == 0 || board[u] >= piece) return(false);
738 if (color[u] == c2) break;
739 m += d;
742 else if (piece == pawn)
744 if (c1 == white) u = sq+8; else u = sq-8;
745 if (color[u] == neutral && atk1[u] >= atk2[u])
746 return(false);
747 if (!((m = m0+Dir[Dpwn[c1]]) & 0x88))
748 if (color[unmap[m]] == c2) return(false);
749 if (!((m = m0+Dir[Dpwn[c1]+1]) & 0x88))
750 if (color[unmap[m]] == c2) return(false);
752 else
754 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
755 if (!((m = m0+Dir[i]) & 0x88))
757 u = unmap[m];
758 if (color[u] != c1)
759 if (atk2[u] == 0 || board[u] >= piece) return(false);
762 return(true);
766 void ExaminePosition()
769 This is done one time before the search is started. Set up arrays
770 Mwpawn, Mbpawn, Mknight, Mbishop, Mking which are used in the
771 SqValue() function to determine the positional value of each piece.
775 register short i,sq;
776 short wpadv,bpadv,wstrong,bstrong,z,side,pp,j,val,Pd,fyle,rank;
778 wking = PieceList[white][0]; bking = PieceList[black][0];
779 ataks(white,atak[white]); ataks(black,atak[black]);
780 Zwmtl = Zbmtl = 0;
781 UpdateWeights();
782 HasPawn[white] = HasPawn[black] = 0;
783 HasKnight[white] = HasKnight[black] = 0;
784 HasBishop[white] = HasBishop[black] = 0;
785 HasRook[white] = HasRook[black] = 0;
786 HasQueen[white] = HasQueen[black] = 0;
787 for (side = white; side <= black; side++)
788 for (i = 0; i <= PieceCnt[side]; i++)
789 switch (board[PieceList[side][i]])
791 case pawn : ++HasPawn[side]; break;
792 case knight : ++HasKnight[side]; break;
793 case bishop : ++HasBishop[side]; break;
794 case rook : ++HasRook[side]; break;
795 case queen : ++HasQueen[side]; break;
797 if (!Developed[white])
798 Developed[white] = (board[1] != knight && board[2] != bishop &&
799 board[5] != bishop && board[6] != knight);
800 if (!Developed[black])
801 Developed[black] = (board[57] != knight && board[58] != bishop &&
802 board[61] != bishop && board[62] != knight);
803 if (!PawnStorm && stage < 5)
804 PawnStorm = ((column[wking] < 3 && column[bking] > 4) ||
805 (column[wking] > 4 && column[bking] < 3));
807 CopyBoard(pknight,Mknight[white]);
808 CopyBoard(pknight,Mknight[black]);
809 CopyBoard(pbishop,Mbishop[white]);
810 CopyBoard(pbishop,Mbishop[black]);
811 BlendBoard(KingOpening,KingEnding,Mking[white]);
812 BlendBoard(KingOpening,KingEnding,Mking[black]);
814 for (sq = 0; sq < 64; sq++)
816 fyle = column[sq]; rank = row[sq];
817 wstrong = bstrong = true;
818 for (i = sq; i < 64; i += 8)
819 if (atak[black][i] >= ctlP) wstrong = false;
820 for (i = sq; i >= 0; i -= 8)
821 if (atak[white][i] >= ctlP) bstrong = false;
822 wpadv = bpadv = PADVNCM;
823 if ((fyle == 0 || PawnCnt[white][fyle-1] == 0) &&
824 (fyle == 7 || PawnCnt[white][fyle+1] == 0)) wpadv = PADVNCI;
825 if ((fyle == 0 || PawnCnt[black][fyle-1] == 0) &&
826 (fyle == 7 || PawnCnt[black][fyle+1] == 0)) bpadv = PADVNCI;
827 Mwpawn[sq] = (wpadv*PawnAdvance[sq]) / 10;
828 Mbpawn[sq] = (bpadv*PawnAdvance[63-sq]) / 10;
829 Mwpawn[sq] += PawnBonus; Mbpawn[sq] += PawnBonus;
830 if (castld[white] || kingmoved[white])
832 if ((fyle < 3 || fyle > 4) && distance(sq,wking) < 3)
833 Mwpawn[sq] += PAWNSHIELD;
835 else if (rank < 3 && (fyle < 2 || fyle > 5))
836 Mwpawn[sq] += PAWNSHIELD / 2;
837 if (castld[black] || kingmoved[black])
839 if ((fyle < 3 || fyle > 4) && distance(sq,bking) < 3)
840 Mbpawn[sq] += PAWNSHIELD;
842 else if (rank > 4 && (fyle < 2 || fyle > 5))
843 Mbpawn[sq] += PAWNSHIELD / 2;
844 if (PawnStorm)
846 if ((column[wking] < 4 && fyle > 4) ||
847 (column[wking] > 3 && fyle < 3)) Mwpawn[sq] += 3*rank - 21;
848 if ((column[bking] < 4 && fyle > 4) ||
849 (column[bking] > 3 && fyle < 3)) Mbpawn[sq] -= 3*rank;
852 Mknight[white][sq] += 5 - distance(sq,bking);
853 Mknight[white][sq] += 5 - distance(sq,wking);
854 Mknight[black][sq] += 5 - distance(sq,wking);
855 Mknight[black][sq] += 5 - distance(sq,bking);
856 Mbishop[white][sq] += BishopBonus;
857 Mbishop[black][sq] += BishopBonus;
858 for (i = 0; i <= PieceCnt[black]; i++)
859 if (distance(sq,PieceList[black][i]) < 3)
860 Mknight[white][sq] += KNIGHTPOST;
861 for (i = 0; i <= PieceCnt[white]; i++)
862 if (distance(sq,PieceList[white][i]) < 3)
863 Mknight[black][sq] += KNIGHTPOST;
864 if (wstrong) Mknight[white][sq] += KNIGHTSTRONG;
865 if (bstrong) Mknight[black][sq] += KNIGHTSTRONG;
866 if (wstrong) Mbishop[white][sq] += BISHOPSTRONG;
867 if (bstrong) Mbishop[black][sq] += BISHOPSTRONG;
869 if (HasBishop[white] == 2) Mbishop[white][sq] += 8;
870 if (HasBishop[black] == 2) Mbishop[black][sq] += 8;
871 if (HasKnight[white] == 2) Mknight[white][sq] += 5;
872 if (HasKnight[black] == 2) Mknight[black][sq] += 5;
874 if (board[sq] == bishop) {
875 if (rank % 2 == fyle % 2) {
876 KBNKsq = 0;
877 } else {
878 KBNKsq = 7;
882 Kfield[white][sq] = Kfield[black][sq] = 0;
883 if (distance(sq,wking) == 1) Kfield[black][sq] = KATAK;
884 if (distance(sq,bking) == 1) Kfield[white][sq] = KATAK;
886 Pd = 0;
887 for (i = 0; i < 64; i++)
888 if (board[i] == pawn)
890 if (color[i] == white)
892 pp = true;
893 if (row[i] == 6) z = i+8; else z = i+16;
894 for (j = i+8; j < 64; j += 8)
895 if (atak[black][j] > ctlP || board[j] == pawn) pp = false;
897 else
899 pp = true;
900 if (row[i] == 1) z = i-8; else z = i-16;
901 for (j = i-8; j >= 0; j -= 8)
902 if (atak[white][j] > ctlP || board[j] == pawn) pp = false;
904 if (pp) Pd += 5*taxicab(sq,z); else Pd += taxicab(sq,z);
906 if (Pd != 0)
908 val = (Pd*stage2) / 10;
909 Mking[white][sq] -= val;
910 Mking[black][sq] -= val;
916 void UpdateWeights()
919 If material balance has changed, determine the values for the
920 positional evaluation terms.
924 register short tmtl;
926 if (mtl[white] != Zwmtl || mtl[black] != Zbmtl)
928 Zwmtl = mtl[white]; Zbmtl = mtl[black];
929 emtl[white] = Zwmtl - pmtl[white] - valueK;
930 emtl[black] = Zbmtl - pmtl[black] - valueK;
931 tmtl = emtl[white] + emtl[black];
932 if (tmtl > 6600) stage = 0;
933 else if (tmtl < 1400) stage = 10;
934 else stage = (6600-tmtl) / 520;
935 if (tmtl > 3600) stage2 = 0;
936 else if (tmtl < 1400) stage2 = 10;
937 else stage2 = (3600-tmtl) / 220;
939 PEDRNK2B = -15; /* centre pawn on 2nd rank & blocked */
940 PBLOK = -4; /* blocked backward pawn */
941 PDOUBLED = -14; /* doubled pawn */
942 PWEAKH = -4; /* weak pawn on half open file */
943 PAWNSHIELD = 10-stage; /* pawn near friendly king */
944 PADVNCM = 10; /* advanced pawn multiplier */
945 PADVNCI = 7; /* muliplier for isolated pawn */
946 PawnBonus = stage;
948 KNIGHTPOST = (stage+2)/3; /* knight near enemy pieces */
949 KNIGHTSTRONG = (stage+6)/2; /* occupies pawn hole */
951 BISHOPSTRONG = (stage+6)/2; /* occupies pawn hole */
952 BishopBonus = 2*stage;
954 RHOPN = 10; /* rook on half open file */
955 RHOPNX = 4;
956 RookBonus = 6*stage;
958 XRAY = 8; /* Xray attack on piece */
959 PINVAL = 10; /* Pin */
961 KHOPN = (3*stage-30) / 2; /* king on half open file */
962 KHOPNX = KHOPN / 2;
963 KCASTLD = 10 - stage;
964 KMOVD = -40 / (stage+1); /* king moved before castling */
965 KATAK = (10-stage) / 2; /* B,R attacks near enemy king */
966 if (stage < 8) KSFTY = 16-2*stage; else KSFTY = 0;
968 ATAKD = -6; /* defender > attacker */
969 HUNGP = -8; /* each hung piece */
970 HUNGX = -12; /* extra for >1 hung piece */
975 int distance(a,b)
976 short a,b;
978 register short d1,d2;
980 d1 = abs(column[a]-column[b]);
981 d2 = abs(row[a]-row[b]);
982 if (d1 > d2) return(d1); else return(d2);
986 void BlendBoard(a,b,c)
987 short a[64],b[64],c[64];
989 register int sq;
990 for (sq = 0; sq < 64; sq++)
991 c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10;
995 void CopyBoard(a,b)
996 short a[64],b[64];
998 register int sq;
999 for (sq = 0; sq < 64; sq++)
1000 b[sq] = a[sq];
1003 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
1006 int SelectMove( short side, short iop , void (*callback)(void), char* move_buffer)
1009 Select a move by calling function search() at progressively deeper
1010 ply until time is up or a mate or draw is reached. An alpha-beta
1011 window of -90 to +90 points is set around the score returned from the
1012 previous iteration. If Sdepth != 0 then the program has correctly
1013 predicted the opponents move and the search will start at a depth of
1014 Sdepth+1 rather than a depth of 1.
1018 static short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt;
1020 timeout = false;
1021 xside = otherside[side];
1022 if (iop != 2) player = side;
1023 if (TCflag)
1025 ResponseTime = (TimeControl.clock[side]) /
1026 (TimeControl.moves[side] + 3) -
1027 OperatorTime;
1028 ResponseTime += (ResponseTime*TimeControl.moves[side])/(2*TCmoves+1);
1030 else ResponseTime = Level;
1031 if (iop == 2) ResponseTime = 999;
1032 if (Sdepth > 0 && root->score > Zscore-zwndw) ResponseTime -= ft;
1033 else if (ResponseTime < 1) ResponseTime = 1;
1034 ExtraTime = 0;
1035 ExaminePosition();
1036 ScorePosition(side,&score);
1037 Pscore[0] = -score;
1039 if (Sdepth == 0)
1041 ZeroTTable();
1042 /*SearchStartStuff(side);*/
1043 for (i = 0; i < 8192; i++) history[i] = 0;
1044 FROMsquare = TOsquare = -1;
1045 PV = 0;
1046 if (iop != 2) hint = 0;
1047 for (i = 0; i < maxdepth; i++)
1048 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
1050 alpha = -9000; beta = 9000;
1051 rpt = 0;
1052 TrPnt[1] = 0; root = &Tree[0];
1053 MoveList(side,1);
1054 for (i = TrPnt[1]; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
1055 if (withbook) OpeningBook();
1056 if (withbook) timeout = true;
1057 NodeCnt = ETnodes = EvalNodes = HashCnt = 0;
1058 Zscore = 0; zwndw = 20;
1061 while (!timeout && Sdepth < MaxSearchDepth)
1063 Sdepth++;
1064 /*ShowDepth(' ');*/
1065 score = search(side,1,Sdepth,alpha,beta,PrVar,&rpt,callback);
1066 for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
1067 if (score < alpha && !timeout)
1069 /*ShowDepth('-');*/
1070 ExtraTime = 10*ResponseTime;
1071 ZeroTTable();
1072 score = search(side,1,Sdepth,-9000,beta,PrVar,&rpt,callback);
1074 if (score > beta && !timeout && !(root->flags & exact))
1076 /*ShowDepth('+');*/
1077 ExtraTime = 0;
1078 ZeroTTable();
1079 score = search(side,1,Sdepth,alpha,9000,PrVar,&rpt,callback);
1081 score = root->score;
1082 if (!timeout)
1083 for (i = TrPnt[1]+1; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
1084 /*ShowResults(score,PrVar,'.');*/
1085 for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
1086 if (score > Zscore-zwndw && score > Tree[1].score+250) ExtraTime = 0;
1087 else if (score > Zscore-3*zwndw) ExtraTime = ResponseTime;
1088 else ExtraTime = 3*ResponseTime;
1089 if (root->flags & exact) timeout = true;
1090 if (Tree[1].score < -9000) timeout = true;
1091 if (4*et > 2*ResponseTime + ExtraTime) timeout = true;
1092 if (!timeout)
1094 Tscore[0] = score;
1095 if (Zscore == 0) Zscore = score;
1096 else Zscore = (Zscore+score)/2;
1098 zwndw = 20+abs(Zscore/12);
1099 beta = score + Bwindow;
1100 if (Zscore < score) alpha = Zscore - Awindow - zwndw;
1101 else alpha = score - Awindow - zwndw;
1104 score = root->score;
1105 if (rpt >= 2 || score < -12000) root->flags |= draw;
1106 if (iop == 2) return(0);
1107 if (!withbook) hint = PrVar[2];
1108 ElapsedTime(1);
1110 if (score > -9999 && rpt <= 2)
1112 MakeMove(side,root,&tempb,&tempc,&tempsf,&tempst);
1113 algbr(root->f,root->t,root->flags & cstlmask);
1115 else mvstr1[0] = '\0';
1116 /*OutputMove();*/
1118 short index;
1119 for (index=0;index<5;index++){
1120 move_buffer[index] = mvstr1[index];
1123 if (score == -9999 || score == 9998) mate = true;
1124 if (mate) hint = 0;
1125 if (root->flags & cstlmask) Game50 = GameCnt;
1126 else if (board[root->t] == pawn || (root->flags & capture))
1127 Game50 = GameCnt;
1128 GameList[GameCnt].score = score;
1129 GameList[GameCnt].nodes = NodeCnt;
1130 GameList[GameCnt].time = (short)et;
1131 GameList[GameCnt].depth = Sdepth;
1132 if (TCflag)
1134 TimeControl.clock[side] -= (et + OperatorTime);
1135 if (--TimeControl.moves[side] == 0) SetTimeControl();
1137 if ((root->flags & draw) && bothsides) quit = true;
1138 if (GameCnt > 238) quit = true;
1139 player = xside;
1140 Sdepth = 0;
1141 return(0);
1145 void OpeningBook()
1148 Go thru each of the opening lines of play and check for a match with
1149 the current game listing. If a match occurs, generate a random number.
1150 If this number is the largest generated so far then the next move in
1151 this line becomes the current "candidate". After all lines are
1152 checked, the candidate move is put at the top of the Tree[] array and
1153 will be played by the program. Note that the program does not handle
1154 book transpositions.
1158 short j,pnt;
1159 unsigned short m;
1160 unsigned r,r0;
1161 int o_c=0 , m_c=0 ;
1163 rb->srand ( *rb->current_tick ) ;
1164 r0 = 0;
1165 m = 0;
1166 while ( o_c < MAX_OPENING ) {
1167 m_c = 0 ;
1168 for (j = 0; j <= GameCnt; j++) {
1169 if ( GameList[j].gmove != OBook[o_c][m_c] ) break;
1170 m_c++;
1172 /* I added ( m != OBook[o_c][m_c] ) trying to get more random games */
1173 if ( ( j > GameCnt ) && ( m != OBook[o_c][m_c] ) ) {
1174 r=rb->rand();
1175 if ( r > r0 ) {
1176 r0 = r; m = OBook[o_c][m_c];
1177 hint = OBook[o_c][m_c+1];
1180 o_c++;
1183 for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
1184 if ((Tree[pnt].f<<8) + Tree[pnt].t == m) Tree[pnt].score = 0;
1185 pick(TrPnt[1],TrPnt[2]-1);
1186 if (Tree[TrPnt[1]].score < 0) withbook = false;
1190 #define UpdateSearchStatus \
1192 if (pnt > TrPnt[1])\
1194 d = best-Zscore; e = best-node->score;\
1195 if (best < alpha) ExtraTime = 10*ResponseTime;\
1196 else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\
1197 else if (d > -zwndw) ExtraTime = 0;\
1198 else if (d > -3*zwndw) ExtraTime = ResponseTime;\
1199 else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\
1200 else ExtraTime = 5*ResponseTime;\
1204 int search( short side, short ply, short depth,
1205 short alpha, short beta, unsigned short bstline[], short *rpt,
1206 void (*callback)(void) )
1209 Perform an alpha-beta search to determine the score for the current
1210 board position. If depth <= 0 only capturing moves, pawn promotions
1211 and responses to check are generated and searched, otherwise all
1212 moves are processed. The search depth is modified for check evasions,
1213 certain re-captures and threats. Extensions may continue for up to 11
1214 ply beyond the nominal search depth.
1217 #define prune (cf && score+node->score < alpha)
1218 #define ReCapture (rcptr && score > alpha && score < beta &&\
1219 ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2] &&\
1220 depth == Sdepth-ply+1)
1221 #define Parry (hung[side] > 1 && ply == Sdepth+1)
1222 #define MateThreat (ply < Sdepth+4 && ply > 4 &&\
1223 ChkFlag[ply-2] && ChkFlag[ply-4] &&\
1224 ChkFlag[ply-2] != ChkFlag[ply-4])
1227 register short j,pnt;
1228 short best,tempb,tempc,tempsf,tempst;
1229 short xside,pbst,d,e,cf,score,rcnt;
1230 unsigned short mv,nxtline[maxdepth];
1231 struct leaf *node,tmp;
1233 /* this is the only place we need to yield */
1234 rb->yield();
1235 /* and check for user interaction */
1236 callback();
1238 NodeCnt++;
1239 xside = otherside[side];
1241 if (ply <= Sdepth+3) repetition(rpt); else *rpt = 0;
1242 if (*rpt >= 2) return(0);
1244 score = evaluate(side,xside,ply,depth,alpha,beta);
1245 if (score > 9000) return(score);
1247 if (depth > 0)
1249 if (InChk || PawnThreat[ply-1] || ReCapture) ++depth;
1251 else
1253 if (score >= alpha &&
1254 (InChk || PawnThreat[ply-1] || Parry)) depth = 1;
1255 else if (score <= beta && MateThreat) depth = 1;
1258 PV = 0;
1259 if (depth > 0 && hashflag && ply > 1)
1261 ProbeTTable(side,depth,&alpha,&beta,&score);
1262 bstline[ply] = PV;
1263 bstline[ply+1] = 0;
1264 if (beta == -20000) return(score);
1265 if (alpha > beta) return(alpha);
1268 if (Sdepth == 1) d = 7; else d = 11;
1269 if (ply > Sdepth+d || (depth <= 0 && score > beta)) return(score);
1271 if (ply > 1) {
1272 if (depth > 0) {
1273 MoveList(side,ply);
1274 } else {
1275 CaptureList(side,xside,ply);
1279 if (TrPnt[ply] == TrPnt[ply+1]) return(score);
1281 cf = (depth < 1 && ply > Sdepth+1 && !ChkFlag[ply-2] && !slk);
1283 if (depth > 0) best = -12000; else best = score;
1284 if (best > alpha) alpha = best;
1286 for (pnt = pbst = TrPnt[ply];
1287 pnt < TrPnt[ply+1] && best <= beta;
1288 pnt++)
1290 if (ply > 1) pick(pnt,TrPnt[ply+1]-1);
1291 node = &Tree[pnt];
1292 mv = (node->f << 8) + node->t;
1293 nxtline[ply+1] = 0;
1295 if (prune) break;
1296 if (ply == 1) UpdateSearchStatus;
1298 if (!(node->flags & exact))
1300 MakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
1301 CptrFlag[ply] = (node->flags & capture);
1302 PawnThreat[ply] = (node->flags & pwnthrt);
1303 Tscore[ply] = node->score;
1304 node->score = -search(xside,ply+1,depth-1,-beta,-alpha,
1305 nxtline,&rcnt,callback);
1306 if (abs(node->score) > 9000) node->flags |= exact;
1307 else if (rcnt == 1) node->score /= 2;
1308 if (rcnt >= 2 || GameCnt-Game50 > 99 ||
1309 (node->score == 9999-ply && !ChkFlag[ply]))
1311 node->flags |= draw; node->flags |= exact;
1312 if (side == computer) node->score = contempt;
1313 else node->score = -contempt;
1315 UnmakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
1317 if (node->score > best && !timeout)
1319 if (depth > 0)
1320 if (node->score > alpha && !(node->flags & exact))
1321 node->score += depth;
1322 best = node->score; pbst = pnt;
1323 if (best > alpha) alpha = best;
1324 for (j = ply+1; nxtline[j] > 0; j++) bstline[j] = nxtline[j];
1325 bstline[j] = 0;
1326 bstline[ply] = mv;
1327 if (ply == 1)
1329 if (best == alpha)
1331 tmp = Tree[pnt];
1332 for (j = pnt-1; j >= 0; j--) Tree[j+1] = Tree[j];
1333 Tree[0] = tmp;
1334 pbst = 0;
1336 /*if (Sdepth > 2)
1337 if (best > beta) ShowResults(best,bstline,'+');
1338 else if (best < alpha) ShowResults(best,bstline,'-');
1339 else ShowResults(best,bstline,'&');*/
1342 if (NodeCnt > ETnodes) ElapsedTime(0);
1343 if (timeout) return(-Tscore[ply-1]);
1346 node = &Tree[pbst];
1347 mv = (node->f<<8) + node->t;
1348 if (hashflag && ply <= Sdepth && *rpt == 0 && best == alpha)
1349 PutInTTable(side,best,depth,alpha,beta,mv);
1350 if (depth > 0)
1352 j = (node->f<<6) + node->t; if (side == black) j |= 0x1000;
1353 if (history[j] < 150) history[j] += 2*depth;
1354 if (node->t != (GameList[GameCnt].gmove & 0xFF)) {
1355 if (best <= beta) {
1356 killr3[ply] = mv;
1357 } else {
1358 if (mv != killr1[ply]) {
1359 killr2[ply] = killr1[ply];
1360 killr1[ply] = mv;
1364 if (best > 9000) killr0[ply] = mv; else killr0[ply] = 0;
1366 return(best);
1370 int evaluate(side,xside,ply,depth,alpha,beta)
1371 short side,xside,ply,depth,alpha,beta;
1374 Compute an estimate of the score by adding the positional score from
1375 the previous ply to the material difference. If this score falls
1376 inside a window which is 180 points wider than the alpha-beta window
1377 (or within a 50 point window during quiescence search) call
1378 ScorePosition() to determine a score, otherwise return the estimated
1379 score. If one side has only a king and the other either has no pawns
1380 or no pieces then the function ScoreLoneKing() is called.
1384 register short evflag;
1386 Xscore = -Pscore[ply-1] - INCscore + mtl[side] - mtl[xside];
1387 hung[white] = hung[black] = 0;
1388 slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
1389 (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));
1391 if (slk) evflag = false;
1392 else evflag =
1393 (ply == 1 || ply < Sdepth ||
1394 (depth == 0 && Xscore > alpha-xwndw && Xscore < beta+xwndw) ||
1395 (depth < 0 && Xscore > alpha-25 && Xscore < beta+25));
1397 if (evflag)
1399 EvalNodes++;
1400 ataks(side,atak[side]);
1401 if (atak[side][PieceList[xside][0]] > 0) return(10001-ply);
1402 ataks(xside,atak[xside]);
1403 InChk = (atak[xside][PieceList[side][0]] > 0);
1404 ScorePosition(side,&Xscore);
1406 else
1408 if (SqAtakd(PieceList[xside][0],side)) return(10001-ply);
1409 InChk = SqAtakd(PieceList[side][0],xside);
1410 if (slk) ScoreLoneKing(side,&Xscore);
1413 Pscore[ply] = Xscore - mtl[side] + mtl[xside];
1414 if (InChk) ChkFlag[ply-1] = Pindex[TOsquare];
1415 else ChkFlag[ply-1] = 0;
1416 return(Xscore);
1420 int ProbeTTable(side,depth,alpha,beta,score)
1421 short side,depth,*alpha,*beta,*score;
1424 Look for the current board position in the transposition table.
1428 short hindx;
1429 if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
1430 hindx = (hashkey & (ttblsz-1));
1431 ptbl = (ttable + hindx);
1432 if (ptbl->depth >= depth && ptbl->hashbd == hashbd)
1434 HashCnt++;
1435 PV = ptbl->mv;
1436 if (ptbl->flags & truescore)
1438 *score = ptbl->score;
1439 *beta = -20000;
1440 return(true);
1443 else if (ptbl->flags & upperbound)
1445 if (ptbl->score < *beta) *beta = ptbl->score+1;
1448 else if (ptbl->flags & lowerbound)
1450 if (ptbl->score > *alpha) *alpha = ptbl->score-1;
1453 return(false);
1457 void PutInTTable(side,score,depth,alpha,beta,mv)
1458 short side,score,depth,alpha,beta;
1459 unsigned short mv;
1462 Store the current board position in the transposition table.
1466 short hindx;
1467 if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
1468 hindx = (hashkey & (ttblsz-1));
1469 ptbl = (ttable + hindx);
1470 ptbl->hashbd = hashbd;
1471 ptbl->depth = depth;
1472 ptbl->score = score;
1473 ptbl->mv = mv;
1474 ptbl->flags = 0;
1475 if (score < alpha) ptbl->flags |= upperbound;
1476 else if (score > beta) ptbl->flags |= lowerbound;
1477 else ptbl->flags |= truescore;
1481 void ZeroTTable()
1483 int i;
1484 if (hashflag)
1485 for (i = 0; i < ttblsz; i++)
1487 ptbl = (ttable + i);
1488 ptbl->depth = 0;
1493 void MoveList(side,ply)
1494 short side,ply;
1497 Fill the array Tree[] with all available moves for side to play. Array
1498 TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1502 register short i,xside,f;
1504 xside = otherside[side];
1505 if (PV == 0) Swag0 = killr0[ply]; else Swag0 = PV;
1506 Swag1 = killr1[ply]; Swag2 = killr2[ply];
1507 Swag3 = killr3[ply]; Swag4 = 0;
1508 if (ply > 2) Swag4 = killr1[ply-2];
1509 TrPnt[ply+1] = TrPnt[ply];
1510 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
1511 for (i = PieceCnt[side]; i >= 0; i--)
1512 GenMoves(ply,PieceList[side][i],side,xside);
1513 if (kingmoved[side] == 0 && !castld[side])
1515 f = PieceList[side][0];
1516 if (castle(side,f,f+2,0))
1518 LinkMove(ply,f,f+2,xside);
1519 Tree[TrPnt[ply+1]-1].flags |= cstlmask;
1521 if (castle(side,f,f-2,0))
1523 LinkMove(ply,f,f-2,xside);
1524 Tree[TrPnt[ply+1]-1].flags |= cstlmask;
1530 void GenMoves(ply,sq,side,xside)
1531 short ply,sq,side,xside;
1534 Generate moves for a piece. The from square is mapped onto a special
1535 board and offsets (taken from array Dir[]) are added to the mapped
1536 location. The newly generated square is tested to see if it falls off
1537 the board by ANDing the square with 88 HEX. Legal moves are linked
1538 into the tree.
1542 register short m,u,d,i,m0,piece;
1544 piece = board[sq]; m0 = map[sq];
1545 if (sweep[piece])
1546 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1548 d = Dir[i]; m = m0+d;
1549 while (!(m & 0x88))
1551 u = unmap[m];
1552 if (color[u] == neutral)
1554 LinkMove(ply,sq,u,xside);
1555 m += d;
1557 else if (color[u] == xside)
1559 LinkMove(ply,sq,u,xside);
1560 break;
1562 else break;
1565 else if (piece == pawn)
1567 if (side == white && color[sq+8] == neutral)
1569 LinkMove(ply,sq,sq+8,xside);
1570 if (row[sq] == 1)
1571 if (color[sq+16] == neutral)
1572 LinkMove(ply,sq,sq+16,xside);
1574 else if (side == black && color[sq-8] == neutral)
1576 LinkMove(ply,sq,sq-8,xside);
1577 if (row[sq] == 6)
1578 if (color[sq-16] == neutral)
1579 LinkMove(ply,sq,sq-16,xside);
1581 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1582 if (!((m = m0+Dir[i]) & 0x88))
1584 u = unmap[m];
1585 if (color[u] == xside || u == epsquare)
1586 LinkMove(ply,sq,u,xside);
1589 else
1591 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1592 if (!((m = m0+Dir[i]) & 0x88))
1594 u = unmap[m];
1595 if (color[u] != side) LinkMove(ply,sq,u,xside);
1601 void LinkMove(ply,f,t,xside)
1602 short ply,f,t,xside;
1605 Add a move to the tree. Assign a bonus to order the moves
1606 as follows:
1607 1. Principle variation
1608 2. Capture of last moved piece
1609 3. Other captures (major pieces first)
1610 4. Killer moves
1611 5. "history" killers
1615 register short s,z;
1616 register unsigned short mv;
1617 struct leaf *node;
1619 node = &Tree[TrPnt[ply+1]];
1620 ++TrPnt[ply+1];
1621 node->flags = 0;
1622 node->f = f; node->t = t;
1623 mv = (f<<8) + t;
1624 s = 0;
1625 if (mv == Swag0) s = 2000;
1626 else if (mv == Swag1) s = 60;
1627 else if (mv == Swag2) s = 50;
1628 else if (mv == Swag3) s = 40;
1629 else if (mv == Swag4) s = 30;
1630 if (color[t] != neutral)
1632 node->flags |= capture;
1633 if (t == TOsquare) s += 500;
1634 s += value[board[t]] - board[f];
1636 if (board[f] == pawn) {
1637 if (row[t] == 0 || row[t] == 7) {
1638 node->flags |= promote;
1639 s += 800;
1640 } else {
1641 if (row[t] == 1 || row[t] == 6) {
1642 node->flags |= pwnthrt;
1643 s += 600;
1644 } else {
1645 if (t == epsquare) node->flags |= epmask;
1649 z = (f<<6) + t; if (xside == white) z |= 0x1000;
1650 s += history[z];
1651 node->score = s - 20000;
1655 void CaptureList(side,xside,ply)
1656 short side,xside,ply;
1659 Generate captures and Pawn promotions only.
1662 #define LinkCapture \
1664 node->f = sq; node->t = u;\
1665 node->flags = capture;\
1666 node->score = value[board[u]] + svalue[board[u]] - piece;\
1667 if (piece == pawn && (u < 8 || u > 55))\
1669 node->flags |= promote;\
1670 node->score = valueQ;\
1672 ++node;\
1673 ++TrPnt[ply+1];\
1677 register short m,u,d,sq,m0;
1678 short i,j,j1,j2,r7,d0,piece,*PL;
1679 struct leaf *node;
1681 TrPnt[ply+1] = TrPnt[ply];
1682 node = &Tree[TrPnt[ply]];
1683 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
1684 if (side == white)
1686 r7 = 6; d0 = 8;
1688 else
1690 r7 = 1; d0 = -8;
1692 PL = PieceList[side];
1693 for (i = 0; i <= PieceCnt[side]; i++)
1695 sq = PL[i];
1696 m0 = map[sq]; piece = board[sq];
1697 j1 = Dstart[piece]; j2 = Dstop[piece];
1698 if (sweep[piece])
1699 for (j = j1; j <= j2; j++)
1701 d = Dir[j]; m = m0+d;
1702 while (!(m & 0x88))
1704 u = unmap[m];
1705 if (color[u] == neutral) m += d;
1706 else
1708 if (color[u] == xside) LinkCapture;
1709 break;
1713 else
1715 for (j = j1; j <= j2; j++)
1716 if (!((m = m0+Dir[j]) & 0x88))
1718 u = unmap[m];
1719 if (color[u] == xside) LinkCapture;
1721 if (piece == pawn && row[sq] == r7)
1723 u = sq+d0;
1724 if (color[u] == neutral) LinkCapture;
1731 int castle(side,kf,kt,iop)
1732 short side,kf,kt,iop;
1735 Make or Unmake a castling move.
1739 register short rf,rt,d,t0,xside;
1741 xside = otherside[side];
1742 if (kt > kf)
1744 rf = kf+3; rt = kt-1; d = 1;
1746 else
1748 rf = kf-4; rt = kt+1; d = -1;
1750 if (iop == 0)
1752 if (board[kf] != king || board[rf] != rook || color[rf] != side)
1753 return(false);
1754 if (color[kt] != neutral || color[rt] != neutral) return(false);
1755 if (d == -1 && color[kt+d] != neutral) return(false);
1756 if (SqAtakd(kf,xside)) return(false);
1757 if (SqAtakd(kt,xside)) return(false);
1758 if (SqAtakd(kf+d,xside)) return(false);
1760 else
1762 if (iop == 1) castld[side] = true; else castld[side] = false;
1763 if (iop == 2)
1765 t0 = kt; kt = kf; kf = t0;
1766 t0 = rt; rt = rf; rf = t0;
1768 board[kt] = king; color[kt] = side; Pindex[kt] = 0;
1769 board[kf] = no_piece; color[kf] = neutral;
1770 board[rt] = rook; color[rt] = side; Pindex[rt] = Pindex[rf];
1771 board[rf] = no_piece; color[rf] = neutral;
1772 PieceList[side][Pindex[kt]] = kt;
1773 PieceList[side][Pindex[rt]] = rt;
1774 if (hashflag)
1776 UpdateHashbd(side,king,kf,kt);
1777 UpdateHashbd(side,rook,rf,rt);
1780 return(true);
1784 void EnPassant(xside,f,t,iop)
1785 short xside,f,t,iop;
1788 Make or unmake an en passant move.
1792 register short l;
1793 if (t > f) l = t-8; else l = t+8;
1794 if (iop == 1)
1796 board[l] = no_piece; color[l] = neutral;
1798 else
1800 board[l] = pawn; color[l] = xside;
1802 InitializeStats();
1806 void MakeMove(side,node,tempb,tempc,tempsf,tempst)
1807 short side,*tempc,*tempb,*tempsf,*tempst;
1808 struct leaf *node;
1811 Update Arrays board[], color[], and Pindex[] to reflect the new board
1812 position obtained after making the move pointed to by node. Also
1813 update miscellaneous stuff that changes when a move is made.
1817 register short f,t,xside,ct,cf;
1819 xside = otherside[side];
1820 f = node->f; t = node->t; epsquare = -1;
1821 FROMsquare = f; TOsquare = t;
1822 INCscore = 0;
1823 GameList[++GameCnt].gmove = (f<<8) + t;
1824 if (node->flags & cstlmask)
1826 GameList[GameCnt].piece = no_piece;
1827 GameList[GameCnt].color = side;
1828 castle(side,f,t,1);
1830 else
1832 *tempc = color[t]; *tempb = board[t];
1833 *tempsf = svalue[f]; *tempst = svalue[t];
1834 GameList[GameCnt].piece = *tempb;
1835 GameList[GameCnt].color = *tempc;
1836 if (*tempc != neutral)
1838 UpdatePieceList(*tempc,t,1);
1839 if (*tempb == pawn) --PawnCnt[*tempc][column[t]];
1840 if (board[f] == pawn)
1842 --PawnCnt[side][column[f]];
1843 ++PawnCnt[side][column[t]];
1844 cf = column[f]; ct = column[t];
1845 if (PawnCnt[side][ct] > 1+PawnCnt[side][cf])
1846 INCscore -= 15;
1847 else if (PawnCnt[side][ct] < 1+PawnCnt[side][cf])
1848 INCscore += 15;
1849 else if (ct == 0 || ct == 7 || PawnCnt[side][ct+ct-cf] == 0)
1850 INCscore -= 15;
1852 mtl[xside] -= value[*tempb];
1853 if (*tempb == pawn) pmtl[xside] -= valueP;
1854 if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
1855 INCscore += *tempst;
1857 color[t] = color[f]; board[t] = board[f]; svalue[t] = svalue[f];
1858 Pindex[t] = Pindex[f]; PieceList[side][Pindex[t]] = t;
1859 color[f] = neutral; board[f] = no_piece;
1860 if (board[t] == pawn) {
1861 if (t-f == 16) {
1862 epsquare = f+8;
1863 } else {
1864 if (f-t == 16) epsquare = f-8;
1867 if (node->flags & promote)
1869 board[t] = queen;
1870 --PawnCnt[side][column[t]];
1871 mtl[side] += valueQ - valueP;
1872 pmtl[side] -= valueP;
1873 HasQueen[side] = true;
1874 if (hashflag)
1876 UpdateHashbd(side,pawn,f,-1);
1877 UpdateHashbd(side,queen,f,-1);
1879 INCscore -= *tempsf;
1881 if (board[t] == king) ++kingmoved[side];
1882 if (node->flags & epmask) EnPassant(xside,f,t,1);
1883 else if (hashflag) UpdateHashbd(side,board[t],f,t);
1888 void UnmakeMove(side,node,tempb,tempc,tempsf,tempst)
1889 short side,*tempc,*tempb,*tempsf,*tempst;
1890 struct leaf *node;
1893 Take back a move.
1897 register short f,t,xside;
1899 xside = otherside[side];
1900 f = node->f; t = node->t; epsquare = -1;
1901 GameCnt--;
1902 if (node->flags & cstlmask) castle(side,f,t,2);
1903 else
1905 color[f] = color[t]; board[f] = board[t]; svalue[f] = *tempsf;
1906 Pindex[f] = Pindex[t]; PieceList[side][Pindex[f]] = f;
1907 color[t] = *tempc; board[t] = *tempb; svalue[t] = *tempst;
1908 if (node->flags & promote)
1910 board[f] = pawn;
1911 ++PawnCnt[side][column[t]];
1912 mtl[side] += valueP - valueQ;
1913 pmtl[side] += valueP;
1914 if (hashflag)
1916 UpdateHashbd(side,queen,-1,t);
1917 UpdateHashbd(side,pawn,-1,t);
1920 if (*tempc != neutral)
1922 UpdatePieceList(*tempc,t,2);
1923 if (*tempb == pawn) ++PawnCnt[*tempc][column[t]];
1924 if (board[f] == pawn)
1926 --PawnCnt[side][column[t]];
1927 ++PawnCnt[side][column[f]];
1929 mtl[xside] += value[*tempb];
1930 if (*tempb == pawn) pmtl[xside] += valueP;
1931 if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
1933 if (board[f] == king) --kingmoved[side];
1934 if (node->flags & epmask) EnPassant(xside,f,t,2);
1935 else if (hashflag) UpdateHashbd(side,board[f],f,t);
1940 void UpdateHashbd(side,piece,f,t)
1941 short side,piece,f,t;
1944 hashbd contains a 32 bit "signature" of the board position. hashkey
1945 contains a 16 bit code used to address the hash table. When a move is
1946 made, XOR'ing the hashcode of moved piece on the from and to squares
1947 with the hashbd and hashkey values keeps things current.
1951 if (f >= 0)
1953 hashbd ^= hashcode[side][piece][f].bd;
1954 hashkey ^= hashcode[side][piece][f].key;
1956 if (t >= 0)
1958 hashbd ^= hashcode[side][piece][t].bd;
1959 hashkey ^= hashcode[side][piece][t].key;
1964 void UpdatePieceList(side,sq,iop)
1965 short side,sq,iop;
1968 Update the PieceList and Pindex arrays when a piece is captured or
1969 when a capture is unmade.
1973 register short i;
1974 if (iop == 1)
1976 PieceCnt[side]--;
1977 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1979 PieceList[side][i] = PieceList[side][i+1];
1980 Pindex[PieceList[side][i]] = i;
1983 else
1985 PieceCnt[side]++;
1986 PieceList[side][PieceCnt[side]] = sq;
1987 Pindex[sq] = PieceCnt[side];
1992 void InitializeStats()
1995 Scan thru the board seeing what's on each square. If a piece is found,
1996 update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1997 determine the material for each side and set the hashkey and hashbd
1998 variables to represent the current board position. Array
1999 PieceList[side][indx] contains the location of all the pieces of
2000 either side. Array Pindex[sq] contains the indx into PieceList for a
2001 given square.
2005 register short i,sq;
2006 epsquare = -1;
2007 for (i = 0; i < 8; i++)
2008 PawnCnt[white][i] = PawnCnt[black][i] = 0;
2009 mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0;
2010 PieceCnt[white] = PieceCnt[black] = 0;
2011 hashbd = hashkey = 0;
2012 for (sq = 0; sq < 64; sq++)
2013 if (color[sq] != neutral)
2015 mtl[color[sq]] += value[board[sq]];
2016 if (board[sq] == pawn)
2018 pmtl[color[sq]] += valueP;
2019 ++PawnCnt[color[sq]][column[sq]];
2021 if (board[sq] == king) Pindex[sq] = 0;
2022 else Pindex[sq] = ++PieceCnt[color[sq]];
2023 PieceList[color[sq]][Pindex[sq]] = sq;
2024 hashbd ^= hashcode[color[sq]][board[sq]][sq].bd;
2025 hashkey ^= hashcode[color[sq]][board[sq]][sq].key;
2030 void pick(p1,p2)
2031 short p1,p2;
2034 Find the best move in the tree between indexes p1 and p2. Swap the
2035 best move into the p1 element.
2039 register short p,s,p0,s0;
2040 struct leaf temp;
2042 s0 = Tree[p1].score; p0 = p1;
2043 for (p = p1+1; p <= p2; p++)
2044 if ((s = Tree[p].score) > s0)
2046 s0 = s; p0 = p;
2048 if (p0 != p1)
2050 temp = Tree[p1]; Tree[p1] = Tree[p0]; Tree[p0] = temp;
2055 void repetition(cnt)
2056 short *cnt;
2059 Check for draw by threefold repetition.
2063 register short i,c,f,t;
2064 short b[64];
2065 unsigned short m;
2066 *cnt = c = 0;
2067 if (GameCnt > Game50+3)
2069 for (i = 0; i < 64; b[i++] = 0);
2070 for (i = GameCnt; i > Game50; i--)
2072 m = GameList[i].gmove; f = m>>8; t = m & 0xFF;
2073 if (++b[f] == 0) c--; else c++;
2074 if (--b[t] == 0) c--; else c++;
2075 if (c == 0) (*cnt)++;
2081 int SqAtakd(sq,side)
2082 short sq,side;
2085 See if any piece with color 'side' ataks sq. First check for pawns
2086 or king, then try other pieces. Array Dcode is used to check for
2087 knight attacks or R,B,Q co-linearity.
2091 register short m,d,m0,m1,i,loc,piece,*PL;
2093 m1 = map[sq];
2094 if (side == white) m = m1-0x0F; else m = m1+0x0F;
2095 if (!(m & 0x88))
2096 if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
2097 if (side == white) m = m1-0x11; else m = m1+0x11;
2098 if (!(m & 0x88))
2099 if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
2100 if (distance(sq,PieceList[side][0]) == 1) return(true);
2102 PL = PieceList[side];
2103 for (i = 1; i <= PieceCnt[side]; i++)
2105 loc = PL[i]; piece = board[loc];
2106 if (piece == pawn) continue;
2107 m0 = map[loc]; d = Dcode[abs(m1-m0)];
2108 if (d == 0 || (Pdir[d] & pbit[piece]) == 0) continue;
2109 if (piece == knight) return(true);
2110 else
2112 if (m1 < m0) d = -d;
2113 for (m = m0+d; m != m1; m += d)
2114 if (color[unmap[m]] != neutral) break;
2115 if (m == m1) return(true);
2118 return(false);
2122 void ataks(side,a)
2123 short side,*a;
2126 Fill array atak[][] with info about ataks to a square. Bits 8-15
2127 are set if the piece (king..pawn) ataks the square. Bits 0-7
2128 contain a count of total ataks to the square.
2132 register short u,m,d,c,m0;
2133 short j,j1,j2,piece,i,sq,*PL;
2135 for (u = 0; u < 64; a[u++] = 0);
2136 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
2137 PL = PieceList[side];
2138 for (i = 0; i <= PieceCnt[side]; i++)
2140 sq = PL[i];
2141 m0 = map[sq];
2142 piece = board[sq];
2143 c = control[piece]; j1 = Dstart[piece]; j2 = Dstop[piece];
2144 if (sweep[piece])
2145 for (j = j1; j <= j2; j++)
2147 d = Dir[j]; m = m0+d;
2148 while (!(m & 0x88))
2150 u = unmap[m];
2151 a[u] = ++a[u] | c;
2152 if (color[u] == neutral) m += d;
2153 else break;
2156 else
2157 for (j = j1; j <= j2; j++)
2158 if (!((m = m0+Dir[j]) & 0x88))
2160 u = unmap[m];
2161 a[u] = ++a[u] | c;
2168 void ElapsedTime(iop)
2171 Determine the time that has passed since the search was started. If
2172 the elapsed time exceeds the target (ResponseTime+ExtraTime) then set
2173 timeout to true which will terminate the search.
2176 short iop;
2178 /*et = time((long *)0) - time0;*/
2179 et = *(rb->current_tick) / HZ - time0;
2180 if (et < 0) et = 0;
2181 ETnodes += 50;
2182 if (et > et0 || iop == 1)
2184 if (et > ResponseTime+ExtraTime && Sdepth > 1) timeout = true;
2185 et0 = et;
2186 if (iop == 1)
2188 /*time0 = time((long *)0);*/
2189 time0 = *(rb->current_tick) / HZ ;
2190 et0 = 0;
2192 /*(void) times(&tmbuf2);
2193 cputimer = 100*(tmbuf2.tms_utime - tmbuf1.tms_utime) / HZ;
2194 if (cputimer > 0) evrate = (100*NodeCnt)/(cputimer+100*ft);
2195 else evrate = 0;*/
2196 ETnodes = NodeCnt + 50;
2197 /*UpdateClocks();*/
2203 void SetTimeControl( void )
2205 if (TCflag)
2207 TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
2208 TimeControl.clock[white] = TimeControl.clock[black] = 60*(long)TCminutes;
2210 else
2212 TimeControl.moves[white] = TimeControl.moves[black] = 0;
2213 TimeControl.clock[white] = TimeControl.clock[black] = 0;
2214 Level = 60*(long)TCminutes;
2216 et = 0;
2217 ElapsedTime(1);
2222 /* ............ INTERFACE ROUTINES ........................... */
2224 /*static void VoidFunction ( void ) {
2225 while (!(quit))
2227 if (bothsides && !mate) SelectMove(opponent,1); else InputCommand();
2228 if (!(quit || mate || force)) SelectMove(computer,1);
2230 ExitChess();
2233 int VerifyMove(short player, char s[],short iop,unsigned short *mv, char *move_buffer)
2236 Compare the string 's' to the list of legal moves available for the
2237 player. If a match is found, make the move on the board. This was originally
2238 fixed for the opponent, but allowing the player to be specified will make
2239 possible to use GnuChess as a human vs human game verifier. It also allows
2240 the PGN functions to verify checkmates.
2244 static short pnt,tempb,tempc,tempsf,tempst,cnt;
2245 static struct leaf xnode;
2246 struct leaf *node;
2247 short opponent_player = (player == white)?black:white;
2249 *mv = 0;
2250 if (iop == 2)
2252 UnmakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst);
2253 return(false);
2255 cnt = 0;
2256 MoveList(player,2);
2257 pnt = TrPnt[2];
2258 while (pnt < TrPnt[3])
2260 node = &Tree[pnt++];
2261 algbr(node->f,node->t,node->flags & cstlmask);
2262 if (rb->strcmp(s,mvstr1) == 0 || rb->strcmp(s,mvstr2) == 0 ||
2263 rb->strcmp(s,mvstr3) == 0)
2265 cnt++; xnode = *node;
2268 if (cnt == 1)
2270 MakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst);
2271 if (SqAtakd(PieceList[player][0],opponent_player))
2273 UnmakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst);
2274 /*ShowMessage("Illegal Move!!");*/
2275 return(false);
2277 else
2279 if (iop == 1) return(true);
2280 /*if (xnode.flags & epmask) UpdateDisplay(0,0,1,0);
2281 else UpdateDisplay(xnode.f,xnode.t,0,xnode.flags & cstlmask);*/
2282 if (xnode.flags & cstlmask) Game50 = GameCnt;
2283 else if (board[xnode.t] == pawn || (xnode.flags & capture))
2284 Game50 = GameCnt;
2285 GameList[GameCnt].depth = GameList[GameCnt].score = 0;
2286 GameList[GameCnt].nodes = 0;
2287 ElapsedTime(1);
2288 GameList[GameCnt].time = (short)et;
2289 TimeControl.clock[player] -= et;
2290 --TimeControl.moves[player];
2291 *mv = (xnode.f << 8) + xnode.t;
2292 algbr(xnode.f,xnode.t,false);
2294 short index;
2295 for (index=0;index<5;index++){
2296 move_buffer[index] = mvstr1[index];
2298 if (SqAtakd(PieceList[opponent_player][0],player)){
2299 move_buffer[4] = '+';
2300 move_buffer[5] = '\0';
2303 return(true);
2306 /*if (cnt > 1) ShowMessage("Ambiguous Move!");*/
2307 return(false);
2311 /* ---- Reset the board and other variables to start a new game. ---- */
2312 void NewGame() {
2313 short l,r,c,p;
2315 mate = quit = reverse = bothsides = post = false;
2316 hashflag = force = PawnStorm = false;
2317 easy = beep = rcptr = true;
2318 lpost = NodeCnt = epsquare = et0 = 0;
2319 dither = 0;
2320 Awindow = 90;
2321 Bwindow = 90;
2322 xwndw = 90;
2323 MaxSearchDepth = 29;
2324 contempt = 0;
2325 GameCnt = -1; Game50 = 0;
2326 Zwmtl = Zbmtl = 0;
2327 Developed[white] = Developed[black] = false;
2328 castld[white] = castld[black] = false;
2329 kingmoved[white] = kingmoved[black] = 0;
2330 PawnThreat[0] = CptrFlag[0] = Threat[0] = false;
2331 Pscore[0] = 12000; Tscore[0] = 12000;
2332 opponent = white; computer = black;
2333 for (r = 0; r < 8; r++)
2334 for (c = 0; c < 8; c++)
2336 l = 8*r+c; locn[r][c] = l;
2337 row[l] = r; column[l] = c;
2338 board[l] = Stboard[l]; color[l] = Stcolor[l];
2340 for (c = white; c <= black; c++)
2341 for (p = pawn; p <= king; p++)
2342 for (l = 0; l < 64; l++)
2344 hashcode[c][p][l].key = (unsigned short)rb->rand();
2345 hashcode[c][p][l].bd = ((unsigned long)rb->rand() << 16) +
2346 (unsigned long)rb->rand();
2348 if (TCflag) SetTimeControl();
2349 /*else if (Level == 0) SelectLevel();*/
2350 /*UpdateDisplay(0,0,1,0);*/
2351 InitializeStats();
2352 /*time0 = time((long *)0);*/
2353 time0 = *(rb->current_tick) / HZ ;
2354 ElapsedTime(1);
2355 withbook = true;
2358 /* ---- Initialize variables and reset board ---- */
2359 void GNUChess_Initialize ( void ) {
2360 /*ttable = (struct hashentry *)malloc(ttblsz *
2361 (unsigned long)sizeof(struct hashentry));*/
2362 /* no malloc, statically allocated */
2363 Level = 1;
2364 OperatorTime = 0;
2365 TCmoves = 60;
2366 TCminutes = 5;
2367 TCflag = true;
2368 NewGame();
2369 MaxSearchDepth = 29 ;
2372 void algbr(f,t,flag)
2373 short f,t,flag;
2375 mvstr1[0] = cxx[column[f]]; mvstr1[1] = rxx[row[f]];
2376 mvstr1[2] = cxx[column[t]]; mvstr1[3] = rxx[row[t]];
2377 mvstr2[0] = qxx[board[f]];
2378 mvstr2[1] = mvstr1[2]; mvstr2[2] = mvstr1[3];
2379 mvstr1[4] = '\0'; mvstr2[3] = '\0';
2380 if (flag) {
2381 if (t > f) {
2382 rb->strcpy(mvstr2,"o-o");
2383 } else {
2384 rb->strcpy(mvstr2,"o-o-o");
2388 if (board[f] == pawn) mvstr3[0] = mvstr1[0];
2389 else mvstr3[0] = qxx[board[f]];
2390 if (color[t] != neutral)
2392 mvstr3[1] = ':';
2393 mvstr3[2] = mvstr1[2];
2394 mvstr3[3] = mvstr1[3];
2395 mvstr3[4] = '\0';
2397 else if (board[f] == pawn)
2399 mvstr3[1] = mvstr1[3];
2400 mvstr3[2] = '\0';
2402 else
2404 mvstr3[1] = mvstr1[0];
2405 mvstr3[2] = mvstr1[1];
2406 mvstr3[3] = mvstr1[2];
2407 mvstr3[4] = mvstr1[3];
2408 mvstr3[5] = '\0';