strcpy(EndSymbol, "Mat");
rate_change = 1;
break;
+ case END_BARE:
+ sprintf(tmp, "%s bared} %s", NameOfLoser, winSymbol);
+ strcpy(EndSymbol, "Bar");
+ rate_change = 1;
+ break;
+ case END_PERPETUAL:
+ sprintf(tmp, "%s perpetually checking} %s", NameOfLoser, winSymbol);
+ strcpy(EndSymbol, "Per");
+ rate_change = 1;
+ break;
case END_RESIGN:
sprintf(tmp, "%s resigns} %s", NameOfLoser, winSymbol);
strcpy(EndSymbol, "Res");
pprintf (p,"\n%s",avail_black);
avail_printed = 1;
}
- if (gl != -1) /* bughouse ? */ {
+ if (gl == -1) /* bughouse ? */ {
if (((player_globals.parray[game_globals.garray[gl].white].b_stats.rating <= pp->availmax) && (player_globals.parray[game_globals.garray[gl].white].b_stats.rating >= pp->availmin)) || (!pp->availmax)) {
pprintf (p,"\n%s",avail_bugwhite);
avail_printed = 1;
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 HONORABLEHORSE; // !!! this is Shogi, so no 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;
{
struct player *pp = &player_globals.parray[p];
struct game *gg;
- int g, result, len, i;
+ int g, result, len, i, f;
struct move_t move;
unsigned now = 0;
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] == '=') {
- switch (tolower(command[strlen(command) - 1])) {
+ if (command[len - 2] == '=' || gg->game_state.drops == 2 && command[len - 2] == '/') { // [HGM] encode gating as promotion
+printf("promo '%s'\n", command);
+ switch (tolower(command[len - 1])) {
case 'n':
pp->promote = KNIGHT;
break;
case 'r':
pp->promote = ROOK;
break;
+ case 'a':
+ pp->promote = CARDINAL;
+ break;
+ case 'c':
+ pp->promote = MARSHALL;
+ break;
+ case 'm':
+ pp->promote = MAN;
+ break;
case 'q':
pp->promote = QUEEN;
break;
+ // courier promotion
+ case 'f':
+ pp->promote = FERZ2;
+ break;
+ // Superchess promotions
+ case 'e':
+ pp->promote = EMPRESS;
+ break;
+ case 's':
+ pp->promote = PRINCESS;
+ break;
+ case 'v':
+ pp->promote = CENTAUR;
+ break;
+ case 'w':
+ pp->promote = WOODY;
+ break;
+ case 'o':
+ pp->promote = SQUIRREL;
+ break;
+ case 'g':
+ pp->promote = MASTODON;
+ break;
+ case 'l':
+ pp->promote = LIEUTENANT;
+ break;
+ case 'k':
+ pp->promote = KING;
+ break;
+ // Shogi promotions
+ case 'h':
+ pp->promote = DRAGONHORSE;
+ break;
+ case 'd':
+ pp->promote = DRAGONKING;
+ break;
+ case '^':
+ case '+':
+ pp->promote = GOLD;
+ break;
+ case '=':
+ pp->promote = NOPIECE;
+ break;
default:
pprintf(p, "Don't understand that move.\n");
return;
}
}
}
+
switch (parse_move(command, &gg->game_state, &move, pp->promote)) {
case MOVE_ILLEGAL:
pprintf(p, "Illegal move.\n");
gg->moveList = (struct move_t *) realloc(gg->moveList, sizeof(struct move_t) * gg->moveListSize);
}
result = execute_move(&gg->game_state, &move, 1);
- if (result == MOVE_OK && gg->link >= 0 && move.pieceCaptured != NOPIECE) {
+ 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 */
- if (was_promoted(&game_globals.garray[g], move.toFile, move.toRank))
- update_holding(gg->link, colorval(move.pieceCaptured) | PAWN);
+ 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 (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(gg->link, move.pieceCaptured);
+ update_holding(partner, victim);
}
now = tenth_secs();
move.atTime = now;
game_ended(g, CToggle(gg->game_state.onMove), END_NOMATERIAL);
}
}
+ if (result == MOVE_BARE) {
+ if (gg->status == GAME_EXAMINE) {
+ int p1;
+
+ for (p1 = 0; p1 < player_globals.p_num; p1++) {
+ if (player_globals.parray[p1].status != PLAYER_PROMPT)
+ continue;
+ if (player_is_observe(p1, g) || player_globals.parray[p1].game == g) {
+ pprintf(p1, "%s bared.\n",
+ (gg->game_state.onMove == BLACK) ? "White" : "Black");
+ }
+ }
+ } else {
+ game_ended(g, gg->game_state.onMove, END_BARE);
+ }
+ }
}
int com_resign(int p, param_list param)
return 0;
}
+static int perp_check(struct game g, int first, int third)
+{
+ struct game_state_t gs = g.game_state; // current position, both first and last of loop
+ int half_move, no_perp = 0;
+printf("perp %d %d\n",first,third);
+ for(half_move=first+1; half_move<third; half_move++) {
+ gs.onMove = CToggle(gs.onMove);
+ if(!in_check(&gs)) no_perp |= (half_move&1) + 1; // 1 = white not in check, 2 = black not in check
+ gs.onMove = CToggle(gs.onMove);
+printf("move%d, p=%d\n",half_move,no_perp);
+ if(no_perp == 3) break;
+ execute_move(&gs, &g.moveList[half_move], 0);
+ }
+ if(no_perp == (third&1) + 1) return END_NOTENDED; // stm was checking, other not: defer judgement
+ if(no_perp == 2 - (third&1)) return END_PERPETUAL; // stm was not checking, other was: stm wins
+ if(no_perp == 0) return END_REPETITION; // mutual perpertual check, draw
+ // here we should check for chasing
+ return END_REPETITION;
+}
+
static char *GetFENpos (int g, int half_move)
{
if (half_move < 0)
{
struct player *pp = &player_globals.parray[p];
struct pending* pend;
- int move_num;
+ int move_num, s1, s2, result = END_REPETITION;
int flag1 = 1, flag2 = 1;
- char *pos1 = GetFENpos (g, game_globals.garray[g].numHalfMoves - 1);
- char *pos2 = GetFENpos (g, game_globals.garray[g].numHalfMoves);
+ int numPly = game_globals.garray[g].numHalfMoves;
+ char *pos1 = GetFENpos (g, numPly - 1); // current position
+ char *pos2 = "";
char *pos;
+ int turn = numPly - 1;
- if (game_globals.garray[g].numHalfMoves < 8) /* can't have three repeats any quicker. */
+ if (numPly < 8) /* can't have three repeats any quicker. */
return 0;
- for (move_num = game_globals.garray[g].game_state.lastIrreversable;
- move_num < game_globals.garray[g].numHalfMoves - 1; move_num++) {
+ if((game_globals.garray[g].white == p) != (numPly&1)) { // claimer has the move
+ pos2 = pos1;
+ pos1 = GetFENpos (g, turn = numPly - 2); // also check position before opponent's move (which could have pre-empted him)
+ } // pos1 is now always a position where the opponent has the move
+
+ for (move_num = numPly - 3; // [HGM] FEN stored in moveList[numHalfMoves-1] !
+ move_num >= game_globals.garray[g].game_state.lastIrreversable - 1; move_num--) {
pos = GetFENpos (g, move_num);
- if (strlen(pos1) == strlen(pos) && !strcmp(pos1, pos))
- flag1++;
- if (strlen(pos2) == strlen(pos) && !strcmp(pos2, pos))
- flag2++;
+ if (!(turn - move_num & 1) && strlen(pos1) == strlen(pos) && !strcmp(pos1, pos))
+ flag1++ == 2 && (s1 = move_num);
+ if ( (turn - move_num & 1) && strlen(pos2) == strlen(pos) && !strcmp(pos2, pos))
+ flag2++ == 2 && (s2 = move_num); // remember start of last two loops
+printf("%2d. %d-%d '%s' '%s' '%s'\n", move_num, flag1, flag2, pos1,pos2,pos);
}
if (flag1 >= 3 || flag2 >= 3) {
if ((pend = find_pend(pp->opponent, p, PEND_DRAW)) != NULL) {
delete_pending(pend);
decline_withdraw_offers(p, -1, -1,DO_DECLINE);
}
- game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, END_REPETITION);
+ if(game_globals.garray[g].game_state.palace) { // [HGM] in Xiangqi we have to test for perpetuals to determine the outcome
+ if(flag2 >= 3) result = perp_check(game_globals.garray[g], s2, numPly);
+ else result = perp_check(game_globals.garray[g], s1, numPly - (pos2[0] != 0));
+ if(result == END_NOTENDED) {
+ pprintf(p, "Perpetuals can be claimed only during the turn of the winner\n");
+ return 1;
+ }
+ game_ended(g, (numPly&1) ? BLACK : WHITE, result); // stm wins
+ return 1;
+ }
+ game_ended(g, (game_globals.garray[g].white == p) ? BLACK : WHITE, result);
return 1;
}
else return 0;
int piece;
int minor_pieces = 0;
- for (i = 0; i < 8; i++)
- for (j = 0; j < 8; j++) {
+ for (i = 0; i < gs->files; i++)
+ for (j = 0; j < gs->ranks; j++) {
piece = gs->board[i][j];
switch (piecetype(piece)) {
case BISHOP: