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