MovesFromString (Board board, int flags, int f, int r, int tx, int ty, int angle, char *desc, MoveCallback cb, VOIDSTAR cl)
{
char buf[80], *p = desc, *atom = NULL;
- int mine, his, dir, bit, occup, i;
+ int mine, his, dir, bit, occup, i, ep, promoRank = -1;
+ ChessMove promo= NormalMove; ChessSquare pc = board[r][f];
+ if(pc == DarkSquare) return; // this is not a piece, but a 'hole' in the board
if(flags & F_WHITE_ON_MOVE) his = 2, mine = 1; else his = 1, mine = 2;
+ 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, 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(islower(*p)) p++; // skip prefixes
break;
case 'N': all = 0xFF; // oblique atom (degenerate 8-fold)
if(tx >= 0) goto king; // continuation legs specified in K/Q system!
+ if(*desc == 'h') { // chiral direction sets 'hr' and 'hl'
+ dirSet = (desc[1] == 'r' ? 0x55 : 0xAA); desc += 2;
+ } else
while(islower(*desc) && (i = dirType[*desc-'a']) != '0') {
int b = dirs2[*desc-'a']; // when alone, use narrow version
if(desc[1] == 'h') b = dirs1[*desc-'a'], desc += 2; // dirs1 is wide version
if(dy == 1) skip = jump - 1, jump = 1; // on W & F atoms 'j' = skip first square
do {
for(dir=0, bit=1; dir<8; dir++, bit += bit) { // loop over directions
- int i = expo, j = skip, hop = mode, vx, vy;
+ int i = expo, j = skip, hop = mode, vx, vy, loop = 0;
if(!(bit & dirSet)) continue; // does not move in this direction
if(dy != 1) j = 0; //
vx = dx*rot[dir][0] + dy*rot[dir][1]; // rotate step vector
do { // traverse ray
x += vx; y += vy; // step to next square
if(y < 0 || y >= BOARD_HEIGHT) break; // vertically off-board: always done
- if(x < BOARD_LEFT) { if(mode & 128) x += BOARD_RGHT - BOARD_LEFT; else break; }
- if(x >= BOARD_RGHT) { if(mode & 128) x -= BOARD_RGHT - BOARD_LEFT; else break; }
+ 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(!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) occup = 4; else // start square counts as empty
+ if(x == f && y == r && !loop) occup = 4; else // start square counts as empty (if not around cylinder!)
if(board[y][x] < BlackPawn) occup = 0x101; else
if(board[y][x] < EmptySquare) occup = 0x102; else
occup = 4;
continue;
}
if(hop & 32+64) { if(occup != 4) { if(hop & 64 && i != 1) i = 2; hop &= 31; } continue; } // hopper
- if(mode & 8 && y == board[EP_RANK] && occup == 4 && board[EP_FILE] == x) { // to e.p. square
+ ep = board[EP_RANK];
+ if(mode & 8 && occup == 4 && board[EP_FILE] == x && (y == (ep & 127) || y - vy == ep - 128)) { // to e.p. square (or 2nd e.p. square)
cb(board, flags, mine == 1 ? WhiteCapturesEnPassant : BlackCapturesEnPassant, r, f, y, x, cl);
}
if(mode & 1024) { // castling
i = 2; // kludge to elongate move indefinitely
if(occup == 4) continue; // skip empty squares
- if(x == BOARD_LEFT && board[y][x] == initialPosition[y][x]) // reached initial corner piece
+ if((x == BOARD_LEFT || vx < 0 && board[y][x-1] == 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(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl);
+ legNr <<= 1; cb(board, flags, NormalMove, r, f, y, f - expo, cl); legNr >>= 1;
+ } else
cb(board, flags, mine == 1 ? WhiteQueenSideCastle : BlackQueenSideCastle, r, f, y, f - expo, cl);
- if(x == BOARD_RGHT-1 && board[y][x] == initialPosition[y][x])
+ }
+ if((x == BOARD_RGHT-1 || vx > 0 && board[y][x+1] == DarkSquare) && board[y][x] == initialPosition[y][x]) {
+ if(pc != WhiteKing && pc != BlackKing) {
+ if(killX < 0) cb(board, flags, FirstLeg, r, f, y, x, cl);
+ legNr <<= 1; cb(board, flags, NormalMove, r, f, y, f + expo, cl); legNr >>= 1;
+ } else
cb(board, flags, mine == 1 ? WhiteKingSideCastle : BlackKingSideCastle, r, f, y, f + expo, cl);
+ }
break;
}
- if(occup & mode) cb(board, flags, NormalMove, r, f, y, x, cl); // allowed, generate
+ if(mode & 16 && (board[y][x] == WhiteKing || board[y][x] == BlackKing)) break; // tame piece, cannot capture royal
+ if(occup & mode) cb(board, flags, y == promoRank ? promo : NormalMove, r, f, y, x, cl); // allowed, generate
if(occup != 4) break; // not valid transit square
} while(--i);
}
CheckTestClosure cl;
ChessSquare king = flags & F_WHITE_ON_MOVE ? WhiteKing : BlackKing;
ChessSquare captured = EmptySquare, ep=0, trampled=0;
+ int saveKill = killX;
/* Suppress warnings on uninitialized variables */
if(gameInfo.variant == VariantXiangqi)
king = flags & F_WHITE_ON_MOVE ? WhiteWazir : BlackWazir;
if(gameInfo.variant == VariantKnightmate)
king = flags & F_WHITE_ON_MOVE ? WhiteUnicorn : BlackUnicorn;
- if(gameInfo.variant == VariantChu) { // strictly speaking this is not needed, as Chu officially has no check
+ if(gameInfo.variant == VariantChu || gameInfo.variant == VariantShogi) { // strictly speaking this is not needed, as Chu officially has no check
int r, f, k = king, royals=0, prince = flags & F_WHITE_ON_MOVE ? WhiteMonarch : BlackMonarch;
+ if(gameInfo.variant == VariantShogi) prince -= 11; // White/BlackFalcon
for(r=0; r<BOARD_HEIGHT; r++) for(f=BOARD_LEFT; f<BOARD_RGHT; f++) {
if(board[r][f] == k || board[r][f] == prince) {
if(++royals > 1) return FALSE; // no check if we have two royals (ignores double captureby Lion!)
board[rf][ft] = EmptySquare;
} else {
captured = board[rt][ft];
- if(killX >= 0) { trampled = board[killY][killX]; board[killY][killX] = EmptySquare; }
+ if(killX >= 0) { trampled = board[killY][killX]; board[killY][killX] = EmptySquare; killX = -1; }
}
if(rf == DROP_RANK) board[rt][ft] = ff; else { // [HGM] drop
board[rt][ft] = board[rf][ff];
board[rf][ft] = captured;
board[rt][ft] = EmptySquare;
} else {
- if(killX >= 0) board[killY][killX] = trampled;
+ if(saveKill >= 0) board[killY][killX = saveKill] = trampled;
board[rt][ft] = captured;
}
board[EP_STATUS] = ep;