📄 move.c
字号:
if (cboard[t] != 0) /* capture */
*s++ = 'x';
strcpy (s, algbr[t]);
s += 2;
}
/* See if it is a checking or mating move */
MakeMove (side, &move);
if (SqAtakd (board.king[1^side], side))
{
TreePtr[ply+2] = TreePtr[ply+1];
GenCheckEscapes (ply+1);
if (TreePtr[ply+1] == TreePtr[ply+2])
*s++ = '#';
else
*s++ = '+';
GenCnt -= TreePtr[ply+2] - TreePtr[ply+1];
}
UnmakeMove (1^side, &move);
*s = '\0';
return;
}
#define ASCIITOFILE(a) ((a) - 'a')
#define ASCIITORANK(a) ((a) - '1')
#define ASCIITOSQ(a,b) (ASCIITOFILE(a)) + (ASCIITORANK(b)) * 8
#define ATOH(a) ((a) >= 'a' && (a) <= 'h')
#define ITO8(a) ((a) >= '1' && (a) <= '8')
inline int piece_id(const char c)
{
/* Given c, what is the piece id. This only takes one char, which
* isn't enough to handle two-character names (common in Russian text
* and old English notation that used Kt), but we're not supposed to
* see such text here anyway. This will
* accept "P" for pawn, and many lowercase chars (but not "b" for Bishop). */
switch (c)
{
case 'n':
case 'N':
return knight;
case 'B':
return bishop;
case 'r':
case 'R':
return rook;
case 'q':
case 'Q':
return queen;
case 'k':
case 'K':
return king;
case 'p':
case 'P':
return pawn;
}
return empty;
}
leaf * ValidateMove (char *s)
/*************************************************************************
*
* This routine takes a string and check to see if it is a legal move.
* Note. At the moment, we accept 2 types of moves notation.
* 1. e2e4 format. 2. SAN format. (e4)
*
**************************************************************************/
{
short f, t, side, rank, file, fileto;
short piece, piece2, kount;
char promote;
char mvstr[MAXSTR], *p;
BitBoard b, b2;
leaf *n1, *n2;
TreePtr[2] = TreePtr[1];
GenMoves (1);
FilterIllegalMoves (1);
side = board.side;
/************************************************************************
* The thing to do now is to clean up the move string. This
* gets rid of things like 'x', '+', '=' and so forth.
************************************************************************/
p = mvstr;
do
{
if (*s != 'x' && *s != '+' && *s != '=' && !isspace(*s))
*p++ = *s;
} while (*s++ != '\0' );
/* Flush castles that check */
if (mvstr[strlen(mvstr)-1] == '+' || mvstr[strlen(mvstr)-1] == '#' ||
mvstr[strlen(mvstr)-1] == '=') mvstr[strlen(mvstr)-1] = '\000';
/* Check for castling */
if (strcmp (mvstr, "O-O") == 0 || strcmp (mvstr, "o-o") == 0 ||
strcmp (mvstr, "0-0") == 0)
{
if (side == white)
{
f = 4; t = 6;
}
else
{
f = 60; t = 62;
}
return (IsInMoveList (1, f, t, ' '));
}
if (strcmp (mvstr, "O-O-O") == 0 || strcmp (mvstr, "o-o-o") == 0 ||
strcmp (mvstr, "0-0-0") == 0)
{
if (side == white)
{
f = 4; t = 2;
}
else
{
f = 60; t = 58;
}
return (IsInMoveList (1, f, t, ' '));
}
/* Test to see if it is e2e4 type notation */
if (ATOH (mvstr[0]) && ITO8 (mvstr[1]) && ATOH (mvstr[2]) &&
ITO8 (mvstr[3]))
{
f = ASCIITOSQ (mvstr[0], mvstr[1]);
t = ASCIITOSQ (mvstr[2], mvstr[3]);
piece = (strlen (mvstr) == 5 ? mvstr[4] : ' ');
return (IsInMoveList (1, f, t, piece));
}
/***********************************************************************
* Its a SAN notation move. More headache!
* We generate all the legal moves and start comparing them with
* the input move.
***********************************************************************/
if (ATOH (mvstr[0])) /* pawn move */
{
if (ITO8 (mvstr[1])) /* e4 type */
{
t = ASCIITOSQ (mvstr[0], mvstr[1]);
f = t + (side == white ? -8 : 8);
/* Add Sanity Check */
if ( f > 0 && f < 64 ) {
if (BitPosArray[f] & board.b[side][pawn])
{
if (mvstr[2] != '\0')
return (IsInMoveList (1, f, t, mvstr[2]));
else
return (IsInMoveList (1, f, t, ' '));
}
f = t + (side == white ? -16 : 16);
if ( f > 0 && f < 64 ) {
if (BitPosArray[f] & board.b[side][pawn])
return (IsInMoveList (1, f, t, ' '));
} /* End bound check +/- 16 */
} /* End bound check +/- 8 */
}
else if (ATOH (mvstr[1]) && ITO8 (mvstr[2])) /* ed4 type */
{
t = ASCIITOSQ (mvstr[1], mvstr[2]);
rank = ASCIITORANK (mvstr[2]) + (side == white ? -1 : 1);
f = rank * 8 + ASCIITOFILE (mvstr[0]);
piece = (strlen (mvstr) == 4 ? mvstr[3] : ' ');
return (IsInMoveList (1, f, t, piece));
}
else if (ATOH (mvstr[1])) /* ed type */
{
file = ASCIITOFILE (mvstr[0]);
fileto = ASCIITOFILE (mvstr[1]);
b = board.b[side][pawn] & FileBit[file];
if (side == white)
b = b >> (fileto < file ? 7 : 9);
else
b = b << (fileto < file ? 9 : 7);
if (board.ep > -1)
b = b & (board.friends[1^side] | BitPosArray[board.ep]);
else
b = b & (board.friends[1^side]);
switch (nbits (b))
{
case 0 : return ((leaf *) NULL);
case 1 : t = leadz (b);
f = t - (side == white ? 8 : -8) + (file - fileto);
piece = (strlen (mvstr) == 3 ? mvstr[2] : ' ');
return (IsInMoveList (1, f, t, piece));
default :
printf ("Ambiguous move: %s %s\n",s,mvstr);
ShowBoard();
/*
getchar();
*/
return ((leaf *) NULL);
}
}
}
else if ((piece = piece_id(mvstr[0])) != empty &&
(piece_id(mvstr[1]) == empty)) /* Is a piece move */
{
/* Since piece_id accepts P as pawns, this will correctly
* handle malformed commands like Pe4 */
b = board.b[side][piece];
t = -1;
if (ITO8 (mvstr[1])) /* N1d2 type move */
{
rank = ASCIITORANK (mvstr[1]);
b &= RankBit[rank];
t = ASCIITOSQ (mvstr[2], mvstr[3]);
}
else if (ATOH (mvstr[1]) && ATOH (mvstr[2])) /* Nbd2 type move */
{
file = ASCIITOFILE (mvstr[1]);
b &= FileBit[file];
t = ASCIITOSQ (mvstr[2], mvstr[3]);
}
else if (ATOH (mvstr[1]) && ITO8 (mvstr[2])) /* Nd2 type move */
{
t = ASCIITOSQ (mvstr[1], mvstr[2]);
}
kount = 0;
n1 = n2 = (leaf *) NULL;
while (b)
{
f = leadz (b);
CLEARBIT (b, f);
if ((n1 = IsInMoveList (1, f, t, ' ')) != (leaf *) NULL )
{
n2 = n1;
kount++;
}
}
if (kount > 1)
{
printf ("Ambiguous move: %s %s\n",s,mvstr);
ShowBoard();
/*
getchar();
*/
return ((leaf *) NULL);
}
else if (kount == 0)
return ((leaf *) NULL);
else
return (n2);
}
else if (((piece = piece_id(mvstr[0])) != empty) &&
((piece2 = piece_id(mvstr[1])) != empty) &&
( (mvstr[2] == '\0') ||
((piece_id(mvstr[2]) != empty) && mvstr[3] == '\0')))
{ /* KxP format */
promote = ' ';
if (piece_id(mvstr[2] != empty)) {
promote = mvstr[2];
}
kount = 0;
n1 = n2 = (leaf *) NULL;
b = board.b[side][piece];
while (b)
{
f = leadz (b);
CLEARBIT (b, f);
b2 = board.b[1^side][piece2];
while (b2)
{
t = leadz (b2);
CLEARBIT (b2, t);
printf("Trying %s: ", AlgbrMove(MOVE(f,t)));
if ((n1 = IsInMoveList (1, f, t, promote)) != (leaf *) NULL)
{
n2 = n1;
kount++;
printf("Y ");
}
else printf("N ");
}
}
if (kount > 1)
{
printf ("Ambiguous move: %s %s\n",s,mvstr);
ShowBoard();
/*
getchar();
*/
return ((leaf *) NULL);
}
else if (kount == 0)
return ((leaf *) NULL);
else
return (n2);
}
/* Fall through. Nothing worked, return that no move was performed. */
return ((leaf *) NULL);
}
leaf * IsInMoveList (int ply, int f, int t, char piece)
/**************************************************************************
*
* Checks to see if from and to square can be found in the movelist
* and is legal.
*
**************************************************************************/
{
leaf *node;
for (node = TreePtr[ply]; node < TreePtr[ply + 1]; node++)
{
if ((int) (node->move & 0x0FFF) == MOVE(f,t) &&
toupper(piece) == notation[PROMOTEPIECE (node->move)])
return (node);
}
return ((leaf *) NULL);
}
int IsLegalMove (int move)
/*****************************************************************************
*
* Check that a move is legal on the current board.
* Perform some preliminary sanity checks.
* 1. If from square is emtpy, illegal.
* 2. Piece not of right color.
* 3. To square is friendly, illegal.
* 4. Promotion move or enpassant, so piece must be pawn.
* 5. Castling move, piece must be king.
* Note that IsLegalMove() no longer care about if a move will place the
* king in check. This will be caught by the Search().
*
*****************************************************************************/
{
int side;
int f, t, piece;
BitBoard blocker, enemy;
f = FROMSQ(move);
t = TOSQ(move);
/* Empty from square */
if (cboard[f] == empty)
return (false);
/* Piece is not right color */
side = board.side;
if (!(BitPosArray[f] & board.friends[side]))
return (false);
/* TO square is a friendly piece, so illegal move */
if (BitPosArray[t] & board.friends[side])
return (false);
piece = cboard[f];
/* If promotion move, piece must be pawn */
if ((move & (PROMOTION | ENPASSANT)) && piece != pawn)
return (false);
/* If enpassant, then the enpassant square must be correct */
if ((move & ENPASSANT) && t != board.ep)
return (false);
/* If castling, then make sure its the king */
if ((move & CASTLING) && piece != king)
return (false);
blocker = board.blocker;
/* Pawn moves need to be handle specially */
if (piece == pawn)
{
if ((move & ENPASSANT) && board.ep > -1)
enemy = board.friends[1^side] | BitPosArray[board.ep];
else
enemy = board.friends[1^side];
if (side == white)
{
if (!(MoveArray[pawn][f] & BitPosArray[t] & enemy) &&
!(t - f == 8 && cboard[t] == empty) &&
!(t - f == 16 && RANK(f) == 1 && !(FromToRay[f][t] & blocker)))
return (false);
}
else if (side == black)
{
if (!(MoveArray[bpawn][f] & BitPosArray[t] & enemy) &&
!(t - f == -8 && cboard[t] == empty) &&
!(t - f == -16 && RANK(f) == 6 && !(FromToRay[f][t] & blocker)))
return (false);
}
}
/* King moves are also special, especially castling */
else if (piece == king)
{
if (side == white)
{
if (!(MoveArray[piece][f] & BitPosArray[t]) &&
!(f == E1 && t == G1 && board.flag & WKINGCASTLE &&
!(FromToRay[E1][G1] & blocker) && !SqAtakd(E1,black) &&
!SqAtakd(F1,black)) &&
!(f == E1 && t == C1 && board.flag & WQUEENCASTLE &&
!(FromToRay[E1][B1] & blocker) && !SqAtakd(E1,black) &&
!SqAtakd(D1,black)))
return (false);
}
if (side == black)
{
if (!(MoveArray[piece][f] & BitPosArray[t]) &&
!(f == E8 && t == G8 && board.flag & BKINGCASTLE &&
!(FromToRay[E8][G8] & blocker) && !SqAtakd(E8,white) &&
!SqAtakd(F8,white)) &&
!(f == E8 && t == C8 && board.flag & BQUEENCASTLE &&
!(FromToRay[E8][B8] & blocker) && !SqAtakd(E8,white) &&
!SqAtakd(D8,white)))
return (false);
}
}
else
{
if (!(MoveArray[piece][f] & BitPosArray[t]))
return (false);
}
/* If there is a blocker on the path from f to t, illegal move */
if (slider[piece])
{
if (FromToRay[f][t] & NotBitPosArray[t] & blocker)
return (false);
}
return (true);
}
char *AlgbrMove (int move)
/*****************************************************************************
*
* Convert an int move format to algebraic format of g1f3.
*
*****************************************************************************/
{
int f, t;
static char s[6];
f = FROMSQ(move);
t = TOSQ(move);
strcpy (s, algbr[f]);
strcpy (s+2, algbr[t]);
if (move & PROMOTION)
{
if (flags & XBOARD)
s[4] = lnotation[PROMOTEPIECE (move)];
else
s[4] = notation[PROMOTEPIECE (move)];
s[5] = '\0';
}
else
s[4] = '\0';
return (s);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -