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