xref: /original-bsd/games/chess/gnuchess.c (revision f4796bea)
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
92 struct leaf
93   {
94     short f,t,score,reply;
95     unsigned short flags;
96   };
97 struct GameRec
98   {
99     unsigned short gmove;
100     short score,depth,time,piece,color;
101     long nodes;
102   };
103 struct TimeControlRec
104   {
105     short moves[2];
106     long clock[2];
107   };
108 struct BookEntry
109   {
110     struct BookEntry *next;
111     unsigned short *mv;
112   };
113 struct hashval
114   {
115     unsigned long bd;
116     unsigned short key;
117   };
118 struct hashentry
119   {
120     unsigned long hashbd;
121     unsigned short mv,flags;
122     short score,depth;
123   };
124 
125 char mvstr1[5],mvstr2[5];
126 struct leaf Tree[2000],*root;
127 short TrPnt[maxdepth],board[64],color[64];
128 short row[64],column[64],locn[8][8],Pindex[64],svalue[64];
129 short PieceList[2][16],PieceCnt[2],atak[2][64],PawnCnt[2][8];
130 short castld[2],kingmoved[2],mtl[2],pmtl[2],emtl[2],hung[2];
131 short c1,c2,*atk1,*atk2,*PC1,*PC2,EnemyKing;
132 short mate,post,opponent,computer,Sdepth,Awindow,Bwindow,dither;
133 long ResponseTime,ExtraTime,Level,et,et0,time0,cputimer,ft;
134 long NodeCnt,evrate,ETnodes,EvalNodes,HashCnt;
135 short quit,reverse,bothsides,hashflag,InChk,player,force,easy,beep;
136 short wking,bking,FROMsquare,TOsquare,timeout,Zscore,zwndw,xwndw,slk;
137 short INCscore;
138 short HasPawn[2],HasKnight[2],HasBishop[2],HasRook[2],HasQueen[2];
139 short ChkFlag[maxdepth],CptrFlag[maxdepth],PawnThreat[maxdepth];
140 short Pscore[maxdepth],Tscore[maxdepth],Threat[maxdepth];
141 struct GameRec GameList[240];
142 short GameCnt,Game50,epsquare,lpost,rcptr,contempt;
143 short MaxSearchDepth;
144 struct BookEntry *Book;
145 struct TimeControlRec TimeControl;
146 short TCflag,TCmoves,TCminutes,OperatorTime;
147 short otherside[3]={1,0,2};
148 short rank7[3]={6,1,0};
149 short 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};
158 short 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};
167 short 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};
176 short 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};
182 short 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};
188 short sweep[7]= {false,false,false,true,true,true,false};
189 short Dpwn[3]={4,6,0};
190 short Dstart[7]={6,4,8,4,0,0,0};
191 short Dstop[7]={7,5,15,7,3,7,7};
192 short Dir[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11,
193                0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21};
194 short 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};
197 short pbit[7]={0,0x01,0x02,0x04,0x08,0x10,0x20};
198 unsigned short killr0[maxdepth],killr1[maxdepth],killr2[maxdepth];
199 unsigned short killr3[maxdepth],PrVar[maxdepth];
200 unsigned short PV,hint,Swag0,Swag1,Swag2,Swag3,Swag4;
201 unsigned short hashkey;
202 unsigned long hashbd;
203 struct hashval hashcode[2][7][64];
204 struct hashentry huge *ttable,*ptbl;
205 unsigned char history[8192];
206 
207 short Mwpawn[64],Mbpawn[64],Mknight[2][64],Mbishop[2][64];
208 short Mking[2][64],Kfield[2][64];
209 short value[7]={0,valueP,valueN,valueB,valueR,valueQ,valueK};
210 short control[7]={0,ctlP,ctlN,ctlB,ctlR,ctlQ,ctlK};
211 short PassedPawn0[8]={0,60,80,120,200,360,600,800};
212 short PassedPawn1[8]={0,30,40,60,100,180,300,800};
213 short PassedPawn2[8]={0,15,25,35,50,90,140,800};
214 short PassedPawn3[8]={0,5,10,15,20,30,140,800};
215 short ISOLANI[8] = {-12,-16,-20,-24,-24,-20,-16,-12};
216 short BACKWARD[8] = {-6,-10,-15,-21,-28,-28,-28,-28};
217 short BMBLTY[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16};
218 short RMBLTY[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14};
219 short Kthreat[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80,
220                      -80,-80,-80,-80};
221 short KNIGHTPOST,KNIGHTSTRONG,BISHOPSTRONG,KATAK,KBNKsq;
222 short PEDRNK2B,PWEAKH,PADVNCM,PADVNCI,PAWNSHIELD,PDOUBLED,PBLOK;
223 short RHOPN,RHOPNX,KHOPN,KHOPNX,KSFTY;
224 short ATAKD,HUNGP,HUNGX,KCASTLD,KMOVD,XRAY,PINVAL;
225 short stage,stage2,Zwmtl,Zbmtl,Developed[2],PawnStorm;
226 short PawnBonus,BishopBonus,RookBonus;
227 short 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};
236 short 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};
245 short 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};
254 short 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};
263 short 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};
272 short 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};
281 short 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 
main(argc,argv)292 main(argc,argv)
293 int 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 
VerifyMove(s,iop,mv)328 int VerifyMove(s,iop,mv)
329 char s[];
330 short iop;
331 unsigned 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 {
339 static short pnt,tempb,tempc,tempsf,tempst,cnt;
340 static struct leaf xnode;
341 struct 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 
NewGame()394 NewGame()
395 
396 /*
397    Reset the board and other variables to start a new game.
398 */
399 
400 {
401 short 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 
algbr(f,t,iscastle)447 algbr(f,t,iscastle)
448 short 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 
SelectMove(side,iop)463 SelectMove(side,iop)
464 short 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 {
476 static 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 
OpeningBook()599 OpeningBook()
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 {
612 short j,pnt;
613 unsigned short m,*mp;
614 unsigned r,r0;
615 struct 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 
search(side,ply,depth,alpha,beta,bstline,rpt)656 int search(side,ply,depth,alpha,beta,bstline,rpt)
657 short side,ply,depth,alpha,beta,*rpt;
658 unsigned 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 {
677 register short j,pnt;
678 short best,tempb,tempc,tempsf,tempst;
679 short xside,pbst,d,e,cf,score,rcnt;
680 unsigned short mv,nxtline[maxdepth];
681 struct 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 
evaluate(side,xside,ply,alpha,beta)814 evaluate(side,xside,ply,alpha,beta)
815 short 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 {
828 short 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 
ProbeTTable(side,depth,alpha,beta,score)867 ProbeTTable(side,depth,alpha,beta,score)
868 short side,depth,*alpha,*beta,*score;
869 
870 /*
871    Look for the current board position in the transposition table.
872 */
873 
874 {
875 short 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 
PutInTTable(side,score,depth,alpha,beta,mv)904 PutInTTable(side,score,depth,alpha,beta,mv)
905 short side,score,depth,alpha,beta;
906 unsigned short mv;
907 
908 /*
909    Store the current board position in the transposition table.
910 */
911 
912 {
913 short 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 
ZeroTTable()928 ZeroTTable()
929 {
930 int i;
931   if (hashflag)
932     for (i = 0; i < ttblsz; i++)
933       {
934         ptbl = (ttable + i);
935         ptbl->depth = 0;
936       }
937 }
938 
939 
MoveList(side,ply)940 MoveList(side,ply)
941 short 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 {
949 register short i;
950 short 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)
GenMoves(ply,sq,side,xside)978 GenMoves(ply,sq,side,xside)
979 short 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 {
990 register short m,u,d;
991 short 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 
LinkMove(ply,f,t,xside)1050 LinkMove(ply,f,t,xside)
1051 short 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 {
1064 register short s,z;
1065 unsigned short mv;
1066 struct 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)
CaptureList(side,xside,ply)1103 CaptureList(side,xside,ply)
1104 short 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 {
1126 register short m,u;
1127 short d,sq,i,j,j1,j2,m0,r7,d0,piece,*PL;
1128 struct 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 
castle(side,kf,kt,iop)1180 int castle(side,kf,kt,iop)
1181 short side,kf,kt,iop;
1182 
1183 /*
1184    Make or Unmake a castling move.
1185 */
1186 
1187 {
1188 short 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 
EnPassant(xside,f,t,iop)1233 EnPassant(xside,f,t,iop)
1234 short xside,f,t,iop;
1235 
1236 /*
1237    Make or unmake an en passant move.
1238 */
1239 
1240 {
1241 short 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 
MakeMove(side,node,tempb,tempc,tempsf,tempst)1255 MakeMove(side,node,tempb,tempc,tempsf,tempst)
1256 short side,*tempc,*tempb,*tempsf,*tempst;
1257 struct 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 {
1266 register short f,t;
1267 short 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 
UnmakeMove(side,node,tempb,tempc,tempsf,tempst)1334 UnmakeMove(side,node,tempb,tempc,tempsf,tempst)
1335 short side,*tempc,*tempb,*tempsf,*tempst;
1336 struct leaf *node;
1337 
1338 /*
1339    Take back a move.
1340 */
1341 
1342 {
1343 register short f,t;
1344 short 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 
UpdateHashbd(side,piece,f,t)1387 UpdateHashbd(side,piece,f,t)
1388 short 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 
UpdatePieceList(side,sq,iop)1411 UpdatePieceList(side,sq,iop)
1412 short 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 {
1420 register 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 
InitializeStats()1439 InitializeStats()
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 {
1452 register 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 
pick(p1,p2)1477 pick(p1,p2)
1478 short 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 {
1486 register short p,s;
1487 short p0,s0;
1488 struct 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 
repetition(cnt)1503 repetition(cnt)
1504 short *cnt;
1505 
1506 /*
1507     Check for draw by threefold repetition.
1508 */
1509 
1510 {
1511 register short i,c;
1512 short f,t,b[64];
1513 unsigned 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)
SqAtakd(sq,side)1532 int SqAtakd(sq,side)
1533 short 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 {
1542 register short m,d;
1543 short 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)
ataks(side,a)1575 ataks(side,a)
1576 short 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 {
1585 register short u,m;
1586 short 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 
ScorePosition(side,score)1625 ScorePosition(side,score)
1626 short 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 {
1635 register short sq,s;
1636 short 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 
ScoreLoneKing(side,score)1675 ScoreLoneKing(side,score)
1676 short 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 {
1684 short 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 
ScoreKPK(side,winner,loser,king1,king2,sq)1707 int ScoreKPK(side,winner,loser,king1,king2,sq)
1708 short side,winner,loser,king1,king2,sq;
1709 
1710 /*
1711    Score King and Pawns versus King endings.
1712 */
1713 
1714 {
1715 short 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 
ScoreKBNK(winner,king1,king2)1737 int ScoreKBNK(winner,king1,king2)
1738 short 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 {
1746 short 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 
SqValue(sq,side)1757 SqValue(sq,side)
1758 short sq,side;
1759 
1760 /*
1761    Calculate the positional value for the piece on 'sq'.
1762 */
1763 
1764 {
1765 register short j,fyle,rank;
1766 short 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)
KingScan(sq,s)1903 KingScan(sq,s)
1904 short 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 {
1918 register short m,u;
1919 short 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)
BRscan(sq,s,mob)1976 BRscan(sq,s,mob)
1977 short 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 {
1985 register short m,u;
1986 short 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)
trapped(sq,piece)2028 int trapped(sq,piece)
2029 short sq,piece;
2030 
2031 /*
2032    See if the attacked piece has unattacked squares to move to.
2033 */
2034 
2035 {
2036 register short u,m,d;
2037 short 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 
ExaminePosition()2077 ExaminePosition()
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 {
2086 register short i,sq;
2087 short 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 
UpdateWeights()2222 UpdateWeights()
2223 
2224 /*
2225    If material balance has changed, determine the values for the
2226    positional evaluation terms.
2227 */
2228 
2229 {
2230 short 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)
distance(a,b)2281 int distance(a,b)
2282 short a,b;
2283 {
2284 register 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 
BlendBoard(a,b,c)2292 BlendBoard(a,b,c)
2293 short a[64],b[64],c[64];
2294 {
2295 register int sq;
2296   for (sq = 0; sq < 64; sq++)
2297     c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10;
2298 }
2299 
2300 
CopyBoard(a,b)2301 CopyBoard(a,b)
2302 short a[64],b[64];
2303 {
2304 register int sq;
2305   for (sq = 0; sq < 64; sq++)
2306     b[sq] = a[sq];
2307 }
2308