home *** CD-ROM | disk | FTP | other *** search
- /************************************************************************/
- /* C source for CHESS */
- /* */
- /* Revision: 4-25-88 */
- /* */
- /* 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. */
- /************************************************************************/
- /* This file has been modified to be compilable with SAS/C 6 for Amiga */
- /* Computers. To optimize compile speed and to make it better to under- */
- /* stand I removed most other machine/compiler specific code. */
- /* */
- /* Also a blank char here or there improves readability by great means. */
- /* */
- /* Some if-constructs replaced by "? :" terms */
- /* */
- /* Declared this-file-use-only functions as static to make possible */
- /* optimizer inlining */
- /* */
- /* Michael Böhnisch, 1993 */
- /* billy@uni-paderborn.de */
- /************************************************************************/
-
- #include <stdio.h>
- #include <ctype.h>
-
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <m68881.h>
- #include <math.h>
-
- #define ttblsz 16384
-
- #include "Proto.h"
- #include "Interface.h"
-
- /* -------------------------------------------------------------------- */
- /* Prototypes for static functions */
- /* -------------------------------------------------------------------- */
-
- static void EnPassant(short, short, short, short);
- static void OpeningBook(void);
- static short search(short, short, short, short, short, unsigned short *, short *);
- static short evaluate(short, short, short, short, short);
- static int ProbeTTable(short, short, short *, short *, short *);
- static void PutInTTable(short, short, short, short, short, unsigned short);
- static void ZeroTTable(void);
- static void GenMoves(short, short, short, short);
- static void LinkMove(short, short, short, short);
- static void CaptureList(short, short, short);
- static void MakeMove(short, struct leaf *, short *, short *, short *, short *);
- static void UnmakeMove(short, struct leaf *, short *, short *, short *, short *);
- static void UpdateHashbd(short, short, short, short);
- static void UpdatePieceList(short, short, short );
- static void pick(short, short);
- static void repetition(short *);
- static void ataks(short, short *);
- static void ScoreLoneKing(short, short *);
- static short ScoreKPK(short, short, short, short, short, short);
- static short ScoreKBNK(short, short, short);
- static void KingScan(short, short *);
- static void BRscan(short, short *, short *);
- static int trapped(short, short);
- static void UpdateWeights(void);
- static void BlendBoard(short *, short *, short *);
- static void CopyBoard(short *, short *);
-
- #define neutral 2
- #define white 0
- #define black 1
- #define no_piece 0
- #define pawn 1
- #define knight 2
- #define bishop 3
- #define rook 4
- #define queen 5
- #define king 6
- #define valueP 100
- #define valueN 350
- #define valueB 355
- #define valueR 550
- #define valueQ 1100
- #define valueK 1200
- #define ctlP 0x4000
- #define ctlN 0x2800
- #define ctlB 0x1800
- #define ctlR 0x0400
- #define ctlQ 0x0200
- #define ctlK 0x0100
- #define ctlBQ 0x1200
- #define ctlRQ 0x0600
- #define ctlNN 0x2000
- #define pxx " PNBRQK"
- #define qxx " pnbrqk"
- #define rxx "12345678"
- #define cxx "abcdefgh"
- #define check 0x0001
- #define capture 0x0002
- #define draw 0x0004
- #define promote 0x0008
- #define cstlmask 0x0010
- #define epmask 0x0020
- #define exact 0x0040
- #define pwnthrt 0x0080
- #define truescore 0x0001
- #define lowerbound 0x0002
- #define upperbound 0x0004
- #define maxdepth 30
- #define true 1
- #define false 0
- #define absv(x) ((x) < 0 ? -(x) : (x))
- #define taxicab(a,b) (abs(column[a]-column[b]) + abs(row[a]-row[b]))
-
- struct leaf {
- short f, t, score, reply;
- unsigned short flags;
- };
-
- struct GameRec {
- unsigned short gmove;
- short score, depth, time, piece, color;
- long nodes;
- };
-
- struct TimeControlRec {
- short moves[2];
- long clock[2];
- };
-
- struct BookEntry {
- struct BookEntry *next;
- unsigned short *mv;
- };
-
- struct hashval {
- unsigned long bd;
- unsigned short key;
- };
-
- struct hashentry {
- unsigned long hashbd;
- unsigned short mv, flags;
- short score, depth;
- };
-
- char mvstr1[5], mvstr2[5];
-
- struct leaf __far Tree[2000];
- struct GameRec __far GameList[240];
- struct leaf *root;
-
- short TrPnt[maxdepth], board[64], color[64], row[64], column[64],
- locn[8][8], Pindex[64], svalue[64], PieceList[2][16],
- PieceCnt[2], atak[2][64], PawnCnt[2][8], castld[2],
- kingmoved[2], mtl[2], pmtl[2], emtl[2], hung[2], c1, c2,
- *atk1, *atk2, *PC1, *PC2, EnemyKing, mate, post, opponent,
- computer, Sdepth, Awindow, Bwindow, dither;
-
- long ResponseTime, ExtraTime, Level, et, et0, time0, cputimer, ft;
- NodeCnt, evrate, ETnodes, EvalNodes, HashCnt;
-
- short quit, reverse, bothsides, hashflag, InChk, player, force,
- beep, wking, bking, FROMsquare, TOsquare, timeout, Zscore,
- zwndw, xwndw, slk, INCscore, HasPawn[2], HasKnight[2],
- HasBishop[2], HasRook[2], HasQueen[2], ChkFlag[maxdepth],
- CptrFlag[maxdepth], PawnThreat[maxdepth], Pscore[maxdepth],
- Tscore[maxdepth], Threat[maxdepth], GameCnt, Game50,
- epsquare, lpost, rcptr, contempt, MaxSearchDepth;
-
- struct BookEntry *Book;
- struct TimeControlRec TimeControl;
-
- short TCflag, TCmoves, TCminutes, OperatorTime,
- otherside[3] = {1, 0, 2},
- rank7[3] = {6, 1, 0};
-
- short map[64]= {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 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
- };
-
- short unmap[120]= {
- 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
- };
-
- short Dcode[120]= {
- 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,
- 0x10, 0, 0, 0, 0, 0, 0, 0x11
- };
-
- short Stboard[64]= {
- 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
- };
-
- short Stcolor[64]= {
- 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},
- Dpwn[3] = { 4, 6, 0 },
- Dstart[7] = { 6, 4, 8, 4, 0, 0, 0 },
- Dstop[7] = { 7, 5, 15, 7, 3, 7, 7 },
- Dir[16] = { 1, 0x10, -1, -0x10, 0x0F, 0x11, -0x0F, -0x11,
- 0x0E, -0x0E, 0x12, -0x12, 0x1F, -0x1F, 0x21, -0x21 },
- 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, 0, 0x02 },
- pbit[7] = { 0, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20};
-
- unsigned short killr0[maxdepth], killr1 [maxdepth], killr2[maxdepth],
- killr3[maxdepth], PrVar[maxdepth],
- PV, hint, Swag0, Swag1, Swag2, Swag3, Swag4,
- hashkey;
-
- unsigned long hashbd;
-
- struct hashval hashcode[2][7][64];
- struct hashentry *ttable, *ptbl;
- unsigned char history[8192];
-
- short Mwpawn[64], Mbpawn[64], Mknight[2][64], Mbishop[2][64],
- Mking[2][64], Kfield[2][64],
- value[7] = { 0, valueP, valueN, valueB, valueR, valueQ, valueK },
- control[7] = { 0, ctlP, ctlN, ctlB, ctlR, ctlQ, ctlK },
- PassedPawn0[8] = { 0, 60, 80, 120, 200, 360, 600, 800 },
- PassedPawn1[8] = { 0, 30, 40, 60, 100, 180, 300, 800 },
- PassedPawn2[8] = { 0, 15, 25, 35, 50, 90, 140, 800 },
- PassedPawn3[8] = { 0, 5, 10, 15, 20, 30, 140, 800 },
- ISOLANI[8] = { -12, -16, -20, -24, -24, -20, -16, -12 },
- BACKWARD[8] = { -6, -10, -15, -21, -28, -28, -28, -28 },
- BMBLTY[14] = { -2, 0, 2, 4, 6, 8, 10, 12, 13, 14, 15, 16, 16, 16 },
- RMBLTY[14] = { 0, 2, 4, 6, 8, 10, 11, 12, 13, 14, 14, 14, 14, 14 },
- Kthreat[16] = { 0, -8, -20, -36, -52, -68, -80, -80,
- -80, -80, -80, -80, -80, -80, -80, -80 },
- KNIGHTPOST, KNIGHTSTRONG, BISHOPSTRONG, KATAK, KBNKsq,
- PEDRNK2B, PWEAKH, PADVNCM, PADVNCI, PAWNSHIELD, PDOUBLED, PBLOK,
- RHOPN, RHOPNX, KHOPN, KHOPNX, KSFTY,
- ATAKD, HUNGP, HUNGX, KCASTLD, KMOVD, XRAY, PINVAL,
- stage, stage2, Zwmtl, Zbmtl, Developed[2], PawnStorm,
- PawnBonus, BishopBonus, RookBonus,
- 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
- },
- 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
- },
- 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
- },
- 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
- },
- 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
- },
- 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
- },
- 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
- };
-
- void main(int argc, char **argv)
- {
- ttable = (struct hashentry *) malloc(ttblsz * sizeof(struct hashentry));
- Level = 0;
- TCflag = false;
- OperatorTime = 0;
- if ( argc == 2 )
- Level = atoi(argv[1]);
- if ( argc == 3 ) {
- TCmoves = atoi(argv[1]);
- TCminutes = atoi(argv[2]);
- TCflag = true;
- }
- Initialize();
- NewGame();
- while ( !(quit) ) {
- if ( bothsides && !mate )
- SelectMove(opponent, 1);
- else
- InputCommand();
- if ( !(quit || mate || force) )
- SelectMove(computer, 1);
- }
- ExitChess();
- }
-
- /* ............... 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. */
- /************************************************************************/
-
- int VerifyMove(char *s, short iop, unsigned short *mv)
- {
- static short pnt, tempb, tempc, tempsf, tempst, cnt;
- static struct leaf xnode;
- struct leaf *node;
-
- *mv = 0;
- if ( iop == 2 ) {
- UnmakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
- return false;
- }
- cnt = 0;
- MoveList(opponent, 2);
- pnt = TrPnt[2];
- while ( pnt < TrPnt[3] ) {
- node = &Tree[pnt++];
- algbr(node->f, node->t, node->flags & cstlmask);
- if ( strcmp(s,mvstr1) == 0 || strcmp(s,mvstr2) == 0 ) {
- cnt++;
- xnode = *node;
- }
- }
- if ( cnt == 1 ) {
- MakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
- if ( SqAtakd(PieceList[opponent][0], computer) ) {
- UnmakeMove(opponent, &xnode, &tempb, &tempc, &tempsf, &tempst);
- ShowMessage("Illegal Move!!");
- return(false);
- }
- else {
- 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) )
- Game50 = GameCnt;
- GameList[GameCnt].depth =
- GameList[GameCnt].score =
- GameList[GameCnt].nodes = 0;
- ElapsedTime(1);
- GameList[GameCnt].time = (short) et;
- TimeControl.clock[opponent] -= et;
- --TimeControl.moves[opponent];
- *mv = (xnode.f << 8) + xnode.t;
- algbr(xnode.f, xnode.t, false);
- return true;
- }
- }
- if ( cnt > 1 )
- ShowMessage("Ambiguous Move!");
- return false ;
- }
-
- /************************************************************************/
- /* Reset the board and other variables to start a new game. */
- /************************************************************************/
-
- void NewGame(void)
- {
- short l, r, c, p;
-
- mate =
- quit =
- force =
- PawnStorm =
- Developed[white] =
- Developed[black] =
- castld[white] =
- castld[black] =
- PawnThreat[0] =
- CptrFlag[0] =
- Threat[0] = false;
- rcptr = true;
- lpost =
- NodeCnt =
- epsquare =
- et0 =
- contempt =
- dither =
- Game50 =
- Zwmtl =
- Zbmtl =
- kingmoved[white] =
- kingmoved[black] = 0;
- GameCnt = -1;
- Pscore[0] =
- Tscore[0] = 12000;
- for ( r = 0; r < 8; r++ )
- for ( c = 0; c < 8; c++ ) {
- 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++ )
- for ( l = 0; l < 64; l++ ) {
- hashcode[c][p][l].key = (unsigned short) rand();
- hashcode[c][p][l].bd = ((unsigned long) rand() << 16) + (unsigned long) rand();
- }
- ClrScreen();
- if ( TCflag )
- SetTimeControl();
- else
- if ( Level == 0 )
- SelectLevel();
- UpdateDisplay(0, 0, 1, 0);
- InitializeStats();
- time0 = time(NULL);
- ElapsedTime(1);
- GetOpenings();
- }
-
-
- void algbr(short f, short t, short iscastle)
- {
- 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 ( iscastle )
- strcpy(mvstr2, (t>f) ? "o-o" : "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. */
- /************************************************************************/
-
- int SelectMove(short side, short iop)
- {
- static short i, alpha, beta, score, tempb, tempc, tempsf, tempst, xside, rpt;
-
- timeout = false;
- xside = otherside[side];
- if ( iop != 2 )
- player = side;
- if ( TCflag ) {
- if ( TimeControl.moves[side] + 3 - OperatorTime )
- ResponseTime = TimeControl.clock[side] / TimeControl.moves[side] + 3 - OperatorTime;
- else
- ResponseTime = 0;
- 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;
- ExtraTime = 0;
- ExaminePosition();
- ScorePosition(side, &score);
- ShowSidetomove();
-
- if ( Sdepth == 0 ) {
- ZeroTTable();
- SearchStartStuff(side);
- memset(history, 0, 8192);
- FROMsquare = TOsquare = -1;
- PV = 0;
- if ( iop != 2 )
- hint = 0;
- for ( i = 0; i < maxdepth; i++ )
- PrVar[i] =
- killr0[i] =
- killr1[i] =
- killr2[i] =
- killr3[i] = 0;
- alpha = score-90;
- beta = score+90;
- rpt =
- TrPnt[1] = 0;
- root = &Tree[0];
- MoveList(side, 1);
- 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 =
- Zscore = 0;
- zwndw = 20;
- }
-
- while ( ! timeout && Sdepth < MaxSearchDepth ) {
- Sdepth++;
- ShowDepth(' ');
- score = search(side, 1, Sdepth, alpha, beta, PrVar, &rpt);
- for ( i = 1; i <= Sdepth; i++ )
- killr0[i] = PrVar[i];
- if ( score < alpha ) {
- ShowDepth('-');
- ExtraTime = 10 * ResponseTime;
- ZeroTTable();
- score = search(side, 1, Sdepth, -9000, beta, PrVar, &rpt);
- }
- if ( score > beta && ! (root->flags & exact) ) {
- ShowDepth('+');
- ExtraTime = 0;
- ZeroTTable();
- score = search(side, 1, Sdepth, alpha, 9000, PrVar, &rpt);
- }
- score = root->score;
- if ( ! timeout )
- 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
- ExtraTime = (score > Zscore-3*zwndw) ? ResponseTime : 3 * ResponseTime;
- if ( (root->flags & exact) || (Tree[1].score < -9000) || (4*et > 2*ResponseTime+ExtraTime) )
- timeout = true;
- if ( ! timeout ) {
- Tscore[0] = score;
- Zscore = Zscore ? (Zscore+score)/2 : score;
- }
- zwndw = 20 + abs(Zscore / 12);
- beta = score + Bwindow;
- alpha = (Zscore < score) ? Zscore-Awindow-zwndw : score-Awindow-zwndw;
- }
-
- score = root->score;
- if ( rpt >= 2 || score < -12000 )
- root->flags |= draw;
- if ( iop == 2 )
- return 0;
- if ( Book == NULL )
- hint = PrVar[2];
- ElapsedTime(1);
-
- if ( score > -9999 && rpt <= 2 ) {
- MakeMove(side, root, &tempb, &tempc, &tempsf, &tempst);
- algbr(root->f, root->t, root->flags & cstlmask);
- }
- else
- mvstr1[0] = '\0';
- OutputMove();
- if ( score == -9999 || score == 9998 )
- mate = true;
- if ( mate )
- hint = 0;
- if ( root->flags & cstlmask )
- Game50 = GameCnt;
- else
- if ( board[root->t] == pawn || (root->flags & capture) )
- Game50 = GameCnt;
- GameList[GameCnt].score = score;
- GameList[GameCnt].nodes = NodeCnt;
- GameList[GameCnt].time = (short) et;
- GameList[GameCnt].depth = Sdepth;
- if ( TCflag ) {
- TimeControl.clock[side] -= et + OperatorTime;
- if ( --TimeControl.moves[side] == 0 )
- SetTimeControl();
- }
- if ( ((root->flags & draw) && bothsides) || (GameCnt > 238) )
- quit = true;
- player = xside;
- Sdepth = 0;
- return(0);
- }
-
- /************************************************************************/
- /* 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 book transpositions. */
- /************************************************************************/
-
- static void OpeningBook(void)
- {
- short j, pnt;
- unsigned short m, *mp;
- unsigned r, r0;
- struct BookEntry *p;
-
- srand((unsigned) time0);
- r0 =
- m = 0;
- p = Book;
- while ( p != NULL ) {
- mp = p->mv;
- for ( j = 0; j <= GameCnt; j++ )
- if ( GameList[j].gmove != *(mp++) )
- break;
- if ( j > GameCnt )
- if ( (r = rand()) > r0 ) {
- r0 = r;
- m = *mp;
- hint = *(++mp);
- }
- p = p->next;
- }
-
- 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); \
- if ( pnt > TrPnt[1] ) { \
- 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; \
- } \
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- static short search(short side, short ply, short depth, short alpha, short beta,
- unsigned short *bstline, short *rpt)
-
- #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 j, pnt;
- short best, tempb, tempc, tempsf, tempst;
- short xside, pbst, d, e, cf, score, rcnt;
- unsigned short mv, nxtline[maxdepth];
- struct leaf *node, tmp;
-
- NodeCnt++;
- xside = otherside[side];
- 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 ( score > 9000 ) {
- bstline[ply] = 0;
- return score;
- }
-
- if ( depth > 0 ) {
- if ( InChk || PawnThreat[ply-1] || ReCapture )
- ++depth;
- }
- else {
- if ( score >= alpha && (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);
- bstline[ply] = PV;
- bstline[ply+1] = 0;
- if ( beta == -20000 )
- return score;
- if ( alpha > beta )
- return alpha;
- }
-
- d = (Sdepth == 1) ? 7 : 11;
-
- if ( ply > Sdepth+d || (depth < 1 && score > beta) )
- return score;
-
- if ( ply > 1 )
- 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);
-
- best = (depth > 0) ? -12000 : score;
-
- if ( best > alpha )
- alpha = best;
-
- for ( pnt = pbst = TrPnt[ply]; pnt < TrPnt[ply+1] && best <= beta; pnt++ ) {
- if ( ply > 1 )
- pick(pnt, TrPnt[ply+1] - 1);
- node = &Tree[pnt];
- mv = (node->f << 8) + node->t;
- nxtline[ply+1] = 0;
-
- if ( prune )
- break;
- 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;
- PV = node->reply;
- node->score = -search(xside, ply+1, depth-1, -beta, -alpha, nxtline, &rcnt);
- 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 | exact;
- node->score = (side == computer) ? contempt : -contempt;
- }
- node->reply = nxtline[ply+1];
- UnmakeMove(side, node, &tempb, &tempc, &tempsf, &tempst);
- }
- if ( node->score > best && !timeout ) {
- if ( depth > 0 )
- if ( node->score > alpha && !(node->flags & exact) )
- node->score += depth;
- best = node->score;
- pbst = pnt;
- if ( best > alpha )
- alpha = best;
- for ( j = ply+1; nxtline[j] > 0; j++ )
- bstline[j] = nxtline[j];
- bstline[j] = 0;
- bstline[ply] = mv;
- if ( ply == 1 ) {
- if ( best == alpha ) {
- tmp = Tree[pnt];
- for ( j = pnt-1; j >= 0; j-- )
- Tree[j+1] = Tree[j];
- Tree[0] = tmp;
- pbst = 0;
- }
- if ( Sdepth > 2 )
- ShowResults(best, bstline, (best < alpha) ? '-' : ((best > beta) ? '+' : '&'));
- }
- }
- if ( NodeCnt > ETnodes )
- ElapsedTime(0);
- if ( timeout )
- return (short) -Tscore[ply-1];
- }
-
- node = &Tree[pbst];
- mv = (node->f<<8) + node->t;
- if ( hashflag && ply <= Sdepth && *rpt == 0 && best == alpha )
- PutInTTable(side, best, depth, alpha, beta, mv);
- if ( depth > 0 ) {
- 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];
- killr1[ply] = mv;
- }
- killr0[ply] = (best > 9000) ? mv : 0;
- }
- return best;
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- static short evaluate(short side, short xside, short ply, short alpha, short beta)
- {
- short s, evflag;
-
- 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] - INCscore;
-
- evflag = slk ?
- false :
- ((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 ( atak[side][PieceList[xside][0]] > 0 )
- return (short) (10001-ply);
- ataks(xside, atak[xside]);
- InChk = (atak[xside][PieceList[side][0]] > 0);
- ScorePosition(side, &s);
- }
- else {
- if ( SqAtakd(PieceList[xside][0],side) )
- return (short) (10001-ply);
- InChk = SqAtakd(PieceList[side][0], xside);
- if ( slk )
- ScoreLoneKing(side, &s);
- }
-
- Pscore[ply] = s - mtl[side] + mtl[xside];
- ChkFlag[ply-1] = InChk ? Pindex[TOsquare] : 0;
- Threat[ply-1] = (hung[side] > 1 && ply == Sdepth+1);
- return s;
- }
-
- /************************************************************************/
- /* Look for the current board position in the transposition table. */
- /************************************************************************/
-
- static int ProbeTTable(short side, short depth, short *alpha, short *beta, short *score)
- {
- short hindx;
-
- if ( side == white )
- hashkey |= 1;
- else
- hashkey &= 0xFFFE;
- hindx = hashkey & (ttblsz-1);
- ptbl = ttable + hindx;
- if ( ptbl->depth >= depth && ptbl->hashbd == hashbd ) {
- HashCnt++;
- PV = ptbl->mv;
- if ( ptbl->flags & truescore ) {
- *score = ptbl->score;
- *beta = -20000;
- return true;
- }
- // else
- // if ( ptbl->flags & upperbound ) {
- // if ( ptbl->score < *beta )
- // *beta = ptbl->score+1;
- // }
- else
- if ( (ptbl->flags & lowerbound) && (ptbl->score > *alpha) )
- *alpha = ptbl->score-1;
- }
- return false;
- }
-
- /************************************************************************/
- /* Store the current board position in the transposition table. */
- /************************************************************************/
-
- static void PutInTTable(short side, short score, short depth, short alpha, short beta, unsigned short mv)
- {
- if ( side == white )
- hashkey |= 1;
- else
- hashkey &= 0xFFFE;
- ptbl = ttable + (hashkey & (ttblsz-1));
- ptbl->hashbd = hashbd;
- ptbl->depth = depth;
- ptbl->score = score;
- ptbl->mv = mv;
- ptbl->flags = (score < alpha) ? upperbound : ((score > beta) ? lowerbound : truescore);
- }
-
-
- static void ZeroTTable(void)
- {
- int i;
-
- if ( hashflag )
- for (i = 0; i < ttblsz; i++) {
- ptbl = ttable + i;
- ptbl->depth = 0;
- }
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- void MoveList(short side, short ply)
- {
- short i;
- short xside, f;
-
- xside = otherside[side];
- Swag0 = PV ? PV : killr0[ply];
- 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] ) {
- f = PieceList[side][0];
- 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;
- }
- }
- }
-
- /************************************************************************/
- /* 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 into the tree. */
- /************************************************************************/
-
- static void GenMoves(short ply, short sq, short side, short xside)
- {
- short m, u, d;
- short i, m0, piece;
-
- piece = board[sq];
- 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] == neutral ) {
- LinkMove(ply,sq,u,xside);
- m += d;
- }
- else {
- if ( color[u] == xside )
- LinkMove(ply, sq, u, xside);
- break;
- }
- }
- }
- else
- if ( piece == pawn ) {
- if ( side == white && color[sq+8] == neutral ) {
- LinkMove(ply, sq, sq+8, xside);
- if ( row[sq] == 1 )
- 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 ( row[sq] == 6 )
- 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) ) {
- u = unmap[m];
- if ( color[u] == xside || u == epsquare )
- LinkMove(ply,sq,u,xside);
- }
- }
- else {
- for ( i = Dstart[piece]; i <= Dstop[piece]; i++ )
- if ( !((m = m0+Dir[i]) & 0x88) ) {
- u = unmap[m];
- if ( color[u] != side )
- LinkMove(ply, sq, u, xside);
- }
- }
- }
-
- /************************************************************************/
- /* Add a move to the tree. Assign a bonus to order the moves as */
- /* follows: */
- /* 1. Principle variation */
- /* 2. Capture of last moved piece */
- /* 3. Other captures (major pieces first) */
- /* 4. Killer moves */
- /* 5. "history" killers */
- /************************************************************************/
-
- static void LinkMove(short ply, short f, short t, short xside)
- {
- short s, z;
- unsigned short mv;
- struct leaf *node;
-
- node = &Tree[TrPnt[ply+1]];
- ++TrPnt[ply+1];
- node->flags =
- node->reply = 0;
- node->f = f;
- node->t = t;
- mv = (f<<8) + t;
- s = 0;
- 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 ( color[t] != neutral ) {
- node->flags |= capture;
- if ( t == TOsquare )
- s += 500;
- s += value[board[t]] - board[f];
- }
- if ( board[f] == pawn )
- switch ( row[t] ) {
- case 0:
- case 7:
- node->flags |= promote;
- s += 800;
- break;
- case 1:
- case 6:
- node->flags |= pwnthrt;
- s += 600;
- break;
- default:
- if ( t == epsquare )
- node->flags |= epmask;
- break;
- }
- z = (f<<6) + t;
- if ( xside == white )
- z |= 0x1000;
- s += history[z];
- node->score = s - 20000;
- }
-
- /************************************************************************/
- /* Generate captures and Pawn promotions only. */
- /************************************************************************/
-
- static void CaptureList(short side, short xside, short ply)
-
- #define LinkCapture { \
- node->f = sq; \
- node->t = u; \
- node->reply = 0; \
- node->flags = capture; \
- node->score = value[board[u]] + svalue[board[u]] - piece; \
- if ( piece == pawn && (u < 8 || u > 55) ) { \
- node->flags |= promote; \
- node->score = valueQ; \
- } \
- ++node; \
- ++TrPnt[ply+1]; \
- }
-
- {
- short m, u;
- short d, sq, i, j, j1, j2, m0, r7, d0, piece, *PL;
- struct leaf *node;
-
- TrPnt[ply+1] = TrPnt[ply];
- node = &Tree[TrPnt[ply]];
- Dstart[pawn] = Dpwn[side];
- Dstop[pawn] = Dstart[pawn] + 1;
- if ( side == white ) {
- r7 = 6;
- d0 = 8;
- }
- else {
- r7 = 1;
- d0 = -8;
- }
- PL = PieceList[side];
- for ( i = 0; i <= PieceCnt[side]; i++ ) {
- sq = PL[i];
- m0 = map[sq];
- piece = board[sq];
- j1 = Dstart[piece];
- j2 = Dstop[piece];
- if ( sweep[piece] )
- for ( j = j1; j <= j2; j++ ) {
- d = Dir[j];
- m = m0+d;
- while ( !(m & 0x88) ) {
- u = unmap[m];
- if ( color[u] == neutral )
- m += d;
- else {
- if ( color[u] == xside )
- LinkCapture;
- break;
- }
- }
- }
- else {
- for ( j = j1; j <= j2; j++ )
- if ( !((m = m0+Dir[j]) & 0x88) ) {
- u = unmap[m];
- if ( color[u] == xside )
- LinkCapture;
- }
- if ( piece == pawn && row[sq] == r7 ) {
- u = sq+d0;
- if ( color[u] == neutral )
- LinkCapture;
- }
- }
- }
- }
-
- /************************************************************************/
- /* Make or Unmake a castling move. */
- /************************************************************************/
-
- int castle(short side, short kf, short kt, short iop)
- {
- short rf, rt, d, t0, xside;
-
- xside = otherside[side];
- if ( kt > kf ) {
- rf = kf+3;
- rt = kt-1;
- d = 1;
- }
- else {
- rf = kf-4;
- rt = kt+1;
- d = -1;
- }
- if ( iop == 0 ) {
- if ( board[kf] != king ||
- board[rf] != rook ||
- color[rf] != side ||
- color[kt] != neutral ||
- color[rt] != neutral ||
- (d == -1 && color[kt+d] != neutral) ||
- SqAtakd(kf, xside) ||
- SqAtakd(kt, xside) ||
- SqAtakd(kf+d, xside)
- )
- return false;
- }
- else {
- castld[side] = (iop == 1) ? true : false;
- if ( iop == 2 ) {
- 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;
- if ( hashflag ) {
- UpdateHashbd(side, king, kf, kt);
- UpdateHashbd(side, rook, rf, rt);
- }
- }
- return true;
- }
-
- /************************************************************************/
- /* Make or unmake an en passant move. */
- /************************************************************************/
-
- static void EnPassant(short xside, short f, short t, short iop)
- {
- short l;
-
- l = (t > f) ? t-8 : t+8;
- if ( iop == 1 ) {
- board[l] = no_piece;
- color[l] = neutral;
- }
- else {
- board[l] = pawn;
- color[l] = xside;
- }
- InitializeStats();
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- static void MakeMove(short side, struct leaf *node, short *tempb, short *tempc, short *tempsf, short *tempst)
- {
- short f, t;
- short xside, ct, cf;
-
- xside = otherside[side];
- f = node->f;
- t = node->t;
- epsquare = -1;
- FROMsquare = f;
- TOsquare = t;
- INCscore = 0;
- GameList[++GameCnt].gmove = (f<<8) + t;
- if ( node->flags & cstlmask ) {
- GameList[GameCnt].piece = no_piece;
- GameList[GameCnt].color = side;
- castle(side, f, t, 1);
- }
- else {
- *tempc = color[t];
- *tempb = board[t];
- *tempsf = svalue[f];
- *tempst = svalue[t];
- GameList[GameCnt].piece = *tempb;
- GameList[GameCnt].color = *tempc;
- if ( *tempc != neutral ) {
- UpdatePieceList(*tempc, t, 1);
- if ( *tempb == pawn )
- --PawnCnt[*tempc][column[t]];
- if ( board[f] == pawn ) {
- --PawnCnt[side][column[f]];
- ++PawnCnt[side][column[t]];
- cf = column[f];
- ct = column[t];
- if ( PawnCnt[side][ct] > 1+PawnCnt[side][cf] )
- INCscore -= 15;
- else
- if ( PawnCnt[side][ct] < 1+PawnCnt[side][cf] )
- INCscore += 15;
- else
- if ( ct == 0 || ct == 7 || PawnCnt[side][ct+ct-cf] == 0 )
- INCscore -= 15;
- }
- mtl[xside] -= value[*tempb];
- if ( *tempb == pawn )
- pmtl[xside] -= valueP;
- if ( hashflag ) UpdateHashbd(xside, *tempb, -1, t);
- INCscore += *tempst;
- }
- 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 ( board[t] == pawn )
- if ( t-f == 16 )
- epsquare = f+8;
- else
- if ( f-t == 16 )
- epsquare = f-8;
- if ( node->flags & promote ) {
- board[t] = queen;
- --PawnCnt[side][column[t]];
- mtl[side] += valueQ - valueP;
- pmtl[side] -= valueP;
- HasQueen[side] = true;
- if ( hashflag ) {
- UpdateHashbd(side, pawn, f, -1);
- UpdateHashbd(side, queen, f, -1);
- }
- INCscore -= *tempsf;
- }
- if ( board[t] == king )
- ++kingmoved[side];
- if ( node->flags & epmask )
- EnPassant(xside, f, t, 1);
- else
- if ( hashflag )
- UpdateHashbd(side, board[t], f, t);
- }
- }
-
- /************************************************************************/
- /* Take back a move. */
- /************************************************************************/
-
- static void UnmakeMove( short side, struct leaf *node, short *tempb, short *tempc, short *tempsf, short *tempst)
- {
- short f, t;
- short xside;
-
- xside = otherside[side];
- f = node->f;
- t = node->t;
- epsquare = -1;
- GameCnt--;
- if ( node->flags & cstlmask )
- castle(side, f, t, 2);
- else {
- 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 ) {
- board[f] = pawn;
- ++PawnCnt[side][column[t]];
- mtl[side] += valueP - valueQ;
- pmtl[side] += valueP;
- if ( hashflag ) {
- UpdateHashbd(side, queen, -1, t);
- UpdateHashbd(side, pawn, -1, t);
- }
- }
- if ( *tempc != neutral ) {
- UpdatePieceList(*tempc, t, 2);
- if ( *tempb == pawn )
- ++PawnCnt[*tempc][column[t]];
- if ( board[f] == pawn ) {
- --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);
- }
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- static void UpdateHashbd(short side, short piece, short f, short t)
- {
- if ( f >= 0 ) {
- hashbd ^= hashcode[side][piece][f].bd;
- hashkey ^= hashcode[side][piece][f].key;
- }
- if ( t >= 0 ) {
- hashbd ^= hashcode[side][piece][t].bd;
- hashkey ^= hashcode[side][piece][t].key;
- }
- }
-
- /************************************************************************/
- /* Update the PieceList and Pindex arrays when a piece is captured or */
- /* when a capture is unmade. */
- /************************************************************************/
-
- static void UpdatePieceList(short side, short sq, short iop)
- {
- short i;
-
- if ( iop == 1 ) {
- PieceCnt[side]--;
- for ( i = Pindex[sq]; i <= PieceCnt[side]; i++ ) {
- PieceList[side][i] = PieceList[side][i+1];
- Pindex[PieceList[side][i]] = i;
- }
- }
- else {
- PieceCnt[side]++;
- 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 given square. */
- /************************************************************************/
-
- void InitializeStats(void)
- {
- short i, sq;
-
- epsquare = -1;
- for ( i = 0; i < 8; i++ )
- PawnCnt[white][i] =
- PawnCnt[black][i] = 0;
- mtl[white] =
- mtl[black] =
- pmtl[white] =
- pmtl[black] =
- PieceCnt[white] =
- PieceCnt[black] =
- hashbd =
- hashkey = 0;
- for ( sq = 0; sq < 64; sq++ )
- if ( color[sq] != neutral ) {
- mtl[color[sq]] += value[board[sq]];
- if ( board[sq] == pawn ) {
- pmtl[color[sq]] += valueP;
- ++PawnCnt[color[sq]][column[sq]];
- }
- Pindex[sq] = (board[sq] == king) ? 0 : ++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. */
- /************************************************************************/
-
- static void pick(short p1, short p2)
- {
- short p, s;
- short p0, s0;
- struct leaf temp;
-
- s0 = Tree[p1].score;
- p0 = p1;
- for ( p = p1+1; p <= p2; p++ )
- if ( (s = Tree[p].score) > s0 ) {
- s0 = s;
- p0 = p;
- }
- if ( p0 != p1 ) {
- temp = Tree[p1];
- Tree[p1] = Tree[p0];
- Tree[p0] = temp;
- }
- }
-
- /************************************************************************/
- /* Check for draw by threefold repetition. */
- /************************************************************************/
-
- static void repetition(short *cnt)
- {
- short i, c;
- short f, t, b[64];
- unsigned short m;
-
- *cnt = c = 0;
- if ( GameCnt > Game50+3 ) {
- // 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++;
- if ( c == 0 )
- (*cnt)++;
- }
- }
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- int SqAtakd(short sq, short side)
- {
- short m, d;
- short i, m0, m1, loc, piece, *PL;
-
- m1 = map[sq];
- m = (side == white) ? m1-0x0F : m1+0x0F;
- if ( !(m & 0x88) )
- if ( board[unmap[m]] == pawn && color[unmap[m]] == side )
- return true;
- m = (side == white) ? m1-0x11 : m1+0x11;
- if ( !(m & 0x88) )
- if (board[unmap[m]] == pawn && color[unmap[m]] == side)
- return true;
- if ( distance(sq,PieceList[side][0]) == 1 )
- return true;
-
- PL = PieceList[side];
- 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;
- else {
- if ( m1 < m0 )
- d = -d;
- for ( m = m0+d; m != m1; m += d )
- if ( color[unmap[m]] != neutral )
- break;
- if ( m == m1 )
- return true;
- }
- }
- return false;
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- static void ataks(short side, short *a)
- {
- short u, m;
- 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;
- PL = PieceList[side];
- for ( i = 0; i <= PieceCnt[side]; i++ ) {
- sq = PL[i];
- m0 = map[sq];
- piece = board[sq];
- c = control[piece];
- j1 = Dstart[piece];
- j2 = Dstop[piece];
- if ( sweep[piece] )
- for ( j = j1; j <= j2; j++ ) {
- d = Dir[j];
- m = m0+d;
- while ( !(m & 0x88) ) {
- u = unmap[m];
- a[u] = ++a[u] | c;
- if ( color[u] == neutral )
- m += d;
- else
- break;
- }
- }
- else
- for ( j = j1; j <= j2; j++ )
- if ( !((m = m0+Dir[j]) & 0x88) ) {
- u = unmap[m];
- a[u] = ++a[u] | c;
- }
- }
- }
-
-
- /* ............ POSITIONAL EVALUATION ROUTINES ............ */
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- void ScorePosition(short side, short *score)
- {
- short sq, s;
- short i, xside,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];
- EnemyKing = (c1 == white) ? bking : 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;
- }
-
- /************************************************************************/
- /* Static evaluation when loser has only a king and winner has no pawns */
- /* or no pieces. */
- /************************************************************************/
-
- static void ScoreLoneKing(short side, short *score)
- {
- short winner, loser, king1, king2, s, i;
-
- UpdateWeights();
- winner = (mtl[white] > mtl[black]) ? white : 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);
- *score = (side == winner) ? s : -s;
- }
-
- /************************************************************************/
- /* Score King and Pawns versus King endings. */
- /************************************************************************/
-
- static short ScoreKPK(short side, short winner, short loser, short king1, short king2, short sq)
- {
- short s, r;
-
- s = (PieceCnt[winner] == 1) ? 50 : 120;
- if ( winner == white ) {
- r = (side == loser) ? row[sq]-1 : row[sq];
- if ( row[king2] >= r && distance(sq, king2) < 8-r )
- s += 10*row[sq];
- else
- s = 500 + 50 * row[sq];
- sq += (row[sq] < 6) ? 16 : 8;
- }
- else {
- r = (side == loser) ? row[sq]+1 : row[sq];
- if ( row[king2] <= r && distance(sq, king2) < r+1 )
- s += 10 * ( 7 - row[sq] );
- else
- s = 500 + 50 * ( 7 - row[sq] );
- sq -= (row[sq] > 1) ? 16 : 8;
- }
- return s += 8 * ( taxicab(king2, sq) - taxicab(king1,sq) );
- }
-
- /************************************************************************/
- /* Score King+Bishop+Knight versus King endings. This doesn't work all */
- /* that well but it's better than nothing. */
- /************************************************************************/
-
- static short ScoreKBNK(short winner, short king1, short king2)
- {
- return (short) (
- emtl[winner] - 300
- + (KBNKsq ? KBNK[locn[row[king2]][7-column[king2]]] : KBNK[king2])
- - taxicab(king1,king2)
- - distance(PieceList[winner][1],king2)
- - distance(PieceList[winner][2],king2));
- }
-
- /************************************************************************/
- /* Calculate the positional value for the piece on 'sq'. */
- /************************************************************************/
-
- short SqValue(short sq, short side)
- {
- short j, fyle, rank;
- short s, piece, a1, a2, 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;
-
- switch ( piece ) {
- case pawn:
- switch ( c1 ) {
- case 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 ) {
- r = (side == black) ? rank-1 : rank;
- in_square = (row[bking] >= r && distance(sq,bking) < 8-r);
- e = (a2 == 0 || side == white) ? 0 : 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
- s += (emtl[black] > 0) ? (stage*PassedPawn1[rank]) / 10 : PassedPawn0[rank];
- }
- break;
-
- case 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 ) {
- r = (side == white) ? rank+1 : rank;
- in_square = (row[wking] <= r && distance(sq,wking) < r+1);
- e = (a2 == 0 || side == black) ? 0 : 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;
- s += (e == 2) ?
- (stage * PassedPawn3[7-rank]) / 10 :
- ((in_square || e == 1) ?
- (stage * PassedPawn2[7-rank]) / 10 :
- ((emtl[white] > 0) ?
- (stage * PassedPawn1[7-rank]) / 10 :
- PassedPawn0[7-rank]));
- }
- break;
- }
- break;
-
- case knight:
- s = Mknight[c1][sq];
- break;
-
- case bishop:
- s = Mbishop[c1][sq];
- BRscan(sq, &s, &mob);
- s += BMBLTY[mob];
- break;
-
- case 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);
- break;
-
- case queen:
- if ( stage > 2 )
- s += 14 - taxicab(sq, EnemyKing);
- if ( distance(sq, EnemyKing) < 3 )
- s += 12;
- break;
-
- case 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;
- switch ( fyle ) {
- case 2:
- if ( PC1[0] == 0 )
- s += KHOPN;
- if ( PC2[0] == 0 )
- s += KHOPNX;
- case 1:
- case 3:
- case 7:
- if ( PC1[fyle-1] == 0 )
- s += KHOPN;
- if ( PC2[fyle-1] == 0 )
- s += KHOPNX;
- break;
- case 5:
- if ( PC1[7] == 0 )
- s += KHOPN;
- if ( PC2[7] == 0 )
- s += KHOPNX;
- case 4:
- case 6:
- case 0:
- if ( PC1[fyle+1] == 0 )
- s += KHOPN;
- if ( PC2[fyle+1] == 0 )
- s += KHOPNX;
- break;
- }
- break;
- }
-
- 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;
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- static void KingScan(short sq, short *s)
-
- #define ScoreThreat \
- if ( color[u] != c2 ) \
- if ( atk1[u] == 0 || (atk2[u] & 0xFF) > 1 ) \
- ++cnt; \
- else \
- *s -= 3
- {
- short m, u;
- short 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;
- }
-
- /************************************************************************/
- /* Find Bishop and Rook mobility, XRAY attacks, and pins. Increment */
- /* the hung[] array if a pin is found. */
- /************************************************************************/
-
- static void BRscan(short sq, short *s, short *mob)
- {
- short m, u;
- short d, j, m0, piece, pin, *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;
- }
- }
- }
-
- /************************************************************************/
- /* See if the attacked piece has unattacked squares to move to. */
- /************************************************************************/
-
- static int trapped(short sq, short piece)
- {
- short u, m, d;
- short 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 ) {
- u = (c1 == white) ? sq+8 : 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;
- }
-
- /************************************************************************/
- /* 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. */
- /************************************************************************/
-
- void ExaminePosition(void)
- {
- 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] =
- HasKnight[white] =
- HasKnight[black] =
- HasBishop[white] =
- HasBishop[black] =
- HasRook[white] =
- HasRook[black] =
- 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] += 10 - distance(sq, bking) - distance(sq, wking);
- Mknight[black][sq] += 10 - distance(sq, wking) - 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 )
- KBNKsq = ( (rank & 1) == (fyle & 1) ) ? 0 : 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;
- z = (row[i] == 6) ? i+8 : i+16;
- for ( j = i+8; j < 64; j += 8 )
- if ( atak[black][j] > ctlP || board[j] == pawn )
- pp = false;
- }
- else {
- pp = true;
- z = (row[i] == 1) ? i-8 : i-16;
- for ( j = i-8; j >= 0; j -= 8 )
- if ( atak[white][j] > ctlP || board[j] == pawn )
- pp = false;
- }
- Pd += pp ? 5 * taxicab(sq, z) : taxicab(sq, z);
- }
- if ( Pd != 0 ) {
- val = (Pd * stage2) / 10;
- Mking[white][sq] -= val;
- Mking[black][sq] -= val;
- }
- }
- }
-
- /************************************************************************/
- /* If material balance has changed, determine the values for the */
- /* positional evaluation terms. */
- /************************************************************************/
-
- static void UpdateWeights(void)
- {
- 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];
- stage = (tmtl > 6600) ?
- 0 :
- ((tmtl < 1400) ?
- 10 :
- (6600 - tmtl) / 520);
- stage2 = (tmtl > 3600) ?
- 0 :
- ((tmtl < 1400) ?
- 10 :
- (3600 - tmtl) / 220);
-
- PEDRNK2B = -15; // centre pawn on 2nd rank & blocked
- PBLOK = // blocked backward pawn
- PWEAKH = -4; // weak pawn on half open file
- PDOUBLED = -14; // doubled pawn
- KCASTLD =
- PAWNSHIELD = 10 - stage; // pawn near friendly king
- PADVNCM = // advanced pawn multiplier
- RHOPN = // rook on half open file
- PINVAL = 10; // Pin
- PADVNCI = 7; // muliplier for isolated pawn
- PawnBonus = stage;
- KNIGHTPOST = (stage + 2) / 3; // knight near enemy pieces
- KNIGHTSTRONG = // occupies pawn hole
- BISHOPSTRONG = (stage + 6) / 2; // occupies pawn hole
- BishopBonus = 2 * stage;
-
- RHOPNX = 4;
- RookBonus = 6 * stage;
-
- XRAY = 8; // Xray attack on piece
-
- KHOPN = (3*stage-30) / 2; // king on half open file
- KHOPNX = KHOPN / 2;
- KMOVD = -40 / (stage+1); // king moved before castling
- KATAK = (10-stage) / 2; // B,R attacks near enemy king
-
- KSFTY = (stage < 8) ? 16-2*stage : 0;
-
- ATAKD = -6; // defender > attacker
- HUNGP = -8; // each hung piece
- HUNGX = -12; // extra for >1 hung piece
- }
- }
-
-
- short distance(short a, short b)
- {
- short d1, d2;
-
- d1 = abs(column[a]-column[b]);
- d2 = abs(row[a]-row[b]);
- return (short) ((d1 > d2) ? d1 : d2);
- }
-
- static void BlendBoard(short *a, short *b, short *c)
- {
- int sq;
-
- for ( sq = 0; sq < 64; sq++ )
- c[sq] = (a[sq]*(10-stage) + b[sq]*stage) / 10;
- }
-
-
- static void CopyBoard(short *a, short *b)
- {
- int sq;
-
- for ( sq = 0; sq < 64; sq++ )
- b[sq] = a[sq];
- }
-