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