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 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 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 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 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 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 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 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 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 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 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 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 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) 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 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) 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 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 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 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 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 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 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 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 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 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) 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) 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 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 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 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 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 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) 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) 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) 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 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 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) 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 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 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