FS#12756 by Marek Salaba - update Czech translation
[maemo-rb.git] / apps / plugins / chessbox / gnuchess.c
blobdf52d1350ba7182a9009432a330876c10c8db788
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) (ABS(x))
64 #define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b]))
66 /* ---- Chess datatypes and variables ---- */
67 struct leaf
69 short f,t,score,reply;
70 unsigned short flags;
72 struct BookEntry
74 struct BookEntry *next;
75 unsigned short *mv;
77 struct hashval
79 unsigned long bd;
80 unsigned short key;
82 struct hashentry
84 unsigned long hashbd;
85 unsigned short mv,flags;
86 short score,depth;
89 char mvstr1[5],mvstr2[5],mvstr3[6];
90 struct leaf Tree[1500],*root;
91 short TrPnt[maxdepth],board[64],color[64];
92 short row[64],column[64],locn[8][8],Pindex[64],svalue[64];
93 short PieceList[2][16],PieceCnt[2],atak[2][64],PawnCnt[2][8];
94 short castld[2],kingmoved[2],mtl[2],pmtl[2],emtl[2],hung[2];
95 short c1,c2,*atk1,*atk2,*PC1,*PC2,EnemyKing;
96 short mate,post,opponent,computer,Sdepth,Awindow,Bwindow,dither;
97 bool withbook ;
98 long ResponseTime,ExtraTime,Level,et,et0,time0,cputimer,ft;
99 long NodeCnt,evrate,ETnodes,EvalNodes,HashCnt;
100 short quit,reverse,bothsides,hashflag,InChk,player,force,easy,beep;
101 short wking,bking,FROMsquare,TOsquare,timeout,Zscore,zwndw,xwndw,slk;
102 short INCscore;
103 short HasPawn[2],HasKnight[2],HasBishop[2],HasRook[2],HasQueen[2];
104 short ChkFlag[maxdepth],CptrFlag[maxdepth],PawnThreat[maxdepth];
105 short Pscore[maxdepth],Tscore[maxdepth],Threat[maxdepth];
106 struct GameRec GameList[240];
107 short GameCnt,Game50,epsquare,lpost,rcptr,contempt;
108 short MaxSearchDepth,Xscore;
109 struct TimeControlRec TimeControl;
110 short TCflag,TCmoves,TCminutes,OperatorTime;
111 short otherside[3]={1,0,2};
112 short rank7[3]={6,1,0};
113 short map[64]=
114 {0,1,2,3,4,5,6,7,
115 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
116 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
117 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
118 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
119 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
120 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
121 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77};
122 short unmap[120]=
123 {0,1,2,3,4,5,6,7,-1,-1,-1,-1,-1,-1,-1,-1,
124 8,9,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,
125 16,17,18,19,20,21,22,23,-1,-1,-1,-1,-1,-1,-1,-1,
126 24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
127 32,33,34,35,36,37,38,39,-1,-1,-1,-1,-1,-1,-1,-1,
128 40,41,42,43,44,45,46,47,-1,-1,-1,-1,-1,-1,-1,-1,
129 48,49,50,51,52,53,54,55,-1,-1,-1,-1,-1,-1,-1,-1,
130 56,57,58,59,60,61,62,63};
131 short Dcode[120]=
132 {0,1,1,1,1,1,1,1,0,0,0,0,0,0,0x0E,0x0F,
133 0x10,0x11,0x12,0,0,0,0,0,0,0,0,0,0,0,0x0F,0x1F,
134 0x10,0x21,0x11,0,0,0,0,0,0,0,0,0,0,0x0F,0,0,
135 0x10,0,0,0x11,0,0,0,0,0,0,0,0,0x0F,0,0,0,
136 0x10,0,0,0,0x11,0,0,0,0,0,0,0x0F,0,0,0,0,
137 0x10,0,0,0,0,0x11,0,0,0,0,0x0F,0,0,0,0,0,
138 0x10,0,0,0,0,0,0x11,0,0,0x0F,0,0,0,0,0,0,
139 0x10,0,0,0,0,0,0,0x11};
140 short Stboard[64]=
141 {rook,knight,bishop,queen,king,bishop,knight,rook,
142 pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
143 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
144 pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
145 rook,knight,bishop,queen,king,bishop,knight,rook};
146 short Stcolor[64]=
147 {white,white,white,white,white,white,white,white,
148 white,white,white,white,white,white,white,white,
149 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,
150 black,black,black,black,black,black,black,black,
151 black,black,black,black,black,black,black,black};
152 short sweep[7]= {false,false,false,true,true,true,false};
153 short Dpwn[3]={4,6,0};
154 short Dstart[7]={6,4,8,4,0,0,0};
155 short Dstop[7]={7,5,15,7,3,7,7};
156 short Dir[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11,
157 0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21};
158 short Pdir[34]={0,0x38,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x35,
159 0x38,0x35,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x02,
160 0,0x02};
161 short pbit[7]={0,0x01,0x02,0x04,0x08,0x10,0x20};
162 unsigned short killr0[maxdepth],killr1[maxdepth],killr2[maxdepth];
163 unsigned short killr3[maxdepth],PrVar[maxdepth];
164 unsigned short PV,hint,Swag0,Swag1,Swag2,Swag3,Swag4;
165 unsigned short hashkey;
166 unsigned long hashbd;
167 struct hashval hashcode[2][7][64];
168 struct hashentry ttable[ttblsz];
169 struct hashentry *ptbl;
170 unsigned char history[8192];
172 short Mwpawn[64],Mbpawn[64],Mknight[2][64],Mbishop[2][64];
173 short Mking[2][64],Kfield[2][64];
174 short value[7]={0,valueP,valueN,valueB,valueR,valueQ,valueK};
175 short control[7]={0,ctlP,ctlN,ctlB,ctlR,ctlQ,ctlK};
176 short PassedPawn0[8]={0,60,80,120,200,360,600,800};
177 short PassedPawn1[8]={0,30,40,60,100,180,300,800};
178 short PassedPawn2[8]={0,15,25,35,50,90,140,800};
179 short PassedPawn3[8]={0,5,10,15,20,30,140,800};
180 short ISOLANI[8] = {-12,-16,-20,-24,-24,-20,-16,-12};
181 short BACKWARD[8] = {-6,-10,-15,-21,-28,-28,-28,-28};
182 short BMBLTY[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16};
183 short RMBLTY[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14};
184 short Kthreat[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80,
185 -80,-80,-80,-80};
186 short KNIGHTPOST,KNIGHTSTRONG,BISHOPSTRONG,KATAK,KBNKsq;
187 short PEDRNK2B,PWEAKH,PADVNCM,PADVNCI,PAWNSHIELD,PDOUBLED,PBLOK;
188 short RHOPN,RHOPNX,KHOPN,KHOPNX,KSFTY;
189 short ATAKD,HUNGP,HUNGX,KCASTLD,KMOVD,XRAY,PINVAL;
190 short stage,stage2,Zwmtl,Zbmtl,Developed[2],PawnStorm;
191 short PawnBonus,BishopBonus,RookBonus;
192 short KingOpening[64]=
193 { 0, 0, -4,-10,-10, -4, 0, 0,
194 -4, -4, -8,-12,-12, -8, -4, -4,
195 -12,-16,-20,-20,-20,-20,-16,-12,
196 -16,-20,-24,-24,-24,-24,-20,-16,
197 -16,-20,-24,-24,-24,-24,-20,-16,
198 -12,-16,-20,-20,-20,-20,-16,-12,
199 -4, -4, -8,-12,-12, -8, -4, -4,
200 0, 0, -4,-10,-10, -4, 0, 0};
201 short KingEnding[64]=
202 { 0, 4, 8,12,12, 8, 4, 0,
203 4,16,20,24,24,20,16, 4,
204 8,20,28,32,32,28,20, 8,
205 12,24,32,36,36,32,24,12,
206 12,24,32,36,36,32,24,12,
207 8,20,28,32,32,28,20, 8,
208 4,16,20,24,24,20,16, 4,
209 0, 4, 8,12,12, 8, 4, 0};
210 short KBNK[64]=
211 {99,90,80,70,60,50,40,40,
212 90,80,60,50,40,30,20,40,
213 80,60,40,30,20,10,30,50,
214 70,50,30,10, 0,20,40,60,
215 60,40,20, 0,10,30,50,70,
216 50,30,10,20,30,40,60,80,
217 40,20,30,40,50,60,80,90,
218 40,40,50,60,70,80,90,99};
219 short pknight[64]=
220 { 0, 4, 8,10,10, 8, 4, 0,
221 4, 8,16,20,20,16, 8, 4,
222 8,16,24,28,28,24,16, 8,
223 10,20,28,32,32,28,20,10,
224 10,20,28,32,32,28,20,10,
225 8,16,24,28,28,24,16, 8,
226 4, 8,16,20,20,16, 8, 4,
227 0, 4, 8,10,10, 8, 4, 0};
228 short pbishop[64]=
229 {14,14,14,14,14,14,14,14,
230 14,22,18,18,18,18,22,14,
231 14,18,22,22,22,22,18,14,
232 14,18,22,22,22,22,18,14,
233 14,18,22,22,22,22,18,14,
234 14,18,22,22,22,22,18,14,
235 14,22,18,18,18,18,22,14,
236 14,14,14,14,14,14,14,14};
237 short PawnAdvance[64]=
238 { 0, 0, 0, 0, 0, 0, 0, 0,
239 4, 4, 4, 0, 0, 4, 4, 4,
240 6, 8, 2,10,10, 2, 8, 6,
241 6, 8,12,16,16,12, 8, 6,
242 8,12,16,24,24,16,12, 8,
243 12,16,24,32,32,24,16,12,
244 12,16,24,32,32,24,16,12,
245 0, 0, 0, 0, 0, 0, 0, 0};
247 /* ............ prototypes ............ */
248 void ScorePosition( short side, short *score );
249 void ScoreLoneKing( short side, short *score );
250 int ScoreKPK( short side, short winner, short loser,
251 short king1, short king2, short sq );
252 int ScoreKBNK( short winner, short king1, short king2 );
253 int SqValue( short sq, short side );
254 void KingScan( short sq, short *s );
255 void BRscan( short sq, short *s, short *mob );
256 int trapped( short sq, short piece );
257 void ExaminePosition( void );
258 void UpdateWeights( void );
259 int distance( short a, short b );
260 void BlendBoard( short a[64] , short b[64] , short c[64] );
261 void CopyBoard( short a[64] , short b[64] );
263 void OpeningBook ( void );
264 int search ( short side, short ply, short depth,
265 short alpha, short beta,
266 unsigned short bstline[], short *rpt,
267 void (*callback)(void) );
268 int evaluate ( short side, short xside, short ply, short depth,
269 short alpha, short beta );
270 int ProbeTTable ( short side, short depth,
271 short *alpha, short *beta, short *score);
272 void PutInTTable ( short side, short score, short depth,
273 short alpha, short beta, unsigned short mv );
274 void ZeroTTable ( void );
275 void MoveList ( short side, short ply );
277 void GenMoves ( short ply, short sq, short side, short xside );
278 void LinkMove ( short ply, short f, short t, short xside );
279 void CaptureList ( short side, short xside, short ply );
280 int castle ( short side, short kf, short kt, short iop );
281 void EnPassant ( short xside, short f, short t, short iop );
282 void MakeMove ( short side, struct leaf *node,
283 short *tempb, short *tempc, short *tempsf, short *tempst );
284 void UnmakeMove ( short side, struct leaf *node,
285 short *tempb, short *tempc, short *tempsf, short *tempst );
286 void UpdateHashbd ( short side, short piece, short f, short t );
287 void UpdatePieceList ( short side, short sq, short iop );
288 void InitializeStats ( void );
289 void pick ( short p1, short p2 );
290 void repetition ( short *cnt );
291 int SqAtakd ( short sq, short side );
292 void ataks ( short side, short *a );
294 void algbr ( short f, short t, short flag );
295 void ElapsedTime( short iop);
297 void NewGame(void);
300 /* ............ POSITIONAL EVALUATION ROUTINES ............ */
303 void ScorePosition(side,score)
304 short side,*score;
307 Perform normal static evaluation of board position. A score is
308 generated for each piece and these are summed to get a score for each
309 side.
313 register short sq,s,i,xside;
314 short pscore[3];
316 wking = PieceList[white][0]; bking = PieceList[black][0];
317 UpdateWeights();
318 xside = otherside[side];
319 pscore[white] = pscore[black] = 0;
321 for (c1 = white; c1 <= black; c1++)
323 c2 = otherside[c1];
324 if (c1 == white) EnemyKing = bking; else EnemyKing = wking;
325 atk1 = atak[c1]; atk2 = atak[c2];
326 PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
327 for (i = 0; i <= PieceCnt[c1]; i++)
329 sq = PieceList[c1][i];
330 s = SqValue(sq,side);
331 pscore[c1] += s;
332 svalue[sq] = s;
335 if (hung[side] > 1) pscore[side] += HUNGX;
336 if (hung[xside] > 1) pscore[xside] += HUNGX;
338 *score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] + 10;
339 if (dither) *score += rb->rand() % dither;
341 if (*score > 0 && pmtl[side] == 0) {
342 if (emtl[side] < valueR) {
343 *score = 0;
344 } else {
345 if (*score < valueR) *score /= 2;
348 if (*score < 0 && pmtl[xside] == 0) {
349 if (emtl[xside] < valueR) {
350 *score = 0;
351 } else {
352 if (-*score < valueR) *score /= 2;
356 if (mtl[xside] == valueK && emtl[side] > valueB) *score += 200;
357 if (mtl[side] == valueK && emtl[xside] > valueB) *score -= 200;
361 void ScoreLoneKing(side,score)
362 short side,*score;
365 Static evaluation when loser has only a king and winner has no pawns
366 or no pieces.
370 register short winner,loser,king1,king2,s,i;
372 UpdateWeights();
373 if (mtl[white] > mtl[black]) winner = white; else winner = black;
374 loser = otherside[winner];
375 king1 = PieceList[winner][0]; king2 = PieceList[loser][0];
377 s = 0;
379 if (pmtl[winner] > 0)
380 for (i = 1; i <= PieceCnt[winner]; i++)
381 s += ScoreKPK(side,winner,loser,king1,king2,PieceList[winner][i]);
383 else if (emtl[winner] == valueB+valueN)
384 s = ScoreKBNK(winner,king1,king2);
386 else if (emtl[winner] > valueB)
387 s = 500 + emtl[winner] - 2*KingEnding[king2] - 2*distance(king1,king2);
389 if (side == winner) *score = s; else *score = -s;
393 int ScoreKPK(side,winner,loser,king1,king2,sq)
394 short side,winner,loser,king1,king2,sq;
397 Score King and Pawns versus King endings.
401 register short s,r;
403 if (PieceCnt[winner] == 1) s = 50; else s = 120;
404 if (winner == white)
406 if (side == loser) r = row[sq]-1; else r = row[sq];
407 if (row[king2] >= r && distance(sq,king2) < 8-r) s += 10*row[sq];
408 else s = 500+50*row[sq];
409 if (row[sq] < 6) sq += 16; else sq += 8;
411 else
413 if (side == loser) r = row[sq]+1; else r = row[sq];
414 if (row[king2] <= r && distance(sq,king2) < r+1) s += 10*(7-row[sq]);
415 else s = 500+50*(7-row[sq]);
416 if (row[sq] > 1) sq -= 16; else sq -= 8;
418 s += 8*(taxicab(king2,sq) - taxicab(king1,sq));
419 return(s);
423 int ScoreKBNK(winner,king1,king2)
424 short winner,king1,king2;
427 Score King+Bishop+Knight versus King endings.
428 This doesn't work all that well but it's better than nothing.
432 register short s;
433 s = emtl[winner] - 300;
434 if (KBNKsq == 0) s += KBNK[king2];
435 else s += KBNK[locn[row[king2]][7-column[king2]]];
436 s -= taxicab(king1,king2);
437 s -= distance(PieceList[winner][1],king2);
438 s -= distance(PieceList[winner][2],king2);
439 return(s);
443 int SqValue(sq,side)
444 short sq,side;
447 Calculate the positional value for the piece on 'sq'.
451 register short j,fyle,rank,a1,a2;
452 short s,piece,in_square,r,mob,e,c;
454 piece = board[sq];
455 a1 = (atk1[sq] & 0x4FFF); a2 = (atk2[sq] & 0x4FFF);
456 rank = row[sq]; fyle = column[sq];
457 s = 0;
458 if (piece == pawn && c1 == white)
460 s = Mwpawn[sq];
461 if (sq == 11 || sq == 12)
462 if (color[sq+8] != neutral) s += PEDRNK2B;
463 if ((fyle == 0 || PC1[fyle-1] == 0) &&
464 (fyle == 7 || PC1[fyle+1] == 0))
465 s += ISOLANI[fyle];
466 else if (PC1[fyle] > 1) s += PDOUBLED;
467 if (a1 < ctlP && atk1[sq+8] < ctlP)
469 s += BACKWARD[a2 & 0xFF];
470 if (PC2[fyle] == 0) s += PWEAKH;
471 if (color[sq+8] != neutral) s += PBLOK;
473 if (PC2[fyle] == 0)
475 if (side == black) r = rank-1; else r = rank;
476 in_square = (row[bking] >= r && distance(sq,bking) < 8-r);
477 if (a2 == 0 || side == white) e = 0; else e = 1;
478 for (j = sq+8; j < 64; j += 8)
479 if (atk2[j] >= ctlP) { e = 2; break; }
480 else if (atk2[j] > 0 || color[j] != neutral) e = 1;
481 if (e == 2) s += (stage*PassedPawn3[rank]) / 10;
482 else if (in_square || e == 1) s += (stage*PassedPawn2[rank]) / 10;
483 else if (emtl[black] > 0) s += (stage*PassedPawn1[rank]) / 10;
484 else s += PassedPawn0[rank];
487 else if (piece == pawn && c1 == black)
489 s = Mbpawn[sq];
490 if (sq == 51 || sq == 52)
491 if (color[sq-8] != neutral) s += PEDRNK2B;
492 if ((fyle == 0 || PC1[fyle-1] == 0) &&
493 (fyle == 7 || PC1[fyle+1] == 0))
494 s += ISOLANI[fyle];
495 else if (PC1[fyle] > 1) s += PDOUBLED;
496 if (a1 < ctlP && atk1[sq-8] < ctlP)
498 s += BACKWARD[a2 & 0xFF];
499 if (PC2[fyle] == 0) s += PWEAKH;
500 if (color[sq-8] != neutral) s += PBLOK;
502 if (PC2[fyle] == 0)
504 if (side == white) r = rank+1; else r = rank;
505 in_square = (row[wking] <= r && distance(sq,wking) < r+1);
506 if (a2 == 0 || side == black) e = 0; else e = 1;
507 for (j = sq-8; j >= 0; j -= 8)
508 if (atk2[j] >= ctlP) { e = 2; break; }
509 else if (atk2[j] > 0 || color[j] != neutral) e = 1;
510 if (e == 2) s += (stage*PassedPawn3[7-rank]) / 10;
511 else if (in_square || e == 1) s += (stage*PassedPawn2[7-rank]) / 10;
512 else if (emtl[white] > 0) s += (stage*PassedPawn1[7-rank]) / 10;
513 else s += PassedPawn0[7-rank];
516 else if (piece == knight)
518 s = Mknight[c1][sq];
520 else if (piece == bishop)
522 s = Mbishop[c1][sq];
523 BRscan(sq,&s,&mob);
524 s += BMBLTY[mob];
526 else if (piece == rook)
528 s += RookBonus;
529 BRscan(sq,&s,&mob);
530 s += RMBLTY[mob];
531 if (PC1[fyle] == 0) s += RHOPN;
532 if (PC2[fyle] == 0) s += RHOPNX;
533 if (rank == rank7[c1] && pmtl[c2] > 100) s += 10;
534 if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
536 else if (piece == queen)
538 if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
539 if (distance(sq,EnemyKing) < 3) s += 12;
541 else if (piece == king)
543 s = Mking[c1][sq];
544 if (KSFTY > 0)
545 if (Developed[c2] || stage > 0) KingScan(sq,&s);
546 if (castld[c1]) s += KCASTLD;
547 else if (kingmoved[c1]) s += KMOVD;
549 if (PC1[fyle] == 0) s += KHOPN;
550 if (PC2[fyle] == 0) s += KHOPNX;
551 if (fyle == 1 || fyle == 2 || fyle == 3 || fyle == 7)
553 if (PC1[fyle-1] == 0) s += KHOPN;
554 if (PC2[fyle-1] == 0) s += KHOPNX;
556 if (fyle == 4 || fyle == 5 || fyle == 6 || fyle == 0)
558 if (PC1[fyle+1] == 0) s += KHOPN;
559 if (PC2[fyle+1] == 0) s += KHOPNX;
561 if (fyle == 2)
563 if (PC1[0] == 0) s += KHOPN;
564 if (PC2[0] == 0) s += KHOPNX;
566 if (fyle == 5)
568 if (PC1[7] == 0) s += KHOPN;
569 if (PC2[7] == 0) s += KHOPNX;
573 if (a2 > 0)
575 c = (control[piece] & 0x4FFF);
576 if (a1 == 0 || a2 > c+1)
578 s += HUNGP;
579 ++hung[c1];
580 if (piece != king && trapped(sq,piece)) ++hung[c1];
582 else if (piece != pawn || a2 > a1)
583 if (a2 >= c || a1 < ctlP) s += ATAKD;
585 return(s);
589 void KingScan(sq,s)
590 short sq,*s;
593 Assign penalties if king can be threatened by checks, if squares
594 near the king are controlled by the enemy (especially the queen),
595 or if there are no pawns near the king.
598 #define ScoreThreat\
599 if (color[u] != c2) {\
600 if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) {\
601 ++cnt;\
602 } else {\
603 *s -= 3; \
608 register short m,u,d,i,m0,cnt,ok;
610 cnt = 0;
611 m0 = map[sq];
612 if (HasBishop[c2] || HasQueen[c2])
613 for (i = Dstart[bishop]; i <= Dstop[bishop]; i++)
615 d = Dir[i]; m = m0+d;
616 while (!(m & 0x88))
618 u = unmap[m];
619 if (atk2[u] & ctlBQ) ScoreThreat
620 if (color[u] != neutral) break;
621 m += d;
624 if (HasRook[c2] || HasQueen[c2])
625 for (i = Dstart[rook]; i <= Dstop[rook]; i++)
627 d = Dir[i]; m = m0+d;
628 while (!(m & 0x88))
630 u = unmap[m];
631 if (atk2[u] & ctlRQ) ScoreThreat
632 if (color[u] != neutral) break;
633 m += d;
636 if (HasKnight[c2])
637 for (i = Dstart[knight]; i <= Dstop[knight]; i++)
638 if (!((m = m0+Dir[i]) & 0x88))
640 u = unmap[m];
641 if (atk2[u] & ctlNN) ScoreThreat
643 *s += (KSFTY*Kthreat[cnt]) / 16;
645 cnt = 0; ok = false;
646 m0 = map[sq];
647 for (i = Dstart[king]; i <= Dstop[king]; i++)
648 if (!((m = m0+Dir[i]) & 0x88))
650 u = unmap[m];
651 if (board[u] == pawn) ok = true;
652 if (atk2[u] > atk1[u])
654 ++cnt;
655 if (atk2[u] & ctlQ)
656 if (atk2[u] > ctlQ+1 && atk1[u] < ctlQ) *s -= 4*KSFTY;
659 if (!ok) *s -= KSFTY;
660 if (cnt > 1) *s -= KSFTY;
664 void BRscan(sq,s,mob)
665 short sq,*s,*mob;
668 Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
669 hung[] array if a pin is found.
673 register short m,u,d,m0,j,piece,pin;
674 short *Kf;
676 Kf = Kfield[c1];
677 *mob = 0;
678 m0 = map[sq]; piece = board[sq];
679 for (j = Dstart[piece]; j <= Dstop[piece]; j++)
681 pin = -1;
682 d = Dir[j]; m = m0+d;
683 while (!(m & 0x88))
685 u = unmap[m]; *s += Kf[u];
686 if (color[u] == neutral)
688 (*mob)++;
689 m += d;
691 else if (pin < 0)
693 if (board[u] == pawn || board[u] == king) break;
694 pin = u;
695 m += d;
697 else if (color[u] == c2 && (board[u] > piece || atk2[u] == 0))
699 if (color[pin] == c2)
701 *s += PINVAL;
702 if (atk2[pin] == 0 ||
703 atk1[pin] > control[board[pin]]+1)
704 ++hung[c2];
706 else *s += XRAY;
707 break;
709 else break;
715 int trapped(sq,piece)
716 short sq,piece;
719 See if the attacked piece has unattacked squares to move to.
723 register short u,m,d,i,m0;
725 m0 = map[sq];
726 if (sweep[piece])
727 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
729 d = Dir[i]; m = m0+d;
730 while (!(m & 0x88))
732 u = unmap[m];
733 if (color[u] == c1) break;
734 if (atk2[u] == 0 || board[u] >= piece) return(false);
735 if (color[u] == c2) break;
736 m += d;
739 else if (piece == pawn)
741 if (c1 == white) u = sq+8; else u = sq-8;
742 if (color[u] == neutral && atk1[u] >= atk2[u])
743 return(false);
744 if (!((m = m0+Dir[Dpwn[c1]]) & 0x88))
745 if (color[unmap[m]] == c2) return(false);
746 if (!((m = m0+Dir[Dpwn[c1]+1]) & 0x88))
747 if (color[unmap[m]] == c2) return(false);
749 else
751 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
752 if (!((m = m0+Dir[i]) & 0x88))
754 u = unmap[m];
755 if (color[u] != c1)
756 if (atk2[u] == 0 || board[u] >= piece) return(false);
759 return(true);
763 void ExaminePosition()
766 This is done one time before the search is started. Set up arrays
767 Mwpawn, Mbpawn, Mknight, Mbishop, Mking which are used in the
768 SqValue() function to determine the positional value of each piece.
772 register short i,sq;
773 short wpadv,bpadv,wstrong,bstrong,z,side,pp,j,val,Pd,fyle,rank;
775 wking = PieceList[white][0]; bking = PieceList[black][0];
776 ataks(white,atak[white]); ataks(black,atak[black]);
777 Zwmtl = Zbmtl = 0;
778 UpdateWeights();
779 HasPawn[white] = HasPawn[black] = 0;
780 HasKnight[white] = HasKnight[black] = 0;
781 HasBishop[white] = HasBishop[black] = 0;
782 HasRook[white] = HasRook[black] = 0;
783 HasQueen[white] = HasQueen[black] = 0;
784 for (side = white; side <= black; side++)
785 for (i = 0; i <= PieceCnt[side]; i++)
786 switch (board[PieceList[side][i]])
788 case pawn : ++HasPawn[side]; break;
789 case knight : ++HasKnight[side]; break;
790 case bishop : ++HasBishop[side]; break;
791 case rook : ++HasRook[side]; break;
792 case queen : ++HasQueen[side]; break;
794 if (!Developed[white])
795 Developed[white] = (board[1] != knight && board[2] != bishop &&
796 board[5] != bishop && board[6] != knight);
797 if (!Developed[black])
798 Developed[black] = (board[57] != knight && board[58] != bishop &&
799 board[61] != bishop && board[62] != knight);
800 if (!PawnStorm && stage < 5)
801 PawnStorm = ((column[wking] < 3 && column[bking] > 4) ||
802 (column[wking] > 4 && column[bking] < 3));
804 CopyBoard(pknight,Mknight[white]);
805 CopyBoard(pknight,Mknight[black]);
806 CopyBoard(pbishop,Mbishop[white]);
807 CopyBoard(pbishop,Mbishop[black]);
808 BlendBoard(KingOpening,KingEnding,Mking[white]);
809 BlendBoard(KingOpening,KingEnding,Mking[black]);
811 for (sq = 0; sq < 64; sq++)
813 fyle = column[sq]; rank = row[sq];
814 wstrong = bstrong = true;
815 for (i = sq; i < 64; i += 8)
816 if (atak[black][i] >= ctlP) wstrong = false;
817 for (i = sq; i >= 0; i -= 8)
818 if (atak[white][i] >= ctlP) bstrong = false;
819 wpadv = bpadv = PADVNCM;
820 if ((fyle == 0 || PawnCnt[white][fyle-1] == 0) &&
821 (fyle == 7 || PawnCnt[white][fyle+1] == 0)) wpadv = PADVNCI;
822 if ((fyle == 0 || PawnCnt[black][fyle-1] == 0) &&
823 (fyle == 7 || PawnCnt[black][fyle+1] == 0)) bpadv = PADVNCI;
824 Mwpawn[sq] = (wpadv*PawnAdvance[sq]) / 10;
825 Mbpawn[sq] = (bpadv*PawnAdvance[63-sq]) / 10;
826 Mwpawn[sq] += PawnBonus; Mbpawn[sq] += PawnBonus;
827 if (castld[white] || kingmoved[white])
829 if ((fyle < 3 || fyle > 4) && distance(sq,wking) < 3)
830 Mwpawn[sq] += PAWNSHIELD;
832 else if (rank < 3 && (fyle < 2 || fyle > 5))
833 Mwpawn[sq] += PAWNSHIELD / 2;
834 if (castld[black] || kingmoved[black])
836 if ((fyle < 3 || fyle > 4) && distance(sq,bking) < 3)
837 Mbpawn[sq] += PAWNSHIELD;
839 else if (rank > 4 && (fyle < 2 || fyle > 5))
840 Mbpawn[sq] += PAWNSHIELD / 2;
841 if (PawnStorm)
843 if ((column[wking] < 4 && fyle > 4) ||
844 (column[wking] > 3 && fyle < 3)) Mwpawn[sq] += 3*rank - 21;
845 if ((column[bking] < 4 && fyle > 4) ||
846 (column[bking] > 3 && fyle < 3)) Mbpawn[sq] -= 3*rank;
849 Mknight[white][sq] += 5 - distance(sq,bking);
850 Mknight[white][sq] += 5 - distance(sq,wking);
851 Mknight[black][sq] += 5 - distance(sq,wking);
852 Mknight[black][sq] += 5 - distance(sq,bking);
853 Mbishop[white][sq] += BishopBonus;
854 Mbishop[black][sq] += BishopBonus;
855 for (i = 0; i <= PieceCnt[black]; i++)
856 if (distance(sq,PieceList[black][i]) < 3)
857 Mknight[white][sq] += KNIGHTPOST;
858 for (i = 0; i <= PieceCnt[white]; i++)
859 if (distance(sq,PieceList[white][i]) < 3)
860 Mknight[black][sq] += KNIGHTPOST;
861 if (wstrong) Mknight[white][sq] += KNIGHTSTRONG;
862 if (bstrong) Mknight[black][sq] += KNIGHTSTRONG;
863 if (wstrong) Mbishop[white][sq] += BISHOPSTRONG;
864 if (bstrong) Mbishop[black][sq] += BISHOPSTRONG;
866 if (HasBishop[white] == 2) Mbishop[white][sq] += 8;
867 if (HasBishop[black] == 2) Mbishop[black][sq] += 8;
868 if (HasKnight[white] == 2) Mknight[white][sq] += 5;
869 if (HasKnight[black] == 2) Mknight[black][sq] += 5;
871 if (board[sq] == bishop) {
872 if (rank % 2 == fyle % 2) {
873 KBNKsq = 0;
874 } else {
875 KBNKsq = 7;
879 Kfield[white][sq] = Kfield[black][sq] = 0;
880 if (distance(sq,wking) == 1) Kfield[black][sq] = KATAK;
881 if (distance(sq,bking) == 1) Kfield[white][sq] = KATAK;
883 Pd = 0;
884 for (i = 0; i < 64; i++)
885 if (board[i] == pawn)
887 if (color[i] == white)
889 pp = true;
890 if (row[i] == 6) z = i+8; else z = i+16;
891 for (j = i+8; j < 64; j += 8)
892 if (atak[black][j] > ctlP || board[j] == pawn) pp = false;
894 else
896 pp = true;
897 if (row[i] == 1) z = i-8; else z = i-16;
898 for (j = i-8; j >= 0; j -= 8)
899 if (atak[white][j] > ctlP || board[j] == pawn) pp = false;
901 if (pp) Pd += 5*taxicab(sq,z); else Pd += taxicab(sq,z);
903 if (Pd != 0)
905 val = (Pd*stage2) / 10;
906 Mking[white][sq] -= val;
907 Mking[black][sq] -= val;
913 void UpdateWeights()
916 If material balance has changed, determine the values for the
917 positional evaluation terms.
921 register short tmtl;
923 if (mtl[white] != Zwmtl || mtl[black] != Zbmtl)
925 Zwmtl = mtl[white]; Zbmtl = mtl[black];
926 emtl[white] = Zwmtl - pmtl[white] - valueK;
927 emtl[black] = Zbmtl - pmtl[black] - valueK;
928 tmtl = emtl[white] + emtl[black];
929 if (tmtl > 6600) stage = 0;
930 else if (tmtl < 1400) stage = 10;
931 else stage = (6600-tmtl) / 520;
932 if (tmtl > 3600) stage2 = 0;
933 else if (tmtl < 1400) stage2 = 10;
934 else stage2 = (3600-tmtl) / 220;
936 PEDRNK2B = -15; /* centre pawn on 2nd rank & blocked */
937 PBLOK = -4; /* blocked backward pawn */
938 PDOUBLED = -14; /* doubled pawn */
939 PWEAKH = -4; /* weak pawn on half open file */
940 PAWNSHIELD = 10-stage; /* pawn near friendly king */
941 PADVNCM = 10; /* advanced pawn multiplier */
942 PADVNCI = 7; /* muliplier for isolated pawn */
943 PawnBonus = stage;
945 KNIGHTPOST = (stage+2)/3; /* knight near enemy pieces */
946 KNIGHTSTRONG = (stage+6)/2; /* occupies pawn hole */
948 BISHOPSTRONG = (stage+6)/2; /* occupies pawn hole */
949 BishopBonus = 2*stage;
951 RHOPN = 10; /* rook on half open file */
952 RHOPNX = 4;
953 RookBonus = 6*stage;
955 XRAY = 8; /* Xray attack on piece */
956 PINVAL = 10; /* Pin */
958 KHOPN = (3*stage-30) / 2; /* king on half open file */
959 KHOPNX = KHOPN / 2;
960 KCASTLD = 10 - stage;
961 KMOVD = -40 / (stage+1); /* king moved before castling */
962 KATAK = (10-stage) / 2; /* B,R attacks near enemy king */
963 if (stage < 8) KSFTY = 16-2*stage; else KSFTY = 0;
965 ATAKD = -6; /* defender > attacker */
966 HUNGP = -8; /* each hung piece */
967 HUNGX = -12; /* extra for >1 hung piece */
972 int distance(a,b)
973 short a,b;
975 register short d1,d2;
977 d1 = abs(column[a]-column[b]);
978 d2 = abs(row[a]-row[b]);
979 if (d1 > d2) return(d1); else return(d2);
983 void BlendBoard(a,b,c)
984 short a[64],b[64],c[64];
986 register int sq;
987 for (sq = 0; sq < 64; sq++)
988 c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10;
992 void CopyBoard(a,b)
993 short a[64],b[64];
995 register int sq;
996 for (sq = 0; sq < 64; sq++)
997 b[sq] = a[sq];
1000 /* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
1003 int SelectMove( short side, short iop , void (*callback)(void), char* move_buffer)
1006 Select a move by calling function search() at progressively deeper
1007 ply until time is up or a mate or draw is reached. An alpha-beta
1008 window of -90 to +90 points is set around the score returned from the
1009 previous iteration. If Sdepth != 0 then the program has correctly
1010 predicted the opponents move and the search will start at a depth of
1011 Sdepth+1 rather than a depth of 1.
1015 static short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt;
1017 timeout = false;
1018 xside = otherside[side];
1019 if (iop != 2) player = side;
1020 if (TCflag)
1022 ResponseTime = (TimeControl.clock[side]) /
1023 (TimeControl.moves[side] + 3) -
1024 OperatorTime;
1025 ResponseTime += (ResponseTime*TimeControl.moves[side])/(2*TCmoves+1);
1027 else ResponseTime = Level;
1028 if (iop == 2) ResponseTime = 999;
1029 if (Sdepth > 0 && root->score > Zscore-zwndw) ResponseTime -= ft;
1030 else if (ResponseTime < 1) ResponseTime = 1;
1031 ExtraTime = 0;
1032 ExaminePosition();
1033 ScorePosition(side,&score);
1034 Pscore[0] = -score;
1036 if (Sdepth == 0)
1038 ZeroTTable();
1039 /*SearchStartStuff(side);*/
1040 for (i = 0; i < 8192; i++) history[i] = 0;
1041 FROMsquare = TOsquare = -1;
1042 PV = 0;
1043 if (iop != 2) hint = 0;
1044 for (i = 0; i < maxdepth; i++)
1045 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
1047 alpha = -9000; beta = 9000;
1048 rpt = 0;
1049 TrPnt[1] = 0; root = &Tree[0];
1050 MoveList(side,1);
1051 for (i = TrPnt[1]; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
1052 if (withbook) OpeningBook();
1053 if (withbook) timeout = true;
1054 NodeCnt = ETnodes = EvalNodes = HashCnt = 0;
1055 Zscore = 0; zwndw = 20;
1058 while (!timeout && Sdepth < MaxSearchDepth)
1060 Sdepth++;
1061 /*ShowDepth(' ');*/
1062 score = search(side,1,Sdepth,alpha,beta,PrVar,&rpt,callback);
1063 for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
1064 if (score < alpha && !timeout)
1066 /*ShowDepth('-');*/
1067 ExtraTime = 10*ResponseTime;
1068 ZeroTTable();
1069 score = search(side,1,Sdepth,-9000,beta,PrVar,&rpt,callback);
1071 if (score > beta && !timeout && !(root->flags & exact))
1073 /*ShowDepth('+');*/
1074 ExtraTime = 0;
1075 ZeroTTable();
1076 score = search(side,1,Sdepth,alpha,9000,PrVar,&rpt,callback);
1078 score = root->score;
1079 if (!timeout)
1080 for (i = TrPnt[1]+1; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
1081 /*ShowResults(score,PrVar,'.');*/
1082 for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
1083 if (score > Zscore-zwndw && score > Tree[1].score+250) ExtraTime = 0;
1084 else if (score > Zscore-3*zwndw) ExtraTime = ResponseTime;
1085 else ExtraTime = 3*ResponseTime;
1086 if (root->flags & exact) timeout = true;
1087 if (Tree[1].score < -9000) timeout = true;
1088 if (4*et > 2*ResponseTime + ExtraTime) timeout = true;
1089 if (!timeout)
1091 Tscore[0] = score;
1092 if (Zscore == 0) Zscore = score;
1093 else Zscore = (Zscore+score)/2;
1095 zwndw = 20+abs(Zscore/12);
1096 beta = score + Bwindow;
1097 if (Zscore < score) alpha = Zscore - Awindow - zwndw;
1098 else alpha = score - Awindow - zwndw;
1101 score = root->score;
1102 if (rpt >= 2 || score < -12000) root->flags |= draw;
1103 if (iop == 2) return(0);
1104 if (!withbook) hint = PrVar[2];
1105 ElapsedTime(1);
1107 if (score > -9999 && rpt <= 2)
1109 MakeMove(side,root,&tempb,&tempc,&tempsf,&tempst);
1110 algbr(root->f,root->t,root->flags & cstlmask);
1112 else mvstr1[0] = '\0';
1113 /*OutputMove();*/
1115 short index;
1116 for (index=0;index<5;index++){
1117 move_buffer[index] = mvstr1[index];
1120 if (score == -9999 || score == 9998) mate = true;
1121 if (mate) hint = 0;
1122 if (root->flags & cstlmask) Game50 = GameCnt;
1123 else if (board[root->t] == pawn || (root->flags & capture))
1124 Game50 = GameCnt;
1125 GameList[GameCnt].score = score;
1126 GameList[GameCnt].nodes = NodeCnt;
1127 GameList[GameCnt].time = (short)et;
1128 GameList[GameCnt].depth = Sdepth;
1129 if (TCflag)
1131 TimeControl.clock[side] -= (et + OperatorTime);
1132 if (--TimeControl.moves[side] == 0) SetTimeControl();
1134 if ((root->flags & draw) && bothsides) quit = true;
1135 if (GameCnt > 238) quit = true;
1136 player = xside;
1137 Sdepth = 0;
1138 return(0);
1142 void OpeningBook()
1145 Go thru each of the opening lines of play and check for a match with
1146 the current game listing. If a match occurs, generate a random number.
1147 If this number is the largest generated so far then the next move in
1148 this line becomes the current "candidate". After all lines are
1149 checked, the candidate move is put at the top of the Tree[] array and
1150 will be played by the program. Note that the program does not handle
1151 book transpositions.
1155 short j,pnt;
1156 unsigned short m;
1157 unsigned r,r0;
1158 int o_c=0 , m_c=0 ;
1160 rb->srand ( *rb->current_tick ) ;
1161 r0 = 0;
1162 m = 0;
1163 while ( o_c < MAX_OPENING ) {
1164 m_c = 0 ;
1165 for (j = 0; j <= GameCnt; j++) {
1166 if ( GameList[j].gmove != OBook[o_c][m_c] ) break;
1167 m_c++;
1169 /* I added ( m != OBook[o_c][m_c] ) trying to get more random games */
1170 if ( ( j > GameCnt ) && ( m != OBook[o_c][m_c] ) ) {
1171 r=rb->rand();
1172 if ( r > r0 ) {
1173 r0 = r; m = OBook[o_c][m_c];
1174 hint = OBook[o_c][m_c+1];
1177 o_c++;
1180 for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
1181 if ((Tree[pnt].f<<8) + Tree[pnt].t == m) Tree[pnt].score = 0;
1182 pick(TrPnt[1],TrPnt[2]-1);
1183 if (Tree[TrPnt[1]].score < 0) withbook = false;
1187 #define UpdateSearchStatus \
1189 if (pnt > TrPnt[1])\
1191 d = best-Zscore; e = best-node->score;\
1192 if (best < alpha) ExtraTime = 10*ResponseTime;\
1193 else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\
1194 else if (d > -zwndw) ExtraTime = 0;\
1195 else if (d > -3*zwndw) ExtraTime = ResponseTime;\
1196 else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\
1197 else ExtraTime = 5*ResponseTime;\
1201 int search( short side, short ply, short depth,
1202 short alpha, short beta, unsigned short bstline[], short *rpt,
1203 void (*callback)(void) )
1206 Perform an alpha-beta search to determine the score for the current
1207 board position. If depth <= 0 only capturing moves, pawn promotions
1208 and responses to check are generated and searched, otherwise all
1209 moves are processed. The search depth is modified for check evasions,
1210 certain re-captures and threats. Extensions may continue for up to 11
1211 ply beyond the nominal search depth.
1214 #define prune (cf && score+node->score < alpha)
1215 #define ReCapture (rcptr && score > alpha && score < beta &&\
1216 ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2] &&\
1217 depth == Sdepth-ply+1)
1218 #define Parry (hung[side] > 1 && ply == Sdepth+1)
1219 #define MateThreat (ply < Sdepth+4 && ply > 4 &&\
1220 ChkFlag[ply-2] && ChkFlag[ply-4] &&\
1221 ChkFlag[ply-2] != ChkFlag[ply-4])
1224 register short j,pnt;
1225 short best,tempb,tempc,tempsf,tempst;
1226 short xside,pbst,d,e,cf,score,rcnt;
1227 unsigned short mv,nxtline[maxdepth];
1228 struct leaf *node,tmp;
1230 /* this is the only place we need to yield */
1231 rb->yield();
1232 /* and check for user interaction */
1233 callback();
1235 NodeCnt++;
1236 xside = otherside[side];
1238 if (ply <= Sdepth+3) repetition(rpt); else *rpt = 0;
1239 if (*rpt >= 2) return(0);
1241 score = evaluate(side,xside,ply,depth,alpha,beta);
1242 if (score > 9000) return(score);
1244 if (depth > 0)
1246 if (InChk || PawnThreat[ply-1] || ReCapture) ++depth;
1248 else
1250 if (score >= alpha &&
1251 (InChk || PawnThreat[ply-1] || Parry)) depth = 1;
1252 else if (score <= beta && MateThreat) depth = 1;
1255 PV = 0;
1256 if (depth > 0 && hashflag && ply > 1)
1258 ProbeTTable(side,depth,&alpha,&beta,&score);
1259 bstline[ply] = PV;
1260 bstline[ply+1] = 0;
1261 if (beta == -20000) return(score);
1262 if (alpha > beta) return(alpha);
1265 if (Sdepth == 1) d = 7; else d = 11;
1266 if (ply > Sdepth+d || (depth <= 0 && score > beta)) return(score);
1268 if (ply > 1) {
1269 if (depth > 0) {
1270 MoveList(side,ply);
1271 } else {
1272 CaptureList(side,xside,ply);
1276 if (TrPnt[ply] == TrPnt[ply+1]) return(score);
1278 cf = (depth < 1 && ply > Sdepth+1 && !ChkFlag[ply-2] && !slk);
1280 if (depth > 0) best = -12000; else best = score;
1281 if (best > alpha) alpha = best;
1283 for (pnt = pbst = TrPnt[ply];
1284 pnt < TrPnt[ply+1] && best <= beta;
1285 pnt++)
1287 if (ply > 1) pick(pnt,TrPnt[ply+1]-1);
1288 node = &Tree[pnt];
1289 mv = (node->f << 8) + node->t;
1290 nxtline[ply+1] = 0;
1292 if (prune) break;
1293 if (ply == 1) UpdateSearchStatus;
1295 if (!(node->flags & exact))
1297 MakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
1298 CptrFlag[ply] = (node->flags & capture);
1299 PawnThreat[ply] = (node->flags & pwnthrt);
1300 Tscore[ply] = node->score;
1301 node->score = -search(xside,ply+1,depth-1,-beta,-alpha,
1302 nxtline,&rcnt,callback);
1303 if (abs(node->score) > 9000) node->flags |= exact;
1304 else if (rcnt == 1) node->score /= 2;
1305 if (rcnt >= 2 || GameCnt-Game50 > 99 ||
1306 (node->score == 9999-ply && !ChkFlag[ply]))
1308 node->flags |= draw; node->flags |= exact;
1309 if (side == computer) node->score = contempt;
1310 else node->score = -contempt;
1312 UnmakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
1314 if (node->score > best && !timeout)
1316 if (depth > 0)
1317 if (node->score > alpha && !(node->flags & exact))
1318 node->score += depth;
1319 best = node->score; pbst = pnt;
1320 if (best > alpha) alpha = best;
1321 for (j = ply+1; nxtline[j] > 0; j++) bstline[j] = nxtline[j];
1322 bstline[j] = 0;
1323 bstline[ply] = mv;
1324 if (ply == 1)
1326 if (best == alpha)
1328 tmp = Tree[pnt];
1329 for (j = pnt-1; j >= 0; j--) Tree[j+1] = Tree[j];
1330 Tree[0] = tmp;
1331 pbst = 0;
1333 /*if (Sdepth > 2)
1334 if (best > beta) ShowResults(best,bstline,'+');
1335 else if (best < alpha) ShowResults(best,bstline,'-');
1336 else ShowResults(best,bstline,'&');*/
1339 if (NodeCnt > ETnodes) ElapsedTime(0);
1340 if (timeout) return(-Tscore[ply-1]);
1343 node = &Tree[pbst];
1344 mv = (node->f<<8) + node->t;
1345 if (hashflag && ply <= Sdepth && *rpt == 0 && best == alpha)
1346 PutInTTable(side,best,depth,alpha,beta,mv);
1347 if (depth > 0)
1349 j = (node->f<<6) + node->t; if (side == black) j |= 0x1000;
1350 if (history[j] < 150) history[j] += 2*depth;
1351 if (node->t != (GameList[GameCnt].gmove & 0xFF)) {
1352 if (best <= beta) {
1353 killr3[ply] = mv;
1354 } else {
1355 if (mv != killr1[ply]) {
1356 killr2[ply] = killr1[ply];
1357 killr1[ply] = mv;
1361 if (best > 9000) killr0[ply] = mv; else killr0[ply] = 0;
1363 return(best);
1367 int evaluate(side,xside,ply,depth,alpha,beta)
1368 short side,xside,ply,depth,alpha,beta;
1371 Compute an estimate of the score by adding the positional score from
1372 the previous ply to the material difference. If this score falls
1373 inside a window which is 180 points wider than the alpha-beta window
1374 (or within a 50 point window during quiescence search) call
1375 ScorePosition() to determine a score, otherwise return the estimated
1376 score. If one side has only a king and the other either has no pawns
1377 or no pieces then the function ScoreLoneKing() is called.
1381 register short evflag;
1383 Xscore = -Pscore[ply-1] - INCscore + mtl[side] - mtl[xside];
1384 hung[white] = hung[black] = 0;
1385 slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
1386 (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));
1388 if (slk) evflag = false;
1389 else evflag =
1390 (ply == 1 || ply < Sdepth ||
1391 (depth == 0 && Xscore > alpha-xwndw && Xscore < beta+xwndw) ||
1392 (depth < 0 && Xscore > alpha-25 && Xscore < beta+25));
1394 if (evflag)
1396 EvalNodes++;
1397 ataks(side,atak[side]);
1398 if (atak[side][PieceList[xside][0]] > 0) return(10001-ply);
1399 ataks(xside,atak[xside]);
1400 InChk = (atak[xside][PieceList[side][0]] > 0);
1401 ScorePosition(side,&Xscore);
1403 else
1405 if (SqAtakd(PieceList[xside][0],side)) return(10001-ply);
1406 InChk = SqAtakd(PieceList[side][0],xside);
1407 if (slk) ScoreLoneKing(side,&Xscore);
1410 Pscore[ply] = Xscore - mtl[side] + mtl[xside];
1411 if (InChk) ChkFlag[ply-1] = Pindex[TOsquare];
1412 else ChkFlag[ply-1] = 0;
1413 return(Xscore);
1417 int ProbeTTable(side,depth,alpha,beta,score)
1418 short side,depth,*alpha,*beta,*score;
1421 Look for the current board position in the transposition table.
1425 short hindx;
1426 if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
1427 hindx = (hashkey & (ttblsz-1));
1428 ptbl = (ttable + hindx);
1429 if (ptbl->depth >= depth && ptbl->hashbd == hashbd)
1431 HashCnt++;
1432 PV = ptbl->mv;
1433 if (ptbl->flags & truescore)
1435 *score = ptbl->score;
1436 *beta = -20000;
1437 return(true);
1440 else if (ptbl->flags & upperbound)
1442 if (ptbl->score < *beta) *beta = ptbl->score+1;
1445 else if (ptbl->flags & lowerbound)
1447 if (ptbl->score > *alpha) *alpha = ptbl->score-1;
1450 return(false);
1454 void PutInTTable(side,score,depth,alpha,beta,mv)
1455 short side,score,depth,alpha,beta;
1456 unsigned short mv;
1459 Store the current board position in the transposition table.
1463 short hindx;
1464 if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
1465 hindx = (hashkey & (ttblsz-1));
1466 ptbl = (ttable + hindx);
1467 ptbl->hashbd = hashbd;
1468 ptbl->depth = depth;
1469 ptbl->score = score;
1470 ptbl->mv = mv;
1471 ptbl->flags = 0;
1472 if (score < alpha) ptbl->flags |= upperbound;
1473 else if (score > beta) ptbl->flags |= lowerbound;
1474 else ptbl->flags |= truescore;
1478 void ZeroTTable()
1480 int i;
1481 if (hashflag)
1482 for (i = 0; i < ttblsz; i++)
1484 ptbl = (ttable + i);
1485 ptbl->depth = 0;
1490 void MoveList(side,ply)
1491 short side,ply;
1494 Fill the array Tree[] with all available moves for side to play. Array
1495 TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1499 register short i,xside,f;
1501 xside = otherside[side];
1502 if (PV == 0) Swag0 = killr0[ply]; else Swag0 = PV;
1503 Swag1 = killr1[ply]; Swag2 = killr2[ply];
1504 Swag3 = killr3[ply]; Swag4 = 0;
1505 if (ply > 2) Swag4 = killr1[ply-2];
1506 TrPnt[ply+1] = TrPnt[ply];
1507 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
1508 for (i = PieceCnt[side]; i >= 0; i--)
1509 GenMoves(ply,PieceList[side][i],side,xside);
1510 if (kingmoved[side] == 0 && !castld[side])
1512 f = PieceList[side][0];
1513 if (castle(side,f,f+2,0))
1515 LinkMove(ply,f,f+2,xside);
1516 Tree[TrPnt[ply+1]-1].flags |= cstlmask;
1518 if (castle(side,f,f-2,0))
1520 LinkMove(ply,f,f-2,xside);
1521 Tree[TrPnt[ply+1]-1].flags |= cstlmask;
1527 void GenMoves(ply,sq,side,xside)
1528 short ply,sq,side,xside;
1531 Generate moves for a piece. The from square is mapped onto a special
1532 board and offsets (taken from array Dir[]) are added to the mapped
1533 location. The newly generated square is tested to see if it falls off
1534 the board by ANDing the square with 88 HEX. Legal moves are linked
1535 into the tree.
1539 register short m,u,d,i,m0,piece;
1541 piece = board[sq]; m0 = map[sq];
1542 if (sweep[piece])
1543 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1545 d = Dir[i]; m = m0+d;
1546 while (!(m & 0x88))
1548 u = unmap[m];
1549 if (color[u] == neutral)
1551 LinkMove(ply,sq,u,xside);
1552 m += d;
1554 else if (color[u] == xside)
1556 LinkMove(ply,sq,u,xside);
1557 break;
1559 else break;
1562 else if (piece == pawn)
1564 if (side == white && color[sq+8] == neutral)
1566 LinkMove(ply,sq,sq+8,xside);
1567 if (row[sq] == 1)
1568 if (color[sq+16] == neutral)
1569 LinkMove(ply,sq,sq+16,xside);
1571 else if (side == black && color[sq-8] == neutral)
1573 LinkMove(ply,sq,sq-8,xside);
1574 if (row[sq] == 6)
1575 if (color[sq-16] == neutral)
1576 LinkMove(ply,sq,sq-16,xside);
1578 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1579 if (!((m = m0+Dir[i]) & 0x88))
1581 u = unmap[m];
1582 if (color[u] == xside || u == epsquare)
1583 LinkMove(ply,sq,u,xside);
1586 else
1588 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1589 if (!((m = m0+Dir[i]) & 0x88))
1591 u = unmap[m];
1592 if (color[u] != side) LinkMove(ply,sq,u,xside);
1598 void LinkMove(ply,f,t,xside)
1599 short ply,f,t,xside;
1602 Add a move to the tree. Assign a bonus to order the moves
1603 as follows:
1604 1. Principle variation
1605 2. Capture of last moved piece
1606 3. Other captures (major pieces first)
1607 4. Killer moves
1608 5. "history" killers
1612 register short s,z;
1613 register unsigned short mv;
1614 struct leaf *node;
1616 node = &Tree[TrPnt[ply+1]];
1617 ++TrPnt[ply+1];
1618 node->flags = 0;
1619 node->f = f; node->t = t;
1620 mv = (f<<8) + t;
1621 s = 0;
1622 if (mv == Swag0) s = 2000;
1623 else if (mv == Swag1) s = 60;
1624 else if (mv == Swag2) s = 50;
1625 else if (mv == Swag3) s = 40;
1626 else if (mv == Swag4) s = 30;
1627 if (color[t] != neutral)
1629 node->flags |= capture;
1630 if (t == TOsquare) s += 500;
1631 s += value[board[t]] - board[f];
1633 if (board[f] == pawn) {
1634 if (row[t] == 0 || row[t] == 7) {
1635 node->flags |= promote;
1636 s += 800;
1637 } else {
1638 if (row[t] == 1 || row[t] == 6) {
1639 node->flags |= pwnthrt;
1640 s += 600;
1641 } else {
1642 if (t == epsquare) node->flags |= epmask;
1646 z = (f<<6) + t; if (xside == white) z |= 0x1000;
1647 s += history[z];
1648 node->score = s - 20000;
1652 void CaptureList(side,xside,ply)
1653 short side,xside,ply;
1656 Generate captures and Pawn promotions only.
1659 #define LinkCapture \
1661 node->f = sq; node->t = u;\
1662 node->flags = capture;\
1663 node->score = value[board[u]] + svalue[board[u]] - piece;\
1664 if (piece == pawn && (u < 8 || u > 55))\
1666 node->flags |= promote;\
1667 node->score = valueQ;\
1669 ++node;\
1670 ++TrPnt[ply+1];\
1674 register short m,u,d,sq,m0;
1675 short i,j,j1,j2,r7,d0,piece,*PL;
1676 struct leaf *node;
1678 TrPnt[ply+1] = TrPnt[ply];
1679 node = &Tree[TrPnt[ply]];
1680 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
1681 if (side == white)
1683 r7 = 6; d0 = 8;
1685 else
1687 r7 = 1; d0 = -8;
1689 PL = PieceList[side];
1690 for (i = 0; i <= PieceCnt[side]; i++)
1692 sq = PL[i];
1693 m0 = map[sq]; piece = board[sq];
1694 j1 = Dstart[piece]; j2 = Dstop[piece];
1695 if (sweep[piece])
1696 for (j = j1; j <= j2; j++)
1698 d = Dir[j]; m = m0+d;
1699 while (!(m & 0x88))
1701 u = unmap[m];
1702 if (color[u] == neutral) m += d;
1703 else
1705 if (color[u] == xside) LinkCapture;
1706 break;
1710 else
1712 for (j = j1; j <= j2; j++)
1713 if (!((m = m0+Dir[j]) & 0x88))
1715 u = unmap[m];
1716 if (color[u] == xside) LinkCapture;
1718 if (piece == pawn && row[sq] == r7)
1720 u = sq+d0;
1721 if (color[u] == neutral) LinkCapture;
1728 int castle(side,kf,kt,iop)
1729 short side,kf,kt,iop;
1732 Make or Unmake a castling move.
1736 register short rf,rt,d,t0,xside;
1738 xside = otherside[side];
1739 if (kt > kf)
1741 rf = kf+3; rt = kt-1; d = 1;
1743 else
1745 rf = kf-4; rt = kt+1; d = -1;
1747 if (iop == 0)
1749 if (board[kf] != king || board[rf] != rook || color[rf] != side)
1750 return(false);
1751 if (color[kt] != neutral || color[rt] != neutral) return(false);
1752 if (d == -1 && color[kt+d] != neutral) return(false);
1753 if (SqAtakd(kf,xside)) return(false);
1754 if (SqAtakd(kt,xside)) return(false);
1755 if (SqAtakd(kf+d,xside)) return(false);
1757 else
1759 if (iop == 1) castld[side] = true; else castld[side] = false;
1760 if (iop == 2)
1762 t0 = kt; kt = kf; kf = t0;
1763 t0 = rt; rt = rf; rf = t0;
1765 board[kt] = king; color[kt] = side; Pindex[kt] = 0;
1766 board[kf] = no_piece; color[kf] = neutral;
1767 board[rt] = rook; color[rt] = side; Pindex[rt] = Pindex[rf];
1768 board[rf] = no_piece; color[rf] = neutral;
1769 PieceList[side][Pindex[kt]] = kt;
1770 PieceList[side][Pindex[rt]] = rt;
1771 if (hashflag)
1773 UpdateHashbd(side,king,kf,kt);
1774 UpdateHashbd(side,rook,rf,rt);
1777 return(true);
1781 void EnPassant(xside,f,t,iop)
1782 short xside,f,t,iop;
1785 Make or unmake an en passant move.
1789 register short l;
1790 if (t > f) l = t-8; else l = t+8;
1791 if (iop == 1)
1793 board[l] = no_piece; color[l] = neutral;
1795 else
1797 board[l] = pawn; color[l] = xside;
1799 InitializeStats();
1803 void MakeMove(side,node,tempb,tempc,tempsf,tempst)
1804 short side,*tempc,*tempb,*tempsf,*tempst;
1805 struct leaf *node;
1808 Update Arrays board[], color[], and Pindex[] to reflect the new board
1809 position obtained after making the move pointed to by node. Also
1810 update miscellaneous stuff that changes when a move is made.
1814 register short f,t,xside,ct,cf;
1816 xside = otherside[side];
1817 f = node->f; t = node->t; epsquare = -1;
1818 FROMsquare = f; TOsquare = t;
1819 INCscore = 0;
1820 GameList[++GameCnt].gmove = (f<<8) + t;
1821 if (node->flags & cstlmask)
1823 GameList[GameCnt].piece = no_piece;
1824 GameList[GameCnt].color = side;
1825 castle(side,f,t,1);
1827 else
1829 *tempc = color[t]; *tempb = board[t];
1830 *tempsf = svalue[f]; *tempst = svalue[t];
1831 GameList[GameCnt].piece = *tempb;
1832 GameList[GameCnt].color = *tempc;
1833 if (*tempc != neutral)
1835 UpdatePieceList(*tempc,t,1);
1836 if (*tempb == pawn) --PawnCnt[*tempc][column[t]];
1837 if (board[f] == pawn)
1839 --PawnCnt[side][column[f]];
1840 ++PawnCnt[side][column[t]];
1841 cf = column[f]; ct = column[t];
1842 if (PawnCnt[side][ct] > 1+PawnCnt[side][cf])
1843 INCscore -= 15;
1844 else if (PawnCnt[side][ct] < 1+PawnCnt[side][cf])
1845 INCscore += 15;
1846 else if (ct == 0 || ct == 7 || PawnCnt[side][ct+ct-cf] == 0)
1847 INCscore -= 15;
1849 mtl[xside] -= value[*tempb];
1850 if (*tempb == pawn) pmtl[xside] -= valueP;
1851 if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
1852 INCscore += *tempst;
1854 color[t] = color[f]; board[t] = board[f]; svalue[t] = svalue[f];
1855 Pindex[t] = Pindex[f]; PieceList[side][Pindex[t]] = t;
1856 color[f] = neutral; board[f] = no_piece;
1857 if (board[t] == pawn) {
1858 if (t-f == 16) {
1859 epsquare = f+8;
1860 } else {
1861 if (f-t == 16) epsquare = f-8;
1864 if (node->flags & promote)
1866 board[t] = queen;
1867 --PawnCnt[side][column[t]];
1868 mtl[side] += valueQ - valueP;
1869 pmtl[side] -= valueP;
1870 HasQueen[side] = true;
1871 if (hashflag)
1873 UpdateHashbd(side,pawn,f,-1);
1874 UpdateHashbd(side,queen,f,-1);
1876 INCscore -= *tempsf;
1878 if (board[t] == king) ++kingmoved[side];
1879 if (node->flags & epmask) EnPassant(xside,f,t,1);
1880 else if (hashflag) UpdateHashbd(side,board[t],f,t);
1885 void UnmakeMove(side,node,tempb,tempc,tempsf,tempst)
1886 short side,*tempc,*tempb,*tempsf,*tempst;
1887 struct leaf *node;
1890 Take back a move.
1894 register short f,t,xside;
1896 xside = otherside[side];
1897 f = node->f; t = node->t; epsquare = -1;
1898 GameCnt--;
1899 if (node->flags & cstlmask) castle(side,f,t,2);
1900 else
1902 color[f] = color[t]; board[f] = board[t]; svalue[f] = *tempsf;
1903 Pindex[f] = Pindex[t]; PieceList[side][Pindex[f]] = f;
1904 color[t] = *tempc; board[t] = *tempb; svalue[t] = *tempst;
1905 if (node->flags & promote)
1907 board[f] = pawn;
1908 ++PawnCnt[side][column[t]];
1909 mtl[side] += valueP - valueQ;
1910 pmtl[side] += valueP;
1911 if (hashflag)
1913 UpdateHashbd(side,queen,-1,t);
1914 UpdateHashbd(side,pawn,-1,t);
1917 if (*tempc != neutral)
1919 UpdatePieceList(*tempc,t,2);
1920 if (*tempb == pawn) ++PawnCnt[*tempc][column[t]];
1921 if (board[f] == pawn)
1923 --PawnCnt[side][column[t]];
1924 ++PawnCnt[side][column[f]];
1926 mtl[xside] += value[*tempb];
1927 if (*tempb == pawn) pmtl[xside] += valueP;
1928 if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
1930 if (board[f] == king) --kingmoved[side];
1931 if (node->flags & epmask) EnPassant(xside,f,t,2);
1932 else if (hashflag) UpdateHashbd(side,board[f],f,t);
1937 void UpdateHashbd(side,piece,f,t)
1938 short side,piece,f,t;
1941 hashbd contains a 32 bit "signature" of the board position. hashkey
1942 contains a 16 bit code used to address the hash table. When a move is
1943 made, XOR'ing the hashcode of moved piece on the from and to squares
1944 with the hashbd and hashkey values keeps things current.
1948 if (f >= 0)
1950 hashbd ^= hashcode[side][piece][f].bd;
1951 hashkey ^= hashcode[side][piece][f].key;
1953 if (t >= 0)
1955 hashbd ^= hashcode[side][piece][t].bd;
1956 hashkey ^= hashcode[side][piece][t].key;
1961 void UpdatePieceList(side,sq,iop)
1962 short side,sq,iop;
1965 Update the PieceList and Pindex arrays when a piece is captured or
1966 when a capture is unmade.
1970 register short i;
1971 if (iop == 1)
1973 PieceCnt[side]--;
1974 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1976 PieceList[side][i] = PieceList[side][i+1];
1977 Pindex[PieceList[side][i]] = i;
1980 else
1982 PieceCnt[side]++;
1983 PieceList[side][PieceCnt[side]] = sq;
1984 Pindex[sq] = PieceCnt[side];
1989 void InitializeStats()
1992 Scan thru the board seeing what's on each square. If a piece is found,
1993 update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
1994 determine the material for each side and set the hashkey and hashbd
1995 variables to represent the current board position. Array
1996 PieceList[side][indx] contains the location of all the pieces of
1997 either side. Array Pindex[sq] contains the indx into PieceList for a
1998 given square.
2002 register short i,sq;
2003 epsquare = -1;
2004 for (i = 0; i < 8; i++)
2005 PawnCnt[white][i] = PawnCnt[black][i] = 0;
2006 mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0;
2007 PieceCnt[white] = PieceCnt[black] = 0;
2008 hashbd = hashkey = 0;
2009 for (sq = 0; sq < 64; sq++)
2010 if (color[sq] != neutral)
2012 mtl[color[sq]] += value[board[sq]];
2013 if (board[sq] == pawn)
2015 pmtl[color[sq]] += valueP;
2016 ++PawnCnt[color[sq]][column[sq]];
2018 if (board[sq] == king) Pindex[sq] = 0;
2019 else Pindex[sq] = ++PieceCnt[color[sq]];
2020 PieceList[color[sq]][Pindex[sq]] = sq;
2021 hashbd ^= hashcode[color[sq]][board[sq]][sq].bd;
2022 hashkey ^= hashcode[color[sq]][board[sq]][sq].key;
2027 void pick(p1,p2)
2028 short p1,p2;
2031 Find the best move in the tree between indexes p1 and p2. Swap the
2032 best move into the p1 element.
2036 register short p,s,p0,s0;
2037 struct leaf temp;
2039 s0 = Tree[p1].score; p0 = p1;
2040 for (p = p1+1; p <= p2; p++)
2041 if ((s = Tree[p].score) > s0)
2043 s0 = s; p0 = p;
2045 if (p0 != p1)
2047 temp = Tree[p1]; Tree[p1] = Tree[p0]; Tree[p0] = temp;
2052 void repetition(cnt)
2053 short *cnt;
2056 Check for draw by threefold repetition.
2060 register short i,c,f,t;
2061 short b[64];
2062 unsigned short m;
2063 *cnt = c = 0;
2064 if (GameCnt > Game50+3)
2066 for (i = 0; i < 64; b[i++] = 0);
2067 for (i = GameCnt; i > Game50; i--)
2069 m = GameList[i].gmove; f = m>>8; t = m & 0xFF;
2070 if (++b[f] == 0) c--; else c++;
2071 if (--b[t] == 0) c--; else c++;
2072 if (c == 0) (*cnt)++;
2078 int SqAtakd(sq,side)
2079 short sq,side;
2082 See if any piece with color 'side' ataks sq. First check for pawns
2083 or king, then try other pieces. Array Dcode is used to check for
2084 knight attacks or R,B,Q co-linearity.
2088 register short m,d,m0,m1,i,loc,piece,*PL;
2090 m1 = map[sq];
2091 if (side == white) m = m1-0x0F; else m = m1+0x0F;
2092 if (!(m & 0x88))
2093 if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
2094 if (side == white) m = m1-0x11; else m = m1+0x11;
2095 if (!(m & 0x88))
2096 if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
2097 if (distance(sq,PieceList[side][0]) == 1) return(true);
2099 PL = PieceList[side];
2100 for (i = 1; i <= PieceCnt[side]; i++)
2102 loc = PL[i]; piece = board[loc];
2103 if (piece == pawn) continue;
2104 m0 = map[loc]; d = Dcode[abs(m1-m0)];
2105 if (d == 0 || (Pdir[d] & pbit[piece]) == 0) continue;
2106 if (piece == knight) return(true);
2107 else
2109 if (m1 < m0) d = -d;
2110 for (m = m0+d; m != m1; m += d)
2111 if (color[unmap[m]] != neutral) break;
2112 if (m == m1) return(true);
2115 return(false);
2119 void ataks(side,a)
2120 short side,*a;
2123 Fill array atak[][] with info about ataks to a square. Bits 8-15
2124 are set if the piece (king..pawn) ataks the square. Bits 0-7
2125 contain a count of total ataks to the square.
2129 register short u,m,d,c,m0;
2130 short j,j1,j2,piece,i,sq,*PL;
2132 for (u = 0; u < 64; a[u++] = 0);
2133 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
2134 PL = PieceList[side];
2135 for (i = 0; i <= PieceCnt[side]; i++)
2137 sq = PL[i];
2138 m0 = map[sq];
2139 piece = board[sq];
2140 c = control[piece]; j1 = Dstart[piece]; j2 = Dstop[piece];
2141 if (sweep[piece])
2142 for (j = j1; j <= j2; j++)
2144 d = Dir[j]; m = m0+d;
2145 while (!(m & 0x88))
2147 u = unmap[m];
2148 a[u] = (a[u]+1) | c;
2149 if (color[u] == neutral) m += d;
2150 else break;
2153 else
2154 for (j = j1; j <= j2; j++)
2155 if (!((m = m0+Dir[j]) & 0x88))
2157 u = unmap[m];
2158 a[u] = (a[u]+1) | c;
2165 void ElapsedTime(iop)
2168 Determine the time that has passed since the search was started. If
2169 the elapsed time exceeds the target (ResponseTime+ExtraTime) then set
2170 timeout to true which will terminate the search.
2173 short iop;
2175 /*et = time((long *)0) - time0;*/
2176 et = *(rb->current_tick) / HZ - time0;
2177 if (et < 0) et = 0;
2178 ETnodes += 50;
2179 if (et > et0 || iop == 1)
2181 if (et > ResponseTime+ExtraTime && Sdepth > 1) timeout = true;
2182 et0 = et;
2183 if (iop == 1)
2185 /*time0 = time((long *)0);*/
2186 time0 = *(rb->current_tick) / HZ ;
2187 et0 = 0;
2189 /*(void) times(&tmbuf2);
2190 cputimer = 100*(tmbuf2.tms_utime - tmbuf1.tms_utime) / HZ;
2191 if (cputimer > 0) evrate = (100*NodeCnt)/(cputimer+100*ft);
2192 else evrate = 0;*/
2193 ETnodes = NodeCnt + 50;
2194 /*UpdateClocks();*/
2200 void SetTimeControl( void )
2202 if (TCflag)
2204 TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
2205 TimeControl.clock[white] = TimeControl.clock[black] = 60*(long)TCminutes;
2207 else
2209 TimeControl.moves[white] = TimeControl.moves[black] = 0;
2210 TimeControl.clock[white] = TimeControl.clock[black] = 0;
2211 Level = 60*(long)TCminutes;
2213 et = 0;
2214 ElapsedTime(1);
2219 /* ............ INTERFACE ROUTINES ........................... */
2221 /*static void VoidFunction ( void ) {
2222 while (!(quit))
2224 if (bothsides && !mate) SelectMove(opponent,1); else InputCommand();
2225 if (!(quit || mate || force)) SelectMove(computer,1);
2227 ExitChess();
2230 int VerifyMove(short player, char s[],short iop,unsigned short *mv, char *move_buffer)
2233 Compare the string 's' to the list of legal moves available for the
2234 player. If a match is found, make the move on the board. This was originally
2235 fixed for the opponent, but allowing the player to be specified will make
2236 possible to use GnuChess as a human vs human game verifier. It also allows
2237 the PGN functions to verify checkmates.
2241 static short pnt,tempb,tempc,tempsf,tempst,cnt;
2242 static struct leaf xnode;
2243 struct leaf *node;
2244 short opponent_player = (player == white)?black:white;
2246 *mv = 0;
2247 if (iop == 2)
2249 UnmakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst);
2250 return(false);
2252 cnt = 0;
2253 MoveList(player,2);
2254 pnt = TrPnt[2];
2255 while (pnt < TrPnt[3])
2257 node = &Tree[pnt++];
2258 algbr(node->f,node->t,node->flags & cstlmask);
2259 if (rb->strcmp(s,mvstr1) == 0 || rb->strcmp(s,mvstr2) == 0 ||
2260 rb->strcmp(s,mvstr3) == 0)
2262 cnt++; xnode = *node;
2265 if (cnt == 1)
2267 MakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst);
2268 if (SqAtakd(PieceList[player][0],opponent_player))
2270 UnmakeMove(player,&xnode,&tempb,&tempc,&tempsf,&tempst);
2271 /*ShowMessage("Illegal Move!!");*/
2272 return(false);
2274 else
2276 if (iop == 1) return(true);
2277 /*if (xnode.flags & epmask) UpdateDisplay(0,0,1,0);
2278 else UpdateDisplay(xnode.f,xnode.t,0,xnode.flags & cstlmask);*/
2279 if (xnode.flags & cstlmask) Game50 = GameCnt;
2280 else if (board[xnode.t] == pawn || (xnode.flags & capture))
2281 Game50 = GameCnt;
2282 GameList[GameCnt].depth = GameList[GameCnt].score = 0;
2283 GameList[GameCnt].nodes = 0;
2284 ElapsedTime(1);
2285 GameList[GameCnt].time = (short)et;
2286 TimeControl.clock[player] -= et;
2287 --TimeControl.moves[player];
2288 *mv = (xnode.f << 8) + xnode.t;
2289 algbr(xnode.f,xnode.t,false);
2291 short index;
2292 for (index=0;index<5;index++){
2293 move_buffer[index] = mvstr1[index];
2295 if (SqAtakd(PieceList[opponent_player][0],player)){
2296 move_buffer[4] = '+';
2297 move_buffer[5] = '\0';
2300 return(true);
2303 /*if (cnt > 1) ShowMessage("Ambiguous Move!");*/
2304 return(false);
2308 /* ---- Reset the board and other variables to start a new game. ---- */
2309 void NewGame() {
2310 short l,r,c,p;
2312 mate = quit = reverse = bothsides = post = false;
2313 hashflag = force = PawnStorm = false;
2314 easy = beep = rcptr = true;
2315 lpost = NodeCnt = epsquare = et0 = 0;
2316 dither = 0;
2317 Awindow = 90;
2318 Bwindow = 90;
2319 xwndw = 90;
2320 MaxSearchDepth = 29;
2321 contempt = 0;
2322 GameCnt = -1; Game50 = 0;
2323 Zwmtl = Zbmtl = 0;
2324 Developed[white] = Developed[black] = false;
2325 castld[white] = castld[black] = false;
2326 kingmoved[white] = kingmoved[black] = 0;
2327 PawnThreat[0] = CptrFlag[0] = Threat[0] = false;
2328 Pscore[0] = 12000; Tscore[0] = 12000;
2329 opponent = white; computer = black;
2330 for (r = 0; r < 8; r++)
2331 for (c = 0; c < 8; c++)
2333 l = 8*r+c; locn[r][c] = l;
2334 row[l] = r; column[l] = c;
2335 board[l] = Stboard[l]; color[l] = Stcolor[l];
2337 for (c = white; c <= black; c++)
2338 for (p = pawn; p <= king; p++)
2339 for (l = 0; l < 64; l++)
2341 hashcode[c][p][l].key = (unsigned short)rb->rand();
2342 hashcode[c][p][l].bd = ((unsigned long)rb->rand() << 16) +
2343 (unsigned long)rb->rand();
2345 if (TCflag) SetTimeControl();
2346 /*else if (Level == 0) SelectLevel();*/
2347 /*UpdateDisplay(0,0,1,0);*/
2348 InitializeStats();
2349 /*time0 = time((long *)0);*/
2350 time0 = *(rb->current_tick) / HZ ;
2351 ElapsedTime(1);
2352 withbook = true;
2355 /* ---- Initialize variables and reset board ---- */
2356 void GNUChess_Initialize ( void ) {
2357 /*ttable = (struct hashentry *)malloc(ttblsz *
2358 (unsigned long)sizeof(struct hashentry));*/
2359 /* no malloc, statically allocated */
2360 Level = 1;
2361 OperatorTime = 0;
2362 TCmoves = 60;
2363 TCminutes = 5;
2364 TCflag = true;
2365 NewGame();
2366 MaxSearchDepth = 29 ;
2369 void algbr(f,t,flag)
2370 short f,t,flag;
2372 mvstr1[0] = cxx[column[f]]; mvstr1[1] = rxx[row[f]];
2373 mvstr1[2] = cxx[column[t]]; mvstr1[3] = rxx[row[t]];
2374 mvstr2[0] = qxx[board[f]];
2375 mvstr2[1] = mvstr1[2]; mvstr2[2] = mvstr1[3];
2376 mvstr1[4] = '\0'; mvstr2[3] = '\0';
2377 if (flag) {
2378 if (t > f) {
2379 rb->strcpy(mvstr2,"o-o");
2380 } else {
2381 rb->memcpy(mvstr2,"o-o-o", 5);
2385 if (board[f] == pawn) mvstr3[0] = mvstr1[0];
2386 else mvstr3[0] = qxx[board[f]];
2387 if (color[t] != neutral)
2389 mvstr3[1] = ':';
2390 mvstr3[2] = mvstr1[2];
2391 mvstr3[3] = mvstr1[3];
2392 mvstr3[4] = '\0';
2394 else if (board[f] == pawn)
2396 mvstr3[1] = mvstr1[3];
2397 mvstr3[2] = '\0';
2399 else
2401 mvstr3[1] = mvstr1[0];
2402 mvstr3[2] = mvstr1[1];
2403 mvstr3[3] = mvstr1[2];
2404 mvstr3[4] = mvstr1[3];
2405 mvstr3[5] = '\0';