summaryrefslogtreecommitdiff
path: root/apps/plugins/chessbox/gnuchess.c
diff options
context:
space:
mode:
authorHristo Kovachev <bger@rockbox.org>2006-02-22 14:24:54 +0000
committerHristo Kovachev <bger@rockbox.org>2006-02-22 14:24:54 +0000
commit91522721f4a6f4449e14e1b3ccb9f6f2add5d814 (patch)
treedbb2ee4d9e4ee752f8eaf6081204be2f44f20fa8 /apps/plugins/chessbox/gnuchess.c
parentb12bcecb297ab8408b25bc9e539d78fa92e6589e (diff)
downloadrockbox-91522721f4a6f4449e14e1b3ccb9f6f2add5d814.tar.gz
rockbox-91522721f4a6f4449e14e1b3ccb9f6f2add5d814.zip
New chessbox plugin by Miguel A. ArГ©valo, based on GNU Chess v2
Not built yet because of a missing dependancy with the pieces' bitmaps. Someone with Makefile knowledge, please, look at it! git-svn-id: svn://svn.rockbox.org/rockbox/trunk@8778 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/plugins/chessbox/gnuchess.c')
-rw-r--r--apps/plugins/chessbox/gnuchess.c2405
1 files changed, 2405 insertions, 0 deletions
diff --git a/apps/plugins/chessbox/gnuchess.c b/apps/plugins/chessbox/gnuchess.c
new file mode 100644
index 0000000000..ed4a7f2a0f
--- /dev/null
+++ b/apps/plugins/chessbox/gnuchess.c
@@ -0,0 +1,2405 @@
1/*
2 C source for CHESS.
3
4 Revision: 5-23-88
5
6 Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
7 Copyright (c) 1988 John Stanback
8
9 This file is part of CHESS.
10
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.
17
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.
25*/
26
27#include "plugin.h"
28
29#include "gnuchess.h"
30
31#include <ctype.h>
32
33#define ttblsz 4096
34
35/*#define ttblsz 16384*/
36#define huge
37
38#define ctlP 0x4000
39#define ctlN 0x2800
40#define ctlB 0x1800
41#define ctlR 0x0400
42#define ctlQ 0x0200
43#define ctlK 0x0100
44#define ctlBQ 0x1200
45#define ctlRQ 0x0600
46#define ctlNN 0x2000
47#define pxx " PNBRQK"
48#define qxx " pnbrqk"
49#define rxx "12345678"
50#define cxx "abcdefgh"
51#define check 0x0001
52#define capture 0x0002
53#define draw 0x0004
54#define promote 0x0008
55#define cstlmask 0x0010
56#define epmask 0x0020
57#define exact 0x0040
58#define pwnthrt 0x0080
59#define truescore 0x0001
60#define lowerbound 0x0002
61#define upperbound 0x0004
62#define maxdepth 30
63#define true 1
64#define false 0
65#define absv(x) ((x) < 0 ? -(x) : (x))
66#define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b]))
67
68/* ---- RockBox datatypes and variables */
69static struct plugin_api* rb;
70
71/* ---- Chess datatypes and variables ---- */
72struct leaf
73 {
74 short f,t,score,reply;
75 unsigned short flags;
76 };
77struct GameRec
78 {
79 unsigned short gmove;
80 short score,depth,time,piece,color;
81 long nodes;
82 };
83struct TimeControlRec
84 {
85 short moves[2];
86 long clock[2];
87 };
88struct BookEntry
89 {
90 struct BookEntry *next;
91 unsigned short *mv;
92 };
93struct hashval
94 {
95 unsigned long bd;
96 unsigned short key;
97 };
98struct hashentry
99 {
100 unsigned long hashbd;
101 unsigned short mv,flags;
102 short score,depth;
103 };
104
105char mvstr1[5],mvstr2[5],mvstr3[6];
106struct leaf Tree[1500],*root;
107short TrPnt[maxdepth],board[64],color[64];
108short row[64],column[64],locn[8][8],Pindex[64],svalue[64];
109short PieceList[2][16],PieceCnt[2],atak[2][64],PawnCnt[2][8];
110short castld[2],kingmoved[2],mtl[2],pmtl[2],emtl[2],hung[2];
111short c1,c2,*atk1,*atk2,*PC1,*PC2,EnemyKing;
112short mate,post,opponent,computer,Sdepth,Awindow,Bwindow,dither;
113long ResponseTime,ExtraTime,Level,et,et0,time0,cputimer,ft;
114long NodeCnt,evrate,ETnodes,EvalNodes,HashCnt;
115short quit,reverse,bothsides,hashflag,InChk,player,force,easy,beep;
116short wking,bking,FROMsquare,TOsquare,timeout,Zscore,zwndw,xwndw,slk;
117short INCscore;
118short HasPawn[2],HasKnight[2],HasBishop[2],HasRook[2],HasQueen[2];
119short ChkFlag[maxdepth],CptrFlag[maxdepth],PawnThreat[maxdepth];
120short Pscore[maxdepth],Tscore[maxdepth],Threat[maxdepth];
121struct GameRec GameList[240];
122short GameCnt,Game50,epsquare,lpost,rcptr,contempt;
123short MaxSearchDepth,Xscore;
124struct BookEntry *Book;
125struct TimeControlRec TimeControl;
126short TCflag,TCmoves,TCminutes,OperatorTime;
127short otherside[3]={1,0,2};
128short rank7[3]={6,1,0};
129short map[64]=
130 {0,1,2,3,4,5,6,7,
131 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
132 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
133 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
134 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
135 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
136 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
137 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77};
138short unmap[120]=
139 {0,1,2,3,4,5,6,7,-1,-1,-1,-1,-1,-1,-1,-1,
140 8,9,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,
141 16,17,18,19,20,21,22,23,-1,-1,-1,-1,-1,-1,-1,-1,
142 24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
143 32,33,34,35,36,37,38,39,-1,-1,-1,-1,-1,-1,-1,-1,
144 40,41,42,43,44,45,46,47,-1,-1,-1,-1,-1,-1,-1,-1,
145 48,49,50,51,52,53,54,55,-1,-1,-1,-1,-1,-1,-1,-1,
146 56,57,58,59,60,61,62,63};
147short Dcode[120]=
148 {0,1,1,1,1,1,1,1,0,0,0,0,0,0,0x0E,0x0F,
149 0x10,0x11,0x12,0,0,0,0,0,0,0,0,0,0,0,0x0F,0x1F,
150 0x10,0x21,0x11,0,0,0,0,0,0,0,0,0,0,0x0F,0,0,
151 0x10,0,0,0x11,0,0,0,0,0,0,0,0,0x0F,0,0,0,
152 0x10,0,0,0,0x11,0,0,0,0,0,0,0x0F,0,0,0,0,
153 0x10,0,0,0,0,0x11,0,0,0,0,0x0F,0,0,0,0,0,
154 0x10,0,0,0,0,0,0x11,0,0,0x0F,0,0,0,0,0,0,
155 0x10,0,0,0,0,0,0,0x11};
156short Stboard[64]=
157 {rook,knight,bishop,queen,king,bishop,knight,rook,
158 pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
159 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,
160 pawn,pawn,pawn,pawn,pawn,pawn,pawn,pawn,
161 rook,knight,bishop,queen,king,bishop,knight,rook};
162short Stcolor[64]=
163 {white,white,white,white,white,white,white,white,
164 white,white,white,white,white,white,white,white,
165 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,
166 black,black,black,black,black,black,black,black,
167 black,black,black,black,black,black,black,black};
168short sweep[7]= {false,false,false,true,true,true,false};
169short Dpwn[3]={4,6,0};
170short Dstart[7]={6,4,8,4,0,0,0};
171short Dstop[7]={7,5,15,7,3,7,7};
172short Dir[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11,
173 0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21};
174short Pdir[34]={0,0x38,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x35,
175 0x38,0x35,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x02,
176 0,0x02};
177short pbit[7]={0,0x01,0x02,0x04,0x08,0x10,0x20};
178unsigned short killr0[maxdepth],killr1[maxdepth],killr2[maxdepth];
179unsigned short killr3[maxdepth],PrVar[maxdepth];
180unsigned short PV,hint,Swag0,Swag1,Swag2,Swag3,Swag4;
181unsigned short hashkey;
182unsigned long hashbd;
183struct hashval hashcode[2][7][64];
184struct hashentry huge *ttable,*ptbl;
185unsigned char history[8192];
186
187short Mwpawn[64],Mbpawn[64],Mknight[2][64],Mbishop[2][64];
188short Mking[2][64],Kfield[2][64];
189short value[7]={0,valueP,valueN,valueB,valueR,valueQ,valueK};
190short control[7]={0,ctlP,ctlN,ctlB,ctlR,ctlQ,ctlK};
191short PassedPawn0[8]={0,60,80,120,200,360,600,800};
192short PassedPawn1[8]={0,30,40,60,100,180,300,800};
193short PassedPawn2[8]={0,15,25,35,50,90,140,800};
194short PassedPawn3[8]={0,5,10,15,20,30,140,800};
195short ISOLANI[8] = {-12,-16,-20,-24,-24,-20,-16,-12};
196short BACKWARD[8] = {-6,-10,-15,-21,-28,-28,-28,-28};
197short BMBLTY[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16};
198short RMBLTY[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14};
199short Kthreat[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80,
200 -80,-80,-80,-80};
201short KNIGHTPOST,KNIGHTSTRONG,BISHOPSTRONG,KATAK,KBNKsq;
202short PEDRNK2B,PWEAKH,PADVNCM,PADVNCI,PAWNSHIELD,PDOUBLED,PBLOK;
203short RHOPN,RHOPNX,KHOPN,KHOPNX,KSFTY;
204short ATAKD,HUNGP,HUNGX,KCASTLD,KMOVD,XRAY,PINVAL;
205short stage,stage2,Zwmtl,Zbmtl,Developed[2],PawnStorm;
206short PawnBonus,BishopBonus,RookBonus;
207short KingOpening[64]=
208 { 0, 0, -4,-10,-10, -4, 0, 0,
209 -4, -4, -8,-12,-12, -8, -4, -4,
210 -12,-16,-20,-20,-20,-20,-16,-12,
211 -16,-20,-24,-24,-24,-24,-20,-16,
212 -16,-20,-24,-24,-24,-24,-20,-16,
213 -12,-16,-20,-20,-20,-20,-16,-12,
214 -4, -4, -8,-12,-12, -8, -4, -4,
215 0, 0, -4,-10,-10, -4, 0, 0};
216short KingEnding[64]=
217 { 0, 4, 8,12,12, 8, 4, 0,
218 4,16,20,24,24,20,16, 4,
219 8,20,28,32,32,28,20, 8,
220 12,24,32,36,36,32,24,12,
221 12,24,32,36,36,32,24,12,
222 8,20,28,32,32,28,20, 8,
223 4,16,20,24,24,20,16, 4,
224 0, 4, 8,12,12, 8, 4, 0};
225short KBNK[64]=
226 {99,90,80,70,60,50,40,40,
227 90,80,60,50,40,30,20,40,
228 80,60,40,30,20,10,30,50,
229 70,50,30,10, 0,20,40,60,
230 60,40,20, 0,10,30,50,70,
231 50,30,10,20,30,40,60,80,
232 40,20,30,40,50,60,80,90,
233 40,40,50,60,70,80,90,99};
234short pknight[64]=
235 { 0, 4, 8,10,10, 8, 4, 0,
236 4, 8,16,20,20,16, 8, 4,
237 8,16,24,28,28,24,16, 8,
238 10,20,28,32,32,28,20,10,
239 10,20,28,32,32,28,20,10,
240 8,16,24,28,28,24,16, 8,
241 4, 8,16,20,20,16, 8, 4,
242 0, 4, 8,10,10, 8, 4, 0};
243short pbishop[64]=
244 {14,14,14,14,14,14,14,14,
245 14,22,18,18,18,18,22,14,
246 14,18,22,22,22,22,18,14,
247 14,18,22,22,22,22,18,14,
248 14,18,22,22,22,22,18,14,
249 14,18,22,22,22,22,18,14,
250 14,22,18,18,18,18,22,14,
251 14,14,14,14,14,14,14,14};
252short PawnAdvance[64]=
253 { 0, 0, 0, 0, 0, 0, 0, 0,
254 4, 4, 4, 0, 0, 4, 4, 4,
255 6, 8, 2,10,10, 2, 8, 6,
256 6, 8,12,16,16,12, 8, 6,
257 8,12,16,24,24,16,12, 8,
258 12,16,24,32,32,24,16,12,
259 12,16,24,32,32,24,16,12,
260 0, 0, 0, 0, 0, 0, 0, 0};
261
262/* ............ prototypes ............ */
263void ScorePosition( short side, short *score );
264void ScoreLoneKing( short side, short *score );
265int ScoreKPK( short side, short winner, short loser,
266 short king1, short king2, short sq );
267int ScoreKBNK( short winner, short king1, short king2 );
268int SqValue( short sq, short side );
269void KingScan( short sq, short *s );
270void BRscan( short sq, short *s, short *mob );
271int trapped( short sq, short piece );
272void ExaminePosition( void );
273void UpdateWeights( void );
274int distance( short a, short b );
275void BlendBoard( short a[64] , short b[64] , short c[64] );
276void CopyBoard( short a[64] , short b[64] );
277
278void OpeningBook ( void );
279int search ( short side, short ply, short depth,
280 short alpha, short beta,
281 unsigned short bstline[], short *rpt );
282int evaluate ( short side, short xside, short ply, short depth,
283 short alpha, short beta );
284int ProbeTTable ( short side, short depth,
285 short *alpha, short *beta, short *score);
286void PutInTTable ( short side, short score, short depth,
287 short alpha, short beta, unsigned short mv );
288void ZeroTTable ( void );
289void MoveList ( short side, short ply );
290
291void GenMoves ( short ply, short sq, short side, short xside );
292void LinkMove ( short ply, short f, short t, short xside );
293void CaptureList ( short side, short xside, short ply );
294int castle ( short side, short kf, short kt, short iop );
295void EnPassant ( short xside, short f, short t, short iop );
296void MakeMove ( short side, struct leaf *node,
297 short *tempb, short *tempc, short *tempsf, short *tempst );
298void UnmakeMove ( short side, struct leaf *node,
299 short *tempb, short *tempc, short *tempsf, short *tempst );
300void UpdateHashbd ( short side, short piece, short f, short t );
301void UpdatePieceList ( short side, short sq, short iop );
302void InitializeStats ( void );
303void pick ( short p1, short p2 );
304void repetition ( short *cnt );
305int SqAtakd ( short sq, short side );
306void ataks ( short side, short *a );
307
308void algbr ( short f, short t, short flag );
309void ElapsedTime( short iop);
310
311void NewGame(void);
312
313
314/* ............ POSITIONAL EVALUATION ROUTINES ............ */
315
316
317void ScorePosition(side,score)
318short side,*score;
319
320/*
321 Perform normal static evaluation of board position. A score is
322 generated for each piece and these are summed to get a score for each
323 side.
324*/
325
326{
327register short sq,s,i,xside;
328short pscore[3];
329
330 wking = PieceList[white][0]; bking = PieceList[black][0];
331 UpdateWeights();
332 xside = otherside[side];
333 pscore[white] = pscore[black] = 0;
334
335 /* ok, I will yield here although this function will be called much more
336 many times than needed I think */
337 rb->yield();
338
339 for (c1 = white; c1 <= black; c1++)
340 {
341 c2 = otherside[c1];
342 if (c1 == white) EnemyKing = bking; else EnemyKing = wking;
343 atk1 = atak[c1]; atk2 = atak[c2];
344 PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
345 for (i = 0; i <= PieceCnt[c1]; i++)
346 {
347 sq = PieceList[c1][i];
348 s = SqValue(sq,side);
349 pscore[c1] += s;
350 svalue[sq] = s;
351 }
352 }
353 if (hung[side] > 1) pscore[side] += HUNGX;
354 if (hung[xside] > 1) pscore[xside] += HUNGX;
355
356 *score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] + 10;
357 if (dither) *score += rb->rand() % dither;
358
359 if (*score > 0 && pmtl[side] == 0) {
360 if (emtl[side] < valueR) {
361 *score = 0;
362 } else {
363 if (*score < valueR) *score /= 2;
364 }
365 }
366 if (*score < 0 && pmtl[xside] == 0) {
367 if (emtl[xside] < valueR) {
368 *score = 0;
369 } else {
370 if (-*score < valueR) *score /= 2;
371 }
372 }
373
374 if (mtl[xside] == valueK && emtl[side] > valueB) *score += 200;
375 if (mtl[side] == valueK && emtl[xside] > valueB) *score -= 200;
376}
377
378
379void ScoreLoneKing(side,score)
380short side,*score;
381
382/*
383 Static evaluation when loser has only a king and winner has no pawns
384 or no pieces.
385*/
386
387{
388register short winner,loser,king1,king2,s,i;
389
390 UpdateWeights();
391 if (mtl[white] > mtl[black]) winner = white; else winner = black;
392 loser = otherside[winner];
393 king1 = PieceList[winner][0]; king2 = PieceList[loser][0];
394
395 s = 0;
396
397 if (pmtl[winner] > 0)
398 for (i = 1; i <= PieceCnt[winner]; i++)
399 s += ScoreKPK(side,winner,loser,king1,king2,PieceList[winner][i]);
400
401 else if (emtl[winner] == valueB+valueN)
402 s = ScoreKBNK(winner,king1,king2);
403
404 else if (emtl[winner] > valueB)
405 s = 500 + emtl[winner] - 2*KingEnding[king2] - 2*distance(king1,king2);
406
407 if (side == winner) *score = s; else *score = -s;
408}
409
410
411int ScoreKPK(side,winner,loser,king1,king2,sq)
412short side,winner,loser,king1,king2,sq;
413
414/*
415 Score King and Pawns versus King endings.
416*/
417
418{
419register short s,r;
420
421 if (PieceCnt[winner] == 1) s = 50; else s = 120;
422 if (winner == white)
423 {
424 if (side == loser) r = row[sq]-1; else r = row[sq];
425 if (row[king2] >= r && distance(sq,king2) < 8-r) s += 10*row[sq];
426 else s = 500+50*row[sq];
427 if (row[sq] < 6) sq += 16; else sq += 8;
428 }
429 else
430 {
431 if (side == loser) r = row[sq]+1; else r = row[sq];
432 if (row[king2] <= r && distance(sq,king2) < r+1) s += 10*(7-row[sq]);
433 else s = 500+50*(7-row[sq]);
434 if (row[sq] > 1) sq -= 16; else sq -= 8;
435 }
436 s += 8*(taxicab(king2,sq) - taxicab(king1,sq));
437 return(s);
438}
439
440
441int ScoreKBNK(winner,king1,king2)
442short winner,king1,king2;
443
444/*
445 Score King+Bishop+Knight versus King endings.
446 This doesn't work all that well but it's better than nothing.
447*/
448
449{
450register short s;
451 s = emtl[winner] - 300;
452 if (KBNKsq == 0) s += KBNK[king2];
453 else s += KBNK[locn[row[king2]][7-column[king2]]];
454 s -= taxicab(king1,king2);
455 s -= distance(PieceList[winner][1],king2);
456 s -= distance(PieceList[winner][2],king2);
457 return(s);
458}
459
460
461int SqValue(sq,side)
462short sq,side;
463
464/*
465 Calculate the positional value for the piece on 'sq'.
466*/
467
468{
469register short j,fyle,rank,a1,a2;
470short s,piece,in_square,r,mob,e,c;
471
472 piece = board[sq];
473 a1 = (atk1[sq] & 0x4FFF); a2 = (atk2[sq] & 0x4FFF);
474 rank = row[sq]; fyle = column[sq];
475 s = 0;
476 if (piece == pawn && c1 == white)
477 {
478 s = Mwpawn[sq];
479 if (sq == 11 || sq == 12)
480 if (color[sq+8] != neutral) s += PEDRNK2B;
481 if ((fyle == 0 || PC1[fyle-1] == 0) &&
482 (fyle == 7 || PC1[fyle+1] == 0))
483 s += ISOLANI[fyle];
484 else if (PC1[fyle] > 1) s += PDOUBLED;
485 if (a1 < ctlP && atk1[sq+8] < ctlP)
486 {
487 s += BACKWARD[a2 & 0xFF];
488 if (PC2[fyle] == 0) s += PWEAKH;
489 if (color[sq+8] != neutral) s += PBLOK;
490 }
491 if (PC2[fyle] == 0)
492 {
493 if (side == black) r = rank-1; else r = rank;
494 in_square = (row[bking] >= r && distance(sq,bking) < 8-r);
495 if (a2 == 0 || side == white) e = 0; else e = 1;
496 for (j = sq+8; j < 64; j += 8)
497 if (atk2[j] >= ctlP) { e = 2; break; }
498 else if (atk2[j] > 0 || color[j] != neutral) e = 1;
499 if (e == 2) s += (stage*PassedPawn3[rank]) / 10;
500 else if (in_square || e == 1) s += (stage*PassedPawn2[rank]) / 10;
501 else if (emtl[black] > 0) s += (stage*PassedPawn1[rank]) / 10;
502 else s += PassedPawn0[rank];
503 }
504 }
505 else if (piece == pawn && c1 == black)
506 {
507 s = Mbpawn[sq];
508 if (sq == 51 || sq == 52)
509 if (color[sq-8] != neutral) s += PEDRNK2B;
510 if ((fyle == 0 || PC1[fyle-1] == 0) &&
511 (fyle == 7 || PC1[fyle+1] == 0))
512 s += ISOLANI[fyle];
513 else if (PC1[fyle] > 1) s += PDOUBLED;
514 if (a1 < ctlP && atk1[sq-8] < ctlP)
515 {
516 s += BACKWARD[a2 & 0xFF];
517 if (PC2[fyle] == 0) s += PWEAKH;
518 if (color[sq-8] != neutral) s += PBLOK;
519 }
520 if (PC2[fyle] == 0)
521 {
522 if (side == white) r = rank+1; else r = rank;
523 in_square = (row[wking] <= r && distance(sq,wking) < r+1);
524 if (a2 == 0 || side == black) e = 0; else e = 1;
525 for (j = sq-8; j >= 0; j -= 8)
526 if (atk2[j] >= ctlP) { e = 2; break; }
527 else if (atk2[j] > 0 || color[j] != neutral) e = 1;
528 if (e == 2) s += (stage*PassedPawn3[7-rank]) / 10;
529 else if (in_square || e == 1) s += (stage*PassedPawn2[7-rank]) / 10;
530 else if (emtl[white] > 0) s += (stage*PassedPawn1[7-rank]) / 10;
531 else s += PassedPawn0[7-rank];
532 }
533 }
534 else if (piece == knight)
535 {
536 s = Mknight[c1][sq];
537 }
538 else if (piece == bishop)
539 {
540 s = Mbishop[c1][sq];
541 BRscan(sq,&s,&mob);
542 s += BMBLTY[mob];
543 }
544 else if (piece == rook)
545 {
546 s += RookBonus;
547 BRscan(sq,&s,&mob);
548 s += RMBLTY[mob];
549 if (PC1[fyle] == 0) s += RHOPN;
550 if (PC2[fyle] == 0) s += RHOPNX;
551 if (rank == rank7[c1] && pmtl[c2] > 100) s += 10;
552 if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
553 }
554 else if (piece == queen)
555 {
556 if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
557 if (distance(sq,EnemyKing) < 3) s += 12;
558 }
559 else if (piece == king)
560 {
561 s = Mking[c1][sq];
562 if (KSFTY > 0)
563 if (Developed[c2] || stage > 0) KingScan(sq,&s);
564 if (castld[c1]) s += KCASTLD;
565 else if (kingmoved[c1]) s += KMOVD;
566
567 if (PC1[fyle] == 0) s += KHOPN;
568 if (PC2[fyle] == 0) s += KHOPNX;
569 if (fyle == 1 || fyle == 2 || fyle == 3 || fyle == 7)
570 {
571 if (PC1[fyle-1] == 0) s += KHOPN;
572 if (PC2[fyle-1] == 0) s += KHOPNX;
573 }
574 if (fyle == 4 || fyle == 5 || fyle == 6 || fyle == 0)
575 {
576 if (PC1[fyle+1] == 0) s += KHOPN;
577 if (PC2[fyle+1] == 0) s += KHOPNX;
578 }
579 if (fyle == 2)
580 {
581 if (PC1[0] == 0) s += KHOPN;
582 if (PC2[0] == 0) s += KHOPNX;
583 }
584 if (fyle == 5)
585 {
586 if (PC1[7] == 0) s += KHOPN;
587 if (PC2[7] == 0) s += KHOPNX;
588 }
589 }
590
591 if (a2 > 0)
592 {
593 c = (control[piece] & 0x4FFF);
594 if (a1 == 0 || a2 > c+1)
595 {
596 s += HUNGP;
597 ++hung[c1];
598 if (piece != king && trapped(sq,piece)) ++hung[c1];
599 }
600 else if (piece != pawn || a2 > a1)
601 if (a2 >= c || a1 < ctlP) s += ATAKD;
602 }
603 return(s);
604}
605
606
607void KingScan(sq,s)
608short sq,*s;
609
610/*
611 Assign penalties if king can be threatened by checks, if squares
612 near the king are controlled by the enemy (especially the queen),
613 or if there are no pawns near the king.
614*/
615
616#define ScoreThreat\
617 if (color[u] != c2) {\
618 if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) {\
619 ++cnt;\
620 } else {\
621 *s -= 3; \
622 }\
623 }
624
625{
626register short m,u,d,i,m0,cnt,ok;
627
628 cnt = 0;
629 m0 = map[sq];
630 if (HasBishop[c2] || HasQueen[c2])
631 for (i = Dstart[bishop]; i <= Dstop[bishop]; i++)
632 {
633 d = Dir[i]; m = m0+d;
634 while (!(m & 0x88))
635 {
636 u = unmap[m];
637 if (atk2[u] & ctlBQ) ScoreThreat
638 if (color[u] != neutral) break;
639 m += d;
640 }
641 }
642 if (HasRook[c2] || HasQueen[c2])
643 for (i = Dstart[rook]; i <= Dstop[rook]; i++)
644 {
645 d = Dir[i]; m = m0+d;
646 while (!(m & 0x88))
647 {
648 u = unmap[m];
649 if (atk2[u] & ctlRQ) ScoreThreat
650 if (color[u] != neutral) break;
651 m += d;
652 }
653 }
654 if (HasKnight[c2])
655 for (i = Dstart[knight]; i <= Dstop[knight]; i++)
656 if (!((m = m0+Dir[i]) & 0x88))
657 {
658 u = unmap[m];
659 if (atk2[u] & ctlNN) ScoreThreat
660 }
661 *s += (KSFTY*Kthreat[cnt]) / 16;
662
663 cnt = 0; ok = false;
664 m0 = map[sq];
665 for (i = Dstart[king]; i <= Dstop[king]; i++)
666 if (!((m = m0+Dir[i]) & 0x88))
667 {
668 u = unmap[m];
669 if (board[u] == pawn) ok = true;
670 if (atk2[u] > atk1[u])
671 {
672 ++cnt;
673 if (atk2[u] & ctlQ)
674 if (atk2[u] > ctlQ+1 && atk1[u] < ctlQ) *s -= 4*KSFTY;
675 }
676 }
677 if (!ok) *s -= KSFTY;
678 if (cnt > 1) *s -= KSFTY;
679}
680
681
682void BRscan(sq,s,mob)
683short sq,*s,*mob;
684
685/*
686 Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
687 hung[] array if a pin is found.
688*/
689
690{
691register short m,u,d,m0,j,piece,pin;
692short *Kf;
693
694 Kf = Kfield[c1];
695 *mob = 0;
696 m0 = map[sq]; piece = board[sq];
697 for (j = Dstart[piece]; j <= Dstop[piece]; j++)
698 {
699 pin = -1;
700 d = Dir[j]; m = m0+d;
701 while (!(m & 0x88))
702 {
703 u = unmap[m]; *s += Kf[u];
704 if (color[u] == neutral)
705 {
706 (*mob)++;
707 m += d;
708 }
709 else if (pin < 0)
710 {
711 if (board[u] == pawn || board[u] == king) break;
712 pin = u;
713 m += d;
714 }
715 else if (color[u] == c2 && (board[u] > piece || atk2[u] == 0))
716 {
717 if (color[pin] == c2)
718 {
719 *s += PINVAL;
720 if (atk2[pin] == 0 ||
721 atk1[pin] > control[board[pin]]+1)
722 ++hung[c2];
723 }
724 else *s += XRAY;
725 break;
726 }
727 else break;
728 }
729 }
730}
731
732
733int trapped(sq,piece)
734short sq,piece;
735
736/*
737 See if the attacked piece has unattacked squares to move to.
738*/
739
740{
741register short u,m,d,i,m0;
742
743 m0 = map[sq];
744 if (sweep[piece])
745 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
746 {
747 d = Dir[i]; m = m0+d;
748 while (!(m & 0x88))
749 {
750 u = unmap[m];
751 if (color[u] == c1) break;
752 if (atk2[u] == 0 || board[u] >= piece) return(false);
753 if (color[u] == c2) break;
754 m += d;
755 }
756 }
757 else if (piece == pawn)
758 {
759 if (c1 == white) u = sq+8; else u = sq-8;
760 if (color[u] == neutral && atk1[u] >= atk2[u])
761 return(false);
762 if (!((m = m0+Dir[Dpwn[c1]]) & 0x88))
763 if (color[unmap[m]] == c2) return(false);
764 if (!((m = m0+Dir[Dpwn[c1]+1]) & 0x88))
765 if (color[unmap[m]] == c2) return(false);
766 }
767 else
768 {
769 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
770 if (!((m = m0+Dir[i]) & 0x88))
771 {
772 u = unmap[m];
773 if (color[u] != c1)
774 if (atk2[u] == 0 || board[u] >= piece) return(false);
775 }
776 }
777 return(true);
778}
779
780
781void ExaminePosition()
782
783/*
784 This is done one time before the search is started. Set up arrays
785 Mwpawn, Mbpawn, Mknight, Mbishop, Mking which are used in the
786 SqValue() function to determine the positional value of each piece.
787*/
788
789{
790register short i,sq;
791short wpadv,bpadv,wstrong,bstrong,z,side,pp,j,val,Pd,fyle,rank;
792
793 wking = PieceList[white][0]; bking = PieceList[black][0];
794 ataks(white,atak[white]); ataks(black,atak[black]);
795 Zwmtl = Zbmtl = 0;
796 UpdateWeights();
797 HasPawn[white] = HasPawn[black] = 0;
798 HasKnight[white] = HasKnight[black] = 0;
799 HasBishop[white] = HasBishop[black] = 0;
800 HasRook[white] = HasRook[black] = 0;
801 HasQueen[white] = HasQueen[black] = 0;
802 for (side = white; side <= black; side++)
803 for (i = 0; i <= PieceCnt[side]; i++)
804 switch (board[PieceList[side][i]])
805 {
806 case pawn : ++HasPawn[side]; break;
807 case knight : ++HasKnight[side]; break;
808 case bishop : ++HasBishop[side]; break;
809 case rook : ++HasRook[side]; break;
810 case queen : ++HasQueen[side]; break;
811 }
812 if (!Developed[white])
813 Developed[white] = (board[1] != knight && board[2] != bishop &&
814 board[5] != bishop && board[6] != knight);
815 if (!Developed[black])
816 Developed[black] = (board[57] != knight && board[58] != bishop &&
817 board[61] != bishop && board[62] != knight);
818 if (!PawnStorm && stage < 5)
819 PawnStorm = ((column[wking] < 3 && column[bking] > 4) ||
820 (column[wking] > 4 && column[bking] < 3));
821
822 CopyBoard(pknight,Mknight[white]);
823 CopyBoard(pknight,Mknight[black]);
824 CopyBoard(pbishop,Mbishop[white]);
825 CopyBoard(pbishop,Mbishop[black]);
826 BlendBoard(KingOpening,KingEnding,Mking[white]);
827 BlendBoard(KingOpening,KingEnding,Mking[black]);
828
829 for (sq = 0; sq < 64; sq++)
830 {
831 fyle = column[sq]; rank = row[sq];
832 wstrong = bstrong = true;
833 for (i = sq; i < 64; i += 8)
834 if (atak[black][i] >= ctlP) wstrong = false;
835 for (i = sq; i >= 0; i -= 8)
836 if (atak[white][i] >= ctlP) bstrong = false;
837 wpadv = bpadv = PADVNCM;
838 if ((fyle == 0 || PawnCnt[white][fyle-1] == 0) &&
839 (fyle == 7 || PawnCnt[white][fyle+1] == 0)) wpadv = PADVNCI;
840 if ((fyle == 0 || PawnCnt[black][fyle-1] == 0) &&
841 (fyle == 7 || PawnCnt[black][fyle+1] == 0)) bpadv = PADVNCI;
842 Mwpawn[sq] = (wpadv*PawnAdvance[sq]) / 10;
843 Mbpawn[sq] = (bpadv*PawnAdvance[63-sq]) / 10;
844 Mwpawn[sq] += PawnBonus; Mbpawn[sq] += PawnBonus;
845 if (castld[white] || kingmoved[white])
846 {
847 if ((fyle < 3 || fyle > 4) && distance(sq,wking) < 3)
848 Mwpawn[sq] += PAWNSHIELD;
849 }
850 else if (rank < 3 && (fyle < 2 || fyle > 5))
851 Mwpawn[sq] += PAWNSHIELD / 2;
852 if (castld[black] || kingmoved[black])
853 {
854 if ((fyle < 3 || fyle > 4) && distance(sq,bking) < 3)
855 Mbpawn[sq] += PAWNSHIELD;
856 }
857 else if (rank > 4 && (fyle < 2 || fyle > 5))
858 Mbpawn[sq] += PAWNSHIELD / 2;
859 if (PawnStorm)
860 {
861 if ((column[wking] < 4 && fyle > 4) ||
862 (column[wking] > 3 && fyle < 3)) Mwpawn[sq] += 3*rank - 21;
863 if ((column[bking] < 4 && fyle > 4) ||
864 (column[bking] > 3 && fyle < 3)) Mbpawn[sq] -= 3*rank;
865 }
866
867 Mknight[white][sq] += 5 - distance(sq,bking);
868 Mknight[white][sq] += 5 - distance(sq,wking);
869 Mknight[black][sq] += 5 - distance(sq,wking);
870 Mknight[black][sq] += 5 - distance(sq,bking);
871 Mbishop[white][sq] += BishopBonus;
872 Mbishop[black][sq] += BishopBonus;
873 for (i = 0; i <= PieceCnt[black]; i++)
874 if (distance(sq,PieceList[black][i]) < 3)
875 Mknight[white][sq] += KNIGHTPOST;
876 for (i = 0; i <= PieceCnt[white]; i++)
877 if (distance(sq,PieceList[white][i]) < 3)
878 Mknight[black][sq] += KNIGHTPOST;
879 if (wstrong) Mknight[white][sq] += KNIGHTSTRONG;
880 if (bstrong) Mknight[black][sq] += KNIGHTSTRONG;
881 if (wstrong) Mbishop[white][sq] += BISHOPSTRONG;
882 if (bstrong) Mbishop[black][sq] += BISHOPSTRONG;
883
884 if (HasBishop[white] == 2) Mbishop[white][sq] += 8;
885 if (HasBishop[black] == 2) Mbishop[black][sq] += 8;
886 if (HasKnight[white] == 2) Mknight[white][sq] += 5;
887 if (HasKnight[black] == 2) Mknight[black][sq] += 5;
888
889 if (board[sq] == bishop) {
890 if (rank % 2 == fyle % 2) {
891 KBNKsq = 0;
892 } else {
893 KBNKsq = 7;
894 }
895 }
896
897 Kfield[white][sq] = Kfield[black][sq] = 0;
898 if (distance(sq,wking) == 1) Kfield[black][sq] = KATAK;
899 if (distance(sq,bking) == 1) Kfield[white][sq] = KATAK;
900
901 Pd = 0;
902 for (i = 0; i < 64; i++)
903 if (board[i] == pawn)
904 {
905 if (color[i] == white)
906 {
907 pp = true;
908 if (row[i] == 6) z = i+8; else z = i+16;
909 for (j = i+8; j < 64; j += 8)
910 if (atak[black][j] > ctlP || board[j] == pawn) pp = false;
911 }
912 else
913 {
914 pp = true;
915 if (row[i] == 1) z = i-8; else z = i-16;
916 for (j = i-8; j >= 0; j -= 8)
917 if (atak[white][j] > ctlP || board[j] == pawn) pp = false;
918 }
919 if (pp) Pd += 5*taxicab(sq,z); else Pd += taxicab(sq,z);
920 }
921 if (Pd != 0)
922 {
923 val = (Pd*stage2) / 10;
924 Mking[white][sq] -= val;
925 Mking[black][sq] -= val;
926 }
927 }
928}
929
930
931void UpdateWeights()
932
933/*
934 If material balance has changed, determine the values for the
935 positional evaluation terms.
936*/
937
938{
939register short tmtl;
940
941 if (mtl[white] != Zwmtl || mtl[black] != Zbmtl)
942 {
943 Zwmtl = mtl[white]; Zbmtl = mtl[black];
944 emtl[white] = Zwmtl - pmtl[white] - valueK;
945 emtl[black] = Zbmtl - pmtl[black] - valueK;
946 tmtl = emtl[white] + emtl[black];
947 if (tmtl > 6600) stage = 0;
948 else if (tmtl < 1400) stage = 10;
949 else stage = (6600-tmtl) / 520;
950 if (tmtl > 3600) stage2 = 0;
951 else if (tmtl < 1400) stage2 = 10;
952 else stage2 = (3600-tmtl) / 220;
953
954 PEDRNK2B = -15; /* centre pawn on 2nd rank & blocked */
955 PBLOK = -4; /* blocked backward pawn */
956 PDOUBLED = -14; /* doubled pawn */
957 PWEAKH = -4; /* weak pawn on half open file */
958 PAWNSHIELD = 10-stage; /* pawn near friendly king */
959 PADVNCM = 10; /* advanced pawn multiplier */
960 PADVNCI = 7; /* muliplier for isolated pawn */
961 PawnBonus = stage;
962
963 KNIGHTPOST = (stage+2)/3; /* knight near enemy pieces */
964 KNIGHTSTRONG = (stage+6)/2; /* occupies pawn hole */
965
966 BISHOPSTRONG = (stage+6)/2; /* occupies pawn hole */
967 BishopBonus = 2*stage;
968
969 RHOPN = 10; /* rook on half open file */
970 RHOPNX = 4;
971 RookBonus = 6*stage;
972
973 XRAY = 8; /* Xray attack on piece */
974 PINVAL = 10; /* Pin */
975
976 KHOPN = (3*stage-30) / 2; /* king on half open file */
977 KHOPNX = KHOPN / 2;
978 KCASTLD = 10 - stage;
979 KMOVD = -40 / (stage+1); /* king moved before castling */
980 KATAK = (10-stage) / 2; /* B,R attacks near enemy king */
981 if (stage < 8) KSFTY = 16-2*stage; else KSFTY = 0;
982
983 ATAKD = -6; /* defender > attacker */
984 HUNGP = -8; /* each hung piece */
985 HUNGX = -12; /* extra for >1 hung piece */
986 }
987}
988
989
990int distance(a,b)
991short a,b;
992{
993register short d1,d2;
994
995 d1 = abs(column[a]-column[b]);
996 d2 = abs(row[a]-row[b]);
997 if (d1 > d2) return(d1); else return(d2);
998}
999
1000
1001void BlendBoard(a,b,c)
1002short a[64],b[64],c[64];
1003{
1004register int sq;
1005 for (sq = 0; sq < 64; sq++)
1006 c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10;
1007}
1008
1009
1010void CopyBoard(a,b)
1011short a[64],b[64];
1012{
1013register int sq;
1014 for (sq = 0; sq < 64; sq++)
1015 b[sq] = a[sq];
1016}
1017
1018/* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
1019
1020
1021int SelectMove(side,iop)
1022short side,iop;
1023
1024/*
1025 Select a move by calling function search() at progressively deeper
1026 ply until time is up or a mate or draw is reached. An alpha-beta
1027 window of -90 to +90 points is set around the score returned from the
1028 previous iteration. If Sdepth != 0 then the program has correctly
1029 predicted the opponents move and the search will start at a depth of
1030 Sdepth+1 rather than a depth of 1.
1031*/
1032
1033{
1034static short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt;
1035
1036 timeout = false;
1037 xside = otherside[side];
1038 if (iop != 2) player = side;
1039 if (TCflag)
1040 {
1041 ResponseTime = (TimeControl.clock[side]) /
1042 (TimeControl.moves[side] + 3) -
1043 OperatorTime;
1044 ResponseTime += (ResponseTime*TimeControl.moves[side])/(2*TCmoves+1);
1045 }
1046 else ResponseTime = Level;
1047 if (iop == 2) ResponseTime = 999;
1048 if (Sdepth > 0 && root->score > Zscore-zwndw) ResponseTime -= ft;
1049 else if (ResponseTime < 1) ResponseTime = 1;
1050 ExtraTime = 0;
1051 ExaminePosition();
1052 ScorePosition(side,&score);
1053 Pscore[0] = -score;
1054
1055 if (Sdepth == 0)
1056 {
1057 ZeroTTable();
1058 /*SearchStartStuff(side);*/
1059 for (i = 0; i < 8192; i++) history[i] = 0;
1060 FROMsquare = TOsquare = -1;
1061 PV = 0;
1062 if (iop != 2) hint = 0;
1063 for (i = 0; i < maxdepth; i++)
1064 PrVar[i] = killr0[i] = killr1[i] = killr2[i] = killr3[i] = 0;
1065
1066 alpha = -9000; beta = 9000;
1067 rpt = 0;
1068 TrPnt[1] = 0; root = &Tree[0];
1069 MoveList(side,1);
1070 for (i = TrPnt[1]; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
1071 /*if (Book != NULL) OpeningBook();*/
1072 if (Book != NULL) timeout = true;
1073 NodeCnt = ETnodes = EvalNodes = HashCnt = 0;
1074 Zscore = 0; zwndw = 20;
1075 }
1076
1077 while (!timeout && Sdepth < MaxSearchDepth)
1078 {
1079 Sdepth++;
1080 /*ShowDepth(' ');*/
1081 score = search(side,1,Sdepth,alpha,beta,PrVar,&rpt);
1082 for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
1083 if (score < alpha && !timeout)
1084 {
1085 /*ShowDepth('-');*/
1086 ExtraTime = 10*ResponseTime;
1087 ZeroTTable();
1088 score = search(side,1,Sdepth,-9000,beta,PrVar,&rpt);
1089 }
1090 if (score > beta && !timeout && !(root->flags & exact))
1091 {
1092 /*ShowDepth('+');*/
1093 ExtraTime = 0;
1094 ZeroTTable();
1095 score = search(side,1,Sdepth,alpha,9000,PrVar,&rpt);
1096 }
1097 score = root->score;
1098 if (!timeout)
1099 for (i = TrPnt[1]+1; i < TrPnt[2]; i++) pick(i,TrPnt[2]-1);
1100 /*ShowResults(score,PrVar,'.');*/
1101 for (i = 1; i <= Sdepth; i++) killr0[i] = PrVar[i];
1102 if (score > Zscore-zwndw && score > Tree[1].score+250) ExtraTime = 0;
1103 else if (score > Zscore-3*zwndw) ExtraTime = ResponseTime;
1104 else ExtraTime = 3*ResponseTime;
1105 if (root->flags & exact) timeout = true;
1106 if (Tree[1].score < -9000) timeout = true;
1107 if (4*et > 2*ResponseTime + ExtraTime) timeout = true;
1108 if (!timeout)
1109 {
1110 Tscore[0] = score;
1111 if (Zscore == 0) Zscore = score;
1112 else Zscore = (Zscore+score)/2;
1113 }
1114 zwndw = 20+abs(Zscore/12);
1115 beta = score + Bwindow;
1116 if (Zscore < score) alpha = Zscore - Awindow - zwndw;
1117 else alpha = score - Awindow - zwndw;
1118 }
1119
1120 score = root->score;
1121 if (rpt >= 2 || score < -12000) root->flags |= draw;
1122 if (iop == 2) return(0);
1123 if (Book == NULL) hint = PrVar[2];
1124 ElapsedTime(1);
1125
1126 if (score > -9999 && rpt <= 2)
1127 {
1128 MakeMove(side,root,&tempb,&tempc,&tempsf,&tempst);
1129 algbr(root->f,root->t,root->flags & cstlmask);
1130 }
1131 else mvstr1[0] = '\0';
1132 /*OutputMove();*/
1133 if (score == -9999 || score == 9998) mate = true;
1134 if (mate) hint = 0;
1135 if (root->flags & cstlmask) Game50 = GameCnt;
1136 else if (board[root->t] == pawn || (root->flags & capture))
1137 Game50 = GameCnt;
1138 GameList[GameCnt].score = score;
1139 GameList[GameCnt].nodes = NodeCnt;
1140 GameList[GameCnt].time = (short)et;
1141 GameList[GameCnt].depth = Sdepth;
1142 if (TCflag)
1143 {
1144 TimeControl.clock[side] -= (et + OperatorTime);
1145 if (--TimeControl.moves[side] == 0) SetTimeControl();
1146 }
1147 if ((root->flags & draw) && bothsides) quit = true;
1148 if (GameCnt > 238) quit = true;
1149 player = xside;
1150 Sdepth = 0;
1151 return(0);
1152}
1153
1154
1155void OpeningBook()
1156
1157/*
1158 Go thru each of the opening lines of play and check for a match with
1159 the current game listing. If a match occurs, generate a random number.
1160 If this number is the largest generated so far then the next move in
1161 this line becomes the current "candidate". After all lines are
1162 checked, the candidate move is put at the top of the Tree[] array and
1163 will be played by the program. Note that the program does not handle
1164 book transpositions.
1165*/
1166
1167{
1168short j,pnt;
1169unsigned short m,*mp;
1170unsigned r,r0;
1171struct BookEntry *p;
1172
1173 rb->srand((unsigned)time0);
1174 r0 = m = 0;
1175 p = Book;
1176 while (p != NULL)
1177 {
1178 mp = p->mv;
1179 for (j = 0; j <= GameCnt; j++)
1180 if (GameList[j].gmove != *(mp++)) break;
1181 if (j > GameCnt)
1182 if ((r=rb->rand()) > r0)
1183 {
1184 r0 = r; m = *mp;
1185 hint = *(++mp);
1186 }
1187 p = p->next;
1188 }
1189
1190 for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++)
1191 if ((Tree[pnt].f<<8) + Tree[pnt].t == m) Tree[pnt].score = 0;
1192 pick(TrPnt[1],TrPnt[2]-1);
1193 if (Tree[TrPnt[1]].score < 0) Book = NULL;
1194}
1195
1196
1197 /*if (post) ShowCurrentMove(pnt,node->f,node->t);\*/
1198#define UpdateSearchStatus \
1199{\
1200 if (pnt > TrPnt[1])\
1201 {\
1202 d = best-Zscore; e = best-node->score;\
1203 if (best < alpha) ExtraTime = 10*ResponseTime;\
1204 else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\
1205 else if (d > -zwndw) ExtraTime = 0;\
1206 else if (d > -3*zwndw) ExtraTime = ResponseTime;\
1207 else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\
1208 else ExtraTime = 5*ResponseTime;\
1209 }\
1210}
1211
1212int search(side,ply,depth,alpha,beta,bstline,rpt)
1213short side,ply,depth,alpha,beta,*rpt;
1214unsigned short bstline[];
1215
1216/*
1217 Perform an alpha-beta search to determine the score for the current
1218 board position. If depth <= 0 only capturing moves, pawn promotions
1219 and responses to check are generated and searched, otherwise all
1220 moves are processed. The search depth is modified for check evasions,
1221 certain re-captures and threats. Extensions may continue for up to 11
1222 ply beyond the nominal search depth.
1223*/
1224
1225#define prune (cf && score+node->score < alpha)
1226#define ReCapture (rcptr && score > alpha && score < beta &&\
1227 ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2] &&\
1228 depth == Sdepth-ply+1)
1229#define Parry (hung[side] > 1 && ply == Sdepth+1)
1230#define MateThreat (ply < Sdepth+4 && ply > 4 &&\
1231 ChkFlag[ply-2] && ChkFlag[ply-4] &&\
1232 ChkFlag[ply-2] != ChkFlag[ply-4])
1233
1234{
1235register short j,pnt;
1236short best,tempb,tempc,tempsf,tempst;
1237short xside,pbst,d,e,cf,score,rcnt;
1238unsigned short mv,nxtline[maxdepth];
1239struct leaf *node,tmp;
1240
1241 NodeCnt++;
1242 xside = otherside[side];
1243
1244 if (ply <= Sdepth+3) repetition(rpt); else *rpt = 0;
1245 if (*rpt >= 2) return(0);
1246
1247 score = evaluate(side,xside,ply,depth,alpha,beta);
1248 if (score > 9000) return(score);
1249
1250 if (depth > 0)
1251 {
1252 if (InChk || PawnThreat[ply-1] || ReCapture) ++depth;
1253 }
1254 else
1255 {
1256 if (score >= alpha &&
1257 (InChk || PawnThreat[ply-1] || Parry)) depth = 1;
1258 else if (score <= beta && MateThreat) depth = 1;
1259 }
1260
1261 PV = 0;
1262 if (depth > 0 && hashflag && ply > 1)
1263 {
1264 ProbeTTable(side,depth,&alpha,&beta,&score);
1265 bstline[ply] = PV;
1266 bstline[ply+1] = 0;
1267 if (beta == -20000) return(score);
1268 if (alpha > beta) return(alpha);
1269 }
1270
1271 if (Sdepth == 1) d = 7; else d = 11;
1272 if (ply > Sdepth+d || (depth <= 0 && score > beta)) return(score);
1273
1274 if (ply > 1) {
1275 if (depth > 0) {
1276 MoveList(side,ply);
1277 } else {
1278 CaptureList(side,xside,ply);
1279 }
1280 }
1281
1282 if (TrPnt[ply] == TrPnt[ply+1]) return(score);
1283
1284 cf = (depth < 1 && ply > Sdepth+1 && !ChkFlag[ply-2] && !slk);
1285
1286 if (depth > 0) best = -12000; else best = score;
1287 if (best > alpha) alpha = best;
1288
1289 for (pnt = pbst = TrPnt[ply];
1290 pnt < TrPnt[ply+1] && best <= beta;
1291 pnt++)
1292 {
1293 if (ply > 1) pick(pnt,TrPnt[ply+1]-1);
1294 node = &Tree[pnt];
1295 mv = (node->f << 8) + node->t;
1296 nxtline[ply+1] = 0;
1297
1298 if (prune) break;
1299 if (ply == 1) UpdateSearchStatus;
1300
1301 if (!(node->flags & exact))
1302 {
1303 MakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
1304 CptrFlag[ply] = (node->flags & capture);
1305 PawnThreat[ply] = (node->flags & pwnthrt);
1306 Tscore[ply] = node->score;
1307 node->score = -search(xside,ply+1,depth-1,-beta,-alpha,
1308 nxtline,&rcnt);
1309 if (abs(node->score) > 9000) node->flags |= exact;
1310 else if (rcnt == 1) node->score /= 2;
1311 if (rcnt >= 2 || GameCnt-Game50 > 99 ||
1312 (node->score == 9999-ply && !ChkFlag[ply]))
1313 {
1314 node->flags |= draw; node->flags |= exact;
1315 if (side == computer) node->score = contempt;
1316 else node->score = -contempt;
1317 }
1318 UnmakeMove(side,node,&tempb,&tempc,&tempsf,&tempst);
1319 }
1320 if (node->score > best && !timeout)
1321 {
1322 if (depth > 0)
1323 if (node->score > alpha && !(node->flags & exact))
1324 node->score += depth;
1325 best = node->score; pbst = pnt;
1326 if (best > alpha) alpha = best;
1327 for (j = ply+1; nxtline[j] > 0; j++) bstline[j] = nxtline[j];
1328 bstline[j] = 0;
1329 bstline[ply] = mv;
1330 if (ply == 1)
1331 {
1332 if (best == alpha)
1333 {
1334 tmp = Tree[pnt];
1335 for (j = pnt-1; j >= 0; j--) Tree[j+1] = Tree[j];
1336 Tree[0] = tmp;
1337 pbst = 0;
1338 }
1339 /*if (Sdepth > 2)
1340 if (best > beta) ShowResults(best,bstline,'+');
1341 else if (best < alpha) ShowResults(best,bstline,'-');
1342 else ShowResults(best,bstline,'&');*/
1343 }
1344 }
1345 if (NodeCnt > ETnodes) ElapsedTime(0);
1346 if (timeout) return(-Tscore[ply-1]);
1347 }
1348
1349 node = &Tree[pbst];
1350 mv = (node->f<<8) + node->t;
1351 if (hashflag && ply <= Sdepth && *rpt == 0 && best == alpha)
1352 PutInTTable(side,best,depth,alpha,beta,mv);
1353 if (depth > 0)
1354 {
1355 j = (node->f<<6) + node->t; if (side == black) j |= 0x1000;
1356 if (history[j] < 150) history[j] += 2*depth;
1357 if (node->t != (GameList[GameCnt].gmove & 0xFF)) {
1358 if (best <= beta) {
1359 killr3[ply] = mv;
1360 } else {
1361 if (mv != killr1[ply]) {
1362 killr2[ply] = killr1[ply];
1363 killr1[ply] = mv;
1364 }
1365 }
1366 }
1367 if (best > 9000) killr0[ply] = mv; else killr0[ply] = 0;
1368 }
1369 return(best);
1370}
1371
1372
1373int evaluate(side,xside,ply,depth,alpha,beta)
1374short side,xside,ply,depth,alpha,beta;
1375
1376/*
1377 Compute an estimate of the score by adding the positional score from
1378 the previous ply to the material difference. If this score falls
1379 inside a window which is 180 points wider than the alpha-beta window
1380 (or within a 50 point window during quiescence search) call
1381 ScorePosition() to determine a score, otherwise return the estimated
1382 score. If one side has only a king and the other either has no pawns
1383 or no pieces then the function ScoreLoneKing() is called.
1384*/
1385
1386{
1387register short evflag;
1388
1389 Xscore = -Pscore[ply-1] - INCscore + mtl[side] - mtl[xside];
1390 hung[white] = hung[black] = 0;
1391 slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
1392 (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));
1393
1394 if (slk) evflag = false;
1395 else evflag =
1396 (ply == 1 || ply < Sdepth ||
1397 (depth == 0 && Xscore > alpha-xwndw && Xscore < beta+xwndw) ||
1398 (depth < 0 && Xscore > alpha-25 && Xscore < beta+25));
1399
1400 if (evflag)
1401 {
1402 EvalNodes++;
1403 ataks(side,atak[side]);
1404 if (atak[side][PieceList[xside][0]] > 0) return(10001-ply);
1405 ataks(xside,atak[xside]);
1406 InChk = (atak[xside][PieceList[side][0]] > 0);
1407 ScorePosition(side,&Xscore);
1408 }
1409 else
1410 {
1411 if (SqAtakd(PieceList[xside][0],side)) return(10001-ply);
1412 InChk = SqAtakd(PieceList[side][0],xside);
1413 if (slk) ScoreLoneKing(side,&Xscore);
1414 }
1415
1416 Pscore[ply] = Xscore - mtl[side] + mtl[xside];
1417 if (InChk) ChkFlag[ply-1] = Pindex[TOsquare];
1418 else ChkFlag[ply-1] = 0;
1419 return(Xscore);
1420}
1421
1422
1423int ProbeTTable(side,depth,alpha,beta,score)
1424short side,depth,*alpha,*beta,*score;
1425
1426/*
1427 Look for the current board position in the transposition table.
1428*/
1429
1430{
1431short hindx;
1432 if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
1433 hindx = (hashkey & (ttblsz-1));
1434 ptbl = (ttable + hindx);
1435 if (ptbl->depth >= depth && ptbl->hashbd == hashbd)
1436 {
1437 HashCnt++;
1438 PV = ptbl->mv;
1439 if (ptbl->flags & truescore)
1440 {
1441 *score = ptbl->score;
1442 *beta = -20000;
1443 return(true);
1444 }
1445/*
1446 else if (ptbl->flags & upperbound)
1447 {
1448 if (ptbl->score < *beta) *beta = ptbl->score+1;
1449 }
1450*/
1451 else if (ptbl->flags & lowerbound)
1452 {
1453 if (ptbl->score > *alpha) *alpha = ptbl->score-1;
1454 }
1455 }
1456 return(false);
1457}
1458
1459
1460void PutInTTable(side,score,depth,alpha,beta,mv)
1461short side,score,depth,alpha,beta;
1462unsigned short mv;
1463
1464/*
1465 Store the current board position in the transposition table.
1466*/
1467
1468{
1469short hindx;
1470 if (side == white) hashkey |= 1; else hashkey &= 0xFFFE;
1471 hindx = (hashkey & (ttblsz-1));
1472 ptbl = (ttable + hindx);
1473 ptbl->hashbd = hashbd;
1474 ptbl->depth = depth;
1475 ptbl->score = score;
1476 ptbl->mv = mv;
1477 ptbl->flags = 0;
1478 if (score < alpha) ptbl->flags |= upperbound;
1479 else if (score > beta) ptbl->flags |= lowerbound;
1480 else ptbl->flags |= truescore;
1481}
1482
1483
1484void ZeroTTable()
1485{
1486int i;
1487 if (hashflag)
1488 for (i = 0; i < ttblsz; i++)
1489 {
1490 ptbl = (ttable + i);
1491 ptbl->depth = 0;
1492 }
1493}
1494
1495
1496void MoveList(side,ply)
1497short side,ply;
1498
1499/*
1500 Fill the array Tree[] with all available moves for side to play. Array
1501 TrPnt[ply] contains the index into Tree[] of the first move at a ply.
1502*/
1503
1504{
1505register short i,xside,f;
1506
1507 xside = otherside[side];
1508 if (PV == 0) Swag0 = killr0[ply]; else Swag0 = PV;
1509 Swag1 = killr1[ply]; Swag2 = killr2[ply];
1510 Swag3 = killr3[ply]; Swag4 = 0;
1511 if (ply > 2) Swag4 = killr1[ply-2];
1512 TrPnt[ply+1] = TrPnt[ply];
1513 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
1514 for (i = PieceCnt[side]; i >= 0; i--)
1515 GenMoves(ply,PieceList[side][i],side,xside);
1516 if (kingmoved[side] == 0 && !castld[side])
1517 {
1518 f = PieceList[side][0];
1519 if (castle(side,f,f+2,0))
1520 {
1521 LinkMove(ply,f,f+2,xside);
1522 Tree[TrPnt[ply+1]-1].flags |= cstlmask;
1523 }
1524 if (castle(side,f,f-2,0))
1525 {
1526 LinkMove(ply,f,f-2,xside);
1527 Tree[TrPnt[ply+1]-1].flags |= cstlmask;
1528 }
1529 }
1530}
1531
1532
1533void GenMoves(ply,sq,side,xside)
1534short ply,sq,side,xside;
1535
1536/*
1537 Generate moves for a piece. The from square is mapped onto a special
1538 board and offsets (taken from array Dir[]) are added to the mapped
1539 location. The newly generated square is tested to see if it falls off
1540 the board by ANDing the square with 88 HEX. Legal moves are linked
1541 into the tree.
1542*/
1543
1544{
1545register short m,u,d,i,m0,piece;
1546
1547 piece = board[sq]; m0 = map[sq];
1548 if (sweep[piece])
1549 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1550 {
1551 d = Dir[i]; m = m0+d;
1552 while (!(m & 0x88))
1553 {
1554 u = unmap[m];
1555 if (color[u] == neutral)
1556 {
1557 LinkMove(ply,sq,u,xside);
1558 m += d;
1559 }
1560 else if (color[u] == xside)
1561 {
1562 LinkMove(ply,sq,u,xside);
1563 break;
1564 }
1565 else break;
1566 }
1567 }
1568 else if (piece == pawn)
1569 {
1570 if (side == white && color[sq+8] == neutral)
1571 {
1572 LinkMove(ply,sq,sq+8,xside);
1573 if (row[sq] == 1)
1574 if (color[sq+16] == neutral)
1575 LinkMove(ply,sq,sq+16,xside);
1576 }
1577 else if (side == black && color[sq-8] == neutral)
1578 {
1579 LinkMove(ply,sq,sq-8,xside);
1580 if (row[sq] == 6)
1581 if (color[sq-16] == neutral)
1582 LinkMove(ply,sq,sq-16,xside);
1583 }
1584 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1585 if (!((m = m0+Dir[i]) & 0x88))
1586 {
1587 u = unmap[m];
1588 if (color[u] == xside || u == epsquare)
1589 LinkMove(ply,sq,u,xside);
1590 }
1591 }
1592 else
1593 {
1594 for (i = Dstart[piece]; i <= Dstop[piece]; i++)
1595 if (!((m = m0+Dir[i]) & 0x88))
1596 {
1597 u = unmap[m];
1598 if (color[u] != side) LinkMove(ply,sq,u,xside);
1599 }
1600 }
1601}
1602
1603
1604void LinkMove(ply,f,t,xside)
1605short ply,f,t,xside;
1606
1607/*
1608 Add a move to the tree. Assign a bonus to order the moves
1609 as follows:
1610 1. Principle variation
1611 2. Capture of last moved piece
1612 3. Other captures (major pieces first)
1613 4. Killer moves
1614 5. "history" killers
1615*/
1616
1617{
1618register short s,z;
1619register unsigned short mv;
1620struct leaf *node;
1621
1622 node = &Tree[TrPnt[ply+1]];
1623 ++TrPnt[ply+1];
1624 node->flags = 0;
1625 node->f = f; node->t = t;
1626 mv = (f<<8) + t;
1627 s = 0;
1628 if (mv == Swag0) s = 2000;
1629 else if (mv == Swag1) s = 60;
1630 else if (mv == Swag2) s = 50;
1631 else if (mv == Swag3) s = 40;
1632 else if (mv == Swag4) s = 30;
1633 if (color[t] != neutral)
1634 {
1635 node->flags |= capture;
1636 if (t == TOsquare) s += 500;
1637 s += value[board[t]] - board[f];
1638 }
1639 if (board[f] == pawn) {
1640 if (row[t] == 0 || row[t] == 7) {
1641 node->flags |= promote;
1642 s += 800;
1643 } else {
1644 if (row[t] == 1 || row[t] == 6) {
1645 node->flags |= pwnthrt;
1646 s += 600;
1647 } else {
1648 if (t == epsquare) node->flags |= epmask;
1649 }
1650 }
1651 }
1652 z = (f<<6) + t; if (xside == white) z |= 0x1000;
1653 s += history[z];
1654 node->score = s - 20000;
1655}
1656
1657
1658void CaptureList(side,xside,ply)
1659short side,xside,ply;
1660
1661/*
1662 Generate captures and Pawn promotions only.
1663*/
1664
1665#define LinkCapture \
1666{\
1667 node->f = sq; node->t = u;\
1668 node->flags = capture;\
1669 node->score = value[board[u]] + svalue[board[u]] - piece;\
1670 if (piece == pawn && (u < 8 || u > 55))\
1671 {\
1672 node->flags |= promote;\
1673 node->score = valueQ;\
1674 }\
1675 ++node;\
1676 ++TrPnt[ply+1];\
1677}
1678
1679{
1680register short m,u,d,sq,m0;
1681short i,j,j1,j2,r7,d0,piece,*PL;
1682struct leaf *node;
1683
1684 TrPnt[ply+1] = TrPnt[ply];
1685 node = &Tree[TrPnt[ply]];
1686 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
1687 if (side == white)
1688 {
1689 r7 = 6; d0 = 8;
1690 }
1691 else
1692 {
1693 r7 = 1; d0 = -8;
1694 }
1695 PL = PieceList[side];
1696 for (i = 0; i <= PieceCnt[side]; i++)
1697 {
1698 sq = PL[i];
1699 m0 = map[sq]; piece = board[sq];
1700 j1 = Dstart[piece]; j2 = Dstop[piece];
1701 if (sweep[piece])
1702 for (j = j1; j <= j2; j++)
1703 {
1704 d = Dir[j]; m = m0+d;
1705 while (!(m & 0x88))
1706 {
1707 u = unmap[m];
1708 if (color[u] == neutral) m += d;
1709 else
1710 {
1711 if (color[u] == xside) LinkCapture;
1712 break;
1713 }
1714 }
1715 }
1716 else
1717 {
1718 for (j = j1; j <= j2; j++)
1719 if (!((m = m0+Dir[j]) & 0x88))
1720 {
1721 u = unmap[m];
1722 if (color[u] == xside) LinkCapture;
1723 }
1724 if (piece == pawn && row[sq] == r7)
1725 {
1726 u = sq+d0;
1727 if (color[u] == neutral) LinkCapture;
1728 }
1729 }
1730 }
1731}
1732
1733
1734int castle(side,kf,kt,iop)
1735short side,kf,kt,iop;
1736
1737/*
1738 Make or Unmake a castling move.
1739*/
1740
1741{
1742register short rf,rt,d,t0,xside;
1743
1744 xside = otherside[side];
1745 if (kt > kf)
1746 {
1747 rf = kf+3; rt = kt-1; d = 1;
1748 }
1749 else
1750 {
1751 rf = kf-4; rt = kt+1; d = -1;
1752 }
1753 if (iop == 0)
1754 {
1755 if (board[kf] != king || board[rf] != rook || color[rf] != side)
1756 return(false);
1757 if (color[kt] != neutral || color[rt] != neutral) return(false);
1758 if (d == -1 && color[kt+d] != neutral) return(false);
1759 if (SqAtakd(kf,xside)) return(false);
1760 if (SqAtakd(kt,xside)) return(false);
1761 if (SqAtakd(kf+d,xside)) return(false);
1762 }
1763 else
1764 {
1765 if (iop == 1) castld[side] = true; else castld[side] = false;
1766 if (iop == 2)
1767 {
1768 t0 = kt; kt = kf; kf = t0;
1769 t0 = rt; rt = rf; rf = t0;
1770 }
1771 board[kt] = king; color[kt] = side; Pindex[kt] = 0;
1772 board[kf] = no_piece; color[kf] = neutral;
1773 board[rt] = rook; color[rt] = side; Pindex[rt] = Pindex[rf];
1774 board[rf] = no_piece; color[rf] = neutral;
1775 PieceList[side][Pindex[kt]] = kt;
1776 PieceList[side][Pindex[rt]] = rt;
1777 if (hashflag)
1778 {
1779 UpdateHashbd(side,king,kf,kt);
1780 UpdateHashbd(side,rook,rf,rt);
1781 }
1782 }
1783 return(true);
1784}
1785
1786
1787void EnPassant(xside,f,t,iop)
1788short xside,f,t,iop;
1789
1790/*
1791 Make or unmake an en passant move.
1792*/
1793
1794{
1795register short l;
1796 if (t > f) l = t-8; else l = t+8;
1797 if (iop == 1)
1798 {
1799 board[l] = no_piece; color[l] = neutral;
1800 }
1801 else
1802 {
1803 board[l] = pawn; color[l] = xside;
1804 }
1805 InitializeStats();
1806}
1807
1808
1809void MakeMove(side,node,tempb,tempc,tempsf,tempst)
1810short side,*tempc,*tempb,*tempsf,*tempst;
1811struct leaf *node;
1812
1813/*
1814 Update Arrays board[], color[], and Pindex[] to reflect the new board
1815 position obtained after making the move pointed to by node. Also
1816 update miscellaneous stuff that changes when a move is made.
1817*/
1818
1819{
1820register short f,t,xside,ct,cf;
1821
1822 xside = otherside[side];
1823 f = node->f; t = node->t; epsquare = -1;
1824 FROMsquare = f; TOsquare = t;
1825 INCscore = 0;
1826 GameList[++GameCnt].gmove = (f<<8) + t;
1827 if (node->flags & cstlmask)
1828 {
1829 GameList[GameCnt].piece = no_piece;
1830 GameList[GameCnt].color = side;
1831 castle(side,f,t,1);
1832 }
1833 else
1834 {
1835 *tempc = color[t]; *tempb = board[t];
1836 *tempsf = svalue[f]; *tempst = svalue[t];
1837 GameList[GameCnt].piece = *tempb;
1838 GameList[GameCnt].color = *tempc;
1839 if (*tempc != neutral)
1840 {
1841 UpdatePieceList(*tempc,t,1);
1842 if (*tempb == pawn) --PawnCnt[*tempc][column[t]];
1843 if (board[f] == pawn)
1844 {
1845 --PawnCnt[side][column[f]];
1846 ++PawnCnt[side][column[t]];
1847 cf = column[f]; ct = column[t];
1848 if (PawnCnt[side][ct] > 1+PawnCnt[side][cf])
1849 INCscore -= 15;
1850 else if (PawnCnt[side][ct] < 1+PawnCnt[side][cf])
1851 INCscore += 15;
1852 else if (ct == 0 || ct == 7 || PawnCnt[side][ct+ct-cf] == 0)
1853 INCscore -= 15;
1854 }
1855 mtl[xside] -= value[*tempb];
1856 if (*tempb == pawn) pmtl[xside] -= valueP;
1857 if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
1858 INCscore += *tempst;
1859 }
1860 color[t] = color[f]; board[t] = board[f]; svalue[t] = svalue[f];
1861 Pindex[t] = Pindex[f]; PieceList[side][Pindex[t]] = t;
1862 color[f] = neutral; board[f] = no_piece;
1863 if (board[t] == pawn) {
1864 if (t-f == 16) {
1865 epsquare = f+8;
1866 } else {
1867 if (f-t == 16) epsquare = f-8;
1868 }
1869 }
1870 if (node->flags & promote)
1871 {
1872 board[t] = queen;
1873 --PawnCnt[side][column[t]];
1874 mtl[side] += valueQ - valueP;
1875 pmtl[side] -= valueP;
1876 HasQueen[side] = true;
1877 if (hashflag)
1878 {
1879 UpdateHashbd(side,pawn,f,-1);
1880 UpdateHashbd(side,queen,f,-1);
1881 }
1882 INCscore -= *tempsf;
1883 }
1884 if (board[t] == king) ++kingmoved[side];
1885 if (node->flags & epmask) EnPassant(xside,f,t,1);
1886 else if (hashflag) UpdateHashbd(side,board[t],f,t);
1887 }
1888}
1889
1890
1891void UnmakeMove(side,node,tempb,tempc,tempsf,tempst)
1892short side,*tempc,*tempb,*tempsf,*tempst;
1893struct leaf *node;
1894
1895/*
1896 Take back a move.
1897*/
1898
1899{
1900register short f,t,xside;
1901
1902 xside = otherside[side];
1903 f = node->f; t = node->t; epsquare = -1;
1904 GameCnt--;
1905 if (node->flags & cstlmask) castle(side,f,t,2);
1906 else
1907 {
1908 color[f] = color[t]; board[f] = board[t]; svalue[f] = *tempsf;
1909 Pindex[f] = Pindex[t]; PieceList[side][Pindex[f]] = f;
1910 color[t] = *tempc; board[t] = *tempb; svalue[t] = *tempst;
1911 if (node->flags & promote)
1912 {
1913 board[f] = pawn;
1914 ++PawnCnt[side][column[t]];
1915 mtl[side] += valueP - valueQ;
1916 pmtl[side] += valueP;
1917 if (hashflag)
1918 {
1919 UpdateHashbd(side,queen,-1,t);
1920 UpdateHashbd(side,pawn,-1,t);
1921 }
1922 }
1923 if (*tempc != neutral)
1924 {
1925 UpdatePieceList(*tempc,t,2);
1926 if (*tempb == pawn) ++PawnCnt[*tempc][column[t]];
1927 if (board[f] == pawn)
1928 {
1929 --PawnCnt[side][column[t]];
1930 ++PawnCnt[side][column[f]];
1931 }
1932 mtl[xside] += value[*tempb];
1933 if (*tempb == pawn) pmtl[xside] += valueP;
1934 if (hashflag) UpdateHashbd(xside,*tempb,-1,t);
1935 }
1936 if (board[f] == king) --kingmoved[side];
1937 if (node->flags & epmask) EnPassant(xside,f,t,2);
1938 else if (hashflag) UpdateHashbd(side,board[f],f,t);
1939 }
1940}
1941
1942
1943void UpdateHashbd(side,piece,f,t)
1944short side,piece,f,t;
1945
1946/*
1947 hashbd contains a 32 bit "signature" of the board position. hashkey
1948 contains a 16 bit code used to address the hash table. When a move is
1949 made, XOR'ing the hashcode of moved piece on the from and to squares
1950 with the hashbd and hashkey values keeps things current.
1951*/
1952
1953{
1954 if (f >= 0)
1955 {
1956 hashbd ^= hashcode[side][piece][f].bd;
1957 hashkey ^= hashcode[side][piece][f].key;
1958 }
1959 if (t >= 0)
1960 {
1961 hashbd ^= hashcode[side][piece][t].bd;
1962 hashkey ^= hashcode[side][piece][t].key;
1963 }
1964}
1965
1966
1967void UpdatePieceList(side,sq,iop)
1968short side,sq,iop;
1969
1970/*
1971 Update the PieceList and Pindex arrays when a piece is captured or
1972 when a capture is unmade.
1973*/
1974
1975{
1976register short i;
1977 if (iop == 1)
1978 {
1979 PieceCnt[side]--;
1980 for (i = Pindex[sq]; i <= PieceCnt[side]; i++)
1981 {
1982 PieceList[side][i] = PieceList[side][i+1];
1983 Pindex[PieceList[side][i]] = i;
1984 }
1985 }
1986 else
1987 {
1988 PieceCnt[side]++;
1989 PieceList[side][PieceCnt[side]] = sq;
1990 Pindex[sq] = PieceCnt[side];
1991 }
1992}
1993
1994
1995void InitializeStats()
1996
1997/*
1998 Scan thru the board seeing what's on each square. If a piece is found,
1999 update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
2000 determine the material for each side and set the hashkey and hashbd
2001 variables to represent the current board position. Array
2002 PieceList[side][indx] contains the location of all the pieces of
2003 either side. Array Pindex[sq] contains the indx into PieceList for a
2004 given square.
2005*/
2006
2007{
2008register short i,sq;
2009 epsquare = -1;
2010 for (i = 0; i < 8; i++)
2011 PawnCnt[white][i] = PawnCnt[black][i] = 0;
2012 mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0;
2013 PieceCnt[white] = PieceCnt[black] = 0;
2014 hashbd = hashkey = 0;
2015 for (sq = 0; sq < 64; sq++)
2016 if (color[sq] != neutral)
2017 {
2018 mtl[color[sq]] += value[board[sq]];
2019 if (board[sq] == pawn)
2020 {
2021 pmtl[color[sq]] += valueP;
2022 ++PawnCnt[color[sq]][column[sq]];
2023 }
2024 if (board[sq] == king) Pindex[sq] = 0;
2025 else Pindex[sq] = ++PieceCnt[color[sq]];
2026 PieceList[color[sq]][Pindex[sq]] = sq;
2027 hashbd ^= hashcode[color[sq]][board[sq]][sq].bd;
2028 hashkey ^= hashcode[color[sq]][board[sq]][sq].key;
2029 }
2030}
2031
2032
2033void pick(p1,p2)
2034short p1,p2;
2035
2036/*
2037 Find the best move in the tree between indexes p1 and p2. Swap the
2038 best move into the p1 element.
2039*/
2040
2041{
2042register short p,s,p0,s0;
2043struct leaf temp;
2044
2045 s0 = Tree[p1].score; p0 = p1;
2046 for (p = p1+1; p <= p2; p++)
2047 if ((s = Tree[p].score) > s0)
2048 {
2049 s0 = s; p0 = p;
2050 }
2051 if (p0 != p1)
2052 {
2053 temp = Tree[p1]; Tree[p1] = Tree[p0]; Tree[p0] = temp;
2054 }
2055}
2056
2057
2058void repetition(cnt)
2059short *cnt;
2060
2061/*
2062 Check for draw by threefold repetition.
2063*/
2064
2065{
2066register short i,c,f,t;
2067short b[64];
2068unsigned short m;
2069 *cnt = c = 0;
2070 if (GameCnt > Game50+3)
2071 {
2072 for (i = 0; i < 64; b[i++] = 0);
2073 for (i = GameCnt; i > Game50; i--)
2074 {
2075 m = GameList[i].gmove; f = m>>8; t = m & 0xFF;
2076 if (++b[f] == 0) c--; else c++;
2077 if (--b[t] == 0) c--; else c++;
2078 if (c == 0) (*cnt)++;
2079 }
2080 }
2081}
2082
2083
2084int SqAtakd(sq,side)
2085short sq,side;
2086
2087/*
2088 See if any piece with color 'side' ataks sq. First check for pawns
2089 or king, then try other pieces. Array Dcode is used to check for
2090 knight attacks or R,B,Q co-linearity.
2091*/
2092
2093{
2094register short m,d,m0,m1,i,loc,piece,*PL;
2095
2096 m1 = map[sq];
2097 if (side == white) m = m1-0x0F; else m = m1+0x0F;
2098 if (!(m & 0x88))
2099 if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
2100 if (side == white) m = m1-0x11; else m = m1+0x11;
2101 if (!(m & 0x88))
2102 if (board[unmap[m]] == pawn && color[unmap[m]] == side) return(true);
2103 if (distance(sq,PieceList[side][0]) == 1) return(true);
2104
2105 PL = PieceList[side];
2106 for (i = 1; i <= PieceCnt[side]; i++)
2107 {
2108 loc = PL[i]; piece = board[loc];
2109 if (piece == pawn) continue;
2110 m0 = map[loc]; d = Dcode[abs(m1-m0)];
2111 if (d == 0 || (Pdir[d] & pbit[piece]) == 0) continue;
2112 if (piece == knight) return(true);
2113 else
2114 {
2115 if (m1 < m0) d = -d;
2116 for (m = m0+d; m != m1; m += d)
2117 if (color[unmap[m]] != neutral) break;
2118 if (m == m1) return(true);
2119 }
2120 }
2121 return(false);
2122}
2123
2124
2125void ataks(side,a)
2126short side,*a;
2127
2128/*
2129 Fill array atak[][] with info about ataks to a square. Bits 8-15
2130 are set if the piece (king..pawn) ataks the square. Bits 0-7
2131 contain a count of total ataks to the square.
2132*/
2133
2134{
2135register short u,m,d,c,m0;
2136short j,j1,j2,piece,i,sq,*PL;
2137
2138 for (u = 0; u < 64; a[u++] = 0);
2139 Dstart[pawn] = Dpwn[side]; Dstop[pawn] = Dstart[pawn] + 1;
2140 PL = PieceList[side];
2141 for (i = 0; i <= PieceCnt[side]; i++)
2142 {
2143 sq = PL[i];
2144 m0 = map[sq];
2145 piece = board[sq];
2146 c = control[piece]; j1 = Dstart[piece]; j2 = Dstop[piece];
2147 if (sweep[piece])
2148 for (j = j1; j <= j2; j++)
2149 {
2150 d = Dir[j]; m = m0+d;
2151 while (!(m & 0x88))
2152 {
2153 u = unmap[m];
2154 a[u] = ++a[u] | c;
2155 if (color[u] == neutral) m += d;
2156 else break;
2157 }
2158 }
2159 else
2160 for (j = j1; j <= j2; j++)
2161 if (!((m = m0+Dir[j]) & 0x88))
2162 {
2163 u = unmap[m];
2164 a[u] = ++a[u] | c;
2165 }
2166 }
2167}
2168
2169
2170
2171void ElapsedTime(iop)
2172
2173/*
2174 Determine the time that has passed since the search was started. If
2175 the elapsed time exceeds the target (ResponseTime+ExtraTime) then set
2176 timeout to true which will terminate the search.
2177*/
2178
2179short iop;
2180{
2181 /*et = time((long *)0) - time0;*/
2182 et = *(rb->current_tick) / HZ - time0;
2183 if (et < 0) et = 0;
2184 ETnodes += 50;
2185 if (et > et0 || iop == 1)
2186 {
2187 if (et > ResponseTime+ExtraTime && Sdepth > 1) timeout = true;
2188 et0 = et;
2189 if (iop == 1)
2190 {
2191 /*time0 = time((long *)0);*/
2192 time0 = *(rb->current_tick) / HZ ;
2193 et0 = 0;
2194 }
2195 /*(void) times(&tmbuf2);
2196 cputimer = 100*(tmbuf2.tms_utime - tmbuf1.tms_utime) / HZ;
2197 if (cputimer > 0) evrate = (100*NodeCnt)/(cputimer+100*ft);
2198 else evrate = 0;*/
2199 ETnodes = NodeCnt + 50;
2200 /*UpdateClocks();*/
2201 }
2202}
2203
2204
2205
2206void SetTimeControl( void )
2207{
2208 if (TCflag)
2209 {
2210 TimeControl.moves[white] = TimeControl.moves[black] = TCmoves;
2211 TimeControl.clock[white] = TimeControl.clock[black] = 60*(long)TCminutes;
2212 }
2213 else
2214 {
2215 TimeControl.moves[white] = TimeControl.moves[black] = 0;
2216 TimeControl.clock[white] = TimeControl.clock[black] = 0;
2217 Level = 60*(long)TCminutes;
2218 }
2219 et = 0;
2220 ElapsedTime(1);
2221}
2222
2223
2224
2225/* ............ INTERFACE ROUTINES ........................... */
2226
2227/*static void VoidFunction ( void ) {
2228 while (!(quit))
2229 {
2230 if (bothsides && !mate) SelectMove(opponent,1); else InputCommand();
2231 if (!(quit || mate || force)) SelectMove(computer,1);
2232 }
2233 ExitChess();
2234}*/
2235
2236int VerifyMove(char s[],short iop,unsigned short *mv)
2237
2238/*
2239 Compare the string 's' to the list of legal moves available for the
2240 opponent. If a match is found, make the move on the board.
2241*/
2242
2243{
2244static short pnt,tempb,tempc,tempsf,tempst,cnt;
2245static struct leaf xnode;
2246struct leaf *node;
2247
2248 *mv = 0;
2249 if (iop == 2)
2250 {
2251 UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
2252 return(false);
2253 }
2254 cnt = 0;
2255 MoveList(opponent,2);
2256 pnt = TrPnt[2];
2257 while (pnt < TrPnt[3])
2258 {
2259 node = &Tree[pnt++];
2260 algbr(node->f,node->t,node->flags & cstlmask);
2261 if (rb->strcmp(s,mvstr1) == 0 || rb->strcmp(s,mvstr2) == 0 ||
2262 rb->strcmp(s,mvstr3) == 0)
2263 {
2264 cnt++; xnode = *node;
2265 }
2266 }
2267 if (cnt == 1)
2268 {
2269 MakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
2270 if (SqAtakd(PieceList[opponent][0],computer))
2271 {
2272 UnmakeMove(opponent,&xnode,&tempb,&tempc,&tempsf,&tempst);
2273 /*ShowMessage("Illegal Move!!");*/
2274 return(false);
2275 }
2276 else
2277 {
2278 if (iop == 1) return(true);
2279 /*if (xnode.flags & epmask) UpdateDisplay(0,0,1,0);
2280 else UpdateDisplay(xnode.f,xnode.t,0,xnode.flags & cstlmask);*/
2281 if (xnode.flags & cstlmask) Game50 = GameCnt;
2282 else if (board[xnode.t] == pawn || (xnode.flags & capture))
2283 Game50 = GameCnt;
2284 GameList[GameCnt].depth = GameList[GameCnt].score = 0;
2285 GameList[GameCnt].nodes = 0;
2286 ElapsedTime(1);
2287 GameList[GameCnt].time = (short)et;
2288 TimeControl.clock[opponent] -= et;
2289 --TimeControl.moves[opponent];
2290 *mv = (xnode.f << 8) + xnode.t;
2291 algbr(xnode.f,xnode.t,false);
2292 return(true);
2293 }
2294 }
2295 /*if (cnt > 1) ShowMessage("Ambiguous Move!");*/
2296 return(false);
2297}
2298
2299
2300/* ---- Reset the board and other variables to start a new game. ---- */
2301void NewGame() {
2302 short l,r,c,p;
2303
2304 mate = quit = reverse = bothsides = post = false;
2305 hashflag = force = PawnStorm = false;
2306 easy = beep = rcptr = true;
2307 lpost = NodeCnt = epsquare = et0 = 0;
2308 dither = 0;
2309 Awindow = 90;
2310 Bwindow = 90;
2311 xwndw = 90;
2312 MaxSearchDepth = 29;
2313 contempt = 0;
2314 GameCnt = -1; Game50 = 0;
2315 Zwmtl = Zbmtl = 0;
2316 Developed[white] = Developed[black] = false;
2317 castld[white] = castld[black] = false;
2318 kingmoved[white] = kingmoved[black] = 0;
2319 PawnThreat[0] = CptrFlag[0] = Threat[0] = false;
2320 Pscore[0] = 12000; Tscore[0] = 12000;
2321 opponent = white; computer = black;
2322 for (r = 0; r < 8; r++)
2323 for (c = 0; c < 8; c++)
2324 {
2325 l = 8*r+c; locn[r][c] = l;
2326 row[l] = r; column[l] = c;
2327 board[l] = Stboard[l]; color[l] = Stcolor[l];
2328 }
2329 for (c = white; c <= black; c++)
2330 for (p = pawn; p <= king; p++)
2331 for (l = 0; l < 64; l++)
2332 {
2333 hashcode[c][p][l].key = (unsigned short)rb->rand();
2334 hashcode[c][p][l].bd = ((unsigned long)rb->rand() << 16) +
2335 (unsigned long)rb->rand();
2336 }
2337 if (TCflag) SetTimeControl();
2338 /*else if (Level == 0) SelectLevel();*/
2339 /*UpdateDisplay(0,0,1,0);*/
2340 InitializeStats();
2341 /*time0 = time((long *)0);*/
2342 time0 = *(rb->current_tick) / HZ ;
2343 ElapsedTime(1);
2344 /*GetOpenings();*/
2345}
2346
2347/* ---- Initialize variables and reset board ---- */
2348void GNUChess_Initialize ( void ) {
2349 int buffer_size;
2350 /* no malloc sir, 64K should be enough for now */
2351 /*char ttablearray[65536];*/
2352 /*ttable = (struct hashentry *)ttablearray;*/
2353 /*ttable = (struct hashentry *)malloc(ttblsz *
2354 (unsigned long)sizeof(struct hashentry));*/
2355 buffer_size = ttblsz * sizeof(struct hashentry);
2356 ttable = rb->plugin_get_buffer( &buffer_size );
2357 Level = 1;
2358 OperatorTime = 0;
2359 TCmoves = 60;
2360 TCminutes = 5;
2361 TCflag = true;
2362 NewGame();
2363 MaxSearchDepth = 29 ;
2364 /* remember to GetOpenings */
2365}
2366
2367void algbr(f,t,flag)
2368short f,t,flag;
2369{
2370 mvstr1[0] = cxx[column[f]]; mvstr1[1] = rxx[row[f]];
2371 mvstr1[2] = cxx[column[t]]; mvstr1[3] = rxx[row[t]];
2372 mvstr2[0] = qxx[board[f]];
2373 mvstr2[1] = mvstr1[2]; mvstr2[2] = mvstr1[3];
2374 mvstr1[4] = '\0'; mvstr2[3] = '\0';
2375 if (flag) {
2376 if (t > f) {
2377 rb->strcpy(mvstr2,"o-o");
2378 } else {
2379 rb->strcpy(mvstr2,"o-o-o");
2380 }
2381 }
2382
2383 if (board[f] == pawn) mvstr3[0] = mvstr1[0];
2384 else mvstr3[0] = qxx[board[f]];
2385 if (color[t] != neutral)
2386 {
2387 mvstr3[1] = ':';
2388 mvstr3[2] = mvstr1[2];
2389 mvstr3[3] = mvstr1[3];
2390 mvstr3[4] = '\0';
2391 }
2392 else if (board[f] == pawn)
2393 {
2394 mvstr3[1] = mvstr1[3];
2395 mvstr3[2] = '\0';
2396 }
2397 else
2398 {
2399 mvstr3[1] = mvstr1[0];
2400 mvstr3[2] = mvstr1[1];
2401 mvstr3[3] = mvstr1[2];
2402 mvstr3[4] = mvstr1[3];
2403 mvstr3[5] = '\0';
2404 }
2405}