X-Git-Url: http://winboard.nl/cgi-bin?p=capablanca.git;a=blobdiff_plain;f=lasker-2.2.3%2Fsrc%2Fmovecheck.c;h=d5759154cb926a53aca30f63e39db6470da8a99c;hp=8f0dd9cb42c4075afdb72c40732835ab1dc2c862;hb=225ee001625a06413e7ceee04d8723972231b9ea;hpb=0673decdb041b796d55fe77e7e4eaf32895265b3 diff --git a/lasker-2.2.3/src/movecheck.c b/lasker-2.2.3/src/movecheck.c index 8f0dd9c..d575915 100644 --- a/lasker-2.2.3/src/movecheck.c +++ b/lasker-2.2.3/src/movecheck.c @@ -45,13 +45,13 @@ 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])) { @@ -178,6 +178,36 @@ static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int return 0; } +static int legal_hoplite_move( struct game_state_t *gs, int ff, int fr, int tf, int tr ) +{ + if (ff == tf) { /* Capture ? */ + if (gs->board[tf][tr] == NOPIECE) return 0; + if (gs->onMove == WHITE) { + if(iscolor(gs->board[tf][tr],WHITE)) return 0; + if (tr - fr == 1) return 1; + } else { + if(iscolor(gs->board[tf][tr],BLACK)) return 0; + if (fr - tr == 1) return 1; + } + return 0; + } + if (ff != tf) { + if (gs->board[tf][tr] != NOPIECE) return 0; + if (gs->onMove == WHITE) { + if (tr == fr+1 && abs(tf-ff) == 1) return 1; + if (tr != fr+2 || abs(tf-ff) != 2) return 0; + if (fr > gs->pawnDblStep) return 0; + return 1; + } else { + if (tr == fr-1 && abs(tf-ff) == 1) return 1; + if (tr != fr-2 || abs(tf-ff) != 2) return 0; + if (fr < gs->ranks - 1 - gs->pawnDblStep) return 0; + return 1; + } + } + return 0; +} + static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) { int dx, dy; @@ -535,6 +565,12 @@ static int legal_modernelephant_move(struct game_state_t * gs, int ff, int fr, i return legal_ferz_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr); } +static int legal_lieutenant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_modernelephant_move(gs, ff, fr, tf, tr) || + fr == tr && abs(ff - tf) == 1 && gs->board[tf][tr] == NOPIECE; +} + static int legal_priestess_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) { return legal_knight_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr) @@ -570,16 +606,18 @@ static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int 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)) && @@ -588,16 +626,18 @@ static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int } } 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)) && @@ -675,6 +715,51 @@ static void possible_pawn_moves(struct game_state_t * gs, } } +static void possible_hoplite_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + if (gs->onMove == WHITE) { // in Spartan Chess there are no white hoplites... + if (gs->board[onf][onr + 1] != NOPIECE && + iscolor(gs->board[onf][onr + 1], BLACK)) { + add_pos(onf, onr + 1, posf, posr, numpos); + } + if (onf > 0) { + if (gs->board[onf - 1][onr + 1] == NOPIECE) { + add_pos(onf - 1, onr + 1, posf, posr, numpos); + if (onf > 1 && (onr <= gs->pawnDblStep) /*&& (gs->board[onf-2][onr + 2] == NOPIECE)*/) + add_pos(onf - 2, onr + 2, posf, posr, numpos); + } + } + if (onf < gs->files-1) { + if (gs->board[onf + 1][onr + 1] == NOPIECE) { + add_pos(onf + 1, onr + 1, posf, posr, numpos); + if (onf < gs->files-2 && (onr <= gs->pawnDblStep) /*&& (gs->board[onf+2][onr + 2] == NOPIECE)*/) + add_pos(onf + 2, onr + 2, posf, posr, numpos); + } + } + } else { + if (gs->board[onf][onr - 1] != NOPIECE && + iscolor(gs->board[onf][onr - 1], WHITE)) { + add_pos(onf, onr - 1, posf, posr, numpos); + } + if (onf > 0) { + if (gs->board[onf - 1][onr - 1] == NOPIECE) { + add_pos(onf - 1, onr - 1, posf, posr, numpos); + if (onf > 1 && (onr >= gs->ranks - gs->pawnDblStep - 1) /*&& (gs->board[onf - 2][onr - 2] == NOPIECE)*/) + add_pos(onf - 2, onr - 2, posf, posr, numpos); + } + } + if (onf < gs->files-1) { + if (gs->board[onf + 1][onr - 1] == NOPIECE) { + add_pos(onf + 1, onr - 1, posf, posr, numpos); + if (onf < gs->files-2 && (onr >= gs->ranks - gs->pawnDblStep - 1) /*&& (gs->board[onf + 2][onr - 2] == NOPIECE)*/) + add_pos(onf + 2, onr - 2, posf, posr, numpos); + } + } + } +} + static void possible_knight_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) @@ -1182,6 +1267,17 @@ static void possible_modernelephant_moves(struct game_state_t * gs, possible_alfil_moves(gs, onf, onr, posf, posr, numpos); } +static void possible_lieutenant_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_modernelephant_moves(gs, onf, onr, posf, posr, numpos); + if (onf < gs->files-1 && (gs->board[onf+1][onr] == NOPIECE)) + add_pos(onf + 1, onr, posf, posr, numpos); + if (onf > 0 && (gs->board[onf-1][onr] == NOPIECE)) + add_pos(onf - 1, onr, posf, posr, numpos); +} + static void possible_priestess_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) @@ -1291,12 +1387,12 @@ int legal_move(struct game_state_t * gs, int fFile, int fRank, int tFile, int tRank) { - int move_piece; + int move_piece, victim; int legal; if (fFile == ALG_DROP) { move_piece = fRank; - if(!gs->drops) return 0; // [HGM] variants: no drops in this variant + if(gs->drops != 1) return 0; // [HGM] variants: no drops in this variant if (move_piece == KING) return 0; if (gs->holding[gs->onMove==WHITE ? 0 : 1][move_piece-1] == 0) @@ -1369,15 +1465,24 @@ int legal_move(struct game_state_t * gs, 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) { case PAWN: legal = legal_pawn_move(gs, fFile, fRank, tFile, tRank); break; + case HOPLITE: + legal = legal_hoplite_move(gs, fFile, fRank, tFile, tRank); + break; case KNIGHT: legal = legal_knight_move(gs, fFile, fRank, tFile, tRank); break; @@ -1387,10 +1492,13 @@ int legal_move(struct game_state_t * gs, case ROOK: legal = legal_rook_move(gs, fFile, fRank, tFile, tRank); break; + case WARLORD: + case HAWK: case CARDINAL: case PRINCESS: legal = legal_cardinal_move(gs, fFile, fRank, tFile, tRank); break; + case SELEPHANT: case MARSHALL: case EMPRESS: legal = legal_marshall_move(gs, fFile, fRank, tFile, tRank); @@ -1408,6 +1516,7 @@ int legal_move(struct game_state_t * gs, case AMAZON: legal = legal_amazon_move(gs, fFile, fRank, tFile, tRank); break; + case CAPTAIN: case WOODY: legal = legal_woody_move(gs, fFile, fRank, tFile, tRank); break; @@ -1433,6 +1542,9 @@ int legal_move(struct game_state_t * gs, case WAZIR: legal = legal_wazir_move(gs, fFile, fRank, tFile, tRank); break; + case LIEUTENANT: + legal = legal_lieutenant_move(gs, fFile, fRank, tFile, tRank); + break; case ALFIL: case ALFIL2: legal = legal_alfil_move(gs, fFile, fRank, tFile, tRank); @@ -1461,6 +1573,7 @@ int legal_move(struct game_state_t * gs, case DRAGONHORSE: legal = legal_dragonhorse_move(gs, fFile, fRank, tFile, tRank); break; + case GENERAL: case DRAGONKING: legal = legal_dragonking_move(gs, fFile, fRank, tFile, tRank); break; @@ -1484,6 +1597,7 @@ int legal_move(struct game_state_t * gs, static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote) { struct game_state_t fakeMove; + int gating = 0, stm; mt->pieceCaptured = gs->board[mt->toFile][mt->toRank]; mt->enPassant = 0; /* Don't know yet, let execute move take care @@ -1497,7 +1611,13 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom } 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][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 int piece = gs->board[mt->fromFile][mt->fromRank]; mt->piecePromotionTo = NOPIECE; @@ -1533,18 +1653,68 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && !gs->palace && // [HGM] XQ: no promotions in xiangqi ((mt->toRank < gs->promoZone) || (mt->toRank >= gs->ranks - gs->promoZone))) { - int stm = colorval(gs->board[mt->fromFile][mt->fromRank]); + if(promote == KING) return MOVE_ILLEGAL; // no king in normal chess if(!promote && (mt->toRank == 0 || mt->toRank == gs->ranks-1)) { // promotion obligatory, but not specified if(gs->promoType != 2) promote = QUEEN; else { // choose a default - for(promote=KING-1; promote>PAWN; promote--) if(gs->holding[stm == BLACK][promote-1]) break; + for(promote=PIECES-1; promote>PAWN; promote--) if(gs->holding[stm == BLACK][promote-1]) break; if(promote == PAWN) return MOVE_ILLEGAL; // nothing available } - } // if not obligatory, we defer unless promoton was explicitly specified! + } // if not obligatory, we defer unless promotion was explicitly specified! if(!gs->pawnDblStep && promote == PRINCESS) promote = MAN2; if(!gs->pawnDblStep && promote != FERZ2 && promote != MAN2) promote = FERZ; // [HGM] kludge to recognize shatranj // non-promotion can still be an option for deeper promotion zones mt->piecePromotionTo = promote ? (promote | stm) : NOPIECE; if(promote && gs->promoType == 2 && !gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified + if(promote == KNIGHT && gs->royalKnight) return MOVE_ILLEGAL; // Knight not allowed in Knightmate + if(gs->promoType != 2 && promote > QUEEN) { // for promoType != 2 we must check explicitly if the requested pieceis compatible with the variant + switch(promote) { + case HAWK: + case SELEPHANT: + if(gs->drops != 2) return MOVE_ILLEGAL; // allowed only in S-Chess + break; + case MARSHALL: + case CARDINAL: + if(!gs->capablancaPieces) return MOVE_ILLEGAL; // allowed when flagged so + break; + case FERZ: + case FERZ2: + if(!gs->pawnDblStep) return MOVE_ILLEGAL; // allowed in Shatranj and Courier + break; + case MAN2: + if(!gs->royalKnight) return MOVE_ILLEGAL; // allowed only in Knightmate + break; + default: + return MOVE_ILLEGAL; + } + } + } else + if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == HOPLITE) && + ((mt->toRank < gs->promoZone) || (mt->toRank >= gs->ranks - gs->promoZone))) { + if(!promote || promote == KING) { + int f, r, k=0, king = gs->onMove == WHITE ? W_KING : B_KING; + for(r=0; rranks;r++) for(f=0; ffiles; f++) k += (gs->board[f][r] == king); + if(k > 1) { // we already have two kings + if(promote == KING) return MOVE_ILLEGAL; // three kings not allowed + promote = WARLORD; // use strongest piece as default + } else promote = KING; // if no promo-piece given, this could be mate test, so test if promoting to King evades + } else + if(promote == MASTODON) promote = GENERAL; else + if(promote == WOODY) promote = WARLORD; else + if(promote == MARSHALL) promote = CAPTAIN; else + if(promote != LIEUTENANT) return MOVE_ILLEGAL; + mt->piecePromotionTo = (promote | stm); + } else if(gs->drops == 2 && promote && mt->fromRank == (stm == WHITE ? 0 : gs->ranks-1)) { // [HGM] Seirawan-style gating + int i; struct game *g = &game_globals.garray[gs->gameNum]; + if(!gs->holding[stm == BLACK][promote-1]) return MOVE_ILLEGAL; // unavailable piece specified + // 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 || + 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 } else { mt->piecePromotionTo = NOPIECE; } @@ -1579,6 +1749,7 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom fakeMove = *gs; /* Calculates enPassant also */ execute_move(&fakeMove, mt, 0); + if(gating) fakeMove.board[mt->fromFile][mt->fromRank] = NOPIECE; // [HGM] gating is only legal if non-gating move was (weird, but true) /* Does making this move leave ME in check? */ if (in_check(&fakeMove)) @@ -1632,12 +1803,20 @@ int in_check(struct game_state_t * gs) } } if (kf < 0) { - d_printf( "CHESSD: Error game with no king!\n"); - return 0; +// d_printf( "CHESSD: Error game with no king!\n"); + return -1; } for (InitPieceLoop(gs->board, &f, &r, gs->onMove); NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) { if (legal_move(gs, f, r, kf, kr)) { /* In Check? */ + if(gs->onMove == WHITE && !strcmp(gs->variant, "spartan")) { // first king is in check, but we might have spare +//printf("spartan K-capt %c%d%c%d\n",f+'a',r+1,kf+'a',kr+1); + gs->board[kf][kr] = B_MAN; // temporarily cure the check on the first King by replacing the latter; + r = in_check(gs); + gs->board[kf][kr] = B_KING; // and put it back +//printf("duple = %d\n",r); + return r != 0; // if we have no second king (r = -1) or the second is also attacked (r = 1) we are in check. + } return 1; } } @@ -1658,6 +1837,9 @@ int has_legal_move(struct game_state_t * gs) case PAWN: possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case HOPLITE: + possible_hoplite_moves(gs, f, r, possiblef, possibler, &numpossible); + break; case KNIGHT: possible_knight_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -1667,10 +1849,13 @@ int has_legal_move(struct game_state_t * gs) case ROOK: possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case WARLORD: + case HAWK: case CARDINAL: case PRINCESS: possible_cardinal_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case SELEPHANT: case MARSHALL: case EMPRESS: possible_marshall_moves(gs, f, r, possiblef, possibler, &numpossible); @@ -1688,6 +1873,7 @@ int has_legal_move(struct game_state_t * gs) case AMAZON: possible_amazon_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case CAPTAIN: case WOODY: possible_woody_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -1720,6 +1906,9 @@ int has_legal_move(struct game_state_t * gs) case MODERNELEPHANT: possible_modernelephant_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case LIEUTENANT: + possible_lieutenant_moves(gs, f, r, possiblef, possibler, &numpossible); + break; case PRIESTESS: possible_priestess_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -1741,6 +1930,7 @@ int has_legal_move(struct game_state_t * gs) case DRAGONHORSE: possible_dragonhorse_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case GENERAL: case DRAGONKING: possible_dragonking_moves(gs, f, r, possiblef, possibler, &numpossible); break; @@ -1793,7 +1983,7 @@ int has_legal_move(struct game_state_t * gs) 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; @@ -1868,6 +2058,11 @@ int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int pro 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; @@ -1880,9 +2075,13 @@ int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int pro if (mt->piecePromotionTo != NOPIECE) { promote = piecetype(mt->piecePromotionTo); - } else if(gs->promoType == 3 && promote == MASTODON) promote = GOLD; + } else if (promote != NOPIECE) { // [HGM] promotion on long algebraic move; correct ambiguous types for variant + if(gs->promoType == 3 && promote == MASTODON) promote = GOLD; + if(gs->drops == 2 && promote == EMPRESS) promote = SELEPHANT; + 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 */ @@ -1919,16 +2118,29 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st gs->board[fKing][backRank] = NOPIECE; 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 + 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]; tookPiece = gs->board[mt->toFile][mt->toRank]; - if (mt->piecePromotionTo == NOPIECE) { + if(gs->drops == 2 && mt->piecePromotionTo != NOPIECE && piecetype(movedPiece) != PAWN) { // [HGM] Seirawan-style gating gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank]; + gs->board[mt->fromFile][mt->fromRank] = mt->piecePromotionTo | gs->onMove;; + gs->holding[gs->onMove==WHITE ? 0 : 1][mt->piecePromotionTo-1]--; // remove gated piece from holdings } else { - gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove; - if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--; + if (mt->piecePromotionTo == NOPIECE) { + gs->board[mt->toFile][mt->toRank] = gs->board[mt->fromFile][mt->fromRank]; + } else { + gs->board[mt->toFile][mt->toRank] = mt->piecePromotionTo | gs->onMove; + if(gs->promoType == 2) gs->holding[gs->onMove][mt->piecePromotionTo-1]--; + } + gs->board[mt->fromFile][mt->fromRank] = NOPIECE; } - gs->board[mt->fromFile][mt->fromRank] = NOPIECE; /* Check if irreversable */ if ((piecetype(movedPiece) == PAWN) && (mt->fromRank != mt->toRank) // [HGM] XQ: sideway Pawn move reversible! || (tookPiece != NOPIECE)) { @@ -2077,7 +2289,7 @@ int backup_move(int g, int mode) { struct game_state_t *gs; struct move_t *m, *m1; - int now, i; + int now, i, piece; if (game_globals.garray[g].link >= 0) /*IanO: not implemented for bughouse yet */ return MOVE_ILLEGAL; @@ -2110,15 +2322,33 @@ int backup_move(int g, int mode) // 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; } - gs->board[m->fromFile][m->fromRank] = gs->board[m->toFile][m->toRank]; - if (m->piecePromotionTo != NOPIECE) { - gs->board[m->fromFile][m->fromRank] = PAWN | - colorval(gs->board[m->fromFile][m->fromRank]); + piece = gs->board[m->toFile][m->toRank]; + 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!) + } else + if (m->piecePromotionTo != NOPIECE) { // it is a real promotion + switch(piecetype(m->piecePromotionTo)) { // Spartan pieces came from Hoplite, Shogi is problematic + case KING: + case CAPTAIN: + case LIEUTENANT: + case WARLORD: + case GENERAL: piece = HOPLITE; break; + case DRAGONHORSE: piece = BISHOP; break; + case DRAGONKING: piece = ROOK; break; + case GOLD: // TODO: figure out what original was + default: piece = PAWN; + } + piece |= colorval(gs->board[m->toFile][m->toRank]); } + gs->board[m->fromFile][m->fromRank] = piece; /****************** When takeback a _first_ move of rook, the ??rmoved variable must be cleared . To check, if the move is first, we should