home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World's Top 500 Windows Games
/
Top500WindowsGames.iso
/
wingame1
/
game
/
chess321
/
eval.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-16
|
36KB
|
1,335 lines
/*
C source for GNU CHESS
Revision: 1990-09-30
Modified by Daryl Baker for use in MS WINDOWS environment
Copyright (C) 1986, 1987, 1988, 1989, 1990 Free Software Foundation, Inc.
Copyright (c) 1988, 1989, 1990 John Stanback
This file is part of CHESS.
CHESS is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY. No author or distributor accepts responsibility to anyone for
the consequences of using it or for whether it serves any particular
purpose or works at all, unless he says so in writing. Refer to the CHESS
General Public License for full details.
Everyone is granted permission to copy, modify and redistribute CHESS, but
only under the conditions described in the CHESS General Public License.
A copy of this license is supposed to have been given to you along with
CHESS so you can know your rights and responsibilities. It should be in a
file named COPYING. Among other things, the copyright notice and this
notice must be preserved on all copies.
*/
#define NOATOM
#define NOCLIPBOARD
#define NOCREATESTRUCT
#define NOFONT
#define NOREGION
#define NOSOUND
#define NOWH
#define NOWINOFFSETS
#define NOCOMM
#define NOKANJI
#include <windows.h>
#include <stdio.h>
#include "gnuchess.h"
#include "defs.h"
/*#define taxicab(a,b) taxidata[a][b]*/
#define taxicab(a,b) *(taxidata+a*64+b)
#define wking PieceList[white][0]
#define bking PieceList[black][0]
#define EnemyKing PieceList[c2][0]
/*extern short distdata[64][64], taxidata[64][64];*/
extern short far *distdata, far *taxidata;
/*extern unsigned char nextpos[8][64][64];*/
/*extern unsigned char nextdir[8][64][64];*/
extern unsigned char far * nextpos;
extern unsigned char far * nextdir;
extern short PieceList[2][16], PawnCnt[2][8];
extern short Pscore[maxdepth], Tscore[maxdepth];
extern short mtl[2], pmtl[2], emtl[2], hung[2];
extern short c1, c2, *atk1, *atk2, *PC1, *PC2, atak[2][64];
extern short ChkFlag[maxdepth], CptrFlag[maxdepth], PawnThreat[maxdepth];
extern short Pindex[64];
extern short PieceCnt[2];
extern short FROMsquare, TOsquare, Zscore, zwndw;
extern short Mking[2][64], Kfield[2][64];
extern short ATAKD, HUNGP, HUNGX, KCASTLD, KMOVD, XRAY, PINVAL;
extern short RHOPN, RHOPNX, KHOPN, KHOPNX, KSFTY;
extern short HasKnight[2], HasBishop[2], HasRook[2], HasQueen[2];
extern short Mwpawn[64], Mbpawn[64], Mknight[2][64], Mbishop[2][64];
extern short Mking[2][64], Kfield[2][64];
extern short KNIGHTPOST, KNIGHTSTRONG, BISHOPSTRONG, KATAK;
extern short PEDRNK2B, PWEAKH, PADVNCM, PADVNCI, PAWNSHIELD, PDOUBLED, PBLOK;
extern short stage, stage2, Developed[2];
extern short PawnBonus, BishopBonus, RookBonus;
static short _based(_segname("_CODE")) KingOpening[64] =
{0, 0, -4, -10, -10, -4, 0, 0,
-4, -4, -8, -12, -12, -8, -4, -4,
-12, -16, -20, -20, -20, -20, -16, -12,
-16, -20, -24, -24, -24, -24, -20, -16,
-16, -20, -24, -24, -24, -24, -20, -16,
-12, -16, -20, -20, -20, -20, -16, -12,
-4, -4, -8, -12, -12, -8, -4, -4,
0, 0, -4, -10, -10, -4, 0, 0};
static short _based(_segname("_CODE")) KingEnding[64] =
{0, 6, 12, 18, 18, 12, 6, 0,
6, 12, 18, 24, 24, 18, 12, 6,
12, 18, 24, 30, 30, 24, 18, 12,
18, 24, 30, 36, 36, 30, 24, 18,
18, 24, 30, 36, 36, 30, 24, 18,
12, 18, 24, 30, 30, 24, 18, 12,
6, 12, 18, 24, 24, 18, 12, 6,
0, 6, 12, 18, 18, 12, 6, 0};
static short _based(_segname("_CODE")) DyingKing[64] =
{0, 8, 16, 24, 24, 16, 8, 0,
8, 32, 40, 48, 48, 40, 32, 8,
16, 40, 56, 64, 64, 56, 40, 16,
24, 48, 64, 72, 72, 64, 48, 24,
24, 48, 64, 72, 72, 64, 48, 24,
16, 40, 56, 64, 64, 56, 40, 16,
8, 32, 40, 48, 48, 40, 32, 8,
0, 8, 16, 24, 24, 16, 8, 0};
static short _based(_segname("_CODE")) KBNK[64] =
{99, 90, 80, 70, 60, 50, 40, 40,
90, 80, 60, 50, 40, 30, 20, 40,
80, 60, 40, 30, 20, 10, 30, 50,
70, 50, 30, 10, 0, 20, 40, 60,
60, 40, 20, 0, 10, 30, 50, 70,
50, 30, 10, 20, 30, 40, 60, 80,
40, 20, 30, 40, 50, 60, 80, 90,
40, 40, 50, 60, 70, 80, 90, 99};
static short _based(_segname("_CODE")) pknight[64] =
{0, 4, 8, 10, 10, 8, 4, 0,
4, 8, 16, 20, 20, 16, 8, 4,
8, 16, 24, 28, 28, 24, 16, 8,
10, 20, 28, 32, 32, 28, 20, 10,
10, 20, 28, 32, 32, 28, 20, 10,
8, 16, 24, 28, 28, 24, 16, 8,
4, 8, 16, 20, 20, 16, 8, 4,
0, 4, 8, 10, 10, 8, 4, 0};
static short _based(_segname("_CODE")) pbishop[64] =
{14, 14, 14, 14, 14, 14, 14, 14,
14, 22, 18, 18, 18, 18, 22, 14,
14, 18, 22, 22, 22, 22, 18, 14,
14, 18, 22, 22, 22, 22, 18, 14,
14, 18, 22, 22, 22, 22, 18, 14,
14, 18, 22, 22, 22, 22, 18, 14,
14, 22, 18, 18, 18, 18, 22, 14,
14, 14, 14, 14, 14, 14, 14, 14};
static short _based(_segname("_CODE")) PawnAdvance[64] =
{0, 0, 0, 0, 0, 0, 0, 0,
4, 4, 4, 0, 0, 4, 4, 4,
6, 8, 2, 10, 10, 2, 8, 6,
6, 8, 12, 16, 16, 12, 8, 6,
8, 12, 16, 24, 24, 16, 12, 8,
12, 16, 24, 32, 32, 24, 16, 12,
12, 16, 24, 32, 32, 24, 16, 12,
0, 0, 0, 0, 0, 0, 0, 0};
static short _based(_segname("_CODE")) value[7] =
{0, valueP, valueN, valueB, valueR, valueQ, valueK};
static short _based(_segname("_CODE")) control[7] =
{0, ctlP, ctlN, ctlB, ctlR, ctlQ, ctlK};
static short _based(_segname("_CODE")) PassedPawn0[8] =
{0, 60, 80, 120, 200, 360, 600, 800};
static short _based(_segname("_CODE")) PassedPawn1[8] =
{0, 30, 40, 60, 100, 180, 300, 800};
static short _based(_segname("_CODE")) PassedPawn2[8] =
{0, 15, 25, 35, 50, 90, 140, 800};
static short _based(_segname("_CODE")) PassedPawn3[8] =
{0, 5, 10, 15, 20, 30, 140, 800};
static short _based(_segname("_CODE")) ISOLANI[8] =
{-12, -16, -20, -24, -24, -20, -16, -12};
static short _based(_segname("_CODE")) BACKWARD[16] =
{-6, -10, -15, -21, -28, -28, -28, -28,
-28, -28, -28, -28, -28, -28, -28, -28};
static short _based(_segname("_CODE")) BMBLTY[14] =
{-2, 0, 2, 4, 6, 8, 10, 12, 13, 14, 15, 16, 16, 16};
static short _based(_segname("_CODE")) RMBLTY[15] =
{0, 2, 4, 6, 8, 10, 11, 12, 13, 14, 14, 14, 14, 14, 14};
static short _based(_segname("_CODE")) KTHRT[36] =
{0, -8, -20, -36, -52, -68, -80, -80, -80, -80, -80, -80,
-80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80,
-80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80};
/*
ptype is used to separate white and black pawns, like this;
ptyp = ptype[side][piece]
piece can be used directly in nextpos/nextdir when generating moves
for pieces that are not black pawns.
*/
static short _based(_segname("_CODE")) ptype[2][8] =
{
no_piece, pawn, knight, bishop, rook, queen, king, no_piece,
no_piece, bpawn, knight, bishop, rook, queen, king, no_piece};
static short _based(_segname("_CODE")) direc[8][8] =
{
0, 0, 0, 0, 0, 0, 0, 0,
10, 9, 11, 0, 0, 0, 0, 0,
8, -8, 12, -12, 19, -19, 21, -21,
9, 11, -9, -11, 0, 0, 0, 0,
1, 10, -1, -10, 0, 0, 0, 0,
1, 10, -1, -10, 9, 11, -9, -11,
1, 10, -1, -10, 9, 11, -9, -11,
-10, -9, -11, 0, 0, 0, 0, 0};
static short _based(_segname("_CODE")) max_steps[8] =
{0, 2, 1, 7, 7, 7, 1, 2};
static short _based(_segname("_CODE")) nunmap[120] =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, -1,
-1, 8, 9, 10, 11, 12, 13, 14, 15, -1,
-1, 16, 17, 18, 19, 20, 21, 22, 23, -1,
-1, 24, 25, 26, 27, 28, 29, 30, 31, -1,
-1, 32, 33, 34, 35, 36, 37, 38, 39, -1,
-1, 40, 41, 42, 43, 44, 45, 46, 47, -1,
-1, 48, 49, 50, 51, 52, 53, 54, 55, -1,
-1, 56, 57, 58, 59, 60, 61, 62, 63, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
static short _based(_segname("_CODE")) qrook[3] = {0, 56, 0};
static short _based(_segname("_CODE")) krook[3] = {7, 63, 0};
static short _based(_segname("_CODE")) kingP[3] = {4, 60, 0};
static short _based(_segname("_CODE")) rank7[3] = {6, 1, 0};
static short _based(_segname("_CODE")) sweep[8] =
{false, false, false, true, true, true, false, false};
/* ............ POSITIONAL EVALUATION ROUTINES ............ */
int
evaluate (short int side,
short int ply,
short int alpha,
short int beta,
short int INCscore,
short int *slk,
short int *InChk)
/*
Compute an estimate of the score by adding the positional score from the
previous ply to the material difference. If this score falls inside a
window which is 180 points wider than the alpha-beta window (or within a
50 point window during quiescence search) call ScorePosition() to
determine a score, otherwise return the estimated score. If one side has
only a king and the other either has no pawns or no pieces then the
function ScoreLoneKing() is called.
*/
{
register short evflag, xside;
short s;
xside = otherside[side];
s = -Pscore[ply - 1] + mtl[side] - mtl[xside] - INCscore;
hung[white] = hung[black] = 0;
*slk = ((mtl[white] == valueK && (pmtl[black] == 0 || emtl[black] == 0)) ||
(mtl[black] == valueK && (pmtl[white] == 0 || emtl[white] == 0)));
if (*slk)
evflag = false;
else
evflag =
(ply == 1 || ply < Sdepth ||
((ply == Sdepth + 1 || ply == Sdepth + 2) &&
(s > alpha - xwndw && s < beta + xwndw)) ||
(ply > Sdepth + 2 && s >= alpha - 25 && s <= beta + 25));
if (evflag)
{
EvalNodes++;
ataks (side, atak[side]);
if (Anyatak (side, PieceList[xside][0]))
return (10001 - ply);
ataks (xside, atak[xside]);
*InChk = Anyatak (xside, PieceList[side][0]);
ScorePosition (side, &s);
}
else
{
if (SqAtakd (PieceList[xside][0], side))
return (10001 - ply);
*InChk = SqAtakd (PieceList[side][0], xside);
if (*slk)
ScoreLoneKing (side, &s);
}
Pscore[ply] = s - mtl[side] + mtl[xside];
if (*InChk)
ChkFlag[ply - 1] = Pindex[TOsquare];
else
ChkFlag[ply - 1] = 0;
return (s);
}
static inline int
ScoreKPK (short int side,
short int winner,
short int loser,
short int king1,
short int king2,
short int 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
if (row(sq) == 6)
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
if (row(sq) == 1)
sq -= 8;
}
s += 8 * (taxicab (king2, sq) - taxicab (king1, sq));
return (s);
}
static inline int
ScoreKBNK (short int winner, short int king1, short int king2)
/*
Score King+Bishop+Knight versus King endings.
This doesn't work all that well but it's better than nothing.
*/
{
register short s, sq, KBNKsq = 0;
for (sq = 0; sq < 64; sq++)
if (board[sq] == bishop)
if (row (sq) % 2 == column (sq) % 2)
KBNKsq = 0;
else
KBNKsq = 7;
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);
}
void
ScoreLoneKing (short int side, short int *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] - DyingKing[king2] - 2 * distance (king1, king2);
if (side == winner)
*score = s;
else
*score = -s;
}
static inline void
BRscan (short int sq, short int *s, short int *mob)
/*
Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
hung[] array if a pin is found.
*/
{
register short u, piece, pin;
unsigned char far *ppos, far *pdir;
short *Kf;
Kf = Kfield[c1];
*mob = 0;
piece = board[sq];
ppos = nextpos+piece*64*64+sq*64;
pdir = nextdir+piece*64*64+sq*64;
u = ppos[sq];
pin = -1; /* start new direction */
do
{
*s += Kf[u];
if (color[u] == neutral)
{
(*mob)++;
if (ppos[u] == pdir[u])
pin = -1; /* oops new direction */
u = ppos[u];
}
else if (pin < 0)
{
if (board[u] == pawn || board[u] == king)
u = pdir[u];
else
{
if (ppos[u] != pdir[u])
pin = u; /* not on the edge and on to find a pin */
u = ppos[u];
}
}
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;
}
pin = -1; /* new direction */
u = pdir[u];
}
} while (u != sq);
}
static inline void
KingScan (short int sq, short int *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.
The following must be true:
board[sq] == king
c1 == color[sq]
c2 == otherside[c1]
*/
#define ScoreThreat \
if (color[u] != c2)\
if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) ++cnt;\
else *s -= 3
{
register short u;
register unsigned char far *ppos, far *pdir;
register short cnt, ok;
cnt = 0;
if (HasBishop[c2] || HasQueen[c2])
{
ppos = nextpos+bishop*64*64+sq*64;
pdir = nextdir+bishop*64*64+sq*64;
u = ppos[sq];
do
{
if (atk2[u] & ctlBQ)
ScoreThreat;
u = (color[u] == neutral) ? ppos[u] : pdir[u];
} while (u != sq);
}
if (HasRook[c2] || HasQueen[c2])
{
ppos = nextpos+rook*64*64+sq*64;
pdir = nextdir+rook*64*64+sq*64;
u = ppos[sq];
do
{
if (atk2[u] & ctlRQ)
ScoreThreat;
u = (color[u] == neutral) ? ppos[u] : pdir[u];
} while (u != sq);
}
if (HasKnight[c2])
{
pdir = nextdir+knight*64*64+sq*64;
u = pdir[sq];
do
{
if (atk2[u] & ctlNN)
ScoreThreat;
u = pdir[u];
} while (u != sq);
}
*s += (KSFTY * KTHRT[cnt]) / 16;
cnt = 0;
ok = false;
pdir = nextpos+king*64*64+sq*64;
u = pdir[sq];
do
{
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;
}
u = pdir[u];
} while (u != sq);
if (!ok)
*s -= KSFTY;
if (cnt > 1)
*s -= KSFTY;
}
static inline int
trapped (short int sq)
/*
See if the attacked piece has unattacked squares to move to.
The following must be true:
c1 == color[sq]
c2 == otherside[c1]
*/
{
register short u, piece;
register unsigned char far *ppos, far *pdir;
piece = board[sq];
ppos = nextpos+(ptype[c1][piece]*64*64)+sq*64;
pdir = nextdir+(ptype[c1][piece]*64*64)+sq*64;
if (piece == pawn)
{
u = ppos[sq]; /* follow no captures thread */
if (color[u] == neutral)
{
if (atk1[u] >= atk2[u])
return (false);
if (atk2[u] < ctlP)
{
u = ppos[u];
if (color[u] == neutral && atk1[u] >= atk2[u])
return (false);
}
}
u = pdir[sq]; /* follow captures thread */
if (color[u] == c2)
return (false);
u = pdir[u];
if (color[u] == c2)
return (false);
}
else
{
u = ppos[sq];
do
{
if (color[u] != c1)
if (atk2[u] == 0 || board[u] >= piece)
return (false);
u = (color[u] == neutral) ? ppos[u] : pdir[u];
} while (u != sq);
}
return (true);
}
static inline int
PawnValue (short int sq, short int side)
/*
Calculate the positional value for a pawn on 'sq'.
*/
{
register short j, fyle, rank;
register short s, a1, a2, in_square, r, e;
a1 = (atk1[sq] & 0x4FFF);
a2 = (atk2[sq] & 0x4FFF);
rank = row (sq);
fyle = column (sq);
s = 0;
if (c1 == white)
{
s = Mwpawn[sq];
if ((sq == 11 && color[19] != neutral)
|| (sq == 12 && color[20] != 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 (c1 == black)
{
s = Mbpawn[sq];
if ((sq == 51 && color[43] != neutral)
|| (sq == 52 && color[44] != 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];
}
}
if (a2 > 0)
{
if (a1 == 0 || a2 > ctlP + 1)
{
s += HUNGP;
++hung[c1];
if (trapped (sq))
++hung[c1];
}
else
if (a2 > a1)
s += ATAKD;
}
return (s);
}
static inline int
KnightValue (short int sq, short int side)
/*
Calculate the positional value for a knight on 'sq'.
*/
{
register short s, a2, a1;
s = Mknight[c1][sq];
a2 = (atk2[sq] & 0x4FFF);
if (a2 > 0)
{
a1 = (atk1[sq] & 0x4FFF);
if (a1 == 0 || a2 > ctlBN + 1)
{
s += HUNGP;
++hung[c1];
if (trapped (sq))
++hung[c1];
}
else
if (a2 >= ctlBN || a1 < ctlP)
s += ATAKD;
}
return (s);
}
static inline int
BishopValue (short int sq, short int side)
/*
Calculate the positional value for a bishop on 'sq'.
*/
{
register short a2, a1;
short s, mob;
s = Mbishop[c1][sq];
BRscan (sq, &s, &mob);
s += BMBLTY[mob];
a2 = (atk2[sq] & 0x4FFF);
if (a2 > 0)
{
a1 = (atk1[sq] & 0x4FFF);
if (a1 == 0 || a2 > ctlBN + 1)
{
s += HUNGP;
++hung[c1];
if (trapped (sq))
++hung[c1];
}
else
if (a2 >= ctlBN || a1 < ctlP)
s += ATAKD;
}
return (s);
}
static inline int
RookValue (short int sq, short int side)
/*
Calculate the positional value for a rook on 'sq'.
*/
{
register short fyle, a2, a1;
short s, mob;
s = RookBonus;
BRscan (sq, &s, &mob);
s += RMBLTY[mob];
fyle = column (sq);
if (PC1[fyle] == 0)
s += RHOPN;
if (PC2[fyle] == 0)
s += RHOPNX;
if (pmtl[c2] > 100 && row (sq) == rank7[c1])
s += 10;
if (stage > 2)
s += 14 - taxicab (sq, EnemyKing);
a2 = (atk2[sq] & 0x4FFF);
if (a2 > 0)
{
a1 = (atk1[sq] & 0x4FFF);
if (a1 == 0 || a2 > ctlR + 1)
{
s += HUNGP;
++hung[c1];
if (trapped (sq))
++hung[c1];
}
else
if (a2 >= ctlR || a1 < ctlP)
s += ATAKD;
}
return (s);
}
static inline int
QueenValue (short int sq, short int side)
/*
Calculate the positional value for a queen on 'sq'.
*/
{
register short s, a2, a1;
s = (distance (sq, EnemyKing) < 3) ? 12 : 0;
if (stage > 2)
s += 14 - taxicab (sq, EnemyKing);
a2 = (atk2[sq] & 0x4FFF);
if (a2 > 0)
{
a1 = (atk1[sq] & 0x4FFF);
if (a1 == 0 || a2 > ctlQ + 1)
{
s += HUNGP;
++hung[c1];
if (trapped (sq))
++hung[c1];
}
else
if (a2 >= ctlQ || a1 < ctlP)
s += ATAKD;
}
return (s);
}
static inline int
KingValue (short int sq, short int side)
/*
Calculate the positional value for a king on 'sq'.
*/
{
register short fyle, a2, a1;
short s;
s = Mking[c1][sq];
if (KSFTY > 0)
if (Developed[c2] || stage > 0)
KingScan (sq, &s);
if (castld[c1])
s += KCASTLD;
else if (Mvboard[kingP[c1]])
s += KMOVD;
fyle = column (sq);
if (PC1[fyle] == 0)
s += KHOPN;
if (PC2[fyle] == 0)
s += KHOPNX;
switch (fyle)
{
case 5:
if (PC1[7] == 0)
s += KHOPN;
if (PC2[7] == 0)
s += KHOPNX;
/* Fall through */
case 4:
case 6:
case 0:
if (PC1[fyle + 1] == 0)
s += KHOPN;
if (PC2[fyle + 1] == 0)
s += KHOPNX;
break;
case 2:
if (PC1[0] == 0)
s += KHOPN;
if (PC2[0] == 0)
s += KHOPNX;
/* Fall through */
case 3:
case 1:
case 7:
if (PC1[fyle - 1] == 0)
s += KHOPN;
if (PC2[fyle - 1] == 0)
s += KHOPNX;
break;
default:
/* Impossible! */
break;
}
a2 = (atk2[sq] & 0x4FFF);
if (a2 > 0)
{
a1 = (atk1[sq] & 0x4FFF);
if (a1 == 0 || a2 > ctlK + 1)
{
s += HUNGP;
++hung[c1];
}
else
s += ATAKD;
}
return (s);
}
void
ScorePosition (short int side, short int *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[2];
UpdateWeights ();
xside = otherside[side];
pscore[white] = pscore[black] = 0;
for (c1 = white; c1 <= black; c1++)
{
c2 = otherside[c1];
atk1 = atak[c1];
atk2 = atak[c2];
PC1 = PawnCnt[c1];
PC2 = PawnCnt[c2];
for (i = PieceCnt[c1]; i >= 0; i--)
{
sq = PieceList[c1][i];
switch (board[sq])
{
case pawn:
s = PawnValue(sq, side);
break;
case knight:
s = KnightValue(sq, side);
break;
case bishop:
s = BishopValue(sq, side);
break;
case rook:
s = RookValue(sq, side);
break;
case queen:
s = QueenValue(sq, side);
break;
case king:
s = KingValue(sq, side);
break;
default:
s = 0;
break;
}
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 += urand () % 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;
}
static inline void
BlendBoard (const short int far a[64], const short int far b[64], short int c[64])
{
register int sq;
for (sq = 0; sq < 64; sq++)
c[sq] = (a[sq] * (10 - stage) + b[sq] * stage) / 10;
}
static inline void
CopyBoard (const short int far a[64], short int b[64])
{
register int sq;
for (sq = 0; sq < 64; sq++)
b[sq] = a[sq];
}
void
ExaminePosition (void)
/*
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, k, val, Pd, fyle, rank;
static short PawnStorm = false;
ataks (white, atak[white]);
ataks (black, atak[black]);
UpdateWeights ();
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 = PieceCnt[side]; i >= 0; i--)
switch (board[PieceList[side][i]])
{
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 (Patak (black, i))
{
wstrong = false;
break;
}
for (i = sq; i >= 0; i -= 8)
if (Patak (white, i))
{
bstrong = false;
break;
}
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 (Mvboard[kingP[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 (Mvboard[kingP[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;
{
int xxxtmp;
for (i = PieceCnt[black]; i >= 0; i--) {
xxxtmp = PieceList[black][i];
if (distance (sq, xxxtmp) < 3)
Mknight[white][sq] += KNIGHTPOST;
}
for (i = PieceCnt[white]; i >= 0; i--) {
xxxtmp = PieceList[white][i];
if (distance (sq, xxxtmp) < 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;
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 (k = 0; k <= PieceCnt[white]; k++)
{
i = PieceList[white][k];
if (board[i] == pawn)
{
pp = true;
if (row (i) == 6)
z = i + 8;
else
z = i + 16;
for (j = i + 8; j < 64; j += 8)
if (Patak (black, j) || board[j] == pawn)
{
pp = false;
break;
}
if (pp)
Pd += 5 * taxicab (sq, z);
else
Pd += taxicab (sq, z);
}
}
for (k = 0; k <= PieceCnt[black]; k++)
{
i = PieceList[black][k];
if (board[i] == pawn)
{
pp = true;
if (row (i) == 1)
z = i - 8;
else
z = i - 16;
for (j = i - 8; j >= 0; j -= 8)
if (Patak (white, j) || board[j] == pawn)
{
pp = false;
break;
}
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;
}
}
}
void
UpdateWeights (void)
/*
If material balance has changed, determine the values for the positional
evaluation terms.
*/
{
register short tmtl, s1;
emtl[white] = mtl[white] - pmtl[white] - valueK;
emtl[black] = mtl[black] - pmtl[black] - valueK;
tmtl = emtl[white] + emtl[black];
s1 = (tmtl > 6600) ? 0 : ((tmtl < 1400) ? 10 : (6600 - tmtl) / 520);
if (s1 != stage)
{
stage = s1;
stage2 = (tmtl > 3600) ? 0 : ((tmtl < 1400) ? 10 : (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 */
}
}