void FEN_to_board(char* FENpos, struct game_state_t* gs)
{
- int f,r;\r
- char next;\r
-printf("FEN, var='%s'\n", gs->variant);\r
- for (r=gs->ranks-1; r >=0; r--) {\r
- f=0;\r
- while (f<gs->files) {\r
- next = *(FENpos++);\r
- if (isalpha(next))\r
- gs->board[f++][r] = CharToPiece(next, gs->variant);\r
- else if (next != '/') {\r
- int t = (next - '0');\r
- if(*FENpos >= '0' && *FENpos <= '9') // [HGM] can be double-digit\r
- t = 10*t + *(FENpos++) - '0';\r
- do\r
- gs->board[f++][r] = NOPIECE;\r
- while (--t && f < gs->files);\r
- }\r
- }\r
- }\r
- if (*(FENpos + 1) == 'w') /* the char after the space */\r
- gs->onMove = WHITE;\r
- else\r
- gs->onMove = BLACK;\r
+ int f,r;
+ char next;
+printf("FEN='%s', var='%s'\n", FENpos, gs->variant);
+ for (r=gs->ranks-1; r >=0; r--) {
+ f=0;
+ while (f<gs->files) {
+ next = *(FENpos++);
+ if (isalpha(next))
+ gs->board[f++][r] = CharToPiece(next, gs->variant);
+ else if (next != '/') {
+ int t = (next - '0');
+ if(*FENpos >= '0' && *FENpos <= '9') // [HGM] can be double-digit
+ t = 10*t + *(FENpos++) - '0';
+ do
+ gs->board[f++][r] = NOPIECE;
+ while (--t && f < gs->files);
+ }
+ }
+ }
+ if (*(FENpos + 1) == 'w') /* the char after the space */
+ gs->onMove = WHITE;
+ else
+ gs->onMove = BLACK;
}
/* converts a board to a FEN pos */
static void board_to_FEN(char* FENpos, struct game_state_t* gs)
{
- int f,r,count;\r
- char piece; \r
-\r
- for (r=gs->ranks-1; r>=0; r--) {\r
- count = 0;\r
- for (f=0; f<gs->files; f++) {\r
- if ((piece = PieceToChar(gs->board[f][r])) != ' ') {\r
- if (count) { \r
- if(count > 9) { count -= 10; *(FENpos++) = '1'; }\r
- *(FENpos++) = count + '0';\r
- count = 0;\r
- }\r
- *(FENpos++) = piece;\r
- } else {\r
- if (f == gs->files-1) {\r
- if(count > 8) { count -= 10; *(FENpos++) = '1'; }\r
- *(FENpos++) = count + '0' + 1;\r
- } else\r
- count++;\r
- }\r
- }\r
- *(FENpos++) = '/';\r
- }\r
-\r
- *(--FENpos) = ' ';\r
-\r
- if (gs->onMove == WHITE)\r
- *(++FENpos) = 'w';\r
- else\r
- *(++FENpos) = 'b';\r
- *(++FENpos) = '\0';\r
+ int f,r,count;
+ char piece;
+
+ for (r=gs->ranks-1; r>=0; r--) {
+ count = 0;
+ for (f=0; f<gs->files; f++) {
+ if ((piece = PieceToChar(gs->board[f][r])) != ' ') {
+ if (count) {
+ if(count > 9) { count -= 10; *(FENpos++) = '1'; }
+ *(FENpos++) = count + '0';
+ count = 0;
+ }
+ *(FENpos++) = piece;
+ } else {
+ if (f == gs->files-1) {
+ if(count > 8) { count -= 10; *(FENpos++) = '1'; }
+ *(FENpos++) = count + '0' + 1;
+ } else
+ count++;
+ }
+ }
+ *(FENpos++) = '/';
+ }
+
+ *(--FENpos) = ' ';
+
+ if (gs->onMove == WHITE)
+ *(++FENpos) = 'w';
+ else
+ *(++FENpos) = 'b';
+ *(++FENpos) = '\0';
}
char *boardToFEN(int g)
int is_move(const char *mstr)
{
int len = strlen(mstr);
- if ((len > 3) && (mstr[len - 2] == '='))
- len -= 2;
-
/* remove the 'mates' marker */
if (mstr[len - 1] == '#')
len--;
+ if ((len > 3) && (mstr[len - 2] == '=' || mstr[len - 2] == '/'))
+ len -= 2;
+
if (len == 4) { /* Test for e2e4 */
if (isfile(mstr[0]) && isrank(mstr[1]) &&
isfile(mstr[2]) && isrank(mstr[3])) {
if (gs->onMove == WHITE) {
/* King side castling */
- if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->wkmoved >= 0)
- && (gs->wkrmoved >= 0) && (gs->board[gs->files-3][0] == NOPIECE) &&
+ if ((fr == 0) && (tr == 0) && ((ff == gs->files/2) && (tf == gs->files-2) ||
+ gs->drops == 2 && (tf == gs->files/2) && (ff == gs->files-1)) // [HGM] reverse Seirawan gating
+ && (gs->wkmoved >= 0) && (gs->wkrmoved >= 0) && (gs->board[gs->files-3][0] == NOPIECE) &&
(gs->board[gs->files-2][0] == NOPIECE) && (gs->board[gs->files-1][0] == W_ROOK) &&
(gs->board[gs->files/2+1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, 0)) &&
(!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, gs->files-3, 0))) {
return 2;
}
/* Queen side castling */
- if ((fr == 0) && (tr == 0) && (ff == gs->files/2) && (tf == 2) && (gs->wkmoved >= 0)
- && (gs->wqrmoved >= 0) && (gs->board[3][0] == NOPIECE) &&
+ if ((fr == 0) && (tr == 0) && ((ff == gs->files/2) && (tf == 2) ||
+ gs->drops == 2 && (tf == gs->files/2) && (ff == 0)) // [HGM] reverse Seirawan gating
+ && (gs->wkmoved >= 0) && (gs->wqrmoved >= 0) && (gs->board[3][0] == NOPIECE) &&
(gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) &&
(gs->board[0][0] == W_ROOK) &&
(gs->board[gs->files/2-1][0] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, 0)) &&
}
} else { /* Black */
/* King side castling */
- if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == gs->files-2) && (gs->bkmoved >= 0)
- && (gs->bkrmoved >= 0) && (gs->board[gs->files-3][7] == NOPIECE) &&
+ if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && ((ff == gs->files/2) && (tf == gs->files-2) ||
+ gs->drops == 2 && (tf == gs->files/2) && (ff == gs->files-1)) // [HGM] reverse Seirawan gating
+ && (gs->bkmoved >= 0) && (gs->bkrmoved >= 0) && (gs->board[gs->files-3][7] == NOPIECE) &&
(gs->board[gs->files-2][gs->ranks-1] == NOPIECE) && (gs->board[gs->files-1][gs->ranks-1] == B_ROOK) &&
(gs->board[gs->files/2+1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2+1, gs->ranks-1)) &&
(!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, gs->files-3, gs->ranks-1))) {
return 2;
}
/* Queen side castling */
- if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && (ff == gs->files/2) && (tf == 2) && (gs->bkmoved >= 0)
- && (gs->bqrmoved >= 0) && (gs->board[3][gs->ranks-1] == NOPIECE) &&
+ if ((fr == gs->ranks-1) && (tr == gs->ranks-1) && ((ff == gs->files/2) && (tf == 2) ||
+ gs->drops == 2 && (tf == gs->files/2) && (ff == 0)) // [HGM] reverse Seirawan gating
+ && (gs->bkmoved >= 0) && (gs->bqrmoved >= 0) && (gs->board[3][gs->ranks-1] == NOPIECE) &&
(gs->board[2][gs->ranks-1] == NOPIECE) && (gs->board[1][gs->ranks-1] == NOPIECE) &&
(gs->board[0][gs->ranks-1] == B_ROOK) &&
(gs->board[gs->files/2-1][gs->ranks-1] == NOPIECE) && (!is_square_attacked(gs, gs->files/2-1, gs->ranks-1)) &&
int fFile, int fRank,
int tFile, int tRank)
{
- int move_piece;
+ int move_piece, victim;
int legal;
if (fFile == ALG_DROP) {
return 0;
if (!iscolor(gs->board[fFile][fRank], gs->onMove)) /* Wrong color */
return 0;
- if ((gs->board[tFile][tRank] != NOPIECE) &&
- iscolor(gs->board[tFile][tRank], gs->onMove)) /* Can't capture own */
- return 0;
+ if (((victim = gs->board[tFile][tRank]) != NOPIECE) &&
+ iscolor(gs->board[tFile][tRank], gs->onMove)) {
+ if(piecetype(move_piece) == KING && piecetype(victim) == ROOK) { // [HGM] could be FRC castling
+ }
+ if(gs->drops== 2 && piecetype(move_piece) == ROOK && piecetype(victim) == KING) { // [HGM] could be Seirawan reverse gating
+ return legal_king_move(gs, fFile, fRank, tFile, tRank);
+ }
+ return 0; /* Can't capture own */
+ }
if ((fFile == tFile) && (fRank == tRank)) /* Same square */
return 0;
switch (move_piece) {
} else if(mt->fromFile == ALG_CASTLE) {
// [HGM] castle: generalized castling, fr and tr give from and to file of Rook.
sprintf(mt->moveString, mt->toRank > mt->toFile ? "o-o-o" : "o-o");
- if(gs->drops == 2 && promote && gs->holding[gs->onMove == BLACK][promote-1])
- mt->piecePromotionTo = promote, gating = 1;
+ if(gs->drops == 2 && promote && gs->holding[gs->onMove == BLACK][abs(promote)-1]) { // promote can be flipped (reverse gating kludge)
+ int c = gs->onMove == WHITE ? 0 : gs->ranks-1;
+ mt->piecePromotionTo = promote; gating = 1;
+ if(promote < 0) sprintf(mt->moveString, "R/%c%d-e%d", mt->fromRank + 'a', c, c); // use RxK notation for Rook-square gatings
+ }
} else {
stm = colorval(gs->board[mt->fromFile][mt->fromRank]);
if(gs->promoType == 3) { // Shogi-style promotions: not just Pawns, but many pieces can promote
// now we must test virginity of the moved piece. Yegh!
for (i = g->numHalfMoves-1; i >= 0; i--) {
if (g->moveList[i].fromFile == mt->fromFile && g->moveList[i].fromRank == mt->fromRank ||
- g->moveList[i].toFile == mt->fromFile && g->moveList[i].toRank == mt->fromRank) return MOVE_ILLEGAL;
+ g->moveList[i].toFile == mt->fromFile && g->moveList[i].toRank == mt->fromRank ||
+ g->moveList[i].fromFile == ALG_CASTLE && (gs->onMove == WHITE ? 0 : gs->ranks-1) == mt->fromRank &&
+ (g->moveList[i].fromRank == mt->fromFile || gs->files>>1 == mt->fromFile )) return MOVE_ILLEGAL;
}
mt->piecePromotionTo = promote; // gating OK
gating = 1; // remember we did it for check test
int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote)
{
int type = is_move(mstr);
- int result;
+ int result, flipflag = 1;
mt->piecePromotionTo = NOPIECE;
mt->color = gs->onMove;
return MOVE_ILLEGAL;
if(result == 2) { // [HGM] castle: orthodox castling was given as King move; convert it to new format
+ int ff=mt->fromFile, tf=mt->toFile;
+ if(piecetype(gs->board[tf][mt->toRank]) == KING) { // [HGM] RxK notation
+ mt->fromFile = tf; mt->toFile = ff > tf ? gs->files-2 : 2; // correct to coventional
+ flipflag = -1; // kludge: flip gated piece
+ }
if(mt->fromFile - mt->toFile > 1) { // Q-side
mt->fromRank = 0;
mt->toRank = mt->toFile+1;
if(gs->drops == 2 && promote == DRAGONHORSE) promote = HAWK;
}
- return move_calculate(gs, mt, promote);
+ return move_calculate(gs, mt, promote*flipflag);
}
/* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */
gs->board[mt->toRank][backRank] = rook; // then put back
gs->board[mt->toFile][backRank] = king;
if(gs->drops == 2 && mt->piecePromotionTo != NOPIECE) { // [HGM] Seirawan-style gating
- gs->board[fKing][backRank] = mt->piecePromotionTo | gs->onMove; // for now always on King square
- gs->holding[gs->onMove==WHITE ? 0 : 1][mt->piecePromotionTo-1]--; // remove gated piece from holdings
+ if(mt->piecePromotionTo > 0)
+ gs->board[fKing][backRank] = mt->piecePromotionTo | gs->onMove; // gate on King square
+ else
+ gs->board[mt->fromRank][backRank] = -mt->piecePromotionTo | gs->onMove; // gate on Rook square
+ gs->holding[gs->onMove==WHITE ? 0 : 1][abs(mt->piecePromotionTo)-1]--; // remove gated piece from holdings
}
} else {
movedPiece = gs->board[mt->fromFile][mt->fromRank];
// remove first, as one might come back to a square the other left
gs->board[m->toFile ][rank] = NOPIECE; // King toSqr
gs->board[m->toRank ][rank] = NOPIECE; // Rook toSqr
+ if(gs->board[m->fromRank][rank] != NOPIECE)
+ gs->holding[gs->onMove==WHITE ? 1 : 0][piecetype(gs->board[m->fromRank][rank])-1]++; // put back in holdings (onMove not flipped yet!)
+ if(gs->board[kingFromFile][rank] != NOPIECE)
+ gs->holding[gs->onMove==WHITE ? 1 : 0][piecetype(gs->board[kingFromFile][rank])-1]++; // put back in holdings (onMove not flipped yet!)
gs->board[m->fromRank][rank] = ROOK | m->color; // Rook fromSqr
gs->board[kingFromFile][rank] = KING | m->color; // King fromSquare
goto cleanupMove;
}
+ if(gs->board[m->fromFile][m->fromRank] != NOPIECE) { // [HGM] from-square occupied; move must have been Seirawan-style gating
+ gs->holding[gs->onMove==WHITE ? 1 : 0][piecetype(gs->board[m->fromFile][m->fromRank])-1]++; // put back in holdings (onMove not flipped yet!)
+ }
gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank];
if (m->piecePromotionTo != NOPIECE) {
gs->board[m->fromFile][m->fromRank] = PAWN |
goto cleanupMove;
}
gs->board[m->toFile][m->toRank] = m->pieceCaptured;
- if(gs->board[m->fromFile][m->fromRank] != NOPIECE) { // [HGM] from-square occupied, must have been Seirawan-style gating
- gs->holding[gs->onMove==WHITE ? 1 : 0][piecetype(gs->board[m->fromFile][m->fromRank])-1]++; // put back in holdings (onMove not flipped yet!)
- }
cleanupMove:
if (game_globals.garray[g].status != GAME_EXAMINE) {
game_update_time(g);