From: H.G. Muller Date: Sun, 10 Oct 2010 10:38:56 +0000 (+0200) Subject: Finish implementation of Shogi X-Git-Url: http://winboard.nl/cgi-bin?p=capablanca.git;a=commitdiff_plain;h=d047d3cf2718e831b4cb81aba3c4111c041fc22d;hp=f5c9190f7e3996a99564e4b54f60641d2b5aaad7 Finish implementation of Shogi Shogi promotions were implemented by introducing a new promoType value (3), which can be set y 'S' in the board status line. Demotion of pieces takes place on capture, by tracing them back with was_promoted() to their original, which now is not automatically Pawn, but derived from the piece mentioned in the move string. Like in Bughouse a promoted Queen is not distinguished from a primordial one on the board, Golds which are promoted Pawns / Lances / Knights / Silvers all look the same as a primordial Gold. The Dragon Horse and Draon King look different from Bishop and Rook, though, and are indicated by the letters I and J on the board. The promotion is indicated in the SAN move by suffix =G, =I or =J. Deferral is not indicated. On input == is understood as deferral, =+ or =^ (or in fact = as promotion). --- diff --git a/lasker-2.2.3/data/boards/shogi/0 b/lasker-2.2.3/data/boards/shogi/0 index f8312fb..68f0338 100644 --- a/lasker-2.2.3/data/boards/shogi/0 +++ b/lasker-2.2.3/data/boards/shogi/0 @@ -1,3 +1,3 @@ -S 9x9 dh +S 9x9 dhS W: P a3 b3 c3 d3 e3 f3 g3 h3 i3 n b1 h1 S c1 g1 G d1 f1 K e1 L a1 i1 R h2 B b2 B: P a7 b7 c7 d7 e7 f7 g7 h7 i7 n b9 h9 S c9 g9 G d9 f9 K e9 L a9 i9 R b8 B h8 diff --git a/lasker-2.2.3/src/algcheck.c b/lasker-2.2.3/src/algcheck.c index d043445..c7b6906 100644 --- a/lasker-2.2.3/src/algcheck.c +++ b/lasker-2.2.3/src/algcheck.c @@ -656,8 +656,8 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) } sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1 - (gs->ranks > 9)); strcat(mStr, tmp); - - if ((piece == PAWN) && (mt->piecePromotionTo != NOPIECE)) { + + if ((piece == PAWN || gs->promoType == 3) && (mt->piecePromotionTo != NOPIECE)) { strcat(mStr, "="); /* = before promoting piece */ switch (piecetype(mt->piecePromotionTo)) { case KNIGHT: @@ -702,6 +702,15 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) case MASTODON: strcat(mStr, "G"); break; + case GOLD: // [HGM] Shogi promotions: avoid use of '+' + strcat(mStr, "G"); + break; + case DRAGONHORSE: + strcat(mStr, "I"); + break; + case DRAGONKING: + strcat(mStr, "J"); + break; default: break; } diff --git a/lasker-2.2.3/src/board.c b/lasker-2.2.3/src/board.c index 5c974f1..315df34 100644 --- a/lasker-2.2.3/src/board.c +++ b/lasker-2.2.3/src/board.c @@ -1032,6 +1032,9 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs) gs->promoType = 2; // only promote to captured pieces gs->holdings = 1; // use holdings to hold own captured pieces break; + case 'S': + gs->promoType = 3; // Shogi-type promotions + break; case 'F': gs->castlingStyle = 2; // FRC castling break; diff --git a/lasker-2.2.3/src/gamedb_old.c b/lasker-2.2.3/src/gamedb_old.c index 15b947e..dd435b4 100644 --- a/lasker-2.2.3/src/gamedb_old.c +++ b/lasker-2.2.3/src/gamedb_old.c @@ -319,6 +319,10 @@ static void ReadOneV1Move(FILE * fp, struct move_t *m) m->algString[i++] = '1' + m->toRank; m->algString[i] = '\0'; } + if (m->piecePromotionTo != 0) { // must be Shogi promotion + strcat(m->algString, "=+"); + m->piecePromotionTo |= m->color; + } } if (m->algString[0] != 'O') sprintf(m->moveString, "%c/%c%d-%c%d", PieceChar, 'a' + m->fromFile, diff --git a/lasker-2.2.3/src/gameproc.c b/lasker-2.2.3/src/gameproc.c index a0dba3f..ec6918c 100644 --- a/lasker-2.2.3/src/gameproc.c +++ b/lasker-2.2.3/src/gameproc.c @@ -413,8 +413,17 @@ static int was_promoted(struct game *g, int f, int r) for (i = g->numHalfMoves-2; i > 0; i -= 2) { if (g->moveList[i].toFile == f && g->moveList[i].toRank == r) { - if (g->moveList[i].piecePromotionTo) - return 1; + if (g->moveList[i].piecePromotionTo) { + switch(g->moveList[i].moveString[0]) { // [HGM] return original piece type rather than just TRUE + case 'P': return PAWN; + case 'N': return KNIGHT; + case 'B': return BISHOP; + case 'R': return ROOK; + case 'L': return LANCE; + case 'S': return SILVER; + default: return GOLD; + } + } if (g->moveList[i].fromFile == ALG_DROP) return 0; f = g->moveList[i].fromFile; @@ -550,6 +559,7 @@ void process_move(int p, char *command) return; } } + pp->promote = NOPIECE; // [HGM] this seemed to be uninitialized, which caused spurious promotion in Shogi if ((len = strlen(command)) > 1) { if (command[len - 2] == '=') { printf("promo '%s'\n", command); @@ -598,6 +608,14 @@ printf("promo '%s'\n", command); case 'g': pp->promote = MASTODON; break; + // Shogi promotions + case '^': + case '+': + pp->promote = GOLD; + break; + case '=': + pp->promote = NOPIECE; + break; default: pprintf(p, "Don't understand that move.\n"); return; @@ -675,14 +693,14 @@ printf("promo '%s'\n", command); if (result == MOVE_OK && (gg->link >= 0 || gg->game_state.holdings) && move.pieceCaptured != NOPIECE) { /* transfer captured piece to partner */ /* check if piece reverts to a pawn */ - int victim = move.pieceCaptured, partner = gg->link; + int victim = move.pieceCaptured, partner = gg->link, demoted; // [HGM] zh: if not Bughouse, the game_state.holdings field decides what happens if(gg->link < 0) { partner = g; // pieces stay with current board if(gg->game_state.holdings == -1) victim ^= WHITE|BLACK; // flip color } - if (was_promoted(&game_globals.garray[g], move.toFile, move.toRank)) - update_holding(partner, colorval(victim) | PAWN); // [HGM] todo: for Shogi we would have to demote differently! + if (demoted = was_promoted(&game_globals.garray[g], move.toFile, move.toRank)) + update_holding(partner, colorval(victim) | demoted); // [HGM] was_promoted now returns original piece type else update_holding(partner, victim); } diff --git a/lasker-2.2.3/src/movecheck.c b/lasker-2.2.3/src/movecheck.c index 953298c..c0dd853 100644 --- a/lasker-2.2.3/src/movecheck.c +++ b/lasker-2.2.3/src/movecheck.c @@ -141,7 +141,7 @@ int InitPieceLoop(board_t b, int *f, int *r, int color) static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int tr ) { if (ff == tf) { - if (gs->board[tf][tr] != NOPIECE && !gs->palace) return 0; // [HGM] XQ pawns can capture straight ahead + if (gs->board[tf][tr] != NOPIECE && !gs->palace && gs->promoType != 3) return 0; // [HGM] XQ and Shogi pawns can capture straight ahead if (gs->onMove == WHITE) { if (tr - fr == 1) return 1; if ((fr <= gs->pawnDblStep) && (tr - fr == 2) && gs->board[ff][fr+1]==NOPIECE) return 1; @@ -151,7 +151,7 @@ static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int } return 0; } - if (ff != tf) { /* Capture ? */ + if (ff != tf && gs->promoType != 3) { /* Capture ? ([HGM] but not in Shogi) */ if ((ff - tf != 1) && (tf - ff != 1)) return 0; if (gs->onMove == WHITE) { if(gs->palace) return (fr >= gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns @@ -621,21 +621,23 @@ static void possible_pawn_moves(struct game_state_t * gs, int *posf, int *posr, int *numpos) { if (gs->onMove == WHITE) { - if (gs->board[onf][onr + 1] == NOPIECE || gs->palace) { + if (gs->board[onf][onr + 1] == NOPIECE || gs->palace || gs->promoType == 3) { add_pos(onf, onr + 1, posf, posr, numpos); if ((onr <= gs->pawnDblStep) && (gs->board[onf][onr + 2] == NOPIECE)) add_pos(onf, onr + 2, posf, posr, numpos); } if (onf > 0) { if (gs->board[onf - 1][onr + 1] != NOPIECE && - iscolor(gs->board[onf - 1][onr + 1], BLACK)) + iscolor(gs->board[onf - 1][onr + 1], BLACK) && + !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi add_pos(onf - 1, onr + 1, posf, posr, numpos); if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf-1][onr] || iscolor(gs->board[onf-1][onr], BLACK))) add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn } if (onf < gs->files-1) { if (gs->board[onf + 1][onr + 1] != NOPIECE && - iscolor(gs->board[onf + 1][onr + 1], BLACK)) + iscolor(gs->board[onf + 1][onr + 1], BLACK) && + !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi add_pos(onf + 1, onr + 1, posf, posr, numpos); if(gs->palace && onr >= gs->ranks/2 && (gs->board[onf+1][onr] || iscolor(gs->board[onf+1][onr], BLACK))) add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn @@ -645,21 +647,23 @@ static void possible_pawn_moves(struct game_state_t * gs, if (gs->ep_possible[0][onf] == 1) add_pos(onf + 1, onr + 1, posf, posr, numpos); } else { - if (gs->board[onf][onr - 1] == NOPIECE || gs->palace) { + if (gs->board[onf][onr - 1] == NOPIECE || gs->palace || gs->promoType == 3) { add_pos(onf, onr - 1, posf, posr, numpos); if ((onr >= gs->ranks - gs->pawnDblStep - 1) && (gs->board[onf][onr - 2] == NOPIECE)) add_pos(onf, onr - 2, posf, posr, numpos); } if (onf > 0) { if (gs->board[onf - 1][onr - 1] != NOPIECE && - iscolor(gs->board[onf - 1][onr - 1], WHITE)) + iscolor(gs->board[onf - 1][onr - 1], WHITE) && + !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi add_pos(onf - 1, onr - 1, posf, posr, numpos); if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf-1][onr], BLACK)) add_pos(onf - 1, onr, posf, posr, numpos); // XQ promoted pawn } if (onf < gs->files-1) { if (gs->board[onf + 1][onr - 1] != NOPIECE && - iscolor(gs->board[onf + 1][onr - 1], WHITE)) + iscolor(gs->board[onf + 1][onr - 1], WHITE) && + !gs->palace && gs->promoType != 3) // no diagonal capture in XQ and Shogi add_pos(onf + 1, onr - 1, posf, posr, numpos); if(gs->palace && onr < gs->ranks/2 && !iscolor(gs->board[onf+1][onr], BLACK)) add_pos(onf + 1, onr, posf, posr, numpos); // XQ promoted pawn @@ -1479,6 +1483,38 @@ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int prom // [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"); } else { + 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; + if(colorval(piece) == WHITE && mt->fromRank < gs->ranks - gs->ranks/3 + && mt->toRank < gs->ranks - gs->ranks/3 || + colorval(piece) == BLACK && mt->fromRank >= gs->ranks/3 + && mt->toRank >= gs->ranks/3 ) + promote = NOPIECE; // suppress promotion outside zone + if(promote) { // promotion piece determined by original, no matter what was requested + switch(piecetype(piece)) { + case PAWN: + case LANCE: + case KNIGHT: + case SILVER: + promote = GOLD; break; + case BISHOP: + promote = DRAGONHORSE; break; + case ROOK: + promote = DRAGONKING; break; + default: promote = NOPIECE; // not a promotion + } + } else + switch(piecetype(piece)) { // force mandatory promotions + case KNIGHT: + if(mt->toRank == 1 || mt->toRank == gs->files-2) promote = GOLD; + case PAWN: + case LANCE: + if(mt->toRank == 0 || mt->toRank == gs->files-1) promote = GOLD; + default: break; + } + if(promote) mt->piecePromotionTo = promote | (colorval(gs->board[mt->fromFile][mt->fromRank])); + } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && !gs->palace && // [HGM] XQ: no promotions in xiangqi ((mt->toRank == 0) || (mt->toRank == gs->ranks-1))) { @@ -1820,8 +1856,9 @@ int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int pro mt->fromFile = ALG_CASTLE; } - if (mt->piecePromotionTo != NOPIECE) { + if (mt->piecePromotionTo != NOPIECE) { promote = piecetype(mt->piecePromotionTo); +printf("promotion piece = %d, type = %d",mt->piecePromotionTo, promote); } return move_calculate(gs, mt, promote);