|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.