* Massachusetts.
*
* Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc.
*
* Enhancements Copyright 2005 Alessandro Scotti
*
int SameColor P((ChessSquare, ChessSquare));
int PosFlags(int index);
-extern signed char initialRights[BOARD_FILES]; /* [HGM] all rights enabled, set in InitPosition */
int quickFlag;
char *pieceDesc[EmptySquare];
char *defaultDesc[EmptySquare] = {
#define SameColor(piece1, piece2) (piece1 < EmptySquare && piece2 < EmptySquare && (piece1 < BlackPawn) == (piece2 < BlackPawn) || piece1 == DarkSquare || piece2 == DarkSquare)
#endif
-char pieceToChar[] = {
+unsigned char pieceToChar[EmptySquare+1] = {
'P', 'N', 'B', 'R', 'Q', 'F', 'E', 'A', 'C', 'W', 'M',
'O', 'H', 'I', 'J', 'G', 'D', 'V', 'L', 'S', 'U', 'K',
'p', 'n', 'b', 'r', 'q', 'f', 'e', 'a', 'c', 'w', 'm',
'o', 'h', 'i', 'j', 'g', 'd', 'v', 'l', 's', 'u', 'k',
'x' };
-char pieceNickName[EmptySquare];
+unsigned char pieceNickName[EmptySquare];
+int promoPartner[EmptySquare];
char
PieceToChar (ChessSquare p)
{
+ int c;
if((int)p < 0 || (int)p >= (int)EmptySquare) return('x'); /* [HGM] for safety */
- return pieceToChar[(int) p];
+ c = pieceToChar[(int) p];
+ if(c & 128) c = c & 63 | 64;
+ return c;
+}
+
+char
+PieceSuffix (ChessSquare p)
+{
+ int c;
+ if((int)p < 0 || (int)p >= (int)EmptySquare) return 0; /* [HGM] for safety */
+ c = pieceToChar[(int) p];
+ if(c < 128) return 0;
+ return SUFFIXES[c - 128 >> 6];
}
int
if(gameInfo.variant == VariantXiangqi) pieceName = xqName;
for(p=WhitePawn; p<EmptySquare; p++) {
if((c = pieceToChar[p]) == '.' || c == '~') continue; // does not participate
- m = pieceDesc[p]; d = (c == '+' ? pieceToChar[DEMOTED p] : c);
+ m = pieceDesc[p]; d = (c == '+' ? pieceToChar[DEMOTED(p)] : c);
if(p >= BlackPawn && pieceToChar[BLACK_TO_WHITE p] == toupper(c)
- && (c != '+' || pieceToChar[DEMOTED BLACK_TO_WHITE p] == d)) { // black member of normal pair
+ && (c != '+' || pieceToChar[DEMOTED(BLACK_TO_WHITE p)] == d)) {// black member of normal pair
char *wm = pieceDesc[BLACK_TO_WHITE p];
if(!m && !wm || m && wm && !strcmp(wm, m)) continue; // moves as a white piece
} else // white or unpaired black
if(pc == WhitePawn || pc == WhiteLance) promo = WhitePromotion, promoRank = BOARD_HEIGHT-1; else
if(pc == BlackPawn || pc == BlackLance) promo = BlackPromotion, promoRank = 0;
while(*p) { // more moves to go
- int expo = 1, dx, dy, x, y, mode, dirSet, ds2=0, retry=0, initial=0, jump=1, skip = 0, all = 0;
+ int expo = -1, dx, dy, x, y, mode, dirSet, ds2=0, retry=0, initial=0, jump=1, skip = 0, all = 0;
char *cont = NULL;
- if(*p == 'i') initial = 1, desc = ++p;
+ while(*p == 'i') initial++, desc = ++p;
while(islower(*p)) p++; // skip prefixes
if(!isupper(*p)) return; // syntax error: no atom
dx = xStep[*p-'A'] - '0';// step vector of atom
if(isdigit(*++p)) expo = atoi(p++); // read exponent
if(expo > 9) p++; // allow double-digit
desc = p; // this is start of next move
+ if(initial == 2) { if(board[r][f] != initialPosition[r-2*his+3][f]) continue; } else
if(initial && (board[r][f] != initialPosition[r][f] ||
r == 0 && board[TOUCHED_W] & 1<<f ||
r == BOARD_HEIGHT-1 && board[TOUCHED_B] & 1<<f ) ) continue;
- if(expo > 1 && dx == 0 && dy == 0) { // castling indicated by O + number
+ if(expo > 0 && dx == 0 && dy == 0) { // castling indicated by O + number
mode |= 1024; dy = 1;
}
+ if(expo < 0) expo = 1; // use 1 for default
if(!cont) {
if(!(mode & 15)) mode |= his + 4; // no mode spec, use default = mc
} else {
if(y < 0 || y >= BOARD_HEIGHT) break; // vertically off-board: always done
if(x < BOARD_LEFT) { if(mode & 128) x += BOARD_RGHT - BOARD_LEFT, loop++; else break; }
if(x >= BOARD_RGHT) { if(mode & 128) x -= BOARD_RGHT - BOARD_LEFT, loop++; else break; }
- if(board[y][x] == DarkSquare) break; // black squares are supposed to be off board
if(j) { j--; continue; } // skip irrespective of occupation
+ if(board[y][x] == DarkSquare) break; // black squares are supposed to be off board
if(!jump && board[y - vy + vy/2][x - vx + vx/2] != EmptySquare) break; // blocked
if(jump > 1 && board[y - vy + vy/2][x - vx + vx/2] == EmptySquare) break; // no hop
if(x == f && y == r && !loop) occup = 4; else // start square counts as empty (if not around cylinder!)
if(occup == 4) continue; // skip empty squares
if((x == BOARD_LEFT + skip || x > BOARD_LEFT + skip && vx < 0 && board[y][x-1-skip] == DarkSquare)
&& board[y][x] == initialPosition[y][x]) { // reached initial corner piece
- if(pc != WhiteKing && pc != BlackKing) { // non-royal castling (to be entered as two-leg move via 'Rook')
+ if(pc != WhiteKing && pc != BlackKing || expo == 1) { // non-royal castling (to be entered as two-leg move via 'Rook')
if(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl); if(killX < f)
legNr <<= 1, cb(board, flags, NormalMove, r, f, y, f - expo, cl), legNr >>= 1;
} else
}
if((x == BOARD_RGHT-1-skip || x < BOARD_RGHT-1-skip && vx > 0 && board[y][x+1+skip] == DarkSquare)
&& board[y][x] == initialPosition[y][x]) {
- if(pc != WhiteKing && pc != BlackKing) {
+ if(pc != WhiteKing && pc != BlackKing || expo == 1) {
if(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl); if(killX > f)
legNr <<= 1, cb(board, flags, NormalMove, r, f, y, f + expo, cl), legNr >>= 1;
} else
if ((flags & F_WHITE_ON_MOVE) != (board[rf][ff] < BlackPawn)) continue; // [HGM] speed: wrong color
m = 0; piece = board[rf][ff];
if(PieceToChar(piece) == '~')
- piece = (ChessSquare) ( DEMOTED piece );
+ piece = (ChessSquare) ( DEMOTED(piece) );
if(filter != EmptySquare && piece != filter) continue;
if(pieceDefs && pieceDesc[piece]) { // [HGM] gen: use engine-defined moves
MovesFromString(board, flags, ff, rf, -1, -1, 0, pieceDesc[piece], callback, closure);
/* Gold General (and all its promoted versions) . First do the */
/* diagonal forward steps, then proceed as normal Wazir */
- case SHOGI (PROMOTED WhitePawn):
+ case SHOGI (PROMO WhitePawn):
if(gameInfo.variant == VariantShogi) goto WhiteGold;
- case SHOGI (PROMOTED BlackPawn):
+ case SHOGI (PROMO BlackPawn):
if(gameInfo.variant == VariantShogi) goto BlackGold;
SlideVertical(board, flags, rf, ff, callback, closure);
break;
- case SHOGI (PROMOTED WhiteKnight):
+ case SHOGI (PROMO WhiteKnight):
if(gameInfo.variant == VariantShogi) goto WhiteGold;
case SHOGI BlackDrunk:
case SHOGI BlackAlfil:
StepBackward(board, flags, rf, ff, callback, closure);
break;
- case SHOGI (PROMOTED BlackKnight):
+ case SHOGI (PROMO BlackKnight):
if(gameInfo.variant == VariantShogi) goto BlackGold;
case SHOGI WhiteDrunk:
case SHOGI WhiteAlfil:
StepSideways(board, flags, rf, ff, callback, closure);
break;
- case SHOGI (PROMOTED WhiteQueen):
+ case SHOGI (PROMO WhiteQueen):
case SHOGI WhiteTokin:
case SHOGI WhiteWazir:
WhiteGold:
Wazir(board, flags, rf, ff, callback, closure);
break;
- case SHOGI (PROMOTED BlackQueen):
+ case SHOGI (PROMO BlackQueen):
case SHOGI BlackTokin:
case SHOGI BlackWazir:
BlackGold:
StepVertical(board, flags, rf, ff, callback, closure);
break;
- case SHOGI (PROMOTED WhiteFerz):
+ case SHOGI (PROMO WhiteFerz):
if(gameInfo.variant == VariantShogi) goto WhiteGold;
- case SHOGI (PROMOTED BlackFerz):
+ case SHOGI (PROMO BlackFerz):
if(gameInfo.variant == VariantShogi) goto BlackGold;
case SHOGI WhitePSword:
case SHOGI BlackPSword:
}
ep = board[EP_STATUS];
if( captured == WhiteLion || captured == BlackLion ) { // [HGM] lion: Chu Lion-capture rules
- ChessSquare victim = killX < 0 ? EmptySquare : trampled;
+ ChessSquare victim = saveKill < 0 ? EmptySquare : trampled;
if( (board[rt][ft] == WhiteLion || board[rt][ft] == BlackLion) && // capturer is Lion
(ff - ft > 1 || ft - ff > 1 || rf - rt > 1 || rt - rf > 1) && // captures from a distance
- (victim == EmptySquare || victim == WhitePawn || victim == BlackPawn) ) // no or worthless 'bridge'
+ (victim == EmptySquare || victim == WhitePawn || victim == BlackPawn // no or worthless 'bridge'
+ || victim == WhiteCobra || victim == BlackCobra) ) // (Pawn or Go Between)
board[EP_STATUS] = EP_ROYAL_LION; // on distant Lion x Lion victim must not be pseudo-legally protected
}
}
if(quickFlag) flags = flags & ~1 | quickFlag & 1; // [HGM] speed: in quick mode quickFlag specifies side-to-move.
if(rf == DROP_RANK) return LegalDrop(board, flags, ff, rt, ft);
piece = filterPiece = board[rf][ff];
- if(PieceToChar(piece) == '~') filterPiece = DEMOTED piece;
+ if(PieceToChar(piece) == '~') filterPiece = DEMOTED(piece);
/* [HGM] Cobra and Falcon are wildcard pieces; consider all their moves legal */
/* (perhaps we should disallow moves that obviously leave us in check?) */
if(cl.kind != NormalMove || promoChar == NULLCHAR || promoChar == '=') return cl.kind;
if(promoChar != '+')
return CharToPiece(promoChar) == EmptySquare ? ImpossibleMove : IllegalMove;
- if(PieceToChar(CHUPROMOTED board[rf][ff]) != '+') return ImpossibleMove;
+ if(PieceToChar(CHUPROMOTED(board[rf][ff])) != '+') {
+ if(PieceToChar(CHUPROMOTED (board[rf][ff] < BlackPawn ? WhitePawn : BlackPawn)) != '.')
+ return ImpossibleMove;
+ }
return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
} else
if(gameInfo.variant == VariantShogi) {
// should test if in zone, really
if(gameInfo.variant == VariantChuChess && (piece == WhiteKnight || piece == BlackKnight) && HasLion(board, flags))
return IllegalMove;
- if(PieceToChar(PROMOTED piece) == '+') return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
+ if(PieceToChar(PROMOTED(piece)) == '+') return flags & F_WHITE_ON_MOVE ? WhitePromotion : BlackPromotion;
} else
if(promoChar == '=') cl.kind = IllegalMove; else // [HGM] shogi: no deferred promotion outside Shogi
if (cl.kind == WhitePromotion || cl.kind == BlackPromotion) {
if ((cl->pieceIn == EmptySquare || cl->pieceIn == board[rf][ff]
|| PieceToChar(board[rf][ff]) == '~'
- && cl->pieceIn == (ChessSquare)(DEMOTED board[rf][ff])
+ && cl->pieceIn == (ChessSquare)(DEMOTED(board[rf][ff]))
) &&
(cl->rfIn == -1 || cl->rfIn == rf) &&
(cl->ffIn == -1 || cl->ffIn == ff) &&
if (closure->kind == WhitePromotion || closure->kind == BlackPromotion) {
if(c == NULLCHAR) { // missing promoChar on mandatory promotion; use default for variant
if(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
- gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN)
+ gameInfo.variant == VariantMakruk)
c = PieceToChar(BlackFerz);
+ else if(gameInfo.variant == VariantASEAN)
+ c = PieceToChar(BlackRook);
else if(gameInfo.variant == VariantGreat)
c = PieceToChar(BlackMan);
else if(gameInfo.variant == VariantGrand)
else if(c == 'l' && gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove;
} else if (c == '+') { // '+' outside shogi, check if pieceToCharTable enabled it
ChessSquare p = closure->piece;
- if(p > WhiteMan && p < BlackPawn || p > BlackMan || PieceToChar(PROMOTED p) != '+')
+ if(p > WhiteMan && p < BlackPawn || p > BlackMan || PieceToChar(PROMOTED(p)) != '+')
closure->kind = ImpossibleMove; // used on non-promotable piece
else if(gameInfo.variant == VariantChuChess && HasLion(board, flags)) closure->kind = IllegalMove;
} else if (c != NULLCHAR) closure->kind = IllegalMove;
if ((rt == cl->rt && ft == cl->ft || rt == rf && ft == ff) && // [HGM] null move matches any toSquare
(board[rf][ff] == cl->piece
|| PieceToChar(board[rf][ff]) == '~' &&
- (ChessSquare) (DEMOTED board[rf][ff]) == cl->piece)
+ (ChessSquare) (DEMOTED(board[rf][ff])) == cl->piece)
) {
if (rf == cl->rf) {
if (ff == cl->ff) {
if (promoChar == 'x') promoChar = NULLCHAR;
piece = board[rf][ff];
- if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED piece);
+ if(PieceToChar(piece)=='~') piece = (ChessSquare)(DEMOTED(piece));
switch (piece) {
case WhitePawn:
cl.kind = IllegalMove;
cl.rank = cl.file = cl.either = 0;
c = PieceToChar(piece) ;
- GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece)); // [HGM] speed
+ GenLegal(board, flags, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED(piece))); // [HGM] speed
if (cl.kind == IllegalMove && !(flags&F_IGNORE_CHECK)) {
/* Generate pretty moves for moving into check, but
still return IllegalMove.
*/
- GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED piece));
+ GenLegal(board, flags|F_IGNORE_CHECK, CoordsToAlgebraicCallback, (VOIDSTAR) &cl, c!='~' ? piece : (DEMOTED(piece)));
if (cl.kind == IllegalMove) break;
cl.kind = IllegalMove;
}
*/
if( c == '~' || c == '+') {
/* [HGM] print nonexistent piece as its demoted version */
- piece = (ChessSquare) (DEMOTED piece - 11*(gameInfo.variant == VariantChu));
+ piece = (ChessSquare) (CHUDEMOTED(piece));
}
if(c=='+') *outp++ = c;
*outp++ = ToUpper(PieceToChar(piece));
+ if(*outp = PieceSuffix(piece)) outp++;
if (cl.file || (cl.either && !cl.rank)) {
*outp++ = ff + AAA;