Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
Copyright (c) 1988 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 lowerbound 0x0002
#define upperbound 0x0004
#define absv(x) ((x) < 0 ? -(x) : (x))
#define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b]))
short score
,depth
,time
,piece
,color
;
char mvstr1
[5],mvstr2
[5];
struct leaf Tree
[2000],*root
;
short TrPnt
[maxdepth
],board
[64],color
[64];
short row
[64],column
[64],locn
[8][8],Pindex
[64],svalue
[64];
short PieceList
[2][16],PieceCnt
[2],atak
[2][64],PawnCnt
[2][8];
short castld
[2],kingmoved
[2],mtl
[2],pmtl
[2],emtl
[2],hung
[2];
short c1
,c2
,*atk1
,*atk2
,*PC1
,*PC2
,EnemyKing
;
short mate
,post
,opponent
,computer
,Sdepth
,Awindow
,Bwindow
,dither
;
long ResponseTime
,ExtraTime
,Level
,et
,et0
,time0
,cputimer
,ft
;
long NodeCnt
,evrate
,ETnodes
,EvalNodes
,HashCnt
;
short quit
,reverse
,bothsides
,hashflag
,InChk
,player
,force
,easy
,beep
;
short wking
,bking
,FROMsquare
,TOsquare
,timeout
,Zscore
,zwndw
,xwndw
,slk
;
short HasPawn
[2],HasKnight
[2],HasBishop
[2],HasRook
[2],HasQueen
[2];
short ChkFlag
[maxdepth
],CptrFlag
[maxdepth
],PawnThreat
[maxdepth
];
short Pscore
[maxdepth
],Tscore
[maxdepth
],Threat
[maxdepth
];
struct GameRec GameList
[240];
short GameCnt
,Game50
,epsquare
,lpost
,rcptr
,contempt
;
struct TimeControlRec TimeControl
;
short TCflag
,TCmoves
,TCminutes
,OperatorTime
;
short otherside
[3]={1,0,2};
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77};
{0,1,2,3,4,5,6,7,-1,-1,-1,-1,-1,-1,-1,-1,
8,9,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,
16,17,18,19,20,21,22,23,-1,-1,-1,-1,-1,-1,-1,-1,
24,25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,
32,33,34,35,36,37,38,39,-1,-1,-1,-1,-1,-1,-1,-1,
40,41,42,43,44,45,46,47,-1,-1,-1,-1,-1,-1,-1,-1,
48,49,50,51,52,53,54,55,-1,-1,-1,-1,-1,-1,-1,-1,
56,57,58,59,60,61,62,63};
{0,1,1,1,1,1,1,1,0,0,0,0,0,0,0x0E,0x0F,
0x10,0x11,0x12,0,0,0,0,0,0,0,0,0,0,0,0x0F,0x1F,
0x10,0x21,0x11,0,0,0,0,0,0,0,0,0,0,0x0F,0,0,
0x10,0,0,0x11,0,0,0,0,0,0,0,0,0x0F,0,0,0,
0x10,0,0,0,0x11,0,0,0,0,0,0,0x0F,0,0,0,0,
0x10,0,0,0,0,0x11,0,0,0,0,0x0F,0,0,0,0,0,
0x10,0,0,0,0,0,0x11,0,0,0x0F,0,0,0,0,0,0,
{rook
,knight
,bishop
,queen
,king
,bishop
,knight
,rook
,
pawn
,pawn
,pawn
,pawn
,pawn
,pawn
,pawn
,pawn
,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
pawn
,pawn
,pawn
,pawn
,pawn
,pawn
,pawn
,pawn
,
rook
,knight
,bishop
,queen
,king
,bishop
,knight
,rook
};
{white
,white
,white
,white
,white
,white
,white
,white
,
white
,white
,white
,white
,white
,white
,white
,white
,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
black
,black
,black
,black
,black
,black
,black
,black
,
black
,black
,black
,black
,black
,black
,black
,black
};
short sweep
[7]= {false,false,false,true,true,true,false};
short Dstart
[7]={6,4,8,4,0,0,0};
short Dstop
[7]={7,5,15,7,3,7,7};
short Dir
[16]={1,0x10,-1,-0x10,0x0F,0x11,-0x0F,-0x11,
0x0E,-0x0E,0x12,-0x12,0x1F,-0x1F,0x21,-0x21};
short Pdir
[34]={0,0x38,0,0,0,0,0,0,0,0,0,0,0,0,0x02,0x35,
0x38,0x35,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0x02,
short pbit
[7]={0,0x01,0x02,0x04,0x08,0x10,0x20};
unsigned short killr0
[maxdepth
],killr1
[maxdepth
],killr2
[maxdepth
];
unsigned short killr3
[maxdepth
],PrVar
[maxdepth
];
unsigned short PV
,hint
,Swag0
,Swag1
,Swag2
,Swag3
,Swag4
;
struct hashval hashcode
[2][7][64];
struct hashentry huge
*ttable
,*ptbl
;
unsigned char history
[8192];
short Mwpawn
[64],Mbpawn
[64],Mknight
[2][64],Mbishop
[2][64];
short Mking
[2][64],Kfield
[2][64];
short value
[7]={0,valueP
,valueN
,valueB
,valueR
,valueQ
,valueK
};
short control
[7]={0,ctlP
,ctlN
,ctlB
,ctlR
,ctlQ
,ctlK
};
short PassedPawn0
[8]={0,60,80,120,200,360,600,800};
short PassedPawn1
[8]={0,30,40,60,100,180,300,800};
short PassedPawn2
[8]={0,15,25,35,50,90,140,800};
short PassedPawn3
[8]={0,5,10,15,20,30,140,800};
short ISOLANI
[8] = {-12,-16,-20,-24,-24,-20,-16,-12};
short BACKWARD
[8] = {-6,-10,-15,-21,-28,-28,-28,-28};
short BMBLTY
[14] = {-2,0,2,4,6,8,10,12,13,14,15,16,16,16};
short RMBLTY
[14] = {0,2,4,6,8,10,11,12,13,14,14,14,14,14};
short Kthreat
[16] = {0,-8,-20,-36,-52,-68,-80,-80,-80,-80,-80,-80,
short KNIGHTPOST
,KNIGHTSTRONG
,BISHOPSTRONG
,KATAK
,KBNKsq
;
short PEDRNK2B
,PWEAKH
,PADVNCM
,PADVNCI
,PAWNSHIELD
,PDOUBLED
,PBLOK
;
short RHOPN
,RHOPNX
,KHOPN
,KHOPNX
,KSFTY
;
short ATAKD
,HUNGP
,HUNGX
,KCASTLD
,KMOVD
,XRAY
,PINVAL
;
short stage
,stage2
,Zwmtl
,Zbmtl
,Developed
[2],PawnStorm
;
short PawnBonus
,BishopBonus
,RookBonus
;
{ 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};
{ 0, 6,12,18,18,12, 6, 0,
{ 0, 8,16,24,24,16, 8, 0,
{99,90,80,70,60,50,40,40,
40,40,50,60,70,80,90,99};
{ 0, 4, 8,10,10, 8, 4, 0,
{14,14,14,14,14,14,14,14,
14,14,14,14,14,14,14,14};
{ 0, 0, 0, 0, 0, 0, 0, 0,
ttable
= (struct hashentry huge
*)farmalloc(ttblsz
*
(unsigned long)sizeof(struct hashentry
));
ttable
= (struct hashentry
*)malloc(ttblsz
*
(unsigned long)sizeof(struct hashentry
));
Level
= 0; TCflag
= false; OperatorTime
= 0;
if (argc
== 2) Level
= atoi(argv
[1]);
TCmoves
= atoi(argv
[1]); TCminutes
= atoi(argv
[2]); TCflag
= true;
if (bothsides
&& !mate
) SelectMove(opponent
,1); else InputCommand();
if (!(quit
|| mate
|| force
)) SelectMove(computer
,1);
/* ............ INTERFACE ROUTINES ........................... */
Compare the string 's' to the list of legal moves available for the
opponent. If a match is found, make the move on the board.
static short pnt
,tempb
,tempc
,tempsf
,tempst
,cnt
;
static struct leaf xnode
;
UnmakeMove(opponent
,&xnode
,&tempb
,&tempc
,&tempsf
,&tempst
);
algbr(node
->f
,node
->t
,(short) node
->flags
& cstlmask
);
if (strcmp(s
,mvstr1
) == 0 || strcmp(s
,mvstr2
) == 0)
MakeMove(opponent
,&xnode
,&tempb
,&tempc
,&tempsf
,&tempst
);
if (SqAtakd(PieceList
[opponent
][0],computer
))
UnmakeMove(opponent
,&xnode
,&tempb
,&tempc
,&tempsf
,&tempst
);
ShowMessage("Illegal Move!!");
if (iop
== 1) return(true);
if (xnode
.flags
& epmask
) UpdateDisplay(0,0,1,0);
else UpdateDisplay(xnode
.f
,xnode
.t
,0,xnode
.flags
& cstlmask
);
if (xnode
.flags
& cstlmask
) Game50
= GameCnt
;
else if (board
[xnode
.t
] == pawn
|| (xnode
.flags
& capture
))
GameList
[GameCnt
].depth
= GameList
[GameCnt
].score
= 0;
GameList
[GameCnt
].nodes
= 0;
GameList
[GameCnt
].time
= (short)et
;
TimeControl
.clock
[opponent
] -= et
;
--TimeControl
.moves
[opponent
];
*mv
= (xnode
.f
<< 8) + xnode
.t
;
algbr(xnode
.f
,xnode
.t
,false);
if (cnt
> 1) ShowMessage("Ambiguous Move!");
Reset the board and other variables to start a new game.
mate
= quit
= reverse
= bothsides
= post
= false;
hashflag
= force
= PawnStorm
= false;
beep
= rcptr
= easy
= true;
lpost
= NodeCnt
= epsquare
= et0
= 0;
GameCnt
= -1; Game50
= 0;
Developed
[white
] = Developed
[black
] = false;
castld
[white
] = castld
[black
] = false;
kingmoved
[white
] = kingmoved
[black
] = 0;
PawnThreat
[0] = CptrFlag
[0] = Threat
[0] = false;
Pscore
[0] = 12000; Tscore
[0] = 12000;
opponent
= white
; computer
= black
;
l
= 8*r
+c
; locn
[r
][c
] = l
;
row
[l
] = r
; column
[l
] = c
;
board
[l
] = Stboard
[l
]; color
[l
] = Stcolor
[l
];
for (c
= white
; c
<= black
; c
++)
for (p
= pawn
; p
<= king
; p
++)
hashcode
[c
][p
][l
].key
= (unsigned short)rand();
hashcode
[c
][p
][l
].bd
= ((unsigned long)rand() << 16) +
if (TCflag
) SetTimeControl();
else if (Level
== 0) SelectLevel();
mvstr1
[0] = cxx
[column
[f
]]; mvstr1
[1] = rxx
[row
[f
]];
mvstr1
[2] = cxx
[column
[t
]]; mvstr1
[3] = rxx
[row
[t
]];
mvstr2
[0] = qxx
[board
[f
]];
mvstr2
[1] = mvstr1
[2]; mvstr2
[2] = mvstr1
[3];
mvstr1
[4] = '\0'; mvstr2
[3] = '\0';
if (t
> f
) strcpy(mvstr2
,"o-o");
else strcpy(mvstr2
,"o-o-o");
/* ............ MOVE GENERATION & SEARCH ROUTINES .............. */
Select a move by calling function search() at progressively deeper
ply until time is up or a mate or draw is reached. An alpha-beta
window of -90 to +90 points is set around the score returned from the
previous iteration. If Sdepth != 0 then the program has correctly
predicted the opponents move and the search will start at a depth of
Sdepth+1 rather than a depth of 1.
static short i
,alpha
,beta
,score
,tempb
,tempc
,tempsf
,tempst
,xside
,rpt
;
if (iop
!= 2) player
= side
;
if (((TimeControl
.moves
[side
] + 3) - OperatorTime
) != 0)
ResponseTime
= (TimeControl
.clock
[side
]) /
(TimeControl
.moves
[side
] + 3) -
ResponseTime
+= (ResponseTime
*TimeControl
.moves
[side
])/(2*TCmoves
+1);
else ResponseTime
= Level
;
if (iop
== 2) ResponseTime
= 999;
if (Sdepth
> 0 && root
->score
> Zscore
-zwndw
) ResponseTime
-= ft
;
else if (ResponseTime
< 1) ResponseTime
= 1;
ScorePosition(side
,&score
);
for (i
= 0; i
< 8192; i
++) history
[i
] = 0;
FROMsquare
= TOsquare
= -1;
for (i
= 0; i
< maxdepth
; i
++)
PrVar
[i
] = killr0
[i
] = killr1
[i
] = killr2
[i
] = killr3
[i
] = 0;
alpha
= score
-90; beta
= score
+90;
TrPnt
[1] = 0; root
= &Tree
[0];
for (i
= TrPnt
[1]; i
< TrPnt
[2]; i
++) pick(i
,TrPnt
[2]-1);
if (Book
!= NULL
) OpeningBook();
if (Book
!= NULL
) timeout
= true;
NodeCnt
= ETnodes
= EvalNodes
= HashCnt
= 0;
while (!timeout
&& Sdepth
< MaxSearchDepth
)
score
= search(side
,1,Sdepth
,alpha
,beta
,PrVar
,&rpt
);
for (i
= 1; i
<= Sdepth
; i
++) killr0
[i
] = PrVar
[i
];
ExtraTime
= 10*ResponseTime
;
score
= search(side
,1,Sdepth
,-9000,beta
,PrVar
,&rpt
);
if (score
> beta
&& !(root
->flags
& exact
))
score
= search(side
,1,Sdepth
,alpha
,9000,PrVar
,&rpt
);
for (i
= TrPnt
[1]+1; i
< TrPnt
[2]; i
++) pick(i
,TrPnt
[2]-1);
ShowResults(score
,PrVar
,'.');
for (i
= 1; i
<= Sdepth
; i
++) killr0
[i
] = PrVar
[i
];
if (score
> Zscore
-zwndw
&& score
> Tree
[1].score
+250) ExtraTime
= 0;
else if (score
> Zscore
-3*zwndw
) ExtraTime
= ResponseTime
;
else ExtraTime
= 3*ResponseTime
;
if (root
->flags
& exact
) timeout
= true;
if (Tree
[1].score
< -9000) timeout
= true;
if (4*et
> 2*ResponseTime
+ ExtraTime
) timeout
= true;
if (Zscore
== 0) Zscore
= score
;
else Zscore
= (Zscore
+score
)/2;
zwndw
= 20+abs(Zscore
/12);
if (Zscore
< score
) alpha
= Zscore
- Awindow
- zwndw
;
else alpha
= score
- Awindow
- zwndw
;
if (rpt
>= 2 || score
< -12000) root
->flags
|= draw
;
if (Book
== NULL
) hint
= PrVar
[2];
if (score
> -9999 && rpt
<= 2)
MakeMove(side
,root
,&tempb
,&tempc
,&tempsf
,&tempst
);
algbr(root
->f
,root
->t
,(short) root
->flags
& cstlmask
);
if (score
== -9999 || score
== 9998) mate
= true;
if (root
->flags
& cstlmask
) Game50
= GameCnt
;
else if (board
[root
->t
] == pawn
|| (root
->flags
& capture
))
GameList
[GameCnt
].score
= score
;
GameList
[GameCnt
].nodes
= NodeCnt
;
GameList
[GameCnt
].time
= (short)et
;
GameList
[GameCnt
].depth
= Sdepth
;
TimeControl
.clock
[side
] -= (et
+ OperatorTime
);
if (--TimeControl
.moves
[side
] == 0) SetTimeControl();
if ((root
->flags
& draw
) && bothsides
) quit
= true;
if (GameCnt
> 238) quit
= true;
Go thru each of the opening lines of play and check for a match with
the current game listing. If a match occurs, generate a random number.
If this number is the largest generated so far then the next move in
this line becomes the current "candidate". After all lines are
checked, the candidate move is put at the top of the Tree[] array and
will be played by the program. Note that the program does not handle
for (j
= 0; j
<= GameCnt
; j
++)
if (GameList
[j
].gmove
!= *(mp
++)) break;
for (pnt
= TrPnt
[1]; pnt
< TrPnt
[2]; pnt
++)
if ((Tree
[pnt
].f
<<8) + Tree
[pnt
].t
== m
) Tree
[pnt
].score
= 0;
pick(TrPnt
[1],TrPnt
[2]-1);
if (Tree
[TrPnt
[1]].score
< 0) Book
= NULL
;
#define UpdateSearchStatus\
if (post) ShowCurrentMove(pnt,node->f,node->t);\
d = best-Zscore; e = best-node->score;\
if (best < alpha) ExtraTime = 10*ResponseTime;\
else if (d > -zwndw && e > 4*zwndw) ExtraTime = -ResponseTime/3;\
else if (d > -zwndw) ExtraTime = 0;\
else if (d > -3*zwndw) ExtraTime = ResponseTime;\
else if (d > -9*zwndw) ExtraTime = 3*ResponseTime;\
else ExtraTime = 5*ResponseTime;\
int search(side
,ply
,depth
,alpha
,beta
,bstline
,rpt
)
short side
,ply
,depth
,alpha
,beta
,*rpt
;
unsigned short bstline
[];
Perform an alpha-beta search to determine the score for the current
board position. If depth <= 0 only capturing moves, pawn promotions
and responses to check are generated and searched, otherwise all
moves are processed. The search depth is modified for check evasions,
certain re-captures and threats. Extensions may continue for up to 11
ply beyond the nominal search depth.
#define prune (cf && score+node->score < alpha)
#define ReCapture (rcptr && score > alpha && score < beta &&\
ply > 2 && CptrFlag[ply-1] && CptrFlag[ply-2])
#define MateThreat (ply < Sdepth+4 && ply > 4 &&\
ChkFlag[ply-2] && ChkFlag[ply-4] &&\
ChkFlag[ply-2] != ChkFlag[ply-4])
short best
,tempb
,tempc
,tempsf
,tempst
;
short xside
,pbst
,d
,e
,cf
,score
,rcnt
;
unsigned short mv
,nxtline
[maxdepth
];
if (depth
< 0) depth
= 0;
if (ply
<= Sdepth
+3) repetition(rpt
); else *rpt
= 0;
if (*rpt
>= 2) return(0);
score
= evaluate(side
,xside
,ply
,alpha
,beta
);
if (InChk
|| PawnThreat
[ply
-1] || ReCapture
) ++depth
;
(InChk
|| PawnThreat
[ply
-1] || Threat
[ply
-1])) ++depth
;
else if (score
<= beta
&& MateThreat
) ++depth
;
if (depth
> 0 && hashflag
&& ply
> 1)
ProbeTTable(side
,depth
,&alpha
,&beta
,&score
);
if (beta
== -20000) return(score
);
if (alpha
> beta
) return(alpha
);
if (Sdepth
== 1) d
= 7; else d
= 11;
if (ply
> Sdepth
+d
|| (depth
< 1 && score
> beta
)) return(score
);
if (depth
> 0) MoveList(side
,ply
);
else CaptureList(side
,xside
,ply
);
if (TrPnt
[ply
] == TrPnt
[ply
+1]) return(score
);
cf
= (depth
< 1 && ply
> Sdepth
+1 && !ChkFlag
[ply
-2] && !slk
);
if (depth
> 0) best
= -12000; else best
= score
;
if (best
> alpha
) alpha
= best
;
for (pnt
= pbst
= TrPnt
[ply
];
pnt
< TrPnt
[ply
+1] && best
<= beta
;
if (ply
> 1) pick(pnt
,TrPnt
[ply
+1]-1);
mv
= (node
->f
<< 8) + node
->t
;
if (ply
== 1) UpdateSearchStatus
;
if (!(node
->flags
& exact
))
MakeMove(side
,node
,&tempb
,&tempc
,&tempsf
,&tempst
);
CptrFlag
[ply
] = (node
->flags
& capture
);
PawnThreat
[ply
] = (node
->flags
& pwnthrt
);
Tscore
[ply
] = node
->score
;
node
->score
= -search(xside
,ply
+1,depth
-1,-beta
,-alpha
,
if (abs(node
->score
) > 9000) node
->flags
|= exact
;
else if (rcnt
== 1) node
->score
/= 2;
if (rcnt
>= 2 || GameCnt
-Game50
> 99 ||
(node
->score
== 9999-ply
&& !ChkFlag
[ply
]))
node
->flags
|= draw
; node
->flags
|= exact
;
if (side
== computer
) node
->score
= contempt
;
else node
->score
= -contempt
;
node
->reply
= nxtline
[ply
+1];
UnmakeMove(side
,node
,&tempb
,&tempc
,&tempsf
,&tempst
);
if (node
->score
> best
&& !timeout
)
if (node
->score
> alpha
&& !(node
->flags
& exact
))
best
= node
->score
; pbst
= pnt
;
if (best
> alpha
) alpha
= best
;
for (j
= ply
+1; nxtline
[j
] > 0; j
++) bstline
[j
] = nxtline
[j
];
for (j
= pnt
-1; j
>= 0; j
--) Tree
[j
+1] = Tree
[j
];
if (best
> beta
) ShowResults(best
,bstline
,'+');
else if (best
< alpha
) ShowResults(best
,bstline
,'-');
else ShowResults(best
,bstline
,'&');
if (NodeCnt
> ETnodes
) ElapsedTime(0);
if (timeout
) return(-Tscore
[ply
-1]);
mv
= (node
->f
<<8) + node
->t
;
if (hashflag
&& ply
<= Sdepth
&& *rpt
== 0 && best
== alpha
)
PutInTTable(side
,best
,depth
,alpha
,beta
,mv
);
j
= (node
->f
<<6) + node
->t
; if (side
== black
) j
|= 0x1000;
if (history
[j
] < 150) history
[j
] += 2*depth
;
if (node
->t
!= (GameList
[GameCnt
].gmove
& 0xFF))
if (best
<= beta
) killr3
[ply
] = mv
;
else if (mv
!= killr1
[ply
])
killr2
[ply
] = killr1
[ply
];
if (best
> 9000) killr0
[ply
] = mv
; else killr0
[ply
] = 0;
evaluate(side
,xside
,ply
,alpha
,beta
)
short side
,xside
,ply
,alpha
,beta
;
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.
hung
[white
] = hung
[black
] = 0;
slk
= ((mtl
[white
] == valueK
&& (pmtl
[black
] == 0 || emtl
[black
] == 0)) ||
(mtl
[black
] == valueK
&& (pmtl
[white
] == 0 || emtl
[white
] == 0)));
s
= -Pscore
[ply
-1] + mtl
[side
] - mtl
[xside
];
(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 (atak
[side
][PieceList
[xside
][0]] > 0) return(10001-ply
);
ataks(xside
,atak
[xside
]);
InChk
= (atak
[xside
][PieceList
[side
][0]] > 0);
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
];
Threat
[ply
-1] = (hung
[side
] > 1 && ply
== Sdepth
+1);
ProbeTTable(side
,depth
,alpha
,beta
,score
)
short side
,depth
,*alpha
,*beta
,*score
;
Look for the current board position in the transposition table.
if (side
== white
) hashkey
|= 1; else hashkey
&= 0xFFFE;
hindx
= (hashkey
& (ttblsz
-1));
if (ptbl
->depth
>= depth
&& ptbl
->hashbd
== hashbd
)
if (ptbl
->flags
& truescore
)
else if (ptbl->flags & upperbound)
if (ptbl->score < *beta) *beta = ptbl->score+1;
else if (ptbl
->flags
& lowerbound
)
if (ptbl
->score
> *alpha
) *alpha
= ptbl
->score
-1;
PutInTTable(side
,score
,depth
,alpha
,beta
,mv
)
short side
,score
,depth
,alpha
,beta
;
Store the current board position in the transposition table.
if (side
== white
) hashkey
|= 1; else hashkey
&= 0xFFFE;
hindx
= (hashkey
& (ttblsz
-1));
if (score
< alpha
) ptbl
->flags
|= upperbound
;
else if (score
> beta
) ptbl
->flags
|= lowerbound
;
else ptbl
->flags
|= truescore
;
for (i
= 0; i
< ttblsz
; i
++)
Fill the array Tree[] with all available moves for side to play. Array
TrPnt[ply] contains the index into Tree[] of the first move at a ply.
if (PV
== 0) Swag0
= killr0
[ply
]; else Swag0
= PV
;
Swag1
= killr1
[ply
]; Swag2
= killr2
[ply
];
Swag3
= killr3
[ply
]; Swag4
= 0;
if (ply
> 2) Swag4
= killr1
[ply
-2];
TrPnt
[ply
+1] = TrPnt
[ply
];
Dstart
[pawn
] = Dpwn
[side
]; Dstop
[pawn
] = Dstart
[pawn
] + 1;
for (i
= PieceCnt
[side
]; i
>= 0; i
--)
GenMoves(ply
,PieceList
[side
][i
],side
,xside
);
if (kingmoved
[side
] == 0 && !castld
[side
])
if (castle(side
,f
,f
+2,0))
LinkMove(ply
,f
,f
+2,xside
);
Tree
[TrPnt
[ply
+1]-1].flags
|= cstlmask
;
if (castle(side
,f
,f
-2,0))
LinkMove(ply
,f
,f
-2,xside
);
Tree
[TrPnt
[ply
+1]-1].flags
|= cstlmask
;
GenMoves(ply
,sq
,side
,xside
)
Generate moves for a piece. The from square is mapped onto a special
board and offsets (taken from array Dir[]) are added to the mapped
location. The newly generated square is tested to see if it falls off
the board by ANDing the square with 88 HEX. Legal moves are linked
piece
= board
[sq
]; m0
= map
[sq
];
for (i
= Dstart
[piece
]; i
<= Dstop
[piece
]; i
++)
LinkMove(ply
,sq
,u
,xside
);
else if (color
[u
] == xside
)
LinkMove(ply
,sq
,u
,xside
);
if (side
== white
&& color
[sq
+8] == neutral
)
LinkMove(ply
,sq
,sq
+8,xside
);
if (color
[sq
+16] == neutral
)
LinkMove(ply
,sq
,sq
+16,xside
);
else if (side
== black
&& color
[sq
-8] == neutral
)
LinkMove(ply
,sq
,sq
-8,xside
);
if (color
[sq
-16] == neutral
)
LinkMove(ply
,sq
,sq
-16,xside
);
for (i
= Dstart
[piece
]; i
<= Dstop
[piece
]; i
++)
if (!((m
= m0
+Dir
[i
]) & 0x88))
if (color
[u
] == xside
|| u
== epsquare
)
LinkMove(ply
,sq
,u
,xside
);
for (i
= Dstart
[piece
]; i
<= Dstop
[piece
]; i
++)
if (!((m
= m0
+Dir
[i
]) & 0x88))
if (color
[u
] != side
) LinkMove(ply
,sq
,u
,xside
);
Add a move to the tree. Assign a bonus to order the moves
2. Capture of last moved piece
3. Other captures (major pieces first)
node
= &Tree
[TrPnt
[ply
+1]];
node
->flags
= node
->reply
= 0;
node
->f
= f
; node
->t
= t
;
if (mv
== Swag0
) s
= 2000;
else if (mv
== Swag1
) s
= 60;
else if (mv
== Swag2
) s
= 50;
else if (mv
== Swag3
) s
= 40;
else if (mv
== Swag4
) s
= 30;
if (t
== TOsquare
) s
+= 500;
s
+= value
[board
[t
]] - board
[f
];
if (row
[t
] == 0 || row
[t
] == 7)
else if (row
[t
] == 1 || row
[t
] == 6)
else if (t
== epsquare
) node
->flags
|= epmask
;
z
= (f
<<6) + t
; if (xside
== white
) z
|= 0x1000;
CaptureList(side
,xside
,ply
)
Generate captures and Pawn promotions only.
node->f = sq; node->t = u;\
node->score = value[board[u]] + svalue[board[u]] - piece;\
if (piece == pawn && (u < 8 || u > 55))\
short d
,sq
,i
,j
,j1
,j2
,m0
,r7
,d0
,piece
,*PL
;
TrPnt
[ply
+1] = TrPnt
[ply
];
node
= &Tree
[TrPnt
[ply
]];
Dstart
[pawn
] = Dpwn
[side
]; Dstop
[pawn
] = Dstart
[pawn
] + 1;
for (i
= 0; i
<= PieceCnt
[side
]; i
++)
m0
= map
[sq
]; piece
= board
[sq
];
j1
= Dstart
[piece
]; j2
= Dstop
[piece
];
for (j
= j1
; j
<= j2
; j
++)
if (color
[u
] == neutral
) m
+= d
;
if (color
[u
] == xside
) LinkCapture
;
for (j
= j1
; j
<= j2
; j
++)
if (!((m
= m0
+Dir
[j
]) & 0x88))
if (color
[u
] == xside
) LinkCapture
;
if (piece
== pawn
&& row
[sq
] == r7
)
if (color
[u
] == neutral
) LinkCapture
;
int castle(side
,kf
,kt
,iop
)
Make or Unmake a castling move.
rf
= kf
+3; rt
= kt
-1; d
= 1;
rf
= kf
-4; rt
= kt
+1; d
= -1;
if (board
[kf
] != king
|| board
[rf
] != rook
|| color
[rf
] != side
)
if (color
[kt
] != neutral
|| color
[rt
] != neutral
) return(false);
if (d
== -1 && color
[kt
+d
] != neutral
) return(false);
if (SqAtakd(kf
,xside
)) return(false);
if (SqAtakd(kt
,xside
)) return(false);
if (SqAtakd(kf
+d
,xside
)) return(false);
if (iop
== 1) castld
[side
] = true; else castld
[side
] = false;
t0
= kt
; kt
= kf
; kf
= t0
;
t0
= rt
; rt
= rf
; rf
= t0
;
board
[kt
] = king
; color
[kt
] = side
; Pindex
[kt
] = 0;
board
[kf
] = no_piece
; color
[kf
] = neutral
;
board
[rt
] = rook
; color
[rt
] = side
; Pindex
[rt
] = Pindex
[rf
];
board
[rf
] = no_piece
; color
[rf
] = neutral
;
PieceList
[side
][Pindex
[kt
]] = kt
;
PieceList
[side
][Pindex
[rt
]] = rt
;
UpdateHashbd(side
,king
,kf
,kt
);
UpdateHashbd(side
,rook
,rf
,rt
);
Make or unmake an en passant move.
if (t
> f
) l
= t
-8; else l
= t
+8;
board
[l
] = no_piece
; color
[l
] = neutral
;
board
[l
] = pawn
; color
[l
] = xside
;
MakeMove(side
,node
,tempb
,tempc
,tempsf
,tempst
)
short side
,*tempc
,*tempb
,*tempsf
,*tempst
;
Update Arrays board[], color[], and Pindex[] to reflect the new board
position obtained after making the move pointed to by node. Also
update miscellaneous stuff that changes when a move is made.
f
= node
->f
; t
= node
->t
; epsquare
= -1;
FROMsquare
= f
; TOsquare
= t
;
GameList
[++GameCnt
].gmove
= (f
<<8) + t
;
if (node
->flags
& cstlmask
)
GameList
[GameCnt
].piece
= no_piece
;
GameList
[GameCnt
].color
= side
;
*tempc
= color
[t
]; *tempb
= board
[t
];
*tempsf
= svalue
[f
]; *tempst
= svalue
[t
];
GameList
[GameCnt
].piece
= *tempb
;
GameList
[GameCnt
].color
= *tempc
;
UpdatePieceList(*tempc
,t
,1);
if (*tempb
== pawn
) --PawnCnt
[*tempc
][column
[t
]];
--PawnCnt
[side
][column
[f
]];
++PawnCnt
[side
][column
[t
]];
cf
= column
[f
]; ct
= column
[t
];
if (PawnCnt
[side
][ct
] > 1+PawnCnt
[side
][cf
])
else if (PawnCnt
[side
][ct
] < 1+PawnCnt
[side
][cf
])
else if (ct
== 0 || ct
== 7 || PawnCnt
[side
][ct
+ct
-cf
] == 0)
mtl
[xside
] -= value
[*tempb
];
if (*tempb
== pawn
) pmtl
[xside
] -= valueP
;
if (hashflag
) UpdateHashbd(xside
,*tempb
,-1,t
);
color
[t
] = color
[f
]; board
[t
] = board
[f
]; svalue
[t
] = svalue
[f
];
Pindex
[t
] = Pindex
[f
]; PieceList
[side
][Pindex
[t
]] = t
;
color
[f
] = neutral
; board
[f
] = no_piece
;
if (t
-f
== 16) epsquare
= f
+8;
else if (f
-t
== 16) epsquare
= f
-8;
if (node
->flags
& promote
)
--PawnCnt
[side
][column
[t
]];
mtl
[side
] += valueQ
- valueP
;
UpdateHashbd(side
,pawn
,f
,-1);
UpdateHashbd(side
,queen
,f
,-1);
if (board
[t
] == king
) ++kingmoved
[side
];
if (node
->flags
& epmask
) EnPassant(xside
,f
,t
,1);
else if (hashflag
) UpdateHashbd(side
,board
[t
],f
,t
);
UnmakeMove(side
,node
,tempb
,tempc
,tempsf
,tempst
)
short side
,*tempc
,*tempb
,*tempsf
,*tempst
;
f
= node
->f
; t
= node
->t
; epsquare
= -1;
if (node
->flags
& cstlmask
) castle(side
,f
,t
,2);
color
[f
] = color
[t
]; board
[f
] = board
[t
]; svalue
[f
] = *tempsf
;
Pindex
[f
] = Pindex
[t
]; PieceList
[side
][Pindex
[f
]] = f
;
color
[t
] = *tempc
; board
[t
] = *tempb
; svalue
[t
] = *tempst
;
if (node
->flags
& promote
)
++PawnCnt
[side
][column
[t
]];
mtl
[side
] += valueP
- valueQ
;
UpdateHashbd(side
,queen
,-1,t
);
UpdateHashbd(side
,pawn
,-1,t
);
UpdatePieceList(*tempc
,t
,2);
if (*tempb
== pawn
) ++PawnCnt
[*tempc
][column
[t
]];
--PawnCnt
[side
][column
[t
]];
++PawnCnt
[side
][column
[f
]];
mtl
[xside
] += value
[*tempb
];
if (*tempb
== pawn
) pmtl
[xside
] += valueP
;
if (hashflag
) UpdateHashbd(xside
,*tempb
,-1,t
);
if (board
[f
] == king
) --kingmoved
[side
];
if (node
->flags
& epmask
) EnPassant(xside
,f
,t
,2);
else if (hashflag
) UpdateHashbd(side
,board
[f
],f
,t
);
UpdateHashbd(side
,piece
,f
,t
)
hashbd contains a 32 bit "signature" of the board position. hashkey
contains a 16 bit code used to address the hash table. When a move is
made, XOR'ing the hashcode of moved piece on the from and to squares
with the hashbd and hashkey values keeps things current.
hashbd
^= hashcode
[side
][piece
][f
].bd
;
hashkey
^= hashcode
[side
][piece
][f
].key
;
hashbd
^= hashcode
[side
][piece
][t
].bd
;
hashkey
^= hashcode
[side
][piece
][t
].key
;
UpdatePieceList(side
,sq
,iop
)
Update the PieceList and Pindex arrays when a piece is captured or
when a capture is unmade.
for (i
= Pindex
[sq
]; i
<= PieceCnt
[side
]; i
++)
PieceList
[side
][i
] = PieceList
[side
][i
+1];
Pindex
[PieceList
[side
][i
]] = i
;
PieceList
[side
][PieceCnt
[side
]] = sq
;
Pindex
[sq
] = PieceCnt
[side
];
Scan thru the board seeing what's on each square. If a piece is found,
update the variables PieceCnt, PawnCnt, Pindex and PieceList. Also
determine the material for each side and set the hashkey and hashbd
variables to represent the current board position. Array
PieceList[side][indx] contains the location of all the pieces of
either side. Array Pindex[sq] contains the indx into PieceList for a
PawnCnt
[white
][i
] = PawnCnt
[black
][i
] = 0;
mtl
[white
] = mtl
[black
] = pmtl
[white
] = pmtl
[black
] = 0;
PieceCnt
[white
] = PieceCnt
[black
] = 0;
for (sq
= 0; sq
< 64; sq
++)
if (color
[sq
] != neutral
)
mtl
[color
[sq
]] += value
[board
[sq
]];
pmtl
[color
[sq
]] += valueP
;
++PawnCnt
[color
[sq
]][column
[sq
]];
if (board
[sq
] == king
) Pindex
[sq
] = 0;
else Pindex
[sq
] = ++PieceCnt
[color
[sq
]];
PieceList
[color
[sq
]][Pindex
[sq
]] = sq
;
hashbd
^= hashcode
[color
[sq
]][board
[sq
]][sq
].bd
;
hashkey
^= hashcode
[color
[sq
]][board
[sq
]][sq
].key
;
Find the best move in the tree between indexes p1 and p2. Swap the
best move into the p1 element.
s0
= Tree
[p1
].score
; p0
= p1
;
for (p
= p1
+1; p
<= p2
; p
++)
if ((s
= Tree
[p
].score
) > s0
)
temp
= Tree
[p1
]; Tree
[p1
] = Tree
[p0
]; Tree
[p0
] = temp
;
Check for draw by threefold repetition.
memset((char *)b,0,64*sizeof(short));
for (i
= 0; i
< 64; b
[i
++] = 0);
for (i
= GameCnt
; i
> Game50
; i
--)
m
= GameList
[i
].gmove
; f
= m
>>8; t
= m
& 0xFF;
if (++b
[f
] == 0) c
--; else c
++;
if (--b
[t
] == 0) c
--; else c
++;
See if any piece with color 'side' ataks sq. First check for pawns
or king, then try other pieces. Array Dcode is used to check for
knight attacks or R,B,Q co-linearity.
short i
,m0
,m1
,loc
,piece
,*PL
;
if (side
== white
) m
= m1
-0x0F; else m
= m1
+0x0F;
if (board
[unmap
[m
]] == pawn
&& color
[unmap
[m
]] == side
) return(true);
if (side
== white
) m
= m1
-0x11; else m
= m1
+0x11;
if (board
[unmap
[m
]] == pawn
&& color
[unmap
[m
]] == side
) return(true);
if (distance(sq
,PieceList
[side
][0]) == 1) return(true);
for (i
= 1; i
<= PieceCnt
[side
]; i
++)
loc
= PL
[i
]; piece
= board
[loc
];
if (piece
== pawn
) continue;
m0
= map
[loc
]; d
= Dcode
[abs(m1
-m0
)];
if (d
== 0 || (Pdir
[d
] & pbit
[piece
]) == 0) continue;
if (piece
== knight
) return(true);
for (m
= m0
+d
; m
!= m1
; m
+= d
)
if (color
[unmap
[m
]] != neutral
) break;
if (m
== m1
) return(true);
Fill array atak[][] with info about ataks to a square. Bits 8-15
are set if the piece (king..pawn) ataks the square. Bits 0-7
contain a count of total ataks to the square.
short d
,c
,j
,j1
,j2
,piece
,i
,m0
,sq
,*PL
;
memset((char *)a,0,64*sizeof(short));
for (u
= 0; u
< 64; a
[u
++] = 0);
Dstart
[pawn
] = Dpwn
[side
]; Dstop
[pawn
] = Dstart
[pawn
] + 1;
for (i
= 0; i
<= PieceCnt
[side
]; i
++)
c
= control
[piece
]; j1
= Dstart
[piece
]; j2
= Dstop
[piece
];
for (j
= j1
; j
<= j2
; j
++)
if (color
[u
] == neutral
) m
+= d
;
for (j
= j1
; j
<= j2
; j
++)
if (!((m
= m0
+Dir
[j
]) & 0x88))
/* ............ POSITIONAL EVALUATION ROUTINES ............ */
ScorePosition(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
wking
= PieceList
[white
][0]; bking
= PieceList
[black
][0];
pscore
[white
] = pscore
[black
] = 0;
for (c1
= white
; c1
<= black
; 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
++)
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
)
Static evaluation when loser has only a king and winner has no pawns
short winner
,loser
,king1
,king2
,s
,i
;
if (mtl
[white
] > mtl
[black
]) winner
= white
; else winner
= black
;
loser
= otherside
[winner
];
king1
= PieceList
[winner
][0]; king2
= PieceList
[loser
][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
;
int ScoreKPK(side
,winner
,loser
,king1
,king2
,sq
)
short side
,winner
,loser
,king1
,king2
,sq
;
Score King and Pawns versus King endings.
if (PieceCnt
[winner
] == 1) s
= 50; else s
= 120;
if (side
== loser
) r
= row
[sq
]-1; else r
= row
[sq
];
if (row
[king2
] >= r
&& distance(sq
,king2
) < 8-r
) s
+= 10*row
[sq
];
if (row
[sq
] < 6) sq
+= 16; else sq
+= 8;
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
));
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.
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
);
Calculate the positional value for the piece on 'sq'.
register short j
,fyle
,rank
;
short s
,piece
,a1
,a2
,in_square
,r
,mob
,e
,c
;
a1
= (atk1
[sq
] & 0x4FFF); a2
= (atk2
[sq
] & 0x4FFF);
rank
= row
[sq
]; fyle
= column
[sq
];
if (piece
== pawn
&& c1
== white
)
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))
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 (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
)
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))
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 (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
)
else if (piece
== bishop
)
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
);
if (stage
> 2) s
+= 14 - taxicab(sq
,EnemyKing
);
if (distance(sq
,EnemyKing
) < 3) s
+= 12;
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 (PC1
[0] == 0) s
+= KHOPN
;
if (PC2
[0] == 0) s
+= KHOPNX
;
if (PC1
[7] == 0) s
+= KHOPN
;
if (PC2
[7] == 0) s
+= KHOPNX
;
c
= (control
[piece
] & 0x4FFF);
if (piece
!= king
&& trapped(sq
,piece
)) ++hung
[c1
];
else if (piece
!= pawn
|| a2
> a1
)
if (a2
>= c
|| a1
< ctlP
) s
+= ATAKD
;
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.
if (atk1[u] == 0 || (atk2[u] & 0xFF) > 1) ++cnt;\
if (HasBishop
[c2
] || HasQueen
[c2
])
for (i
= Dstart
[bishop
]; i
<= Dstop
[bishop
]; i
++)
if (atk2
[u
] & ctlBQ
) ScoreThreat
;
if (color
[u
] != neutral
) break;
if (HasRook
[c2
] || HasQueen
[c2
])
for (i
= Dstart
[rook
]; i
<= Dstop
[rook
]; i
++)
if (atk2
[u
] & ctlRQ
) ScoreThreat
;
if (color
[u
] != neutral
) break;
for (i
= Dstart
[knight
]; i
<= Dstop
[knight
]; i
++)
if (!((m
= m0
+Dir
[i
]) & 0x88))
if (atk2
[u
] & ctlNN
) ScoreThreat
;
*s
+= (KSFTY
*Kthreat
[cnt
]) / 16;
for (i
= Dstart
[king
]; i
<= Dstop
[king
]; i
++)
if (!((m
= m0
+Dir
[i
]) & 0x88))
if (board
[u
] == pawn
) ok
= true;
if (atk2
[u
] > ctlQ
+1 && atk1
[u
] < ctlQ
) *s
-= 4*KSFTY
;
if (cnt
> 1) *s
-= KSFTY
;
Find Bishop and Rook mobility, XRAY attacks, and pins. Increment the
hung[] array if a pin is found.
short d
,j
,m0
,piece
,pin
,*Kf
;
m0
= map
[sq
]; piece
= board
[sq
];
for (j
= Dstart
[piece
]; j
<= Dstop
[piece
]; j
++)
u
= unmap
[m
]; *s
+= Kf
[u
];
if (board
[u
] == pawn
|| board
[u
] == king
) break;
else if (color
[u
] == c2
&& (board
[u
] > piece
|| atk2
[u
] == 0))
atk1
[pin
] > control
[board
[pin
]]+1)
See if the attacked piece has unattacked squares to move to.
for (i
= Dstart
[piece
]; i
<= Dstop
[piece
]; i
++)
if (color
[u
] == c1
) break;
if (atk2
[u
] == 0 || board
[u
] >= piece
) return(false);
if (color
[u
] == c2
) break;
if (c1
== white
) u
= sq
+8; else u
= sq
-8;
if (color
[u
] == neutral
&& atk1
[u
] >= atk2
[u
])
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);
for (i
= Dstart
[piece
]; i
<= Dstop
[piece
]; i
++)
if (!((m
= m0
+Dir
[i
]) & 0x88))
if (atk2
[u
] == 0 || board
[u
] >= piece
) return(false);
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.
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
]);
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;
Developed
[white
] = (board
[1] != knight
&& board
[2] != bishop
&&
board
[5] != bishop
&& board
[6] != knight
);
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;
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 ((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 (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
;
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;
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 material balance has changed, determine the values for the
positional evaluation terms.
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 */
KNIGHTPOST
= (stage
+2)/3; /* knight near enemy pieces */
KNIGHTSTRONG
= (stage
+6)/2; /* occupies pawn hole */
BISHOPSTRONG
= (stage
+6)/2; /* occupies pawn hole */
RHOPN
= 10; /* rook on half open file */
XRAY
= 8; /* Xray attack on piece */
KHOPN
= (3*stage
-30) / 2; /* king on half open file */
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 */
d1
= abs(column
[a
]-column
[b
]);
return(d1
> d2
? d1
: d2
);
for (sq
= 0; sq
< 64; sq
++)
c
[sq
] = (a
[sq
]*(10-stage
) + b
[sq
]*stage
) / 10;
for (sq
= 0; sq
< 64; sq
++)