mwm@hasler.ascom.ch (Mike McGann) (05/17/91)
Submitted-by: Mike McGann <mwm@hasler.ascom.ch> Posting-number: Volume 19, Issue 76 Archive-name: gnuchess/part04 #!/bin/sh # do not concatenate these parts, unpack them in order with /bin/sh # file gnuchess.c continued # if test ! -r _shar_seq_.tmp; then echo 'Please unpack part 1 first!' exit 1 fi (read Scheck if test "$Scheck" != 4; then echo Please unpack part "$Scheck" next! exit 1 else exit 0 fi ) < _shar_seq_.tmp || exit 1 if test ! -f _shar_wnt_.tmp; then echo 'x - still skipping gnuchess.c' else echo 'x - continuing file gnuchess.c' sed 's/^X//' << 'SHAR_EOF' >> 'gnuchess.c' && X { X root->flags |= draw; X DRAW = "No moves"; X } X if (iop == 2) X return; X if (Book == NULL) X hint = PrVar[2]; X ElapsedTime (1); X X if (score > -9999 && rpt <= 2) X { X MakeMove (side, root, &tempb, &tempc, &tempsf, &tempst, &INCscore); X algbr (root->f, root->t, (short) root->flags); X } X else X algbr (0, 0, 0); X OutputMove (); X if (score == -9999 || score == 9998) X flag.mate = true; X if (flag.mate) X hint = 0; X if ((board[root->t] == pawn) || (root->flags & (capture | cstlmask))) X { X Game50 = GameCnt; X ZeroRPT (); X } X g = &GameList[GameCnt]; X g->score = score; X g->nodes = NodeCnt; X g->time = (short) et; X g->depth = Sdepth; X g->flags = root->flags; X if (TCflag) X { X TimeControl.clock[side] -= (et + OperatorTime); X if (--TimeControl.moves[side] == 0) X SetTimeControl (); X } X if ((root->flags & draw) && flag.bothsides) X flag.mate = true; X if (GameCnt > 190) X flag.mate = true; /* out of move store, you loose */ X player = xside; X Sdepth = 0; X fflush (stdin); } X int parse (FILE * fd, short unsigned int *mv, short int side) { X int c, i, r1, r2, c1, c2; X char s[100]; X while ((c = getc (fd)) == ' ') ; X i = 0; X s[0] = (char) c; X while (c != ' ' && c != '\n' && c != EOF) X s[++i] = (char) (c = getc (fd)); X s[++i] = '\0'; X if (c == EOF) X return (-1); X if (s[0] == '!' || s[0] == ';' || i < 3) X { X while (c != '\n' && c != EOF) X c = getc (fd); X return (0); X } X if (s[4] == 'o') X *mv = (side == black) ? 0x3C3A : 0x0402; X else if (s[0] == 'o') X *mv = (side == black) ? 0x3C3E : 0x0406; X else X { X c1 = s[0] - 'a'; X r1 = s[1] - '1'; X c2 = s[2] - 'a'; X r2 = s[3] - '1'; X *mv = (locn (r1, c1) << 8) | locn (r2, c2); X } X return (1); } X void GetOpenings (void) X /* X Read in the Opening Book file and parse the algebraic notation for a move X into an unsigned integer format indicating the from and to square. Create X a linked list of opening lines of play, with entry->next pointing to the X next line and entry->move pointing to a chunk of memory containing the X moves. More Opening lines of up to 256 half moves may be added to X gnuchess.book. */ #ifndef BOOK #define BOOK "/usr/games/lib/gnuchess.book" #endif /* BOOK */ { X FILE *fd; X int c, i, j, side; X /* char buffr[2048]; */ X struct BookEntry *entry; X unsigned short mv, *mp, tmp[100]; X X if ((fd = fopen (BOOK, "r")) == NULL) X fd = fopen ("gnuchess.book", "r"); X if (fd != NULL) X { X /* setvbuf(fd,buffr,_IOFBF,2048); */ X Book = NULL; X i = 0; X side = white; X while ((c = parse (fd, &mv, side)) >= 0) X if (c == 1) X { X tmp[++i] = mv; X side = otherside[side]; X } X else if (c == 0 && i > 0) X { X entry = (struct BookEntry *) malloc (sizeof (struct BookEntry)); X mp = (unsigned short *) malloc ((i + 1) * sizeof (unsigned short)); X if (!entry || !mp) X { X Book = NULL; X ShowMessage ("warning: can't load book, out of memory."); X return; X } X entry->mv = mp; X entry->next = Book; X Book = entry; X for (j = 1; j <= i; j++) X *(mp++) = tmp[j]; X *mp = 0; X i = 0; X side = white; X } X fclose (fd); X BKBook = Book; X } X else X ShowMessage ("warning: can't find book."); } X X void OpeningBook (unsigned short *hint) X /* X Go thru each of the opening lines of play and check for a match with the X current game listing. If a match occurs, generate a random number. If this X number is the largest generated so far then the next move in this line X becomes the current "candidate". After all lines are checked, the X candidate move is put at the top of the Tree[] array and will be played by X the program. Note that the program does not handle book transpositions. */ X { X short j, pnt; X unsigned short m, *mp; X unsigned r, r0; X struct BookEntry *p; X X srand ((unsigned int) time ((long *) 0)); X r0 = m = 0; X p = Book; X while (p != NULL) X { X mp = p->mv; X for (j = 1; j <= GameCnt; j++) X if (GameList[j].gmove != *(mp++)) X break; X if (j > GameCnt) X if ((r = urand ()) > r0) X { X r0 = r; X m = *mp; X *hint = *(++mp); X } X p = p->next; X } X X for (pnt = TrPnt[1]; pnt < TrPnt[2]; pnt++) X if (((Tree[pnt].f << 8) | Tree[pnt].t) == m) X Tree[pnt].score = 0; X pick (TrPnt[1], TrPnt[2] - 1); X if (Tree[TrPnt[1]].score < 0) X Book = NULL; } X X inline void repetition (short int *cnt) X /* X Check for draw by threefold repetition. */ X { X register short i, c, f, t; X short b[64]; X unsigned short m; X X *cnt = c = 0; X if (GameCnt > Game50 + 3) X { #ifdef NOMEMSET X for (i = 0; i < 64; b[i++] = 0) ; #else X memset ((char *) b, 0, sizeof (b)); #endif /* NOMEMSET */ X for (i = GameCnt; i > Game50; i--) X { X m = GameList[i].gmove; X f = m >> 8; X t = m & 0xFF; X if (++b[f] == 0) X c--; X else X c++; X if (--b[t] == 0) X c--; X else X c++; X if (c == 0) X (*cnt)++; X } X } } X X int search (short int side, X short int ply, X short int depth, X short int alpha, X short int beta, X short unsigned int *bstline, X short int *rpt) X /* X Perform an alpha-beta search to determine the score for the current board X position. If depth <= 0 only capturing moves, pawn promotions and X responses to check are generated and searched, otherwise all moves are X processed. The search depth is modified for check evasions, certain X re-captures and threats. Extensions may continue for up to 11 ply beyond X the nominal search depth. X */ X #define UpdateSearchStatus \ {\ X if (flag.post) ShowCurrentMove(pnt,node->f,node->t);\ X if (pnt > TrPnt[1])\ X {\ X d = best-Zscore; e = best-node->score;\ X if (best < alpha) ExtraTime = 10*ResponseTime;\ X else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\ X else if (d > -zwndw) ExtraTime = 0;\ X else if (d > -3*zwndw) ExtraTime = ResponseTime;\ X else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\ X else ExtraTime = 5*ResponseTime;\ X }\ X } #define prune (cf && score+node->score < alpha) #define ReCapture (flag.rcptr && score > alpha && score < beta &&\ X ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2]) /* && depth == Sdepth-ply+1 */ #define Parry (hung[side] > 1 && ply == Sdepth+1) #define MateThreat (ply < Sdepth+4 && ply > 4 &&\ X ChkFlag[ply-2] && ChkFlag[ply-4] &&\ X ChkFlag[ply-2] != ChkFlag[ply-4]) X { X register short j, pnt; X short best, tempb, tempc, tempsf, tempst; X short xside, pbst, d, e, cf, score, rcnt, slk, InChk; X unsigned short mv, nxtline[maxdepth]; X struct leaf *node, tmp; X X NodeCnt++; X xside = otherside[side]; X X if ((ply <= Sdepth + 3) && rpthash[side][hashkey & 0xFF] > 0) X repetition (rpt); X else X *rpt = 0; X /* Detect repetitions a bit earlier. SMC. 12/89 */ X if (*rpt == 1 && ply > 1) X return (0); X /* if (*rpt >= 2) return(0); */ X /* slk is lone king indicator for either side */ X score = evaluate (side, ply, alpha, beta, INCscore, &slk, &InChk); X if (score > 9000) X { X bstline[ply] = 0; X return (score); X } X if (depth > 0) X { X /* Allow opponent a chance to check again */ X if (InChk) X depth = (depth < 2) ? 2 : depth; X else if (PawnThreat[ply - 1] || ReCapture) X ++depth; X } X else X { X if (score >= alpha && (InChk || PawnThreat[ply - 1] || Parry)) X depth = 1; X else if (score <= beta && MateThreat) X depth = 1; X } X #if ttblsz X if (depth > 0 && flag.hash && ply > 1) X { X if (ProbeTTable (side, depth, &alpha, &beta, &score) == true) X { X bstline[ply] = PV; X bstline[ply + 1] = 0; X if (beta == -20000) X return (score); X if (alpha > beta) X return (alpha); X } #ifdef HASHFILE X else if (hashfile && (depth > HashDepth) && (GameCnt < HashMoveLimit) X && (ProbeFTable (side, depth, &alpha, &beta, &score) == true)) X { X PutInTTable (side, score, depth, alpha, beta, PV); X bstline[ply] = PV; X bstline[ply + 1] = 0; X if (beta == -20000) X return (score); X if (alpha > beta) X return (alpha); X } #endif /* HASHFILE */ X } #endif /* ttblsz */ X d = (Sdepth == 1) ? 7 : 11; X if (ply > Sdepth + d || (depth < 1 && score > beta)) X return (score); /* score >= beta ?? */ X X if (ply > 1) X if (depth > 0) X MoveList (side, ply); X else X CaptureList (side, ply); X X if (TrPnt[ply] == TrPnt[ply + 1]) X return (score); X X cf = (depth < 1 && ply > Sdepth + 1 && !ChkFlag[ply - 2] && !slk); X X best = (depth > 0) ? -12000 : score; X if (best > alpha) X alpha = best; X /* look at each move until no more or beta cutoff */ X for (pnt = pbst = TrPnt[ply]; X pnt < TrPnt[ply + 1] && best < beta; /* best < beta ?? */ X pnt++) X { X /* find the most interesting looking of the remaining moves */ X if (ply > 1) X pick (pnt, TrPnt[ply + 1] - 1); X node = &Tree[pnt]; X mv = (node->f << 8) | node->t; X nxtline[ply + 1] = 0; X if (prune) X break; /* alpha cutoff */ X if (ply == 1) X UpdateSearchStatus; X X if (!(node->flags & exact)) X { X /* make the move and go deeper */ X MakeMove (side, node, &tempb, &tempc, &tempsf, &tempst, &INCscore); X CptrFlag[ply] = (node->flags & capture); X PawnThreat[ply] = (node->flags & pwnthrt); X Tscore[ply] = node->score; X PV = node->reply; X node->score = -search (xside, ply + 1, X (depth > 0) ? depth - 1 : 0, X -beta, -alpha, X nxtline, &rcnt); X if (abs (node->score) > 9000) X node->flags |= exact; X else if (rcnt == 1) X node->score /= 2; X /* but why doesnt this detect draws??? */ X if (rcnt >= 2 || GameCnt - Game50 > 99 || X (node->score == 9999 - ply && !ChkFlag[ply])) X { X node->flags |= (draw | exact); X DRAW = ""; X node->score = (side == computer) ? contempt : -contempt; X } X node->reply = nxtline[ply + 1]; X /* reset to try next move */ X UnmakeMove (side, node, &tempb, &tempc, &tempsf, &tempst); X } X if (node->score > best && !flag.timeout) X { X if (depth > 0 && node->score > alpha && !(node->flags & exact)) X node->score += depth; X best = node->score; X pbst = pnt; X if (best > alpha) X alpha = best; X for (j = ply + 1; nxtline[j] > 0; j++) X bstline[j] = nxtline[j]; X bstline[j] = 0; X bstline[ply] = mv; #ifdef DEBUG X if(ply == 1) X ShowDBLine ("IS", ply, depth, alpha, beta, score, &bstline[ply-1]); #endif /*DEBUG*/ X if (ply == 1) X { X if (best > root->score) X { X tmp = Tree[pnt]; X for (j = pnt - 1; j >= 0; j--) X Tree[j + 1] = Tree[j]; X Tree[0] = tmp; X pbst = 0; X } X if (Sdepth > 2) X if (best > beta) X ShowResults (best, bstline, '+'); X else if (best < alpha) X ShowResults (best, bstline, '-'); X else X ShowResults (best, bstline, '&'); X } X } X if (NodeCnt > ETnodes) X ElapsedTime (0); X if (flag.timeout) X return (-Tscore[ply - 1]); X } X X node = &Tree[pbst]; X mv = (node->f << 8) | node->t; #if ttblsz X if (flag.hash && ply <= Sdepth && *rpt == 0 && best == alpha) X { X if (PutInTTable (side, best, depth, alpha, beta, mv) #ifdef HASHFILE X && hashfile && (depth > HashDepth) && (GameCnt < HashMoveLimit)) X { X PutInFTable (side, best, depth, alpha, beta, node->f, node->t); X } #else X ); #endif /* HASHFILE */ X } #endif /* ttblsz */ X if (depth > 0) X { X j = (node->f << 6) | node->t; X if (side == black) X j |= 0x1000; X if (history[j] < 150) X history[j] += (unsigned char) 2 *depth; X X if (node->t != (GameList[GameCnt].gmove & 0xFF)) X if (best <= beta) X killr3[ply] = mv; X else if (mv != killr1[ply]) X { X killr2[ply] = killr1[ply]; X killr1[ply] = mv; X } X if (best > 9000) X killr0[ply] = mv; X else X killr0[ply] = 0; X } X return (best); } X #if ttblsz /* X hashbd contains a 32 bit "signature" of the board position. hashkey X contains a 16 bit code used to address the hash table. When a move is X made, XOR'ing the hashcode of moved piece on the from and to squares with X the hashbd and hashkey values keeps things current. */ #define UpdateHashbd(side, piece, f, t) \ {\ X if ((f) >= 0)\ X {\ X hashbd ^= hashcode[side][piece][f].bd;\ X hashkey ^= hashcode[side][piece][f].key;\ X }\ X if ((t) >= 0)\ X {\ X hashbd ^= hashcode[side][piece][t].bd;\ X hashkey ^= hashcode[side][piece][t].key;\ X }\ } X #define CB(i) (unsigned char) ((color[2 * (i)] ? 0x80 : 0)\ X | (board[2 * (i)] << 4)\ X | (color[2 * (i) + 1] ? 0x8 : 0)\ X | (board[2 * (i) + 1])) X int ProbeTTable (short int side, X short int depth, X short int *alpha, X short int *beta, X short int *score) X /* X Look for the current board position in the transposition table. */ X { X register struct hashentry *ptbl; X register unsigned short i; X X ptbl = &ttable[side][hashkey & (ttblsz - 1)]; X X /* rehash max rehash times */ X for (i = 1; ptbl->hashbd != hashbd && i <= rehash; i++) X ptbl = &ttable[side][(hashkey + i) & (ttblsz - 1)]; X if ((short) ptbl->depth >= depth && ptbl->hashbd == hashbd) X { X HashCnt++; #ifdef HASHTEST X for (i = 0; i < 32; i++) X { X if (ptbl->bd[i] != CB (i)) X { X HashCol++; X ShowMessage ("ttable collision detected"); X break; X } X } #endif /* HASHTEST */ X X PV = ptbl->mv; X if (ptbl->flags & truescore) X { X *score = ptbl->score; X *beta = -20000; X } #if 0 /* commented out, why? */ X else if (ptbl->flags & upperbound) X { X if (ptbl->score < *beta) X *beta = ptbl->score + 1; X } #endif X else if (ptbl->flags & lowerbound) X { X if (ptbl->score > *alpha) X *alpha = ptbl->score - 1; X } X return (true); X } X return (false); } X int PutInTTable (short int side, X short int score, X short int depth, X short int alpha, X short int beta, X short unsigned int mv) X /* X Store the current board position in the transposition table. */ X { X register struct hashentry *ptbl; X register unsigned short i; X X ptbl = &ttable[side][hashkey & (ttblsz - 1)]; X X /* rehash max rehash times */ X for (i = 1; depth < ptbl->depth && ptbl->hashbd != hashbd && i <= rehash; i++) X ptbl = &ttable[side][(hashkey + i) & (ttblsz - 1)]; X if (depth >= ptbl->depth || ptbl->hashbd != hashbd) X { X HashAdd++; X ptbl->hashbd = hashbd; X ptbl->depth = (unsigned char) depth; X ptbl->score = score; X ptbl->mv = mv; X if (score < alpha) X ptbl->flags = upperbound; X else if (score > beta) X ptbl->flags = lowerbound; X else X ptbl->flags = truescore; #ifdef HASHTEST X for (i = 0; i < 32; i++) X { X ptbl->bd[i] = CB (i); X } #endif /* HASHTEST */ X return true; X } X return false; } X void ZeroTTable (void) { X register int side, i; X X if (flag.hash) X for (side = white; side <= black; side++) X for (i = 0; i < ttblsz; i++) X ttable[side][i].depth = 0; } X #ifdef HASHFILE int ProbeFTable (short int side, X short int depth, X short int *alpha, X short int *beta, X short int *score) X /* X Look for the current board position in the persistent transposition table. */ X { X register unsigned short i, j; X register unsigned long hashix; X short s; X struct fileentry new, t; X X hashix = ((side == white) ? (hashkey & 0xFFFFFFFE) : (hashkey | 1)) & filesz; X X for (i = 0; i < 32; i++) X new.bd[i] = CB (i); X new.flags = 0; X if (Mvboard[kingP[side]] == 0) X { X if (Mvboard[qrook[side]] == 0) X new.flags |= queencastle; X if (Mvboard[krook[side]] == 0) X new.flags |= kingcastle; X } X X for (i = 0; i < frehash; i++) X { X fseek (hashfile, X sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)), X SEEK_SET); X fread (&t, sizeof (struct fileentry), 1, hashfile); X for (j = 0; j < 32; j++) X if (t.bd[j] != new.bd[j]) X break; X if (((short) t.depth >= depth) && (j >= 32) X && (new.flags == (t.flags & (kingcastle | queencastle)))) X { X FHashCnt++; X PV = (t.f << 8) | t.t; X s = (t.sh << 8) | t.sl; X if (t.flags & truescore) X { X *score = s; X *beta = -20000; X } X else if (t.flags & lowerbound) X { X if (s > *alpha) X *alpha = s - 1; X } X return (true); X } X } X return (false); } X void PutInFTable (short int side, X short int score, X short int depth, X short int alpha, X short int beta, X short unsigned int f, X short unsigned int t) X /* X Store the current board position in the persistent transposition table. */ X { X register unsigned short i; X register unsigned long hashix; X struct fileentry new, tmp; X X FHashAdd++; X hashix = ((side == white) ? (hashkey & 0xFFFFFFFE) : (hashkey | 1)) & filesz; X for (i = 0; i < 32; i++) X new.bd[i] = CB (i); X new.f = (unsigned char) f; X new.t = (unsigned char) t; X if (score < alpha) X new.flags = upperbound; X else X new.flags = (score > beta) ? lowerbound : truescore; X if (Mvboard[kingP[side]] == 0) X { X if (Mvboard[qrook[side]] == 0) X new.flags |= queencastle; X if (Mvboard[krook[side]] == 0) X new.flags |= kingcastle; X } X new.depth = (unsigned char) depth; X new.sh = (unsigned char) (score >> 8); X new.sl = (unsigned char) (score & 0xFF); X X for (i = 0; i < frehash; i++) X { X fseek (hashfile, X sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)), X SEEK_SET); X fread (&tmp, sizeof (struct fileentry), 1, hashfile); X if ((short) tmp.depth <= depth) X { X fseek (hashfile, X sizeof (struct fileentry) * ((hashix + 2 * i) & (filesz)), X SEEK_SET); X fwrite (&new, sizeof (struct fileentry), 1, hashfile); X break; X } X } } X #endif /* HASHFILE */ #endif /* ttblsz */ X void ZeroRPT (void) { X register int side, i; X X for (side = white; side <= black; side++) X for (i = 0; i < 256; i++) X rpthash[side][i] = 0; } X #define Link(from,to,flag,s) \ {\ X node->f = from; node->t = to;\ X node->reply = 0;\ X node->flags = flag;\ X node->score = s;\ X ++node;\ X ++TrPnt[ply+1];\ X } X static inline void LinkMove (short int ply, X short int f, X short int t, X short int flag, X short int xside) X /* X Add a move to the tree. Assign a bonus to order the moves X as follows: X 1. Principle variation X 2. Capture of last moved piece X 3. Other captures (major pieces first) X 4. Killer moves X 5. "history" killers */ X { X register short s, z; X register unsigned short mv; X register struct leaf *node; X extern char mvstr[4][6]; X X node = &Tree[TrPnt[ply + 1]]; X mv = (f << 8) | t; X s = 0; X if (mv == Swag0) X s = 2000; X else if (mv == Swag1) X s = 60; X else if (mv == Swag2) X s = 50; X else if (mv == Swag3) X s = 40; X else if (mv == Swag4) X s = 30; X z = (f << 6) | t; X if (xside == white) X z |= 0x1000; X s += history[z]; X if (color[t] != neutral) X { X if (t == TOsquare) X s += 500; X s += value[board[t]] - board[f]; X } X if (board[f] == pawn) X if (row (t) == 0 || row (t) == 7) X { X flag |= promote; X s += 800; X Link (f, t, flag | queen, s - 20000); X s -= 200; X Link (f, t, flag | knight, s - 20000); X s -= 50; X Link (f, t, flag | rook, s - 20000); X flag |= bishop; X s -= 50; X } X else if (row (t) == 1 || row (t) == 6) X { X flag |= pwnthrt; X s += 600; X } X Link (f, t, flag, s - 20000); } X X static inline void GenMoves (short int ply, short int sq, short int side, short int xside) X /* X Generate moves for a piece. The moves are taken from the precalulated X array nextpos/nextdir. If the board is free, next move is choosen from X nextpos else from nextdir. */ X { X register short u, piece; X register unsigned char *ppos, *pdir; X X piece = board[sq]; X ppos = nextpos[ptype[side][piece]][sq]; X pdir = nextdir[ptype[side][piece]][sq]; X if (piece == pawn) X { X u = ppos[sq]; /* follow no captures thread */ X if (color[u] == neutral) X { X LinkMove (ply, sq, u, 0, xside); X u = ppos[u]; X if (color[u] == neutral) X LinkMove (ply, sq, u, 0, xside); X } X u = pdir[sq]; /* follow captures thread */ X if (color[u] == xside) X LinkMove (ply, sq, u, capture, xside); X else if (u == epsquare) X LinkMove (ply, sq, u, capture | epmask, xside); X u = pdir[u]; X if (color[u] == xside) X LinkMove (ply, sq, u, capture, xside); X else if (u == epsquare) X LinkMove (ply, sq, u, capture | epmask, xside); X } X else X { X u = ppos[sq]; X do X { X if (color[u] == neutral) X { X LinkMove (ply, sq, u, 0, xside); X u = ppos[u]; X } X else X { X if (color[u] == xside) X LinkMove (ply, sq, u, capture, xside); X u = pdir[u]; X } X } while (u != sq); X } } X void MoveList (short int side, short int ply) X /* X Fill the array Tree[] with all available moves for side to play. Array X TrPnt[ply] contains the index into Tree[] of the first move at a ply. */ X { X register short i, xside, f; X X xside = otherside[side]; X TrPnt[ply + 1] = TrPnt[ply]; X Swag0 = (PV) ? killr0[ply] : PV; X Swag1 = killr1[ply]; X Swag2 = killr2[ply]; X Swag3 = killr3[ply]; X Swag4 = (ply > 2) ? killr1[ply - 2] : 0; X for (i = PieceCnt[side]; i >= 0; i--) X GenMoves (ply, PieceList[side][i], side, xside); X if (!castld[side]) X { X f = PieceList[side][0]; X if (castle (side, f, f + 2, 0)) X { X LinkMove (ply, f, f + 2, cstlmask, xside); X } X if (castle (side, f, f - 2, 0)) X { X LinkMove (ply, f, f - 2, cstlmask, xside); X } X } } X void CaptureList (short int side, short int ply) X /* X Fill the array Tree[] with all available cature and promote moves for X side to play. Array TrPnt[ply] contains the index into Tree[] X of the first move at a ply. */ X { X register short u, sq, xside; X register struct leaf *node; X register unsigned char *ppos, *pdir; X short i, piece, *PL, r7; X X xside = otherside[side]; X TrPnt[ply + 1] = TrPnt[ply]; X node = &Tree[TrPnt[ply]]; X r7 = rank7[side]; X PL = PieceList[side]; X for (i = 0; i <= PieceCnt[side]; i++) X { X sq = PL[i]; X piece = board[sq]; X if (sweep[piece]) X { X ppos = nextpos[piece][sq]; X pdir = nextdir[piece][sq]; X u = ppos[sq]; X do X { X if (color[u] == neutral) X u = ppos[u]; X else X { X if (color[u] == xside) X Link (sq, u, capture, value[board[u]] + svalue[board[u]] - piece); X u = pdir[u]; X } X } while (u != sq); X } X else X { X pdir = nextdir[ptype[side][piece]][sq]; X if (piece == pawn && row (sq) == r7) X { X u = pdir[sq]; X if (color[u] == xside) X Link (sq, u, capture | promote | queen, valueQ); X u = pdir[u]; X if (color[u] == xside) X Link (sq, u, capture | promote | queen, valueQ); X ppos = nextpos[ptype[side][piece]][sq]; X u = ppos[sq]; /* also generate non capture promote */ X if (color[u] == neutral) X Link (sq, u, promote | queen, valueQ); X } X else X { X u = pdir[sq]; X do X { X if (color[u] == xside) X Link (sq, u, capture, value[board[u]] + svalue[board[u]] - piece); X u = pdir[u]; X } while (u != sq); X } X } X } } X X int castle (short int side, short int kf, short int kt, short int iop) X /* Make or Unmake a castling move. */ X { X register short rf, rt, t0, xside; X X xside = otherside[side]; X if (kt > kf) X { X rf = kf + 3; X rt = kt - 1; X } X else X { X rf = kf - 4; X rt = kt + 1; X } X if (iop == 0) X { X if (kf != kingP[side] || X board[kf] != king || X board[rf] != rook || X Mvboard[kf] != 0 || X Mvboard[rf] != 0 || X color[kt] != neutral || X color[rt] != neutral || X color[kt - 1] != neutral || X SqAtakd (kf, xside) || X SqAtakd (kt, xside) || X SqAtakd (rt, xside)) X return (false); X } X else X { X if (iop == 1) X { X castld[side] = true; X Mvboard[kf]++; X Mvboard[rf]++; X } X else X { X castld[side] = false; X Mvboard[kf]--; X Mvboard[rf]--; X t0 = kt; X kt = kf; X kf = t0; X t0 = rt; X rt = rf; X rf = t0; X } X board[kt] = king; X color[rt] = color[kt] = side; X Pindex[kt] = 0; X board[kf] = no_piece; X color[rf] = color[kf] = neutral; X board[rt] = rook; X Pindex[rt] = Pindex[rf]; X board[rf] = no_piece; X PieceList[side][Pindex[kt]] = kt; X PieceList[side][Pindex[rt]] = rt; #if ttblsz X UpdateHashbd (side, king, kf, kt); X UpdateHashbd (side, rook, rf, rt); #endif /* ttblsz */ X } X return (true); } X X void EnPassant (short int xside, short int f, short int t, short int iop) X /* X Make or unmake an en passant move. */ X { X register short l; X X l = (t > f) ? t - 8 : t + 8; X if (iop == 1) X { X board[l] = no_piece; X color[l] = neutral; X } X else X { X board[l] = pawn; X color[l] = xside; X } X InitializeStats (); } X X static inline void UpdatePieceList (short int side, short int sq, short int iop) X /* X Update the PieceList and Pindex arrays when a piece is captured or when a X capture is unmade. */ X { X register short i; X if (iop == 1) X { X PieceCnt[side]--; X for (i = Pindex[sq]; i <= PieceCnt[side]; i++) X { X PieceList[side][i] = PieceList[side][i + 1]; X Pindex[PieceList[side][i]] = i; X } X } X else X { X PieceCnt[side]++; X PieceList[side][PieceCnt[side]] = sq; X Pindex[sq] = PieceCnt[side]; X } } X void MakeMove (short int side, X struct leaf * node, X short int *tempb, X short int *tempc, X short int *tempsf, X short int *tempst, X short int *INCscore) X /* X Update Arrays board[], color[], and Pindex[] to reflect the new board X position obtained after making the move pointed to by node. Also update X miscellaneous stuff that changes when a move is made. */ X { X register short f, t, xside, ct, cf; X X xside = otherside[side]; X GameCnt++; X f = node->f; X t = node->t; X epsquare = -1; X FROMsquare = f; X TOsquare = t; X *INCscore = 0; X GameList[GameCnt].gmove = (f << 8) | t; X GameList[GameCnt].flags = node->flags; X if (node->flags & cstlmask) X { X GameList[GameCnt].piece = no_piece; X GameList[GameCnt].color = side; X (void) castle (side, f, t, 1); X } X else X { X if (!(node->flags & capture) && (board[f] != pawn)) X rpthash[side][hashkey & 0xFF]++; X *tempc = color[t]; X *tempb = board[t]; X *tempsf = svalue[f]; X *tempst = svalue[t]; X GameList[GameCnt].piece = *tempb; X GameList[GameCnt].color = *tempc; X if (*tempc != neutral) X { X UpdatePieceList (*tempc, t, 1); X if (*tempb == pawn) X --PawnCnt[*tempc][column (t)]; X if (board[f] == pawn) X { X --PawnCnt[side][column (f)]; X ++PawnCnt[side][column (t)]; X cf = column (f); X ct = column (t); X if (PawnCnt[side][ct] > 1 + PawnCnt[side][cf]) X *INCscore -= 15; X else if (PawnCnt[side][ct] < 1 + PawnCnt[side][cf]) X *INCscore += 15; X else if (ct == 0 || ct == 7 || PawnCnt[side][ct + ct - cf] == 0) X *INCscore -= 15; X } X mtl[xside] -= value[*tempb]; X if (*tempb == pawn) X pmtl[xside] -= valueP; #if ttblsz X UpdateHashbd (xside, *tempb, -1, t); #endif /* ttblsz */ X *INCscore += *tempst; X Mvboard[t]++; X } X color[t] = color[f]; X board[t] = board[f]; X svalue[t] = svalue[f]; X Pindex[t] = Pindex[f]; X PieceList[side][Pindex[t]] = t; X color[f] = neutral; X board[f] = no_piece; X if (board[t] == pawn) X if (t - f == 16) X epsquare = f + 8; X else if (f - t == 16) X epsquare = f - 8; X if (node->flags & promote) X { X board[t] = node->flags & pmask; X if (board[t] == queen) X HasQueen[side]++; X else if (board[t] == rook) X HasRook[side]++; X else if (board[t] == bishop) X HasBishop[side]++; X else if (board[t] == knight) X HasKnight[side]++; X --PawnCnt[side][column (t)]; X mtl[side] += value[board[t]] - valueP; X pmtl[side] -= valueP; #if ttblsz X UpdateHashbd (side, pawn, f, -1); X UpdateHashbd (side, board[t], f, -1); #endif /* ttblsz */ X *INCscore -= *tempsf; X } X if (node->flags & epmask) X EnPassant (xside, f, t, 1); X else #if ttblsz X UpdateHashbd (side, board[t], f, t); #else X /* NOOP */ ; #endif /* ttblsz */ X Mvboard[f]++; X } } X void UnmakeMove (short int side, X struct leaf * node, X short int *tempb, X short int *tempc, X short int *tempsf, X short int *tempst) X /* X Take back a move. */ X { X register short f, t, xside; X X xside = otherside[side]; X f = node->f; X t = node->t; X epsquare = -1; X GameCnt--; X if (node->flags & cstlmask) X (void) castle (side, f, t, 2); X else X { X color[f] = color[t]; X board[f] = board[t]; X svalue[f] = *tempsf; X Pindex[f] = Pindex[t]; X PieceList[side][Pindex[f]] = f; X color[t] = *tempc; X board[t] = *tempb; X svalue[t] = *tempst; X if (node->flags & promote) X { X board[f] = pawn; X ++PawnCnt[side][column (t)]; X mtl[side] += valueP - value[node->flags & pmask]; X pmtl[side] += valueP; #if ttblsz X UpdateHashbd (side, (short) node->flags & pmask, -1, t); X UpdateHashbd (side, pawn, -1, t); #endif /* ttblsz */ X } X if (*tempc != neutral) X { X UpdatePieceList (*tempc, t, 2); X if (*tempb == pawn) X ++PawnCnt[*tempc][column (t)]; X if (board[f] == pawn) X { X --PawnCnt[side][column (t)]; X ++PawnCnt[side][column (f)]; X } X mtl[xside] += value[*tempb]; X if (*tempb == pawn) X pmtl[xside] += valueP; #if ttblsz X UpdateHashbd (xside, *tempb, -1, t); #endif /* ttblsz */ X Mvboard[t]--; X } X if (node->flags & epmask) X EnPassant (xside, f, t, 2); X else #if ttblsz X UpdateHashbd (side, board[f], f, t); #else X /* NOOP */ ; #endif /* ttblsz */ X Mvboard[f]--; X if (!(node->flags & capture) && (board[f] != pawn)) X rpthash[side][hashkey & 0xFF]--; X } } X X void InitializeStats (void) X /* X Scan thru the board seeing what's on each square. If a piece is found, X update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also X determine the material for each side and set the hashkey and hashbd X variables to represent the current board position. Array X PieceList[side][indx] contains the location of all the pieces of either X side. Array Pindex[sq] contains the indx into PieceList for a given X square. */ X { X register short i, sq; X epsquare = -1; X for (i = 0; i < 8; i++) X PawnCnt[white][i] = PawnCnt[black][i] = 0; X mtl[white] = mtl[black] = pmtl[white] = pmtl[black] = 0; X PieceCnt[white] = PieceCnt[black] = 0; #if ttblsz X hashbd = hashkey = 0; #endif /* ttblsz */ X for (sq = 0; sq < 64; sq++) X if (color[sq] != neutral) X { X mtl[color[sq]] += value[board[sq]]; X if (board[sq] == pawn) X { X pmtl[color[sq]] += valueP; X ++PawnCnt[color[sq]][column (sq)]; X } X Pindex[sq] = (board[sq] == king) ? 0 : ++PieceCnt[color[sq]]; X PieceList[color[sq]][Pindex[sq]] = sq; #if ttblsz X hashbd ^= hashcode[color[sq]][board[sq]][sq].bd; X hashkey ^= hashcode[color[sq]][board[sq]][sq].key; #endif /* ttblsz */ X } } X X int SqAtakd (short int sq, short int side) X /* X See if any piece with color 'side' ataks sq. First check pawns then Queen, X Bishop, Rook and King and last Knight. */ X { X register short u; X register unsigned char *ppos, *pdir; X short xside; X X xside = otherside[side]; X pdir = nextdir[ptype[xside][pawn]][sq]; X u = pdir[sq]; /* follow captures thread */ X if (u != sq) X { X if (board[u] == pawn && color[u] == side) X return (true); X u = pdir[u]; X if (u != sq && board[u] == pawn && color[u] == side) X return (true); X } X /* king capture */ X if (distance (sq, PieceList[side][0]) == 1) X return (true); X /* try a queen bishop capture */ X ppos = nextpos[bishop][sq]; X pdir = nextdir[bishop][sq]; X u = ppos[sq]; X do X { X if (color[u] == neutral) X u = ppos[u]; X else X { X if (color[u] == side && (board[u] == queen || board[u] == bishop)) X return (true); X u = pdir[u]; X } X } while (u != sq); X /* try a queen rook capture */ X ppos = nextpos[rook][sq]; X pdir = nextdir[rook][sq]; X u = ppos[sq]; X do X { X if (color[u] == neutral) X u = ppos[u]; X else X { X if (color[u] == side && (board[u] == queen || board[u] == rook)) X return (true); X u = pdir[u]; X } X } while (u != sq); X /* try a knight capture */ X pdir = nextdir[knight][sq]; X u = pdir[sq]; X do X { X if (color[u] == side && board[u] == knight) X return (true); X u = pdir[u]; X } while (u != sq); X return (false); } X static inline void ataks (short int side, short int *a) X /* X Fill array atak[][] with info about ataks to a square. Bits 8-15 are set X if the piece (king..pawn) ataks the square. Bits 0-7 contain a count of X total ataks to the square. */ X { X register short u, c, sq; X register unsigned char *ppos, *pdir; X short i, piece, *PL; X #ifdef NOMEMSET X for (u = 64; u; a[--u] = 0) ; #else X memset ((char *) a, 0, 64 * sizeof (a[0])); #endif /* NOMEMSET */ X PL = PieceList[side]; X for (i = PieceCnt[side]; i >= 0; i--) X { X sq = PL[i]; X piece = board[sq]; X c = control[piece]; X if (sweep[piece]) X { X ppos = nextpos[piece][sq]; X pdir = nextdir[piece][sq]; X u = ppos[sq]; X do X { X a[u] = ++a[u] | c; X u = (color[u] == neutral) ? ppos[u] : pdir[u]; X } while (u != sq); X } X else X { X pdir = nextdir[ptype[side][piece]][sq]; X u = pdir[sq]; /* follow captures thread for pawns */ X do X { X a[u] = ++a[u] | c; X u = pdir[u]; X } while (u != sq); X } X } } X X /* ............ POSITIONAL EVALUATION ROUTINES ............ */ X int evaluate (short int side, X short int ply, X short int alpha, X short int beta, X short int INCscore, X short int *slk, X short int *InChk) X /* X Compute an estimate of the score by adding the positional score from the X previous ply to the material difference. If this score falls inside a X window which is 180 points wider than the alpha-beta window (or within a X 50 point window during quiescence search) call ScorePosition() to X determine a score, otherwise return the estimated score. If one side has X only a king and the other either has no pawns or no pieces then the X function ScoreLoneKing() is called. */ X { X register short evflag, xside; X short s; X X xside = otherside[side]; X s = -Pscore[ply - 1] + mtl[side] - mtl[xside] - INCscore; X hung[white] = hung[black] = 0; X *slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) || X (mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0))); X X if (*slk) X evflag = false; X else X evflag = (ply == 1 || ply < Sdepth || X ((ply == Sdepth + 1 || ply == Sdepth + 2) && X (s > alpha - xwndw && s < beta + xwndw)) || X (ply > Sdepth + 2 && s >= alpha - 25 && s <= beta + 25)); X X if (evflag) X { X EvalNodes++; X ataks (side, atak[side]); X if (Anyatak (side, PieceList[xside][0])) X return (10001 - ply); X ataks (xside, atak[xside]); X *InChk = Anyatak (xside, PieceList[side][0]); X ScorePosition (side, &s); X } X else X { X if (SqAtakd (PieceList[xside][0], side)) X return (10001 - ply); X *InChk = SqAtakd (PieceList[side][0], xside); X if (*slk) X ScoreLoneKing (side, &s); X } X X Pscore[ply] = s - mtl[side] + mtl[xside]; X if (*InChk) X ChkFlag[ply - 1] = Pindex[TOsquare]; X else X ChkFlag[ply - 1] = 0; X return (s); } X X static inline int ScoreKPK (short int side, X short int winner, X short int loser, X short int king1, X short int king2, X short int sq) X /* X Score King and Pawns versus King endings. */ X { X register short s, r; X X if (PieceCnt[winner] == 1) X s = 50; X else X s = 120; X if (winner == white) X { X if (side == loser) X r = row (sq) - 1; X else X r = row (sq); X if (row (king2) >= r && distance (sq, king2) < 8 - r) X s += 10 * row (sq); X else X s = 500 + 50 * row (sq); X if (row (sq) < 6) X sq += 16; X else if (row (sq) == 6) X sq += 8; X } X else X { X if (side == loser) X r = row (sq) + 1; X else X r = row (sq); X if (row (king2) <= r && distance (sq, king2) < r + 1) X s += 10 * (7 - row (sq)); X else X s = 500 + 50 * (7 - row (sq)); X if (row (sq) > 1) X sq -= 16; X else if (row (sq) == 1) X sq -= 8; X } X s += 8 * (taxicab (king2, sq) - taxicab (king1, sq)); X return (s); } X X static inline int ScoreKBNK (short int winner, short int king1, short int king2) X X /* X Score King+Bishop+Knight versus King endings. X This doesn't work all that well but it's better than nothing. */ X { X register short s, sq, KBNKsq = 0; X X for (sq = 0; sq < 64; sq++) X if (board[sq] == bishop) X if (row (sq) % 2 == column (sq) % 2) X KBNKsq = 0; X else X KBNKsq = 7; X X s = emtl[winner] - 300; X if (KBNKsq == 0) X s += KBNK[king2]; X else X s += KBNK[locn (row (king2), 7 - column (king2))]; X s -= taxicab (king1, king2); X s -= distance (PieceList[winner][1], king2); X s -= distance (PieceList[winner][2], king2); X return (s); } X X void ScoreLoneKing (short int side, short int *score) X /* X Static evaluation when loser has only a king and winner has no pawns or no X pieces. */ X { X register short winner, loser, king1, king2, s, i; X X UpdateWeights (); X if (mtl[white] > mtl[black]) X winner = white; X else X winner = black; X loser = otherside[winner]; X king1 = PieceList[winner][0]; X king2 = PieceList[loser][0]; X X s = 0; X X if (pmtl[winner] > 0) X for (i = 1; i <= PieceCnt[winner]; i++) X s += ScoreKPK (side, winner, loser, king1, king2, PieceList[winner][i]); X X else if (emtl[winner] == valueB + valueN) X s = ScoreKBNK (winner, king1, king2); X X else if (emtl[winner] > valueB) X s = 500 + emtl[winner] - DyingKing[king2] - 2 * distance (king1, king2); X X if (side == winner) X *score = s; X else X *score = -s; } X X static inline void BRscan (short int sq, short int *s, short int *mob) X /* X Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the X hung[] array if a pin is found. */ { X register short u, piece, pin; X register unsigned char *ppos, *pdir; X short *Kf; X X Kf = Kfield[c1]; X *mob = 0; X piece = board[sq]; X ppos = nextpos[piece][sq]; X pdir = nextdir[piece][sq]; X u = ppos[sq]; X pin = -1; /* start new direction */ X do X { X *s += Kf[u]; X if (color[u] == neutral) X { X (*mob)++; X if (ppos[u] == pdir[u]) X pin = -1; /* oops new direction */ X u = ppos[u]; X } X else if (pin < 0) X { X if (board[u] == pawn || board[u] == king) X u = pdir[u]; X else X { X if (ppos[u] != pdir[u]) X pin = u; /* not on the edge and on to find a pin */ X u = ppos[u]; X } X } X else X { X if (color[u] == c2 && (board[u] > piece || atk2[u] == 0)) X { X if (color[pin] == c2) X { X *s += PINVAL; X if (atk2[pin] == 0 || X atk1[pin] > control[board[pin]] + 1) X ++hung[c2]; X } X else X *s += XRAY; X } X pin = -1; /* new direction */ X u = pdir[u]; X } X } while (u != sq); } X X static inline void KingScan (short int sq, short int *s) X /* X Assign penalties if king can be threatened by checks, if squares X near the king are controlled by the enemy (especially the queen), X or if there are no pawns near the king. X The following must be true: X board[sq] == king X c1 == color[sq] X c2 == otherside[c1] */ X #define ScoreThreat \ X if (color[u] != c2)\ X if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) ++cnt;\ X else *s -= 3 X { X register short u; X register unsigned char *ppos, *pdir; X register short cnt, ok; X X cnt = 0; X if (HasBishop[c2] || HasQueen[c2]) X { X ppos = nextpos[bishop][sq]; X pdir = nextdir[bishop][sq]; X u = ppos[sq]; X do X { X if (atk2[u] & ctlBQ) X ScoreThreat; X u = (color[u] == neutral) ? ppos[u] : pdir[u]; X } while (u != sq); X } X if (HasRook[c2] || HasQueen[c2]) X { X ppos = nextpos[rook][sq]; X pdir = nextdir[rook][sq]; X u = ppos[sq]; X do X { X if (atk2[u] & ctlRQ) X ScoreThreat; X u = (color[u] == neutral) ? ppos[u] : pdir[u]; X } while (u != sq); X } X if (HasKnight[c2]) X { X pdir = nextdir[knight][sq]; X u = pdir[sq]; X do X { X if (atk2[u] & ctlNN) X ScoreThreat; X u = pdir[u]; X } while (u != sq); X } X *s += (KSFTY * KTHRT[cnt]) / 16; X X cnt = 0; X ok = false; X pdir = nextpos[king][sq]; X u = pdir[sq]; X do X { X if (board[u] == pawn) X ok = true; X if (atk2[u] > atk1[u]) X { X ++cnt; X if (atk2[u] & ctlQ) X if (atk2[u] > ctlQ + 1 && atk1[u] < ctlQ) X *s -= 4 * KSFTY; X } X u = pdir[u]; X } while (u != sq); X if (!ok) X *s -= KSFTY; X if (cnt > 1) X *s -= KSFTY; } X X static inline int trapped (short int sq) X /* X See if the attacked piece has unattacked squares to move to. X The following must be true: X c1 == color[sq] X c2 == otherside[c1] */ X { X register short u, piece; X register unsigned char *ppos, *pdir; X X piece = board[sq]; X ppos = nextpos[ptype[c1][piece]][sq]; X pdir = nextdir[ptype[c1][piece]][sq]; X if (piece == pawn) X { X u = ppos[sq]; /* follow no captures thread */ X if (color[u] == neutral) X { X if (atk1[u] >= atk2[u]) X return (false); X if (atk2[u] < ctlP) X { X u = ppos[u]; X if (color[u] == neutral && atk1[u] >= atk2[u]) X return (false); X } X } X u = pdir[sq]; /* follow captures thread */ X if (color[u] == c2) X return (false); X u = pdir[u]; X if (color[u] == c2) X return (false); X } X else X { X u = ppos[sq]; X do X { X if (color[u] != c1) X if (atk2[u] == 0 || board[u] >= piece) X return (false); X u = (color[u] == neutral) ? ppos[u] : pdir[u]; X } while (u != sq); X } X return (true); } X X static inline int PawnValue (short int sq, short int side) X /* X Calculate the positional value for a pawn on 'sq'. */ X { X register short j, fyle, rank; X register short s, a1, a2, in_square, r, e; X X a1 = (atk1[sq] & 0x4FFF); X a2 = (atk2[sq] & 0x4FFF); X rank = row (sq); X fyle = column (sq); X s = 0; X if (c1 == white) X { X s = Mwpawn[sq]; X if ((sq == 11 && color[19] != neutral) X || (sq == 12 && color[20] != neutral)) X s += PEDRNK2B; X if ((fyle == 0 || PC1[fyle - 1] == 0) X && (fyle == 7 || PC1[fyle + 1] == 0)) X s += ISOLANI[fyle]; X else if (PC1[fyle] > 1) X s += PDOUBLED; X if (a1 < ctlP && atk1[sq + 8] < ctlP) X { X s += BACKWARD[a2 & 0xFF]; X if (PC2[fyle] == 0) X s += PWEAKH; X if (color[sq + 8] != neutral) X s += PBLOK; X } X if (PC2[fyle] == 0) X { X if (side == black) X r = rank - 1; X else X r = rank; X in_square = (row (bking) >= r && distance (sq, bking) < 8 - r); X if (a2 == 0 || side == white) X e = 0; X else X e = 1; X for (j = sq + 8; j < 64; j += 8) X if (atk2[j] >= ctlP) X { X e = 2; X break; X } X else if (atk2[j] > 0 || color[j] != neutral) X e = 1; X if (e == 2) X s += (stage * PassedPawn3[rank]) / 10; X else if (in_square || e == 1) X s += (stage * PassedPawn2[rank]) / 10; X else if (emtl[black] > 0) X s += (stage * PassedPawn1[rank]) / 10; X else X s += PassedPawn0[rank]; X } X } X else if (c1 == black) X { X s = Mbpawn[sq]; X if ((sq == 51 && color[43] != neutral) X || (sq == 52 && color[44] != neutral)) X s += PEDRNK2B; X if ((fyle == 0 || PC1[fyle - 1] == 0) && X (fyle == 7 || PC1[fyle + 1] == 0)) X s += ISOLANI[fyle]; X else if (PC1[fyle] > 1) X s += PDOUBLED; X if (a1 < ctlP && atk1[sq - 8] < ctlP) X { X s += BACKWARD[a2 & 0xFF]; X if (PC2[fyle] == 0) X s += PWEAKH; X if (color[sq - 8] != neutral) X s += PBLOK; X } X if (PC2[fyle] == 0) X { X if (side == white) X r = rank + 1; X else X r = rank; X in_square = (row (wking) <= r && distance (sq, wking) < r + 1); X if (a2 == 0 || side == black) X e = 0; X else X e = 1; X for (j = sq - 8; j >= 0; j -= 8) X if (atk2[j] >= ctlP) X { X e = 2; X break; X } X else if (atk2[j] > 0 || color[j] != neutral) X e = 1; X if (e == 2) X s += (stage * PassedPawn3[7 - rank]) / 10; X else if (in_square || e == 1) X s += (stage * PassedPawn2[7 - rank]) / 10; X else if (emtl[white] > 0) X s += (stage * PassedPawn1[7 - rank]) / 10; X else X s += PassedPawn0[7 - rank]; X } X } X if (a2 > 0) X { X if (a1 == 0 || a2 > ctlP + 1) X { X s += HUNGP; X ++hung[c1]; X if (trapped (sq)) X ++hung[c1]; X } X else if (a2 > a1) X s += ATAKD; X } X return (s); } X X static inline int KnightValue (short int sq, short int side) X /* X Calculate the positional value for a knight on 'sq'. */ X { X register short s, a2, a1; X X s = Mknight[c1][sq]; X a2 = (atk2[sq] & 0x4FFF); X if (a2 > 0) X { X a1 = (atk1[sq] & 0x4FFF); X if (a1 == 0 || a2 > ctlBN + 1) X { X s += HUNGP; X ++hung[c1]; X if (trapped (sq)) X ++hung[c1]; X } X else if (a2 >= ctlBN || a1 < ctlP) X s += ATAKD; X } X return (s); } X X static inline int BishopValue (short int sq, short int side) X /* X Calculate the positional value for a bishop on 'sq'. */ X { X register short a2, a1; X short s, mob; X X s = Mbishop[c1][sq]; X BRscan (sq, &s, &mob); X s += BMBLTY[mob]; X a2 = (atk2[sq] & 0x4FFF); X if (a2 > 0) X { X a1 = (atk1[sq] & 0x4FFF); X if (a1 == 0 || a2 > ctlBN + 1) X { X s += HUNGP; X ++hung[c1]; X if (trapped (sq)) X ++hung[c1]; X } X else if (a2 >= ctlBN || a1 < ctlP) X s += ATAKD; X } X return (s); } X X static inline int RookValue (short int sq, short int side) X /* X Calculate the positional value for a rook on 'sq'. */ X { X register short fyle, a2, a1; X short s, mob; X X s = RookBonus; X BRscan (sq, &s, &mob); X s += RMBLTY[mob]; X fyle = column (sq); X if (PC1[fyle] == 0) X s += RHOPN; X if (PC2[fyle] == 0) X s += RHOPNX; X if (pmtl[c2] > 100 && row (sq) == rank7[c1]) X s += 10; X if (stage > 2) X s += 14 - taxicab (sq, EnemyKing); X a2 = (atk2[sq] & 0x4FFF); X if (a2 > 0) X { X a1 = (atk1[sq] & 0x4FFF); X if (a1 == 0 || a2 > ctlR + 1) X { X s += HUNGP; X ++hung[c1]; X X if (trapped (sq)) X ++hung[c1]; X } X else if (a2 >= ctlR || a1 < ctlP) X s += ATAKD; X } X return (s); } X X static inline int QueenValue (short int sq, short int side) X /* X Calculate the positional value for a queen on 'sq'. */ X { X register short s, a2, a1; X X s = (distance (sq, EnemyKing) < 3) ? 12 : 0; X if (stage > 2) X s += 14 - taxicab (sq, EnemyKing); X a2 = (atk2[sq] & 0x4FFF); X if (a2 > 0) X { X a1 = (atk1[sq] & 0x4FFF); X if (a1 == 0 || a2 > ctlQ + 1) X { X s += HUNGP; X ++hung[c1]; X if (trapped (sq)) X ++hung[c1]; X } X else if (a2 >= ctlQ || a1 < ctlP) X s += ATAKD; X } X return (s); } X X static inline int KingValue (short int sq, short int side) X /* X Calculate the positional value for a king on 'sq'. */ X { X register short fyle, a2, a1; X short s; X X s = Mking[c1][sq]; X if (KSFTY > 0) X if (Developed[c2] || stage > 0) X KingScan (sq, &s); X if (castld[c1]) X s += KCASTLD; X else if (Mvboard[kingP[c1]]) X s += KMOVD; X X fyle = column (sq); X if (PC1[fyle] == 0) X s += KHOPN; X if (PC2[fyle] == 0) X s += KHOPNX; X switch (fyle) X { X case 5: X if (PC1[7] == 0) X s += KHOPN; X if (PC2[7] == 0) X s += KHOPNX; X /* Fall through */ X case 4: X case 6: X case 0: X if (PC1[fyle + 1] == 0) X s += KHOPN; X if (PC2[fyle + 1] == 0) X s += KHOPNX; X break; X case 2: X if (PC1[0] == 0) X s += KHOPN; X if (PC2[0] == 0) X s += KHOPNX; X /* Fall through */ X case 3: X case 1: X case 7: X if (PC1[fyle - 1] == 0) X s += KHOPN; X if (PC2[fyle - 1] == 0) X s += KHOPNX; X break; X default: X /* Impossible! */ X break; X } X X a2 = (atk2[sq] & 0x4FFF); X if (a2 > 0) X { X a1 = (atk1[sq] & 0x4FFF); X if (a1 == 0 || a2 > ctlK + 1) X { X s += HUNGP; X ++hung[c1]; X } X else X s += ATAKD; X } X return (s); } X X void ScorePosition (short int side, short int *score) X /* X Perform normal static evaluation of board position. A score is generated X for each piece and these are summed to get a score for each side. */ X { X register short sq, s, i, xside; X short pscore[2]; X X UpdateWeights (); X xside = otherside[side]; X pscore[white] = pscore[black] = 0; X X for (c1 = white; c1 <= black; c1++) X { X c2 = otherside[c1]; X atk1 = atak[c1]; X atk2 = atak[c2]; X PC1 = PawnCnt[c1]; X PC2 = PawnCnt[c2]; X for (i = PieceCnt[c1]; i >= 0; i--) X { X sq = PieceList[c1][i]; X switch (board[sq]) X { X case pawn: X s = PawnValue (sq, side); X break; SHAR_EOF true || echo 'restore of gnuchess.c failed' fi echo 'End of part 4' echo 'File gnuchess.c is continued in part 5' echo 5 > _shar_seq_.tmp exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.