v19i076: gnuchess - gnuchess version 3.1+, Part04/07
Mike McGann
mwm at hasler.ascom.ch
Fri May 17 12:45:06 AEST 1991
Submitted-by: Mike McGann <mwm at 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 at 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 at uunet.uu.net.
More information about the Comp.sources.misc
mailing list