home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
games
/
volume4
/
gnuchess2
/
part04
/
gnuchess.c2
Wrap
Text File
|
1988-06-10
|
20KB
|
683 lines
/* ............ POSITIONAL EVALUATION ROUTINES ............ */
ScorePosition(side,score)
short side,*score;
/*
Perform normal static evaluation of board position. A score is
generated for each piece and these are summed to get a score for each
side.
*/
{
register short sq,s,i,xside;
short pscore[3];
wking = PieceList[white][0]; bking = PieceList[black][0];
UpdateWeights();
xside = otherside[side];
pscore[white] = pscore[black] = 0;
for (c1 = white; c1 <= black; c1++)
{
c2 = otherside[c1];
if (c1 == white) EnemyKing = bking; else EnemyKing = wking;
atk1 = atak[c1]; atk2 = atak[c2];
PC1 = PawnCnt[c1]; PC2 = PawnCnt[c2];
for (i = 0; i <= PieceCnt[c1]; i++)
{
sq = PieceList[c1][i];
s = SqValue(sq,side);
pscore[c1] += s;
svalue[sq] = s;
}
}
if (hung[side] > 1) pscore[side] += HUNGX;
if (hung[xside] > 1) pscore[xside] += HUNGX;
*score = mtl[side] - mtl[xside] + pscore[side] - pscore[xside] + 10;
if (dither) *score += rand() % dither;
if (*score > 0 && pmtl[side] == 0)
if (emtl[side] < valueR) *score = 0;
else if (*score < valueR) *score /= 2;
if (*score < 0 && pmtl[xside] == 0)
if (emtl[xside] < valueR) *score = 0;
else if (-*score < valueR) *score /= 2;
if (mtl[xside] == valueK && emtl[side] > valueB) *score += 200;
if (mtl[side] == valueK && emtl[xside] > valueB) *score -= 200;
}
ScoreLoneKing(side,score)
short side,*score;
/*
Static evaluation when loser has only a king and winner has no pawns
or no pieces.
*/
{
register short winner,loser,king1,king2,s,i;
UpdateWeights();
if (mtl[white] > mtl[black]) winner = white; else winner = black;
loser = otherside[winner];
king1 = PieceList[winner][0]; king2 = PieceList[loser][0];
s = 0;
if (pmtl[winner] > 0)
for (i = 1; i <= PieceCnt[winner]; i++)
s += ScoreKPK(side,winner,loser,king1,king2,PieceList[winner][i]);
else if (emtl[winner] == valueB+valueN)
s = ScoreKBNK(winner,king1,king2);
else if (emtl[winner] > valueB)
s = 500 + emtl[winner] - 2*KingEnding[king2] - 2*distance(king1,king2);
if (side == winner) *score = s; else *score = -s;
}
int ScoreKPK(side,winner,loser,king1,king2,sq)
short side,winner,loser,king1,king2,sq;
/*
Score King and Pawns versus King endings.
*/
{
register short s,r;
if (PieceCnt[winner] == 1) s = 50; else s = 120;
if (winner == white)
{
if (side == loser) r = row[sq]-1; else r = row[sq];
if (row[king2] >= r && distance(sq,king2) < 8-r) s += 10*row[sq];
else s = 500+50*row[sq];
if (row[sq] < 6) sq += 16; else sq += 8;
}
else
{
if (side == loser) r = row[sq]+1; else r = row[sq];
if (row[king2] <= r && distance(sq,king2) < r+1) s += 10*(7-row[sq]);
else s = 500+50*(7-row[sq]);
if (row[sq] > 1) sq -= 16; else sq -= 8;
}
s += 8*(taxicab(king2,sq) - taxicab(king1,sq));
return(s);
}
int ScoreKBNK(winner,king1,king2)
short winner,king1,king2;
/*
Score King+Bishop+Knight versus King endings.
This doesn't work all that well but it's better than nothing.
*/
{
register short s;
s = emtl[winner] - 300;
if (KBNKsq == 0) s += KBNK[king2];
else s += KBNK[locn[row[king2]][7-column[king2]]];
s -= taxicab(king1,king2);
s -= distance(PieceList[winner][1],king2);
s -= distance(PieceList[winner][2],king2);
return(s);
}
SqValue(sq,side)
short sq,side;
/*
Calculate the positional value for the piece on 'sq'.
*/
{
register short j,fyle,rank,a1,a2;
short s,piece,in_square,r,mob,e,c;
piece = board[sq];
a1 = (atk1[sq] & 0x4FFF); a2 = (atk2[sq] & 0x4FFF);
rank = row[sq]; fyle = column[sq];
s = 0;
if (piece == pawn && c1 == white)
{
s = Mwpawn[sq];
if (sq == 11 || sq == 12)
if (color[sq+8] != neutral) s += PEDRNK2B;
if ((fyle == 0 || PC1[fyle-1] == 0) &&
(fyle == 7 || PC1[fyle+1] == 0))
s += ISOLANI[fyle];
else if (PC1[fyle] > 1) s += PDOUBLED;
if (a1 < ctlP && atk1[sq+8] < ctlP)
{
s += BACKWARD[a2 & 0xFF];
if (PC2[fyle] == 0) s += PWEAKH;
if (color[sq+8] != neutral) s += PBLOK;
}
if (PC2[fyle] == 0)
{
if (side == black) r = rank-1; else r = rank;
in_square = (row[bking] >= r && distance(sq,bking) < 8-r);
if (a2 == 0 || side == white) e = 0; else e = 1;
for (j = sq+8; j < 64; j += 8)
if (atk2[j] >= ctlP) { e = 2; break; }
else if (atk2[j] > 0 || color[j] != neutral) e = 1;
if (e == 2) s += (stage*PassedPawn3[rank]) / 10;
else if (in_square || e == 1) s += (stage*PassedPawn2[rank]) / 10;
else if (emtl[black] > 0) s += (stage*PassedPawn1[rank]) / 10;
else s += PassedPawn0[rank];
}
}
else if (piece == pawn && c1 == black)
{
s = Mbpawn[sq];
if (sq == 51 || sq == 52)
if (color[sq-8] != neutral) s += PEDRNK2B;
if ((fyle == 0 || PC1[fyle-1] == 0) &&
(fyle == 7 || PC1[fyle+1] == 0))
s += ISOLANI[fyle];
else if (PC1[fyle] > 1) s += PDOUBLED;
if (a1 < ctlP && atk1[sq-8] < ctlP)
{
s += BACKWARD[a2 & 0xFF];
if (PC2[fyle] == 0) s += PWEAKH;
if (color[sq-8] != neutral) s += PBLOK;
}
if (PC2[fyle] == 0)
{
if (side == white) r = rank+1; else r = rank;
in_square = (row[wking] <= r && distance(sq,wking) < r+1);
if (a2 == 0 || side == black) e = 0; else e = 1;
for (j = sq-8; j >= 0; j -= 8)
if (atk2[j] >= ctlP) { e = 2; break; }
else if (atk2[j] > 0 || color[j] != neutral) e = 1;
if (e == 2) s += (stage*PassedPawn3[7-rank]) / 10;
else if (in_square || e == 1) s += (stage*PassedPawn2[7-rank]) / 10;
else if (emtl[white] > 0) s += (stage*PassedPawn1[7-rank]) / 10;
else s += PassedPawn0[7-rank];
}
}
else if (piece == knight)
{
s = Mknight[c1][sq];
}
else if (piece == bishop)
{
s = Mbishop[c1][sq];
BRscan(sq,&s,&mob);
s += BMBLTY[mob];
}
else if (piece == rook)
{
s += RookBonus;
BRscan(sq,&s,&mob);
s += RMBLTY[mob];
if (PC1[fyle] == 0) s += RHOPN;
if (PC2[fyle] == 0) s += RHOPNX;
if (rank == rank7[c1] && pmtl[c2] > 100) s += 10;
if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
}
else if (piece == queen)
{
if (stage > 2) s += 14 - taxicab(sq,EnemyKing);
if (distance(sq,EnemyKing) < 3) s += 12;
}
else if (piece == king)
{
s = Mking[c1][sq];
if (KSFTY > 0)
if (Developed[c2] || stage > 0) KingScan(sq,&s);
if (castld[c1]) s += KCASTLD;
else if (kingmoved[c1]) s += KMOVD;
if (PC1[fyle] == 0) s += KHOPN;
if (PC2[fyle] == 0) s += KHOPNX;
if (fyle == 1 || fyle == 2 || fyle == 3 || fyle == 7)
{
if (PC1[fyle-1] == 0) s += KHOPN;
if (PC2[fyle-1] == 0) s += KHOPNX;
}
if (fyle == 4 || fyle == 5 || fyle == 6 || fyle == 0)
{
if (PC1[fyle+1] == 0) s += KHOPN;
if (PC2[fyle+1] == 0) s += KHOPNX;
}
if (fyle == 2)
{
if (PC1[0] == 0) s += KHOPN;
if (PC2[0] == 0) s += KHOPNX;
}
if (fyle == 5)
{
if (PC1[7] == 0) s += KHOPN;
if (PC2[7] == 0) s += KHOPNX;
}
}
if (a2 > 0)
{
c = (control[piece] & 0x4FFF);
if (a1 == 0 || a2 > c+1)
{
s += HUNGP;
++hung[c1];
if (piece != king && trapped(sq,piece)) ++hung[c1];
}
else if (piece != pawn || a2 > a1)
if (a2 >= c || a1 < ctlP) s += ATAKD;
}
return(s);
}
KingScan(sq,s)
short sq,*s;
/*
Assign penalties if king can be threatened by checks, if squares
near the king are controlled by the enemy (especially the queen),
or if there are no pawns near the king.
*/
#define ScoreThreat\
if (color[u] != c2)\
if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) ++cnt;\
else *s -= 3
{
register short m,u,d,i,m0,cnt,ok;
cnt = 0;
m0 = map[sq];
if (HasBishop[c2] || HasQueen[c2])
for (i = Dstart[bishop]; i <= Dstop[bishop]; i++)
{
d = Dir[i]; m = m0+d;
while (!(m & 0x88))
{
u = unmap[m];
if (atk2[u] & ctlBQ) ScoreThreat;
if (color[u] != neutral) break;
m += d;
}
}
if (HasRook[c2] || HasQueen[c2])
for (i = Dstart[rook]; i <= Dstop[rook]; i++)
{
d = Dir[i]; m = m0+d;
while (!(m & 0x88))
{
u = unmap[m];
if (atk2[u] & ctlRQ) ScoreThreat;
if (color[u] != neutral) break;
m += d;
}
}
if (HasKnight[c2])
for (i = Dstart[knight]; i <= Dstop[knight]; i++)
if (!((m = m0+Dir[i]) & 0x88))
{
u = unmap[m];
if (atk2[u] & ctlNN) ScoreThreat;
}
*s += (KSFTY*Kthreat[cnt]) / 16;
cnt = 0; ok = false;
m0 = map[sq];
for (i = Dstart[king]; i <= Dstop[king]; i++)
if (!((m = m0+Dir[i]) & 0x88))
{
u = unmap[m];
if (board[u] == pawn) ok = true;
if (atk2[u] > atk1[u])
{
++cnt;
if (atk2[u] & ctlQ)
if (atk2[u] > ctlQ+1 && atk1[u] < ctlQ) *s -= 4*KSFTY;
}
}
if (!ok) *s -= KSFTY;
if (cnt > 1) *s -= KSFTY;
}
BRscan(sq,s,mob)
short sq,*s,*mob;
/*
Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
hung[] array if a pin is found.
*/
{
register short m,u,d,m0,j,piece,pin;
short *Kf;
Kf = Kfield[c1];
*mob = 0;
m0 = map[sq]; piece = board[sq];
for (j = Dstart[piece]; j <= Dstop[piece]; j++)
{
pin = -1;
d = Dir[j]; m = m0+d;
while (!(m & 0x88))
{
u = unmap[m]; *s += Kf[u];
if (color[u] == neutral)
{
(*mob)++;
m += d;
}
else if (pin < 0)
{
if (board[u] == pawn || board[u] == king) break;
pin = u;
m += d;
}
else if (color[u] == c2 && (board[u] > piece || atk2[u] == 0))
{
if (color[pin] == c2)
{
*s += PINVAL;
if (atk2[pin] == 0 ||
atk1[pin] > control[board[pin]]+1)
++hung[c2];
}
else *s += XRAY;
break;
}
else break;
}
}
}
int trapped(sq,piece)
short sq,piece;
/*
See if the attacked piece has unattacked squares to move to.
*/
{
register short u,m,d,i,m0;
m0 = map[sq];
if (sweep[piece])
for (i = Dstart[piece]; i <= Dstop[piece]; i++)
{
d = Dir[i]; m = m0+d;
while (!(m & 0x88))
{
u = unmap[m];
if (color[u] == c1) break;
if (atk2[u] == 0 || board[u] >= piece) return(false);
if (color[u] == c2) break;
m += d;
}
}
else if (piece == pawn)
{
if (c1 == white) u = sq+8; else u = sq-8;
if (color[u] == neutral && atk1[u] >= atk2[u])
return(false);
if (!((m = m0+Dir[Dpwn[c1]]) & 0x88))
if (color[unmap[m]] == c2) return(false);
if (!((m = m0+Dir[Dpwn[c1]+1]) & 0x88))
if (color[unmap[m]] == c2) return(false);
}
else
{
for (i = Dstart[piece]; i <= Dstop[piece]; i++)
if (!((m = m0+Dir[i]) & 0x88))
{
u = unmap[m];
if (color[u] != c1)
if (atk2[u] == 0 || board[u] >= piece) return(false);
}
}
return(true);
}
ExaminePosition()
/*
This is done one time before the search is started. Set up arrays
Mwpawn, Mbpawn, Mknight, Mbishop, Mking which are used in the
SqValue() function to determine the positional value of each piece.
*/
{
register short i,sq;
short wpadv,bpadv,wstrong,bstrong,z,side,pp,j,val,Pd,fyle,rank;
wking = PieceList[white][0]; bking = PieceList[black][0];
ataks(white,atak[white]); ataks(black,atak[black]);
Zwmtl = Zbmtl = 0;
UpdateWeights();
HasPawn[white] = HasPawn[black] = 0;
HasKnight[white] = HasKnight[black] = 0;
HasBishop[white] = HasBishop[black] = 0;
HasRook[white] = HasRook[black] = 0;
HasQueen[white] = HasQueen[black] = 0;
for (side = white; side <= black; side++)
for (i = 0; i <= PieceCnt[side]; i++)
switch (board[PieceList[side][i]])
{
case pawn : ++HasPawn[side]; break;
case knight : ++HasKnight[side]; break;
case bishop : ++HasBishop[side]; break;
case rook : ++HasRook[side]; break;
case queen : ++HasQueen[side]; break;
}
if (!Developed[white])
Developed[white] = (board[1] != knight && board[2] != bishop &&
board[5] != bishop && board[6] != knight);
if (!Developed[black])
Developed[black] = (board[57] != knight && board[58] != bishop &&
board[61] != bishop && board[62] != knight);
if (!PawnStorm && stage < 5)
PawnStorm = ((column[wking] < 3 && column[bking] > 4) ||
(column[wking] > 4 && column[bking] < 3));
CopyBoard(pknight,Mknight[white]);
CopyBoard(pknight,Mknight[black]);
CopyBoard(pbishop,Mbishop[white]);
CopyBoard(pbishop,Mbishop[black]);
BlendBoard(KingOpening,KingEnding,Mking[white]);
BlendBoard(KingOpening,KingEnding,Mking[black]);
for (sq = 0; sq < 64; sq++)
{
fyle = column[sq]; rank = row[sq];
wstrong = bstrong = true;
for (i = sq; i < 64; i += 8)
if (atak[black][i] >= ctlP) wstrong = false;
for (i = sq; i >= 0; i -= 8)
if (atak[white][i] >= ctlP) bstrong = false;
wpadv = bpadv = PADVNCM;
if ((fyle == 0 || PawnCnt[white][fyle-1] == 0) &&
(fyle == 7 || PawnCnt[white][fyle+1] == 0)) wpadv = PADVNCI;
if ((fyle == 0 || PawnCnt[black][fyle-1] == 0) &&
(fyle == 7 || PawnCnt[black][fyle+1] == 0)) bpadv = PADVNCI;
Mwpawn[sq] = (wpadv*PawnAdvance[sq]) / 10;
Mbpawn[sq] = (bpadv*PawnAdvance[63-sq]) / 10;
Mwpawn[sq] += PawnBonus; Mbpawn[sq] += PawnBonus;
if (castld[white] || kingmoved[white])
{
if ((fyle < 3 || fyle > 4) && distance(sq,wking) < 3)
Mwpawn[sq] += PAWNSHIELD;
}
else if (rank < 3 && (fyle < 2 || fyle > 5))
Mwpawn[sq] += PAWNSHIELD / 2;
if (castld[black] || kingmoved[black])
{
if ((fyle < 3 || fyle > 4) && distance(sq,bking) < 3)
Mbpawn[sq] += PAWNSHIELD;
}
else if (rank > 4 && (fyle < 2 || fyle > 5))
Mbpawn[sq] += PAWNSHIELD / 2;
if (PawnStorm)
{
if ((column[wking] < 4 && fyle > 4) ||
(column[wking] > 3 && fyle < 3)) Mwpawn[sq] += 3*rank - 21;
if ((column[bking] < 4 && fyle > 4) ||
(column[bking] > 3 && fyle < 3)) Mbpawn[sq] -= 3*rank;
}
Mknight[white][sq] += 5 - distance(sq,bking);
Mknight[white][sq] += 5 - distance(sq,wking);
Mknight[black][sq] += 5 - distance(sq,wking);
Mknight[black][sq] += 5 - distance(sq,bking);
Mbishop[white][sq] += BishopBonus;
Mbishop[black][sq] += BishopBonus;
for (i = 0; i <= PieceCnt[black]; i++)
if (distance(sq,PieceList[black][i]) < 3)
Mknight[white][sq] += KNIGHTPOST;
for (i = 0; i <= PieceCnt[white]; i++)
if (distance(sq,PieceList[white][i]) < 3)
Mknight[black][sq] += KNIGHTPOST;
if (wstrong) Mknight[white][sq] += KNIGHTSTRONG;
if (bstrong) Mknight[black][sq] += KNIGHTSTRONG;
if (wstrong) Mbishop[white][sq] += BISHOPSTRONG;
if (bstrong) Mbishop[black][sq] += BISHOPSTRONG;
if (HasBishop[white] == 2) Mbishop[white][sq] += 8;
if (HasBishop[black] == 2) Mbishop[black][sq] += 8;
if (HasKnight[white] == 2) Mknight[white][sq] += 5;
if (HasKnight[black] == 2) Mknight[black][sq] += 5;
if (board[sq] == bishop)
if (rank % 2 == fyle % 2) KBNKsq = 0; else KBNKsq = 7;
Kfield[white][sq] = Kfield[black][sq] = 0;
if (distance(sq,wking) == 1) Kfield[black][sq] = KATAK;
if (distance(sq,bking) == 1) Kfield[white][sq] = KATAK;
Pd = 0;
for (i = 0; i < 64; i++)
if (board[i] == pawn)
{
if (color[i] == white)
{
pp = true;
if (row[i] == 6) z = i+8; else z = i+16;
for (j = i+8; j < 64; j += 8)
if (atak[black][j] > ctlP || board[j] == pawn) pp = false;
}
else
{
pp = true;
if (row[i] == 1) z = i-8; else z = i-16;
for (j = i-8; j >= 0; j -= 8)
if (atak[white][j] > ctlP || board[j] == pawn) pp = false;
}
if (pp) Pd += 5*taxicab(sq,z); else Pd += taxicab(sq,z);
}
if (Pd != 0)
{
val = (Pd*stage2) / 10;
Mking[white][sq] -= val;
Mking[black][sq] -= val;
}
}
}
UpdateWeights()
/*
If material balance has changed, determine the values for the
positional evaluation terms.
*/
{
register short tmtl;
if (mtl[white] != Zwmtl || mtl[black] != Zbmtl)
{
Zwmtl = mtl[white]; Zbmtl = mtl[black];
emtl[white] = Zwmtl - pmtl[white] - valueK;
emtl[black] = Zbmtl - pmtl[black] - valueK;
tmtl = emtl[white] + emtl[black];
if (tmtl > 6600) stage = 0;
else if (tmtl < 1400) stage = 10;
else stage = (6600-tmtl) / 520;
if (tmtl > 3600) stage2 = 0;
else if (tmtl < 1400) stage2 = 10;
else stage2 = (3600-tmtl) / 220;
PEDRNK2B = -15; /* centre pawn on 2nd rank & blocked */
PBLOK = -4; /* blocked backward pawn */
PDOUBLED = -14; /* doubled pawn */
PWEAKH = -4; /* weak pawn on half open file */
PAWNSHIELD = 10-stage; /* pawn near friendly king */
PADVNCM = 10; /* advanced pawn multiplier */
PADVNCI = 7; /* muliplier for isolated pawn */
PawnBonus = stage;
KNIGHTPOST = (stage+2)/3; /* knight near enemy pieces */
KNIGHTSTRONG = (stage+6)/2; /* occupies pawn hole */
BISHOPSTRONG = (stage+6)/2; /* occupies pawn hole */
BishopBonus = 2*stage;
RHOPN = 10; /* rook on half open file */
RHOPNX = 4;
RookBonus = 6*stage;
XRAY = 8; /* Xray attack on piece */
PINVAL = 10; /* Pin */
KHOPN = (3*stage-30) / 2; /* king on half open file */
KHOPNX = KHOPN / 2;
KCASTLD = 10 - stage;
KMOVD = -40 / (stage+1); /* king moved before castling */
KATAK = (10-stage) / 2; /* B,R attacks near enemy king */
if (stage < 8) KSFTY = 16-2*stage; else KSFTY = 0;
ATAKD = -6; /* defender > attacker */
HUNGP = -8; /* each hung piece */
HUNGX = -12; /* extra for >1 hung piece */
}
}
int distance(a,b)
short a,b;
{
register short d1,d2;
d1 = abs(column[a]-column[b]);
d2 = abs(row[a]-row[b]);
if (d1 > d2) return(d1); else return(d2);
}
BlendBoard(a,b,c)
short a[64],b[64],c[64];
{
register int sq;
for (sq = 0; sq < 64; sq++)
c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10;
}
CopyBoard(a,b)
short a[64],b[64];
{
register int sq;
for (sq = 0; sq < 64; sq++)
b[sq] = a[sq];
}