From: H.G. Muller Date: Mon, 18 Jan 2010 12:20:48 +0000 (+0100) Subject: Check-in modifications made by HGM so far X-Git-Url: http://winboard.nl/cgi-bin?p=capablanca.git;a=commitdiff_plain;h=fc8a38817986f2ad7a034db0d413762e509a7cac Check-in modifications made by HGM so far This is the version of the variant ICS that first started running permanently on my ADSL connection. --- diff --git a/lasker-2.2.3/data/boards/wild/CVS/Entries b/lasker-2.2.3/data/boards/wild/CVS/Entries deleted file mode 100644 index 1784810..0000000 --- a/lasker-2.2.3/data/boards/wild/CVS/Entries +++ /dev/null @@ -1 +0,0 @@ -D diff --git a/lasker-2.2.3/data/boards/wild/CVS/Repository b/lasker-2.2.3/data/boards/wild/CVS/Repository deleted file mode 100644 index 5cc55ef..0000000 --- a/lasker-2.2.3/data/boards/wild/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -lasker/data/boards/wild diff --git a/lasker-2.2.3/data/boards/wild/CVS/Root b/lasker-2.2.3/data/boards/wild/CVS/Root deleted file mode 100644 index c42ba94..0000000 --- a/lasker-2.2.3/data/boards/wild/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -/home/cvs diff --git a/lasker-2.2.3/src/Makefile.in b/lasker-2.2.3/src/Makefile.in index 7e465f8..24cb2df 100644 --- a/lasker-2.2.3/src/Makefile.in +++ b/lasker-2.2.3/src/Makefile.in @@ -126,6 +126,21 @@ install: $(ALL) install -d -m0755 ${CHESSDDIR}/data/messages install -d -m0755 ${CHESSDDIR}/data/stats install -d -m0755 ${CHESSDDIR}/data/boards/wild + install -d -m0755 ${CHESSDDIR}/data/boards/capablanca + install -d -m0755 ${CHESSDDIR}/data/boards/knightmate + install -d -m0755 ${CHESSDDIR}/data/boards/gothic + install -d -m0755 ${CHESSDDIR}/data/boards/super + install -d -m0755 ${CHESSDDIR}/data/boards/crazyhouse + install -d -m0755 ${CHESSDDIR}/data/boards/fischerandom + install -d -m0755 ${CHESSDDIR}/data/boards/fr + install -d -m0755 ${CHESSDDIR}/data/boards/zh + install -d -m0755 ${CHESSDDIR}/data/boards/shatranj + install -d -m0755 ${CHESSDDIR}/data/boards/xiangqi + install -d -m0755 ${CHESSDDIR}/data/boards/shogi + install -d -m0755 ${CHESSDDIR}/data/boards/caparandom + install -d -m0755 ${CHESSDDIR}/data/boards/courier + install -d -m0755 ${CHESSDDIR}/data/boards/fairy + install -d -m0755 ${CHESSDDIR}/data/boards/great install -d -m0755 ${CHESSDDIR}/games/history install -d -m0755 ${CHESSDDIR}/games/journal install -d -m0755 ${CHESSDDIR}/games/adjourned @@ -135,6 +150,20 @@ install: $(ALL) cp -u ${srcdir}/../data/help/[a-z]* ${CHESSDDIR}/data/help cp -u ${srcdir}/../data/usage/[a-z]* ${CHESSDDIR}/data/usage cp -u ${srcdir}/../data/messages/[a-z]* ${CHESSDDIR}/data/messages + cp -u ${srcdir}/../data/boards/capablanca/* ${CHESSDDIR}/data/boards/capablanca + cp -u ${srcdir}/../data/boards/gothic/* ${CHESSDDIR}/data/boards/gothic + cp -u ${srcdir}/../data/boards/knightmate/* ${CHESSDDIR}/data/boards/knightmate + cp -u ${srcdir}/../data/boards/fischerandom/* ${CHESSDDIR}/data/boards/fischerandom + cp -u ${srcdir}/../data/boards/shatranj/* ${CHESSDDIR}/data/boards/shatranj + cp -u ${srcdir}/../data/boards/crazyhouse/* ${CHESSDDIR}/data/boards/crazyhouse + cp -u ${srcdir}/../data/boards/super/* ${CHESSDDIR}/data/boards/super + cp -u ${srcdir}/../data/boards/wild/* ${CHESSDDIR}/data/boards/wild + cp -u ${srcdir}/../data/boards/xiangqi/* ${CHESSDDIR}/data/boards/xiangqi + cp -u ${srcdir}/../data/boards/shogi/* ${CHESSDDIR}/data/boards/shogi + cp -u ${srcdir}/../data/boards/courier/* ${CHESSDDIR}/data/boards/courier + cp -u ${srcdir}/../data/boards/fairy/* ${CHESSDDIR}/data/boards/fairy + cp -u ${srcdir}/../data/boards/great/* ${CHESSDDIR}/data/boards/great + cp -u ${srcdir}/../data/boards/caparandom/* ${CHESSDDIR}/data/boards/caparandom perl -e 'mkdir("${CHESSDDIR}/players/$$_",0755) for ("a".."z")' perl -e 'mkdir("${CHESSDDIR}/games/history/$$_",0755) for ("0".."99")' perl -e 'mkdir("${CHESSDDIR}/games/journal/$$_",0755) for ("a".."z")' diff --git a/lasker-2.2.3/src/algcheck.c b/lasker-2.2.3/src/algcheck.c old mode 100644 new mode 100755 index 32bdba1..d043445 --- a/lasker-2.2.3/src/algcheck.c +++ b/lasker-2.2.3/src/algcheck.c @@ -96,7 +96,7 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf, for (j = len - 1; j >= 0; j--) { switch (alg_list[i][j]) { case 'f': - if ((tmp[j] < 'a') || (tmp[j] > 'h')) + if ((tmp[j] < 'a') || (tmp[j] > 'l')) // [HGM] upto l-file goto nomatch; if (ltf == ALG_UNKNOWN) ltf = tmp[j] - 'a'; @@ -104,12 +104,12 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf, lff = tmp[j] - 'a'; break; case 'r': - if ((tmp[j] < '1') || (tmp[j] > '8')) + if ((tmp[j] < '0') || (tmp[j] > '9')) // [HGM] also match 0- and 9-rank goto nomatch; - if (ltr == ALG_UNKNOWN) - ltr = tmp[j] - '1'; - else - lfr = tmp[j] - '1'; + if (ltr == ALG_UNKNOWN) + ltr = tmp[j] - '0'; // [HGM] allow 0-rank for Xiangqi, correct later + else + lfr = tmp[j] - '0'; break; case 'p': if (isupper(tmp[j])) @@ -118,8 +118,32 @@ static int get_move_info(const char *str, int *piece, int *ff, int *fr, int *tf, c = tmp[j]; if (c == 'k') lpiece = KING; + else if (c == 'e') // [HGM] note that som piece indicators are ambiguous, + lpiece = ELEPHANT; // and their true meaning depends on the variant, + else if (c == 'v') // which we do not know at this point. + lpiece = CENTAUR; + else if (c == 's') + lpiece = SILVER; + else if (c == 'g') + lpiece = GOLD; + else if (c == 'l') + lpiece = LANCE; + else if (c == 'f') + lpiece = FERZ; + else if (c == 'h') + lpiece = HORSE; + else if (c == 'w') + lpiece = WAZIR; + else if (c == 'o') + lpiece = SQUIRREL; else if (c == 'q') lpiece = QUEEN; + else if (c == 'c') + lpiece = MARSHALL; + else if (c == 'a') + lpiece = CARDINAL; + else if (c == 'm') + lpiece = MAN; else if (c == 'r') lpiece = ROOK; else if (c == 'b') @@ -190,7 +214,7 @@ int alg_is_move(const char *mstr) static void add_promotion(struct game_state_t *gs, const char *mstr, struct move_t * mt) { char *s; - int piece; + int piece, i; s = strchr(mstr, '='); if (s == NULL) { return; @@ -199,14 +223,29 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move if (piecetype(gs->board[mt->fromFile][mt->fromRank]) != PAWN) { return; } - if (mt->toRank != 7 && mt->toRank != 0) { + if (mt->toRank != gs->ranks-1 && mt->toRank != 0) { return; } switch (tolower(s[1])) { + case 'f': + piece = FERZ2; + break; case 'q': piece = QUEEN; break; + case 'c': + if(!gs->capablancaPieces) return; // [HGM] should make variant-dependent piece mask + piece = MARSHALL; + break; + case 'a': + if(!gs->capablancaPieces) return; + piece = CARDINAL; + break; + case 'm': + if(!gs->royalKnight) return; // [HGM] only in knightmate + piece = MAN; + break; case 'r': piece = ROOK; break; @@ -214,12 +253,35 @@ static void add_promotion(struct game_state_t *gs, const char *mstr, struct move piece = BISHOP; break; case 'n': + if(gs->royalKnight) return; // [HGM] not in knightmate piece = KNIGHT; break; + // Superchess promotons: filtered out later by promoType + case 'g': + piece = MASTODON; + break; + case 'o': + piece = SQUIRREL; + break; + case 'w': + piece = WOODY; + break; + case 'v': + piece = CENTAUR; + break; + case 'e': + piece = EMPRESS; + break; + case 's': + piece = PRINCESS; + break; default: return; } + i = colorval(gs->board[mt->fromFile][mt->fromRank]) == WHITE ? 0 : 1; + if(piece >= WOODY && (gs->promoType != 2 || gs->holding[i][piece-1] == 0)) return; + mt->piecePromotionTo = piece | colorval(gs->board[mt->fromFile][mt->fromRank]); } @@ -233,6 +295,56 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt) d_printf( "CHESSD: Shouldn't try to algebraicly parse non-algabraic move string.\n"); return MOVE_ILLEGAL; } + + // [HGM] check if move does not stray off board + if(gs->ranks < 10) { + if(tr == 0 || fr == 0) return MOVE_ILLEGAL; // used nonexistent 0-rank + if(tr != ALG_UNKNOWN) tr--; if(fr != ALG_UNKNOWN) fr--; // shift to lowest rank = 1 + } + if(tr >= gs->ranks || fr >= gs->ranks || tf >= gs->files || ff >= gs->files) + return MOVE_ILLEGAL; + + // [HGM] resolve ambiguity in piece, type based on variant + switch(piece) { + case ELEPHANT: + if(strstr(gs->variant, "super")) piece = EMPRESS; else + if(strstr(gs->variant, "great")) piece = MODERNELEPHANT; else + if(strstr(gs->variant, "courier")) piece = ALFIL2; + break; + case CARDINAL: + if(strstr(gs->variant, "super")) piece = AMAZON; else + if(strstr(gs->variant, "xiangqi")) piece = MANDARIN; + break; + case MARSHALL: + if(strstr(gs->variant, "xiangqi")) piece = CANNON; + break; + case SILVER: + if(strstr(gs->variant, "super")) piece = PRINCESS; + if(strstr(gs->variant, "great")) piece = MAN2; + break; + case BISHOP: + if(strstr(gs->variant, "shatranj")) piece = ALFIL; + break; + case QUEEN: + if(strstr(gs->variant, "shatranj")) piece = FERZ; + break; + case WAZIR: + if(strstr(gs->variant, "super")) piece = WOODY; + break; + case KNIGHT: + if(strstr(gs->variant, "shogi")) piece = HONORABLEHORSE; + break; + case MAN: + if(strstr(gs->variant, "great")) piece = MINISTER; + break; + case HORSE: + if(strstr(gs->variant, "great")) piece = PRIESTESS; + break; + case GOLD: + if(strstr(gs->variant, "great")) piece = MASTODON; + break; + } + /* Resolve ambiguities in to-ness */ if (tf == ALG_UNKNOWN) { d_printf("Ambiguous %s(%d)\n", __FUNCTION__, __LINE__); @@ -250,7 +362,7 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt) } /* Need to find pawn on ff that can take to tf and fill in ranks */ for (InitPieceLoop(gs->board, &f, &r, gs->onMove); - NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) { if ((ff != ALG_UNKNOWN) && (ff != f)) continue; if (piecetype(gs->board[f][r]) != piece) @@ -286,25 +398,27 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt) ff = ALG_UNKNOWN; fr = ALG_UNKNOWN; for (InitPieceLoop(gs->board, &f, &r, gs->onMove); - NextPieceLoop(gs->board, &f, &r, gs->onMove);) { - if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != BISHOP)) { + NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) { + if ((piecetype(gs->board[f][r]) != PAWN) && (piecetype(gs->board[f][r]) != piece)) { + // note that the interpretation Bxc4 is matched last, and has set piece to BISHOP continue; } + if (legal_andcheck_move(gs, f, r, tf, tr)) { - if ((piecetype(gs->board[f][r]) == PAWN) && (f != 1)) { + if ((piecetype(gs->board[f][r]) == PAWN) && (f != tolower(mstr[0]) - 'a')) { continue; } /* if its a lowercase 'b' then prefer the pawn move if there is one */ if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) && - piecetype(gs->board[f][r]) == PAWN && mstr[0] == 'b') { + piecetype(gs->board[f][r]) == PAWN && mstr[0] >= 'a') { ff = f; fr = r; continue; } if ((ff != ALG_UNKNOWN) && (fr != ALG_UNKNOWN) && - piecetype(gs->board[ff][fr]) == PAWN && mstr[0] == 'b') { + piecetype(gs->board[ff][fr]) == PAWN && mstr[0] >= 'a') { continue; } @@ -322,7 +436,7 @@ int alg_parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt) if ((ff == ALG_UNKNOWN) || (fr == ALG_UNKNOWN)) { /* Need to find a piece that can go to tf, tr */ for (InitPieceLoop(gs->board, &f, &r, gs->onMove); - NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) { if ((ff != ALG_UNKNOWN) && (ff != f)) continue; if ((fr != ALG_UNKNOWN) && (fr != r)) @@ -381,20 +495,21 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) piece = piecetype(gs->board[mt->fromFile][mt->fromRank]); } - if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 6))) { - strcpy(mStr, "O-O"); - goto check; - } - if ((piece == KING) && ((mt->fromFile == 4) && (mt->toFile == 2))) { - strcpy(mStr, "O-O-O"); - goto check; - } + if ((mt->fromFile == ALG_CASTLE) && (mt->toFile > mt->toRank)) { // [HGM] castle: K ends right of R + strcpy(mStr, "O-O"); + goto check; + } + if ((mt->fromFile == ALG_CASTLE) && (mt->toFile < mt->toRank)) { // [HGM] castle: K ends left of R + strcpy(mStr, "O-O-O"); + goto check; + } strcpy(mStr, ""); switch (piece) { case PAWN: if (mt->fromFile == ALG_DROP) { strcpy(mStr,"P"); - } else if (mt->fromFile != mt->toFile) { + } else if (mt->fromFile != mt->toFile + || gs->board[mt->toFile][mt->toRank] != NOPIECE) { // [HGM] XQ: forward captures as "axa6" sprintf(tmp, "%c", mt->fromFile + 'a'); strcpy(mStr, tmp); } @@ -408,9 +523,68 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) case ROOK: strcpy(mStr, "R"); break; + case ALFIL2: + case AMAZON: + case CARDINAL: + strcpy(mStr, "A"); + break; + case CANNON: + case MARSHALL: + strcpy(mStr, "C"); + break; + case MAN: + strcpy(mStr, "M"); + break; + case FERZ: case QUEEN: strcpy(mStr, "Q"); break; + case EMPRESS: + case ELEPHANT: + strcpy(mStr, "E"); + break; + case ALFIL: + strcpy(mStr, "B"); + break; + case FERZ2: + strcpy(mStr, "F"); + break; + case WOODY: + case WAZIR: + strcpy(mStr, "W"); + break; + case SQUIRREL: + strcpy(mStr, "O"); + break; + case CENTAUR: + strcpy(mStr, "V"); + break; + case HORSE: + strcpy(mStr, "H"); + break; + case HONORABLEHORSE: + strcpy(mStr, "N"); + break; + case DRAGONKING: + strcpy(mStr, "J"); + break; + case DRAGONHORSE: + strcpy(mStr, "I"); + break; + case LANCE: + strcpy(mStr, "L"); + break; + case PRINCESS: + case SILVER: + strcpy(mStr, "S"); + break; + case MASTODON: + case GOLD: + strcpy(mStr, "G"); + break; + case MANDARIN: + strcpy(mStr, "A"); + break; case KING: strcpy(mStr, "K"); break; @@ -425,8 +599,8 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) /* Checks for ambiguity in short notation ( Ncb3, R8e8 or so) */ if (piece != PAWN) { ambig = r_ambig = f_ambig = 0; - for (r = 0; r < 8; r++) - for (f = 0; f < 8; f++) { + for (r = 0; r < gs->ranks; r++) + for (f = 0; f < gs->files; f++) { if ((gs->board[f][r] != NOPIECE) && iscolor(gs->board[f][r], gs->onMove) && (piecetype(gs->board[f][r]) == piece) && ((f != mt->fromFile) || (r != mt->fromRank))) { @@ -460,48 +634,78 @@ char *alg_unparse(struct game_state_t * gs, struct move_t * mt) } } } - if (ambig > 0) { - /* Ambiguity in short notation, need to add file,rank or _both_ in - notation */ - if (f_ambig == 0) { - sprintf(tmp, "%c", mt->fromFile + 'a'); - strcat(mStr, tmp); - } else if (r_ambig == 0) { - sprintf(tmp, "%d", mt->fromRank + 1); - strcat(mStr, tmp); - } else { - sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1); - strcat(mStr, tmp); - } - } - } - if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) || - ((piece == PAWN) && (mt->fromFile != mt->toFile))) { - strcat(mStr, "x"); - } - } - sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1); - strcat(mStr, tmp); - - if ((piece == PAWN) && (mt->piecePromotionTo != NOPIECE)) { - strcat(mStr, "="); /* = before promoting piece */ - switch (piecetype(mt->piecePromotionTo)) { - case KNIGHT: - strcat(mStr, "N"); - break; - case BISHOP: - strcat(mStr, "B"); - break; - case ROOK: - strcat(mStr, "R"); - break; - case QUEEN: - strcat(mStr, "Q"); - break; - default: - break; - } - } + if (ambig > 0) { + /* Ambiguity in short notation, need to add file,rank or _both_ in + notation */ + if (f_ambig == 0) { + sprintf(tmp, "%c", mt->fromFile + 'a'); + strcat(mStr, tmp); + } else if (r_ambig == 0) { + sprintf(tmp, "%d", mt->fromRank + 1 - (gs->ranks > 9)); + strcat(mStr, tmp); + } else { + sprintf(tmp, "%c%d", mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks > 9)); + strcat(mStr, tmp); + } + } + } + if ((gs->board[mt->toFile][mt->toRank] != NOPIECE) || + ((piece == PAWN) && (mt->fromFile != mt->toFile))) { + strcat(mStr, "x"); + } + } + sprintf(tmp, "%c%d", mt->toFile + 'a', mt->toRank + 1 - (gs->ranks > 9)); + strcat(mStr, tmp); + + if ((piece == PAWN) && (mt->piecePromotionTo != NOPIECE)) { + strcat(mStr, "="); /* = before promoting piece */ + switch (piecetype(mt->piecePromotionTo)) { + case KNIGHT: + strcat(mStr, "N"); + break; + case BISHOP: + strcat(mStr, "B"); + break; + case ROOK: + strcat(mStr, "R"); + break; + case CARDINAL: + strcat(mStr, "A"); + break; + case MARSHALL: + strcat(mStr, "C"); + break; + case MAN: + strcat(mStr, "M"); + break; + case QUEEN: + strcat(mStr, "Q"); + break; + case FERZ2: + strcat(mStr, "F"); + break; + case WOODY: + strcat(mStr, "W"); + break; + case EMPRESS: + strcat(mStr, "E"); + break; + case CENTAUR: + strcat(mStr, "V"); + break; + case PRINCESS: + strcat(mStr, "S"); + break; + case SQUIRREL: + strcat(mStr, "O"); + break; + case MASTODON: + strcat(mStr, "G"); + break; + default: + break; + } + } check:; fakeMove = *gs; execute_move(&fakeMove, mt, 0); diff --git a/lasker-2.2.3/src/board.c b/lasker-2.2.3/src/board.c index 8fdbb0e..5c974f1 100644 --- a/lasker-2.2.3/src/board.c +++ b/lasker-2.2.3/src/board.c @@ -23,18 +23,20 @@ #include "includes.h" -const char *wpstring[] = {" ", "P", "N", "B", "R", "Q", "K"}; -static const char *bpstring[] = {" ", "p", "n", "b", "r", "q", "k"}; +const char *wpstring[] = {" ", "P", "N", "B", "R", "A", "C", "M", "Q", "E", "B", "Q", "W", "H", "N", "J", "I", "L", + "C", "S", "G", "H", "A", "F", "E", "H", "M", "S", "E", "W", "O", "G", "V", "S", "E", "A", "K"}; +const char *bpstring[] = {" ", "p", "n", "b", "r", "a", "c", "m", "q", "e", "b", "q", "w", "h", "n", "j", "i", "l", + "c", "s", "g", "h", "a", "f", "e", "h", "m", "s", "e", "w", "o", "g", "v", "s", "e", "a", "k"}; -static int pieceValues[7] = {0, 1, 3, 3, 5, 9, 0}; +int pieceValues[KING+1] = {0, 1, 3, 3, 5, 8, 9, 3, 9, 1, 1, 2, 2, 2, 1, 6, 5, 2, 3, 3, 3, 1, 5, 2, 1, 7, 7, 3, 3, 3, 7, 7, 7, 8, 9, 12, 0}; static const int mach_type = (1<<7) | (1<<8) | (1<<9) | (1<<10) | (1<<11); #define IsMachineStyle(n) (((1<<(n)) & mach_type) != 0) -static char bstring[MAX_BOARD_STRING_LEGTH]; +static char bstring[MAX_BOARD_STRING_LENGTH]; static int board_read_file(char *category, char *gname, struct game_state_t *gs); -static void wild_update(int style); +static void wild_update(board_t b, int style); static int style1(struct game_state_t *b, struct move_t *ml); static int style2(struct game_state_t *b, struct move_t *ml); @@ -71,14 +73,16 @@ static void reset_board_vars(struct game_state_t *gs) { int f,r; + if(gs->files <= 0) gs->files = 8; // [HGM] for pristine board, set default size + if(gs->ranks <= 0) gs->ranks = 8; for (f = 0; f < 2; f++) { - for (r = 0; r < 8; r++) + for (r = 0; r < BW; r++) gs->ep_possible[f][r] = 0; - for (r = PAWN; r <= QUEEN; r++) + for (r = PAWN; r <= KING-1; r++) gs->holding[f][r-PAWN] = 0; } - gs->wkmoved = gs->wqrmoved = gs->wkrmoved = 0; - gs->bkmoved = gs->bqrmoved = gs->bkrmoved = 0; + gs->wkmoved = gs->wqrmoved = gs->wkrmoved = -1; // [HGM] castle: no rights + gs->bkmoved = gs->bqrmoved = gs->bkrmoved = -1; gs->onMove = WHITE; gs->moveNum = 1; gs->lastIrreversable = -1; @@ -89,8 +93,8 @@ void board_clear(struct game_state_t *gs) { int f,r; - for (f = 0; f < 8; f++) - for (r = 0; r < 8; r++) + for (f = 0; f < BW; f++) + for (r = 0; r < BH; r++) gs->board[f][r] = NOPIECE; reset_board_vars(gs); } @@ -99,48 +103,141 @@ void board_standard(struct game_state_t *gs) { int f,r; - for (f = 0; f < 8; f++) - for (r = 2; r < 6; r++) - gs->board[f][r] = NOPIECE; - for (f = 0; f < 8; f++) - gs->board[f][1] = W_PAWN; - for (f = 0; f < 8; f++) - gs->board[f][6] = B_PAWN; - gs->board[0][0] = W_ROOK; - gs->board[1][0] = W_KNIGHT; - gs->board[2][0] = W_BISHOP; - gs->board[3][0] = W_QUEEN; - gs->board[4][0] = W_KING; - gs->board[5][0] = W_BISHOP; - gs->board[6][0] = W_KNIGHT; - gs->board[7][0] = W_ROOK; - gs->board[0][7] = B_ROOK; - gs->board[1][7] = B_KNIGHT; - gs->board[2][7] = B_BISHOP; - gs->board[3][7] = B_QUEEN; - gs->board[4][7] = B_KING; - gs->board[5][7] = B_BISHOP; - gs->board[6][7] = B_KNIGHT; - gs->board[7][7] = B_ROOK; + for (f = 0; f < BW; f++) + for (r = 0; r < BH; r++) + gs->board[f][r] = NOPIECE; + for (f = 0; f < gs->files; f++) + gs->board[f][gs->ranks-7] = W_PAWN; + for (f = 0; f < gs->files; f++) + gs->board[f][6] = B_PAWN; + gs->board[0][0] = W_ROOK; + gs->board[1][0] = W_KNIGHT; + gs->board[2][0] = W_BISHOP; + gs->board[3][0] = W_QUEEN; + gs->board[gs->files/2][0] = W_KING; + gs->board[gs->files-3][0] = W_BISHOP; + gs->board[gs->files-2][0] = W_KNIGHT; + gs->board[gs->files-1][0] = W_ROOK; + gs->board[0][gs->ranks-1] = B_ROOK; + gs->board[1][gs->ranks-1] = B_KNIGHT; + gs->board[2][gs->ranks-1] = B_BISHOP; + gs->board[3][gs->ranks-1] = B_QUEEN; + gs->board[gs->files/2][gs->ranks-1] = B_KING; + gs->board[gs->files-3][gs->ranks-1] = B_BISHOP; + gs->board[gs->files-2][gs->ranks-1] = B_KNIGHT; + gs->board[gs->files-1][gs->ranks-1] = B_ROOK; +#if 1 + if(gs->files == 10) { + gs->board[6][0] = W_CARDINAL; + gs->board[4][0] = W_MARSHALL; + gs->board[6][gs->ranks-1] = B_CARDINAL; + gs->board[4][gs->ranks-1] = B_MARSHALL; + } + if(gs->royalKnight) { + gs->board[1][0] = W_MAN; + gs->board[gs->files-2][0] = W_MAN; + gs->board[1][gs->ranks-1] = B_MAN; + gs->board[gs->files-2][gs->ranks-1] = B_MAN; + } +#endif + reset_board_vars(gs); + // [HGM] castle: standard setup has rights for corner Rooks and central King + gs->wkmoved = gs->files/2; + gs->bkmoved = gs->files/2; + gs->wkrmoved = gs->files-1; + gs->bkrmoved = gs->files-1; + gs->wqrmoved = 0; + gs->bqrmoved = 0; } int board_init(int g,struct game_state_t *b, char *category, char *board) { int retval = 0; - int wval; - - if (!category || !board || !category[0] || !board[0]) - /* accounts for bughouse too */ - board_standard(b); + int wval, i, j; + + b->files = b->ranks = 8; + b->pawnDblStep = (!category || strcmp(category, "shatranj")); + b->royalKnight = (category && !strcmp(category, "knightmate")); + b->capablancaPieces = 0; + b->holdings = 0; + b->drops = 0; + b->castlingStyle = 1; + b->palace = 0; + b->setup = 0; + b->bareKingLoses = 0; + b->stalemate = 1; + b->promoType = 1; + b->variant[0] = 0; // [HGM] variant: default is normal, if variant name is missing + if (!category || !board || !category[0] || !board[0]) + /* accounts for bughouse too */ + board_standard(b); else { - if (!strcmp(category, "wild")) { - if (sscanf(board, "%d", &wval) == 1 && wval >= 1 && wval <= 4) - wild_update(wval); + if(category && category[0]) strcpy(b->variant, category); // [HGM] variant: remember category name + if (!strcmp(category, "wild") && sscanf(board, "%d", &wval) == 1) { + if(wval >= 1 && wval <= 4) + wild_update(b->board, wval); + sprintf(b->variant, "wild/%d", wval); + } + + if (board && !strcmp(board, "0")) + b->setup = 0; // [HGM] variant: any board in the default file "0" is supposed to be implied by the variant + + if (!strcmp(category, "knightmate")) { + board_standard(b); + } else if (!strcmp(category, "super")) { + board_standard(b); + b->holdings = 1; + b->promoType = 2; + for(i=CENTAUR; i<=AMAZON; i++) { + int placed = 0; + do { int p, newp; + j = random() % 8; + if((p = piecetype(b->board[j][0])) >= CENTAUR) continue; // includes King + b->holding[1][p-PAWN] = ++b->holding[0][p-PAWN]; // piece to holding + if(board && !strcmp(board, "1")) newp = i - CENTAUR + WOODY; else newp = i; + if(board && !strcmp(board, "2")) newp = WOODY + random()%7; + b->board[j][0] = newp | WHITE; // place replacements + b->board[j][7] = newp | BLACK; + placed = 1; + } while(!placed); } - retval = board_read_file(category, board, b); + b->setup = 1; + } else if (!strcmp(category, "fischerandom")) { + wild_update(b->board, 22); + b->castlingStyle = 2; + b->setup = 1; // [HGM] FRC: even the default is a setup position, for which an initial board has to be printed + } else if (!strcmp(category, "caparandom")) { + b->files = 10; + wild_update(b->board, 46); + b->castlingStyle = 2; + b->setup = 1; + } else retval = board_read_file(category, board, b); + } + if(b->setup && game_globals.garray[g].FENstartPos[0]) // [HGM] use pre-existing start position, if one available + FEN_to_board(game_globals.garray[g].FENstartPos, b); // (could be wild board, or shuffle variant) + if(b->castlingStyle == 1) { + b->wkmoved = b->files/2; + b->bkmoved = b->files/2; + b->wkrmoved = b->files-1; + b->bkrmoved = b->files-1; + b->wqrmoved = 0; + b->bqrmoved = 0; + } else if(b->castlingStyle == 2) { + for(i=j=0; i < b->files; i++) { + int p = b->board[i][0]; + if(p == W_ROOK || p == W_KING) { + switch(j++) { + case 0: b->wqrmoved = b->bqrmoved = i; break; + case 1: b->wkmoved = b->bkmoved = i; break; + case 2: b->wkrmoved = b->bkrmoved = i; break; + } + } + } } + MakeFENpos(g, game_globals.garray[g].FENstartPos); + return retval; } @@ -150,8 +247,8 @@ void board_calc_strength(struct game_state_t *b, int *ws, int *bs) int *p; *ws = *bs = 0; - for (f = 0; f < 8; f++) { - for (r = 0; r < 8; r++) { + for (f = 0; f < b->ranks; f++) { + for (r = 0; r < b->files; r++) { if (colorval(b->board[r][f]) == WHITE) p = ws; else @@ -159,7 +256,7 @@ void board_calc_strength(struct game_state_t *b, int *ws, int *bs) *p += pieceValues[piecetype(b->board[r][f])]; } } - for (r = PAWN; r <= QUEEN; r++) { + for (r = PAWN; r < KING; r++) { *ws += b->holding[0][r-1] * pieceValues[r]; *bs += b->holding[1][r-1] * pieceValues[r]; } @@ -167,11 +264,11 @@ void board_calc_strength(struct game_state_t *b, int *ws, int *bs) static char *holding_str(int *holding) { - static char tmp[30]; + static char tmp[80]; int p,i,j; i = 0; - for (p = PAWN; p <= QUEEN; p++) { + for (p = PAWN; p < KING; p++) { for (j = 0; j < holding[p-1]; j++) { tmp[i++] = wpstring[p][0]; } @@ -183,7 +280,7 @@ static char *holding_str(int *holding) static char *append_holding_machine(char *buf, int g, int c, int p) { struct game_state_t *gs = &game_globals.garray[g].game_state; - char tmp[50]; + char tmp[160]; sprintf(tmp, " game %d white [%s] black [", g+1, holding_str(gs->holding[0])); strcat(tmp, holding_str(gs->holding[1])); @@ -213,7 +310,7 @@ void update_holding(int g, int pieceCaptured) int c = colorval(pieceCaptured); struct game_state_t *gs = &game_globals.garray[g].game_state; int pp, pl; - char tmp1[80], tmp2[80]; + char tmp1[160], tmp2[160]; if (c == WHITE) { c = 0; @@ -251,7 +348,8 @@ char *board_to_string(char *wn, char *bn, int orientation, int relation, int p) { - int bh = (b->gameNum >= 0 && game_globals.garray[b->gameNum].link >= 0); + int bh = (b->gameNum >= 0 && game_globals.garray[b->gameNum].link >= 0 + || b->holdings ); // [HGM] zh: make sure holdings are printed orient = orientation; myTurn = relation; @@ -262,6 +360,7 @@ char *board_to_string(char *wn, char *bn, move happened, not current time */ if (game_globals.garray[b->gameNum].status == GAME_EXAMINE) { unsigned nhm = game_globals.garray[b->gameNum].numHalfMoves; + if (nhm > 0) { wTime = ml[nhm - 1].wTime; bTime = ml[nhm - 1].bTime; @@ -288,8 +387,10 @@ char *board_to_string(char *wn, char *bn, bstring[0] = '\0'; if (bh && !IsMachineStyle(style)) append_holding_display(bstring, b, orientation==BLACK); + if (styleFuncs[style] (b, ml)) return NULL; + if (bh) { if (IsMachineStyle(style)) append_holding_machine(bstring, b->gameNum, 0, 0); @@ -302,490 +403,582 @@ char *board_to_string(char *wn, char *bn, char *move_and_time(struct move_t *m) { static char tmp[20]; +#if 0 + if(m->depth>0) + sprintf(tmp, "%-7s (%s%.2f/%d)", m->algString, /* tenth_str(m->tookTime, 0), */ + m->score>0 ? "+" : "", m->score, m->depth); + else +#endif sprintf(tmp, "%-7s (%s)", m->algString, tenth_str(m->tookTime, 0)); return tmp; } /* The following take the game state and whole move list */ +void Enlarge(char *a, int ss, int w) +{ + int l, i; + char *p, *q; + if(strlen(a) < ss) return; + for(i=8; iranks-1; + firstF = b->files-1; + lastR = lastF = 0; + inc = -1; + } else { + firstR = firstF = 0; + lastR = b->ranks-1; + lastF = b->files-1; + inc = 1; } - strcat(bstring, top); - for (f = first, count = 7; f != last + inc; f += inc, count--) { - sprintf(tmp, " %d %s", f + 1, start); - strcat(bstring, tmp); - for (r = last; r != first - inc; r = r - inc) { - if (square_color(r, f) == WHITE) - strcat(bstring, wsqr); - else - strcat(bstring, bsqr); - if (piecetype(b->board[r][f]) == NOPIECE) { - if (square_color(r, f) == WHITE) - strcat(bstring, bp[0]); - else - strcat(bstring, wp[0]); + strcpy(myTop, top); + strcpy(myMid, mid); + Enlarge(myTop, sqrSize, b->files); + Enlarge(myMid, sqrSize, b->files); + strcat(bstring, myTop); + for (f = firstR, count = b->ranks-1; f != lastR + inc; f += inc, count--) { + sprintf(tmp, " %d %s", f + (b->ranks < 10), start); + strcat(bstring, tmp); + for (r = lastF; r != firstF - inc; r = r - inc) { + if (square_color(r, f) == WHITE) + strcat(bstring, wsqr); + else + strcat(bstring, bsqr); + if (piecetype(b->board[r][f]) == NOPIECE) { + if (square_color(r, f) == WHITE) + strcat(bstring, bp[0]); + else + strcat(bstring, wp[0]); } else { - if (colorval(b->board[r][f]) == WHITE) - strcat(bstring, wp[piecetype(b->board[r][f])]); - else - strcat(bstring, bp[piecetype(b->board[r][f])]); - } - } - sprintf(tmp, "%s", end); - strcat(bstring, tmp); - switch (count) { - case 7: - sprintf(tmp, " Move # : %d (%s)", b->moveNum, CString(b->onMove)); - strcat(bstring, tmp); - break; - case 6: -/* if ((b->moveNum > 1) || (b->onMove == BLACK)) { */ -/* The change from the above line to the one below is a kludge by hersco. */ - if (game_globals.garray[b->gameNum].numHalfMoves > 0) { -/* loon: think this fixes the crashing ascii board on takeback bug */ - sprintf(tmp, " %s Moves : '%s'", CString(CToggle(b->onMove)), - move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1])); - strcat(bstring, tmp); - } - break; - case 5: - break; - case 4: - sprintf(tmp, " Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1)); - strcat(bstring, tmp); - break; - case 3: - sprintf(tmp, " White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1)); - strcat(bstring, tmp); - break; - case 2: - sprintf(tmp, " Black Strength : %d", bs); - strcat(bstring, tmp); - break; - case 1: - sprintf(tmp, " White Strength : %d", ws); - strcat(bstring, tmp); - break; - case 0: - break; - } - strcat(bstring, "\n"); - if (count != 0) - strcat(bstring, mid); - else - strcat(bstring, top); - } - if (orient == WHITE) - strcat(bstring, label); - else - strcat(bstring, blabel); - return 0; -} - -/* Experimental ANSI board for colour representation */ -static int style13(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {" ", "\033[37m\033[1m P ", "\033[37m\033[1m N ", "\033[37m\033[1m B ", "\033[37m\033[1m R ", "\033[37m\033[1m Q ", "\033[37m\033[1m K "}; - static const char *bp[] = {" ", "\033[21m\033[37m P ", "\033[21m\033[37m N ", "\033[21m\033[37m B ", "\033[21m\033[37m R ", "\033[21m\033[37m Q ", "\033[21m\033[37m K "}; - static const char *wsqr = "\033[40m"; - static const char *bsqr = "\033[45m"; - static const char *top = "\t+------------------------+\n"; - static const char *mid = ""; - static const char *start = "|"; - static const char *end = "\033[0m|"; - static const char *label = "\t a b c d e f g h\n"; - static const char *blabel = "\t h g f e d c b a\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* Standard ICS */ -static int style1(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {" |", " P |", " N |", " B |", " R |", " Q |", " K |"}; - static const char *bp[] = {" |", " *P|", " *N|", " *B|", " *R|", " *Q|", " *K|"}; - static char *wsqr = ""; - static char *bsqr = ""; - static char *top = "\t---------------------------------\n"; - static char *mid = "\t|---+---+---+---+---+---+---+---|\n"; - static char *start = "|"; - static char *end = ""; - static char *label = "\t a b c d e f g h\n"; - static char *blabel = "\t h g f e d c b a\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* USA-Today Sports Center-style board */ -static int style2(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {"+ ", "P ", "N ", "B ", "R ", "Q ", "K "}; - static const char *bp[] = {"- ", "p' ", "n' ", "b' ", "r' ", "q' ", "k' "}; - static char *wsqr = ""; - static char *bsqr = ""; - static char *top = ""; - static char *mid = ""; - static char *start = ""; - static char *end = ""; - static char *label = "\ta b c d e f g h\n"; - static char *blabel = "\th g f e d c b a\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* Experimental vt-100 ANSI board for dark backgrounds */ -static int style3(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " Q ", " K "}; - static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *Q", " *K"}; - static char *wsqr = "\033[0m"; - static char *bsqr = "\033[7m"; - static char *top = "\t+------------------------+\n"; - static char *mid = ""; - static char *start = "|"; - static char *end = "\033[0m|"; - static char *label = "\t a b c d e f g h\n"; - static char *blabel = "\t h g f e d c b a\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* Experimental vt-100 ANSI board for light backgrounds */ -static int style4(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " Q ", " K "}; - static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *Q", " *K"}; - static char *wsqr = "\033[7m"; - static char *bsqr = "\033[0m"; - static char *top = "\t+------------------------+\n"; - static char *mid = ""; - static char *start = "|"; - static char *end = "\033[0m|"; - static char *label = "\t a b c d e f g h\n"; - static char *blabel = "\t h g f e d c b a\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* Style suggested by ajpierce@med.unc.edu */ -static int style5(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {" ", " o ", " :N:", " ", " |R|", " {Q}", " =K="}; - static const char *bp[] = {" ", " p ", " :n:", " ", " |r|", " {q}", " =k="}; - static char *wsqr = ""; - static char *bsqr = ""; - static char *top = " . . . . . . . . .\n"; - static char *mid = " . . . . . . . . .\n"; - static char *start = ""; - static char *end = ""; - static char *label = "\t a b c d e f g h\n"; - static char *blabel = "\t h g f e d c b a\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */ -static int style6(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {" |", " wp |", " WN |", " WB |", " WR |", " WQ |", " WK |"}; - static const char *bp[] = {" |", " bp |", " BN |", " BB |", " BR |", " BQ |", " BK |"}; - static char *wsqr = ""; - static char *bsqr = ""; - static char *top = "\t-----------------------------------------\n"; - static char *mid = "\t-----------------------------------------\n"; - static char *start = "|"; - static char *end = ""; - static char *label = "\t A B C D E F G H\n"; - static char *blabel = "\t H G F E D C B A\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* Miniature board */ -static int style7(struct game_state_t *b, struct move_t *ml) -{ - static const char *wp[] = {" ", " P", " N", " B", " R", " Q", " K"}; - static const char *bp[] = {" -", " p", " n", " b", " r", " q", " k"}; - static char *wsqr = ""; - static char *bsqr = ""; - static char *top = "\t:::::::::::::::::::::\n"; - static char *mid = ""; - static char *start = ".."; - static char *end = " .."; - static char *label = "\t a b c d e f g h\n"; - static char *blabel = "\t h g f e d c b a\n"; - - return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); -} - -/* ICS interface maker board-- raw data dump */ -static int style8(struct game_state_t *b, struct move_t *ml) -{ - char tmp[80]; - int f, r; - int ws, bs; - - board_calc_strength(b, &ws, &bs); - sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1, - game_globals.garray[b->gameNum].white_name, - (orient == WHITE) ? "*" : ":", - game_globals.garray[b->gameNum].black_name, - (orient == WHITE) ? ":" : "*"); - strcat(bstring, tmp); - for (r = 0; r < 8; r++) { - for (f = 0; f < 8; f++) { - if (b->board[f][r] == NOPIECE) { - strcat(bstring, " "); - } else { - if (colorval(b->board[f][r]) == WHITE) - strcat(bstring, wpstring[piecetype(b->board[f][r])]); - else - strcat(bstring, bpstring[piecetype(b->board[f][r])]); - } - } - } - sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n", - game_globals.garray[b->gameNum].numHalfMoves / 2 + 1, - (b->onMove == WHITE) ? "W" : "B", - ws, - bs, - (wTime + 5) / 10, - (bTime + 5) / 10, - game_globals.garray[b->gameNum].numHalfMoves ? - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString : - "none", - game_globals.garray[b->gameNum].numHalfMoves ? - tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : - "0:00"); - strcat(bstring, tmp); - return 0; -} - -/* last 2 moves only (previous non-verbose mode) */ -static int style9(struct game_state_t *b, struct move_t *ml) -{ - int i, count; - char tmp[80]; - int startmove; - - sprintf(tmp, "\nMove %-23s%s\n", - game_globals.garray[b->gameNum].white_name, - game_globals.garray[b->gameNum].black_name); - strcat(bstring, tmp); - sprintf(tmp, "---- -------------- --------------\n"); - strcat(bstring, tmp); - startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2; - if (startmove < 0) - startmove = 0; - for (i = startmove, count = 0; - i < game_globals.garray[b->gameNum].numHalfMoves && count < 4; - i++, count++) { - if (!(i & 0x01)) { - sprintf(tmp, " %2d ", i / 2 + 1); - strcat(bstring, tmp); - } - sprintf(tmp, "%-23s", move_and_time(&ml[i])); - strcat(bstring, tmp); - if (i & 0x01) - strcat(bstring, "\n"); - } - if (i & 0x01) - strcat(bstring, "\n"); - return 0; -} - -/* Sleator's 'new and improved' raw dump format... */ -static int style10(struct game_state_t *b, struct move_t *ml) -{ - int f, r; - char tmp[80]; - int ws, bs; - - board_calc_strength(b, &ws, &bs); - sprintf(tmp, "<10>\n"); - strcat(bstring, tmp); - for (r = 7; r >= 0; r--) { - strcat(bstring, "|"); - for (f = 0; f < 8; f++) { - if (b->board[f][r] == NOPIECE) { - strcat(bstring, " "); - } else { - if (colorval(b->board[f][r]) == WHITE) - strcat(bstring, wpstring[piecetype(b->board[f][r])]); - else - strcat(bstring, bpstring[piecetype(b->board[f][r])]); - } + int piece = piecetype(b->board[r][f]); +// if(piece > QUEEN) piece = ELEPHANT + (piece == KING); // All fairies become elephants in ascii styles + if (colorval(b->board[r][f]) == WHITE) + strcat(bstring, wp[piece]); + else + strcat(bstring, bp[piece]); + } + } + sprintf(tmp, "%s", end); + strcat(bstring, tmp); + switch (count) { + case 7: + sprintf(tmp, " Move # : %d (%s)", b->moveNum, CString(b->onMove)); + strcat(bstring, tmp); + break; + case 6: +/* if ((b->moveNum > 1) || (b->onMove == BLACK)) { */ +/* The change from the above line to the one below is a kludge by hersco. */ + if (game_globals.garray[b->gameNum].numHalfMoves > 0) { +/* loon: think this fixes the crashing ascii board on takeback bug */ + sprintf(tmp, " %s Moves : '%s'", CString(CToggle(b->onMove)), + move_and_time(&ml[game_globals.garray[b->gameNum].numHalfMoves - 1])); + strcat(bstring, tmp); + } + break; + case 5: + break; + case 4: + sprintf(tmp, " Black Clock : %s", tenth_str(((bTime > 0) ? bTime : 0), 1)); + strcat(bstring, tmp); + break; + case 3: + sprintf(tmp, " White Clock : %s", tenth_str(((wTime > 0) ? wTime : 0), 1)); + strcat(bstring, tmp); + break; + case 2: + sprintf(tmp, " Black Strength : %d", bs); + strcat(bstring, tmp); + break; + case 1: + sprintf(tmp, " White Strength : %d", ws); + strcat(bstring, tmp); + break; + case 0: + break; + } + strcat(bstring, "\n"); + if (count != 0) + strcat(bstring, myMid); + else + strcat(bstring, myTop); + } + q = mylabel; i = 0; + if (orient == WHITE) { + p = label; + while(*p) { + switch(*p) { + case ' ': + case '\t': + case '\n': + *q++ = *p++; break; + default: + if(++i > b->files) { *q++ = '\n'; *q++ = 0; } + *q++ = *p++; + } } - strcat(bstring, "|\n"); - } - strcat(bstring, (b->onMove == WHITE) ? "W " : "B "); - if (game_globals.garray[b->gameNum].numHalfMoves) { - sprintf(tmp, "%d ", - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn); } else { - sprintf(tmp, "-1 "); - } - strcat(bstring, tmp); - sprintf(tmp, "%d %d %d %d %d\n", - !(b->wkmoved || b->wkrmoved), - !(b->wkmoved || b->wqrmoved), - !(b->bkmoved || b->bkrmoved), - !(b->bkmoved || b->bqrmoved), - (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 : - b->lastIrreversable))); - strcat(bstring, tmp); - sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n", - b->gameNum, - game_globals.garray[b->gameNum].white_name, - game_globals.garray[b->gameNum].black_name, - myTurn, - game_globals.garray[b->gameNum].wInitTime / 600, - game_globals.garray[b->gameNum].wIncrement / 10, - ws, - bs, - (wTime + 5) / 10, - (bTime + 5) / 10, - game_globals.garray[b->gameNum].numHalfMoves / 2 + 1, - game_globals.garray[b->gameNum].numHalfMoves ? - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString : - "none", - game_globals.garray[b->gameNum].numHalfMoves ? - tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : - "0:00", - game_globals.garray[b->gameNum].numHalfMoves ? - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString : - "none", - (orient == WHITE) ? 0 : 1); - strcat(bstring, tmp); - sprintf(tmp, ">10<\n"); - strcat(bstring, tmp); - return 0; -} - -/* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */ -static int style11(struct game_state_t *b, struct move_t *ml) -{ - char tmp[80]; - int f, r; - int ws, bs; - - board_calc_strength(b, &ws, &bs); - sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum, - game_globals.garray[b->gameNum].white_name, - (orient == WHITE) ? "*" : ":", - game_globals.garray[b->gameNum].black_name, - (orient == WHITE) ? ":" : "*"); - strcat(bstring, tmp); - for (r = 0; r < 8; r++) { - for (f = 0; f < 8; f++) { - if (b->board[f][r] == NOPIECE) { - strcat(bstring, " "); - } else { - if (colorval(b->board[f][r]) == WHITE) - strcat(bstring, wpstring[piecetype(b->board[f][r])]); - else - strcat(bstring, bpstring[piecetype(b->board[f][r])]); - } - } - } - sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n", - game_globals.garray[b->gameNum].numHalfMoves / 2 + 1, - (b->onMove == WHITE) ? "W" : "B", - ws, - bs, - (wTime + 5) / 10, - (bTime + 5) / 10, - game_globals.garray[b->gameNum].numHalfMoves ? - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString : - "none", - game_globals.garray[b->gameNum].numHalfMoves ? - tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : - "0:00"); - strcat(bstring, tmp); - return 0; + p = blabel; + while(*p) { + switch(*p) { + case ' ': + case '\t': + case '\n': + *q++ = *p++; break; + default: + *q++ = *p++ + b->files - 12; + if(++i >= b->files) { *q++ = '\n'; *q++ = 0; } + } + } + } + *q++ = 0; + strcat(bstring, mylabel); + return 0; } -/* Similar to style 10. See the "style12" help file for information */ -static int style12(struct game_state_t *b, struct move_t *ml) -{ - int f, r; - char tmp[80]; - int ws, bs; - - board_calc_strength(b, &ws, &bs); - sprintf(bstring, "<12> "); - for (r = 7; r >= 0; r--) { - for (f = 0; f < 8; f++) { - if (b->board[f][r] == NOPIECE) { - strcat(bstring, "-"); - } else { - if (colorval(b->board[f][r]) == WHITE) - strcat(bstring, wpstring[piecetype(b->board[f][r])]); - else - strcat(bstring, bpstring[piecetype(b->board[f][r])]); - } - } - strcat(bstring, " "); - } - strcat(bstring, (b->onMove == WHITE) ? "W " : "B "); - if (game_globals.garray[b->gameNum].numHalfMoves) { - sprintf(tmp, "%d ", - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn); - } else { - sprintf(tmp, "-1 "); +/* Experimental ANSI board for colour representation */ +static int style13(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {" ", "\033[37m\033[1m P ", "\033[37m\033[1m N ", "\033[37m\033[1m B ", "\033[37m\033[1m R ", "\033[37m\033[1m A ", "\033[37m\033[1m C ", "\033[37m\033[1m M ", "\033[37m\033[1m Q ", "\033[37m\033[1m E ", "\033[37m\033[1m K "}; + static const char *bp[] = {" ", "\033[21m\033[37m P ", "\033[21m\033[37m N ", "\033[21m\033[37m B ", "\033[21m\033[37m R ", "\033[21m\033[37m A ", "\033[21m\033[37m C ", "\033[21m\033[37m M ", "\033[21m\033[37m Q ", "\033[21m\033[37m E ", "\033[21m\033[37m K "}; + static const char *wsqr = "\033[40m"; + static const char *bsqr = "\033[45m"; + static const char *top = "\t+------------------------+\n"; + static const char *mid = ""; + static const char *start = "|"; + static const char *end = "\033[0m|"; + static const char *label = "\t a b c d e f g h i j k l\n"; + static const char *blabel = "\t l k j i h g f e d c b a\n"; +return 0; + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* Standard ICS */ +static int style1(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {" |", " P |", " N |", " B |", " R |", " A |", " C |", " M |", " Q |", " E |", " B |", " Q |", + " W |", " H |", " N |", " J |", " I |", " L |", " C |", " S |", " G |", " H |", " A |", " F |", + " E |", " H |", " M |", " S |", " E |", " W |", " O |", " G |", " V |", " S |", " E |", " A |", " K |"}; + static const char *bp[] = {" |", " *P|", " *N|", " *B|", " *R|", " *A|", " *C|", " *M|", " *Q|", " *E|", " *B|", " *Q|", + " *W|", " *H|", " *N|", " *J|", " *I|", " *L|", " *C|", " *S|", " *G|", " *H|", " *A|", " *F|", + " *E|", " *H|", " *M|", " *S|", " *E|", " *W|", " *O|", " *G|", " *V|", " *S|", " *E|", " *A|", " *K|"}; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = "\t---------------------------------\n"; + static char *mid = "\t|---+---+---+---+---+---+---+---|\n"; + static char *start = "|"; + static char *end = ""; + static char *label = "\t a b c d e f g h i j k l\n"; + static char *blabel = "\t l k j i h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* USA-Today Sports Center-style board */ +static int style2(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {"- ", "P ", "N ", "B ", "R ", "A ", "C ", "M ", "Q ", "E ", "B ", "Q ", + "W ", "H ", "N ", "J ", "I ", "L ", "C ", "S ", "G ", "H ", "A ", "F ", + "E ", "H ", "M ", "S ", "E ", "W ", "O ", "G ", "V ", "S ", "E ", "A ", "K "}; + static const char *bp[] = {"+ ", "p' ", "n' ", "b' ", "r' ", "a' ", "c' ", "m' ", "q' ", "e' ", "b' ", "q' ", + "w' ", "h' ", "n' ", "j' ", "i' ", "l' ", "c' ", "s' ", "g' ", "h' ", "a' ", "f' ", + "e' ", "h' ", "m' ", "s' ", "e' ", "w' ", "o' ", "g' ", "v' ", "s' ", "e' ", "a' ", "k' "}; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = ""; + static char *mid = ""; + static char *start = ""; + static char *end = ""; + static char *label = "\ta b c d e f g h i j k l\n"; + static char *blabel = "\tl k j i h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* Experimental vt-100 ANSI board for dark backgrounds */ +static int style3(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", + " W ", " H ", " N ", " J ", " I ", " L ", " C ", " S ", " G ", " H ", " A ", " F ", + " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K "}; + static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", + " *W", " *H", " *N", " *J", " *I", " *L", " *C", " *S", " *G", " *H", " *A", " *F", + " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K"}; + static char *wsqr = "\033[0m"; + static char *bsqr = "\033[7m"; + static char *top = "\t+------------------------+\n"; + static char *mid = ""; + static char *start = "|"; + static char *end = "\033[0m|"; + static char *label = "\t a b c d e f g h i j k l\n"; + static char *blabel = "\t l k j i h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* Experimental vt-100 ANSI board for light backgrounds */ +static int style4(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {" ", " P ", " N ", " B ", " R ", " A ", " C ", " M ", " Q ", " E ", " B ", " Q ", + " W ", " H ", " N ", " J ", " I ", " L ", " C ", " S ", " G ", " H ", " A ", " F ", + " E ", " H ", " M ", " S ", " E ", " W ", " O ", " G ", " V ", " S ", " E ", " A ", " K "}; + static const char *bp[] = {" ", " *P", " *N", " *B", " *R", " *A", " *C", " *M", " *Q", " *E", " *B", " *Q", + " *W", " *H", " *N", " *J", " *I", " *L", " *C", " *S", " *G", " *H", " *A", " *F", + " *E", " *H", " *M", " *S", " *E", " *W", " *O", " *G", " *V", " *S", " *E", " *A", " *K"}; + static char *wsqr = "\033[7m"; + static char *bsqr = "\033[0m"; + static char *top = "\t+------------------------+\n"; + static char *mid = ""; + static char *start = "|"; + static char *end = "\033[0m|"; + static char *label = "\t a b c d e f g h i j k l\n"; + static char *blabel = "\t l k j i h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* Style suggested by ajpierce@med.unc.edu */ +static int style5(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {" ", " o ", " :N:", " ", " |R|", " (A)", " [C]", " :M:", " {Q}", " !E!", + " ", " {Q}", " .W.", " :H:", " :N:", " ", " |I|", " |L|", + " |C|", " !S!", " :G:", " :H:", " {A}", " {F}", " !E!", " (H)", " [M]", " :S:", + " !E!", " |W|", " *O*", " {G}", " :V:", " (S)", " [E]", " &A&", " =K="}; + static const char *bp[] = {" ", " p ", " :n:", " ", " |r|", " (a)", " [c]", " :m:", " {q}", " !e!", + " ", " {q}", " .w.", " :h:", " :n:", " ", " |i|", " |l|", + " |c|", " !s!", " :g:", " :h:", " {a}", " {f}", " !e!", " (h)", " [m]", " :s:", + " !e!", " |w|", " *o*", " {g}", " :v:", " (s)", " [e]", " &a&", " =k="}; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = " . . . . . . . . .\n"; + static char *mid = " . . . . . . . . .\n"; + static char *start = ""; + static char *end = ""; + static char *label = "\t a b c d e f g h i j k l\n"; + static char *blabel = "\t l k j i h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* Email Board suggested by Thomas Fought (tlf@rsch.oclc.org) */ +static int style6(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {" |", " wp |", " WN |", " WB |", " WR |", " WA |", " WC |", " WM |", " WQ |", + " WE |", " WB |", " WQ |", " WW |", " WH |", " WN |", " WJ |", " WI |", " WL |", + " WC |", " WS |", " WG |", " WH |", " WA |", " WF |", " WE |", " WH |", " WM |", + " WS |", " WE |", " WW |", " WO |", " WG |", " WV |", " WS |", " WE |", " WA |", " WK |"}; + static const char *bp[] = {" |", " bp |", " BN |", " BB |", " BR |", " BA |", " BC |", " BM |", " BQ |", + " BE |", " BB |", " BQ |", " BW |", " BH |", " BN |", " BJ |", " BI |", " BL |", + " BC |", " BS |", " BG |", " BH |", " BA |", " BF |", " BE |", " BH |", " BM |", + " BS |", " BE |", " BW |", " BO |", " BG |", " BV |", " BS |", " BE |", " BA |", " BK |"}; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = "\t-----------------------------------------\n"; + static char *mid = "\t-----------------------------------------\n"; + static char *start = "|"; + static char *end = ""; + static char *label = "\t A B C D E F G H I J K L\n"; + static char *blabel = "\t L K J I H G F E D C B A\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* Miniature board */ +static int style7(struct game_state_t *b, struct move_t *ml) +{ + static const char *wp[] = {" ", " P", " N", " B", " R", " A", " C", " M", " Q", " E", " B", " Q", " W", " H", " N", " J", " I", " L", + " C", " S", " G", " H", " A", " F", " E", " H", " M", " S", " E", " W", " O", " G", " V", " S", " E", " A", " K"}; + static const char *bp[] = {" -", " p", " n", " b", " r", " a", " c", " m", " q", " e", " b", " q", " w", " h", " n", " j", " i", " l", + " c", " s", " g", " h", " a", " f", " e", " h", " m", " s", " e", " w", " o", " g", " v", " s", " e", " a", " k"}; + static char *wsqr = ""; + static char *bsqr = ""; + static char *top = "\t:::::::::::::::::::::\n"; + static char *mid = ""; + static char *start = ".."; + static char *end = " .."; + static char *label = "\t a b c d e f g h i j k l\n"; + static char *blabel = "\t l k j i h g f e d c b a\n"; + + return genstyle(b, ml, wp, bp, wsqr, bsqr, top, mid, start, end, label, blabel); +} + +/* ICS interface maker board-- raw data dump */ +static int style8(struct game_state_t *b, struct move_t *ml) +{ + char tmp[160]; + int f, r; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum + 1, + game_globals.garray[b->gameNum].white_name, + (orient == WHITE) ? "*" : ":", + game_globals.garray[b->gameNum].black_name, + (orient == WHITE) ? ":" : "*"); + strcat(bstring, tmp); + for (r = 0; r < b->ranks; r++) { + for (f = 0; f < b->files; f++) { + if (b->board[f][r] == NOPIECE) { + strcat(bstring, " "); + } else { + if (colorval(b->board[f][r]) == WHITE) + strcat(bstring, wpstring[piecetype(b->board[f][r])]); + else + strcat(bstring, bpstring[piecetype(b->board[f][r])]); + } + } + } + sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n", + game_globals.garray[b->gameNum].numHalfMoves / 2 + 1, + (b->onMove == WHITE) ? "W" : "B", + ws, + bs, + (wTime + 5) / 10, + (bTime + 5) / 10, + game_globals.garray[b->gameNum].numHalfMoves ? + ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString : + "none", + game_globals.garray[b->gameNum].numHalfMoves ? + tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : + "0:00"); + strcat(bstring, tmp); + return 0; +} + +/* last 2 moves only (previous non-verbose mode) */ +static int style9(struct game_state_t *b, struct move_t *ml) +{ + int i, count; + char tmp[160]; + int startmove; + + sprintf(tmp, "\nMove %-23s%s\n", + game_globals.garray[b->gameNum].white_name, + game_globals.garray[b->gameNum].black_name); + strcat(bstring, tmp); + sprintf(tmp, "---- -------------- --------------\n"); + strcat(bstring, tmp); + startmove = ((game_globals.garray[b->gameNum].numHalfMoves - 3) / 2) * 2; + if (startmove < 0) + startmove = 0; + for (i = startmove, count = 0; + i < game_globals.garray[b->gameNum].numHalfMoves && count < 4; + i++, count++) { + if (!(i & 0x01)) { + sprintf(tmp, " %2d ", i / 2 + 1); + strcat(bstring, tmp); + } + sprintf(tmp, "%-23s", move_and_time(&ml[i])); + strcat(bstring, tmp); + if (i & 0x01) + strcat(bstring, "\n"); + } + if (i & 0x01) + strcat(bstring, "\n"); + return 0; +} + +/* Sleator's 'new and improved' raw dump format... */ +static int style10(struct game_state_t *b, struct move_t *ml) +{ + int f, r; + char tmp[160]; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + sprintf(tmp, "<10>\n"); + strcat(bstring, tmp); + for (r = b->ranks-1; r >= 0; r--) { + strcat(bstring, "|"); + for (f = 0; f < b->files; f++) { + if (b->board[f][r] == NOPIECE) { + strcat(bstring, " "); + } else { + if (colorval(b->board[f][r]) == WHITE) + strcat(bstring, wpstring[piecetype(b->board[f][r])]); + else + strcat(bstring, bpstring[piecetype(b->board[f][r])]); + } + } + strcat(bstring, "|\n"); + } + strcat(bstring, (b->onMove == WHITE) ? "W " : "B "); + if (game_globals.garray[b->gameNum].numHalfMoves) { + sprintf(tmp, "%d ", + ml[game_globals.garray[b->gameNum].numHalfMoves - 1].doublePawn); + } else { + sprintf(tmp, "-1 "); + } + strcat(bstring, tmp); + sprintf(tmp, "%d %d %d %d %d\n", + (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights + (b->wkmoved >= 0 && b->wqrmoved >= 0), + (b->bkmoved >= 0 && b->bkrmoved >= 0), + (b->bkmoved >= 0 && b->bqrmoved >= 0), + (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 : + b->lastIrreversable))); + strcat(bstring, tmp); + sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d\n", + b->gameNum, + game_globals.garray[b->gameNum].white_name, + game_globals.garray[b->gameNum].black_name, + myTurn, + game_globals.garray[b->gameNum].wInitTime / 600, + game_globals.garray[b->gameNum].wIncrement / 10, + ws, + bs, + (wTime + 5) / 10, + (bTime + 5) / 10, + game_globals.garray[b->gameNum].numHalfMoves / 2 + 1, + game_globals.garray[b->gameNum].numHalfMoves ? + ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString : + "none", + game_globals.garray[b->gameNum].numHalfMoves ? + tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : + "0:00", + game_globals.garray[b->gameNum].numHalfMoves ? + ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString : + "none", + (orient == WHITE) ? 0 : 1); + strcat(bstring, tmp); + sprintf(tmp, ">10<\n"); + strcat(bstring, tmp); + return 0; +} + +/* Same as 8, but with verbose moves ("P/e3-e4", instead of "e4") */ +static int style11(struct game_state_t *b, struct move_t *ml) +{ + char tmp[160]; + int f, r; + int ws, bs; + + board_calc_strength(b, &ws, &bs); + sprintf(tmp, "#@#%03d%-16s%s%-16s%s", b->gameNum, + game_globals.garray[b->gameNum].white_name, + (orient == WHITE) ? "*" : ":", + game_globals.garray[b->gameNum].black_name, + (orient == WHITE) ? ":" : "*"); + strcat(bstring, tmp); + for (r = 0; r < b->ranks; r++) { + for (f = 0; f < b->files; f++) { + if (b->board[f][r] == NOPIECE) { + strcat(bstring, " "); + } else { + if (colorval(b->board[f][r]) == WHITE) + strcat(bstring, wpstring[piecetype(b->board[f][r])]); + else + strcat(bstring, bpstring[piecetype(b->board[f][r])]); + } + } + } + sprintf(tmp, "%03d%s%02d%02d%05d%05d%-7s(%s)@#@\n", + game_globals.garray[b->gameNum].numHalfMoves / 2 + 1, + (b->onMove == WHITE) ? "W" : "B", + ws, + bs, + (wTime + 5) / 10, + (bTime + 5) / 10, + game_globals.garray[b->gameNum].numHalfMoves ? + ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString : + "none", + game_globals.garray[b->gameNum].numHalfMoves ? + tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : + "0:00"); + strcat(bstring, tmp); + return 0; +} + + +int kludgeFlag = 0; +/* Similar to style 10. See the "style12" help file for information */ +static int style12(struct game_state_t *b, struct move_t *ml) +{ + int f, r; + char tmp[160]; // [HGM] 80 caused problems with long login names + int ws, bs; + int nhm = kludgeFlag ? 0 : game_globals.garray[b->gameNum].numHalfMoves; + // [HGM] setup: the number of half moves appeared in this routine an enormous number of times, + // and had to be dug out of the game_globals, so that this routine could only be used to print + // a board from a game, and not just any board given by an isolated game_state_t. This was very + // inconvenient for printing initial boards in move lists of shuffle variants, so I added the + // global kludgeFlag to signal that we want to print an initial position, and force nhm = 0. + + board_calc_strength(b, &ws, &bs); + + sprintf(bstring, "<12> "); + for (r = b->ranks-1; r >= 0; r--) { + for (f = 0; f < b->files; f++) { + if (b->board[f][r] == NOPIECE) { + strcat(bstring, "-"); + } else { + if (colorval(b->board[f][r]) == WHITE) + strcat(bstring, wpstring[piecetype(b->board[f][r])]); + else + strcat(bstring, bpstring[piecetype(b->board[f][r])]); + } + } + strcat(bstring, " "); } + + strcat(bstring, (b->onMove == WHITE) ? "W " : "B "); + if (nhm) { + sprintf(tmp, "%d ", + ml[nhm - 1].doublePawn); + } else { + sprintf(tmp, "-1 "); + } + strcat(bstring, tmp); + sprintf(tmp, "%d %d %d %d %d ", + (b->wkmoved >= 0 && b->wkrmoved >= 0), // [HGM] castle: inverted the logic, both must have rights + (b->wkmoved >= 0 && b->wqrmoved >= 0), + (b->bkmoved >= 0 && b->bkrmoved >= 0), + (b->bkmoved >= 0 && b->bqrmoved >= 0), + (nhm - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable))); strcat(bstring, tmp); - sprintf(tmp, "%d %d %d %d %d ", - !(b->wkmoved || b->wkrmoved), - !(b->wkmoved || b->wqrmoved), - !(b->bkmoved || b->bkrmoved), - !(b->bkmoved || b->bqrmoved), - (game_globals.garray[b->gameNum].numHalfMoves - ((b->lastIrreversable == -1) ? 0 : b->lastIrreversable))); - strcat(bstring, tmp); - sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n", - b->gameNum + 1, - game_globals.garray[b->gameNum].white_name, - game_globals.garray[b->gameNum].black_name, - myTurn, - game_globals.garray[b->gameNum].wInitTime / 600, - game_globals.garray[b->gameNum].wIncrement / 10, - ws, - bs, - (wTime / 10), - (bTime / 10), - game_globals.garray[b->gameNum].numHalfMoves / 2 + 1, - game_globals.garray[b->gameNum].numHalfMoves ? - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].moveString : - "none", - game_globals.garray[b->gameNum].numHalfMoves ? - tenth_str(ml[game_globals.garray[b->gameNum].numHalfMoves - 1].tookTime, 0) : - "0:00", - game_globals.garray[b->gameNum].numHalfMoves ? - ml[game_globals.garray[b->gameNum].numHalfMoves - 1].algString : - "none", (orient == WHITE) ? 0 : 1, - b->moveNum > 1 ? 1 : 0); /* ticking */ - - strcat(bstring, tmp); - return 0; -} + sprintf(tmp, "%d %s %s %d %d %d %d %d %d %d %d %s (%s) %s %d %d\n", + b->gameNum + 1, + game_globals.garray[b->gameNum].white_name, + game_globals.garray[b->gameNum].black_name, + myTurn, + game_globals.garray[b->gameNum].wInitTime / 600, + game_globals.garray[b->gameNum].wIncrement / 10, + ws, + bs, + (wTime / 10), + (bTime / 10), + nhm / 2 + 1, + nhm ? + ml[nhm - 1].moveString : + "none", + nhm ? + tenth_str(ml[nhm - 1].tookTime, 0) : + "0:00", + nhm ? + ml[nhm - 1].algString : + "none", (orient == WHITE) ? 0 : 1, + b->moveNum > 1 ? 1 : 0); /* ticking */ + + strcat(bstring, tmp); + return 0; +} static int board_read_file(char *category, char *gname, struct game_state_t *gs) { @@ -802,6 +995,7 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs) return 1; board_clear(gs); + gs->setup = 1; while (!feof(fp)) { c = fgetc(fp); if (onNewLine) { @@ -813,6 +1007,55 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs) onColor = BLACK; if (gs->onMove < 0) gs->onMove = BLACK; + } else if (c == 'S') { int f=8, r=8; + // [HGM] rules: read rule modifiers + fscanf(fp, "%dx%d", &f, &r); gs->files=f; gs->ranks = r; + while (!feof(fp) && c != '\n') { + c = fgetc(fp); + switch(c) { + case 'r': + gs->royalKnight = 1; + break; + case 'c': + gs->capablancaPieces = 1; + break; + case 'd': + gs->drops = 1; + break; + case 'h': + gs->holdings = -1; // color-flip holdings + break; + case 'p': + gs->palace = 3; + break; + case 'P': + gs->promoType = 2; // only promote to captured pieces + gs->holdings = 1; // use holdings to hold own captured pieces + break; + case 'F': + gs->castlingStyle = 2; // FRC castling + break; + case 'w': + gs->castlingStyle = 1; // wild castling, from both center files + break; + case 'n': + gs->castlingStyle = 0; // no castling + break; + case 'f': + gs->castlingStyle = 3; // free castling + break; + case 'D': + gs->pawnDblStep = 0; // suppress pawn double step + break; + case 'b': + gs->bareKingLoses = 1; // apply baring rule + break; + case 's': + gs->stalemate = 0; // stalemate loses + break; + } + } + continue; } else if (c == '#') { while (!feof(fp) && c != '\n') c = fgetc(fp); /* Comment line */ @@ -837,36 +1080,128 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs) case 'B': onPiece = BISHOP; break; + case 'A': + onPiece = CARDINAL; + break; + case 'C': + onPiece = MARSHALL; + break; + case 'M': + onPiece = MAN; + break; case 'Q': onPiece = QUEEN; break; - case 'K': - onPiece = KING; + case 'T': + onPiece = ELEPHANT; break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'g': - case 'h': - onFile = c - 'a'; - onRank = -1; + case 'E': + onPiece = ALFIL; + break; + case 't': + onPiece = ALFIL2; + break; + case 'q': + onPiece = FERZ; + break; + case 'F': + onPiece = FERZ2; + break; + case 'W': + onPiece = WAZIR; + break; + case 'w': + onPiece = WOODY; + break; + case 'p': + onPiece = PRIESTESS; + break; + case 'r': + onPiece = MINISTER; + break; + case 'z': + onPiece = MAN2; + break; + case 'u': + onPiece = NIGHTRIDER; + break; + case 'o': + onPiece = MODERNELEPHANT; + break; + case 's': + onPiece = MASTODON; + break; + case 'Z': + onPiece = AMAZON; + break; + case 'V': + onPiece = CENTAUR; + break; + case 'H': + onPiece = HORSE; + break; + case 'n': + onPiece = HONORABLEHORSE; + break; + case 'J': + onPiece = DRAGONKING; break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - onRank = c - '1'; - if (onFile >= 0 && onColor >= 0 && onPiece >= 0) - gs->board[onFile][onRank] = onPiece | onColor; + case 'I': + onPiece = DRAGONHORSE; break; - case '#': + case 'L': + onPiece = LANCE; + break; + case 'O': + onPiece = CANNON; + break; + case 'S': + onPiece = SILVER; + break; + case 'G': + onPiece = GOLD; + break; + case 'm': + onPiece = MANDARIN; + break; + case 'K': + onPiece = KING; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + onFile = c - 'a'; + if(onFile >= gs->files) { onFile = -1; break; } + onRank = -1; + break; + case '@': + if (onColor >= 0 && onPiece >= 0) // allow placement in holdings + gs->holding[onColor == BLACK][onPiece-1]++; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '0': + onRank = c - '1' + (gs->ranks > 9); + if(onRank < 0 || onRank >= gs->ranks) { onRank = -1; break; } + if (onFile >= 0 && onColor >= 0 && onPiece >= 0) + gs->board[onFile][onRank] = onPiece | onColor; + break; case '#': while (!feof(fp) && c != '\n') c = fgetc(fp); /* Comment line */ case '\n': @@ -890,8 +1225,8 @@ static int board_read_file(char *category, char *gname, struct game_state_t *gs) #define ANY_SQUARE -1 #define SquareColor(f, r) ((f ^ r) & 1) -static void place_piece(board_t b, int piece, int squareColor) -{ +static void place_piece(board_t b, int piece, int squareColor, int width) +{ //[HGM] board: make width a variable int r, f; int placed = 0; @@ -902,9 +1237,9 @@ static void place_piece(board_t b, int piece, int squareColor) while (!placed) { if (squareColor == ANY_SQUARE) { - f = random() % 8; + f = random() % width; } else { - f = (random() % 4) * 2; + f = (random() % ((width+1)/2)) * 2; // to not overflow odd-width boards if (SquareColor(f, r) != squareColor) f++; } @@ -915,12 +1250,11 @@ static void place_piece(board_t b, int piece, int squareColor) } } -static void wild_update(int style) +static void wild_update(board_t b, int style) { - int f, r, i; - board_t b; + int f, r, i, j; - for (f = 0; f < 8; f++) + for (f = 0; f < BW; f++) // [HGM] board: make sure also works with wider boards for (r = 0; r < 8; r++) b[f][r] = NOPIECE; for (f = 0; f < 8; f++) { @@ -947,24 +1281,24 @@ static void wild_update(int style) b[0][7] = b[7][7] = B_ROOK; /* Must do bishops before knights to be sure opposite colored squares are available. */ - place_piece(b, W_BISHOP, WHITE_SQUARE); - place_piece(b, W_BISHOP, BLACK_SQUARE); - place_piece(b, W_KNIGHT, ANY_SQUARE); - place_piece(b, W_KNIGHT, ANY_SQUARE); - place_piece(b, B_BISHOP, WHITE_SQUARE); - place_piece(b, B_BISHOP, BLACK_SQUARE); - place_piece(b, B_KNIGHT, ANY_SQUARE); - place_piece(b, B_KNIGHT, ANY_SQUARE); + place_piece(b, W_BISHOP, WHITE_SQUARE, 8); + place_piece(b, W_BISHOP, BLACK_SQUARE, 8); + place_piece(b, W_KNIGHT, ANY_SQUARE, 8); + place_piece(b, W_KNIGHT, ANY_SQUARE, 8); + place_piece(b, B_BISHOP, WHITE_SQUARE, 8); + place_piece(b, B_BISHOP, BLACK_SQUARE, 8); + place_piece(b, B_KNIGHT, ANY_SQUARE, 8); + place_piece(b, B_KNIGHT, ANY_SQUARE, 8); break; case 2: - place_piece(b, W_KING, ANY_SQUARE); - place_piece(b, W_QUEEN, ANY_SQUARE); - place_piece(b, W_ROOK, ANY_SQUARE); - place_piece(b, W_ROOK, ANY_SQUARE); - place_piece(b, W_BISHOP, ANY_SQUARE); - place_piece(b, W_BISHOP, ANY_SQUARE); - place_piece(b, W_KNIGHT, ANY_SQUARE); - place_piece(b, W_KNIGHT, ANY_SQUARE); + place_piece(b, W_KING, ANY_SQUARE, 8); + place_piece(b, W_QUEEN, ANY_SQUARE, 8); + place_piece(b, W_ROOK, ANY_SQUARE, 8); + place_piece(b, W_ROOK, ANY_SQUARE, 8); + place_piece(b, W_BISHOP, ANY_SQUARE, 8); + place_piece(b, W_BISHOP, ANY_SQUARE, 8); + place_piece(b, W_KNIGHT, ANY_SQUARE, 8); + place_piece(b, W_KNIGHT, ANY_SQUARE, 8); /* Black mirrors White */ for (i = 0; i < 8; i++) { b[i][7] = b[i][0] | BLACK; @@ -972,7 +1306,7 @@ static void wild_update(int style) break; case 3: /* Generate White king on random square plus random set of pieces */ - place_piece(b, W_KING, ANY_SQUARE); + place_piece(b, W_KING, ANY_SQUARE, 8); for (i = 0; i < 8; i++) { if (b[i][0] != W_KING) { b[i][0] = (random() % 4) + 2; @@ -985,7 +1319,7 @@ static void wild_update(int style) break; case 4: /* Generate White king on random square plus random set of pieces */ - place_piece(b, W_KING, ANY_SQUARE); + place_piece(b, W_KING, ANY_SQUARE, 8); for (i = 0; i < 8; i++) { if (b[i][0] != W_KING) { b[i][0] = (random() % 4) + 2; @@ -997,15 +1331,47 @@ static void wild_update(int style) to be sure there are enough squares left of the correct color. */ for (i = 0; i < 8; i++) { if (b[i][0] == W_BISHOP) { - place_piece(b, B_BISHOP, !SquareColor(i, 0)); + place_piece(b, B_BISHOP, !SquareColor(i, 0), 8); } } for (i = 0; i < 8; i++) { if (b[i][0] != W_BISHOP) { - place_piece(b, b[i][0] | BLACK, ANY_SQUARE); + place_piece(b, b[i][0] | BLACK, ANY_SQUARE, 8); } } break; + case 22: + /* Chess960 placement: King between R */ + place_piece(b, W_BISHOP, WHITE_SQUARE, 8); + place_piece(b, W_BISHOP, BLACK_SQUARE, 8); + place_piece(b, W_QUEEN, ANY_SQUARE, 8); + place_piece(b, W_KNIGHT, ANY_SQUARE, 8); + place_piece(b, W_KNIGHT, ANY_SQUARE, 8); + for (i = j = 0; i < 8; i++) { + if(b[i][0] == NOPIECE) b[i][0] = (j++ == 1 ? W_KING : W_ROOK); + } + /* Black mirrors White */ + for (i = 0; i < 8; i++) { + b[i][7] = b[i][0] | BLACK; + } + break; + case 46: + /* Chess960 placement: King between R */ + place_piece(b, W_BISHOP, WHITE_SQUARE, 10); + place_piece(b, W_BISHOP, BLACK_SQUARE, 10); + place_piece(b, W_QUEEN, ANY_SQUARE, 10); + place_piece(b, W_MARSHALL, ANY_SQUARE, 10); + place_piece(b, W_CARDINAL, ANY_SQUARE, 10); + place_piece(b, W_KNIGHT, ANY_SQUARE, 10); + place_piece(b, W_KNIGHT, ANY_SQUARE, 10); + for (i = j = 0; i < 10; i++) { + if(b[i][0] == NOPIECE) j++ == 1 ? W_KING : W_ROOK; + } + /* Black mirrors White */ + for (i = 0; i < 10; i++) { + b[i][7] = b[i][0] | BLACK; + } + break; default: return; break; @@ -1048,9 +1414,10 @@ static void wild_update(int style) void wild_init(void) { - wild_update(1); - wild_update(2); - wild_update(3); - wild_update(4); + board_t b; + wild_update(b, 1); + wild_update(b, 2); + wild_update(b, 3); + wild_update(b, 4); } diff --git a/lasker-2.2.3/src/board.h b/lasker-2.2.3/src/board.h index 051866b..a94a96e 100644 --- a/lasker-2.2.3/src/board.h +++ b/lasker-2.2.3/src/board.h @@ -28,30 +28,116 @@ /* These will go into an array */ -#define NOPIECE 0x00 -#define PAWN 0x01 -#define KNIGHT 0x02 -#define BISHOP 0x03 -#define ROOK 0x04 -#define QUEEN 0x05 -#define KING 0x06 - -#define MAX_BOARD_STRING_LEGTH 1280 /* Abitrarily 80 * 16 */ +#define NOPIECE 0 +#define PAWN 1 +#define KNIGHT 2 +#define BISHOP 3 +#define ROOK 4 +#define CARDINAL 5 +#define MARSHALL 6 +#define MAN 7 +#define QUEEN 8 +#define ELEPHANT 9 +#define ALFIL 10 +#define FERZ 11 +#define WAZIR 12 +#define HORSE 13 +#define HONORABLEHORSE 14 +#define DRAGONKING 15 +#define DRAGONHORSE 16 +#define LANCE 17 +#define CANNON 18 +#define SILVER 19 +#define GOLD 20 +#define NIGHTRIDER 21 +#define MANDARIN 22 +#define FERZ2 23 +#define ALFIL2 24 +#define PRIESTESS 25 +#define MINISTER 26 +#define MAN2 27 +#define MODERNELEPHANT 28 +#define WOODY 29 +#define SQUIRREL 30 +#define MASTODON 31 +#define CENTAUR 32 +#define PRINCESS 33 +#define EMPRESS 34 +#define AMAZON 35 +#define KING 36 + +#define MAX_BOARD_STRING_LENGTH 1280 /* Abitrarily 80 * 16 */ #define MAX_STYLES 13 #define W_PAWN (PAWN | WHITE) #define W_KNIGHT (KNIGHT | WHITE) #define W_BISHOP (BISHOP | WHITE) #define W_ROOK (ROOK | WHITE) +#define W_CARDINAL (CARDINAL | WHITE) +#define W_MARSHALL (MARSHALL | WHITE) +#define W_MAN (MAN | WHITE) #define W_QUEEN (QUEEN | WHITE) +#define W_ELEPHANT (ELEPHANT | WHITE) +#define W_ALFIL (ALFIL | WHITE) +#define W_FERZ (FERZ | WHITE) +#define W_WAZIR (WAZIR | WHITE) +#define W_ALFIL2 (ALFIL2 | WHITE) +#define W_FERZ2 (FERZ2 | WHITE) +#define W_AMAZON (AMAZON | WHITE) +#define W_CENTAUR (CENTAUR | WHITE) +#define W_HORSE (HORSE | WHITE) +#define W_HONORABLEHORSE (HONORABLEHORSE | WHITE) +#define W_DRAGONKING (DRAGONKING | WHITE) +#define W_DRAGONHORSE (DRAGONHORSE | WHITE) +#define W_LANCE (LANCE | WHITE) +#define W_CANNON (CANNON | WHITE) +#define W_SILVER (SILVER | WHITE) +#define W_GOLD (GOLD | WHITE) #define W_KING (KING | WHITE) +#define W_MANDARIN (MANDARIN | WHITE) +#define W_EMPRESS (EMPRESS | WHITE) +#define W_PRINCESS (PRINCESS | WHITE) +#define W_WOODY (WOODY | WHITE) +#define W_MINISTER (MINISTER | WHITE) +#define W_PRIESTESS (PRIESTESS | WHITE) +#define W_MASTODON (MASTODON | WHITE) +#define W_MAN2 (MAN2 | WHITE) +#define W_NIGHTRIDER (NIGHTRIDER | WHITE) #define B_PAWN (PAWN | BLACK) #define B_KNIGHT (KNIGHT | BLACK) #define B_BISHOP (BISHOP | BLACK) #define B_ROOK (ROOK | BLACK) +#define B_CARDINAL (CARDINAL | BLACK) +#define B_MARSHALL (MARSHALL | BLACK) +#define B_MAN (MAN | BLACK) #define B_QUEEN (QUEEN | BLACK) +#define B_ELEPHANT (ELEPHANT | BLACK) +#define B_ALFIL (ALFIL | BLACK) +#define B_FERZ (FERZ | BLACK) +#define B_WAZIR (WAZIR | BLACK) +#define B_ALFIL2 (ALFIL2 | BLACK) +#define B_FERZ2 (FERZ2 | BLACK) +#define B_AMAZON (AMAZON | BLACK) +#define B_CENTAUR (CENTAUR | BLACK) +#define B_HORSE (HORSE | BLACK) +#define B_HONORABLEHORSE (HONORABLEHORSE | BLACK) +#define B_DRAGONKING (DRAGONKING | BLACK) +#define B_DRAGONHORSE (DRAGONHORSE | BLACK) +#define B_LANCE (LANCE | BLACK) +#define B_CANNON (CANNON | BLACK) +#define B_SILVER (SILVER | BLACK) +#define B_GOLD (GOLD | BLACK) #define B_KING (KING | BLACK) +#define B_MANDARIN (MANDARIN | BLACK) +#define B_EMPRESS (EMPRESS | BLACK) +#define B_PRINCESS (PRINCESS | BLACK) +#define B_WOODY (WOODY | BLACK) +#define B_MINISTER (MINISTER | BLACK) +#define B_PRIESTESS (PRIESTESS | BLACK) +#define B_MASTODON (MASTODON | BLACK) +#define B_MAN2 (MAN2 | BLACK) +#define B_NIGHTRIDER (NIGHTRIDER | BLACK) #define isblack(p) ((p) & BLACK) #define iswhite(p) (!isblack(p)) @@ -60,29 +146,46 @@ #define colorval(p) ((p) & 0x80) #define square_color(r,f) ((((r)+(f)) & 0x01) ? BLACK : WHITE) -extern int pieceValues[7]; +extern int pieceValues[KING+1]; +#define BW 12 +#define BH 10 /* Treated as [file][rank] */ -typedef int board_t[8][8]; +typedef int board_t[BW][BH]; GENSTRUCT struct game_state_t { - int board[8][8]; + int board[BW][BH]; /* for bughouse */ - int holding[2][5]; + int holding[2][KING]; /* For castling */ - unsigned char wkmoved, wqrmoved, wkrmoved; - unsigned char bkmoved, bqrmoved, bkrmoved; + char wkmoved, wqrmoved, wkrmoved; + char bkmoved, bqrmoved, bkrmoved; /* for ep */ - int ep_possible[2][8]; + int ep_possible[2][BW]; /* For draws */ int lastIrreversable; int onMove; int moveNum; /* Game num not saved, must be restored when read */ int gameNum; + char royalKnight; + char capablancaPieces; + char pawnDblStep; + char ranks; + char files; + char holdings; + char drops; + char castlingStyle; + char palace; + char setup; + char bareKingLoses; + char stalemate; + char promoType; + char variant[20]; }; #define ALG_DROP -2 +#define ALG_CASTLE -3 /* bughouse: if a drop move, then fromFile is ALG_DROP and fromRank is piece */ @@ -103,6 +206,10 @@ GENSTRUCT struct move_t { /* these are used when examining a game */ int wTime; int bTime; + + /* [HGM] these are used for computer games */ + float score; + int depth; }; #define MoveToHalfMove( gs ) ((((gs)->moveNum - 1) * 2) + (((gs)->onMove == WHITE) ? 0 : 1)) @@ -110,6 +217,8 @@ GENSTRUCT struct move_t { extern const char *wpstring[]; extern const char *bpstring[]; +extern int kludgeFlag; // [HGM] setup: forces move nr to zero in board printing + /* the FEN for the default initial position */ #define INITIAL_FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w" diff --git a/lasker-2.2.3/src/command.c b/lasker-2.2.3/src/command.c index f779206..7d440c5 100644 --- a/lasker-2.2.3/src/command.c +++ b/lasker-2.2.3/src/command.c @@ -21,7 +21,7 @@ #include "includes.h" #include "command_list.h" -static const char *usage_dir[NUM_LANGS] = {USAGE_DIR, USAGE_SPANISH, +const char *usage_dir[NUM_LANGS] = {USAGE_DIR, USAGE_SPANISH, USAGE_FRENCH, USAGE_DANISH}; static int lastCommandFound = -1; diff --git a/lasker-2.2.3/src/config.h b/lasker-2.2.3/src/config.h index f18571c..69509ee 100644 --- a/lasker-2.2.3/src/config.h +++ b/lasker-2.2.3/src/config.h @@ -90,7 +90,7 @@ #define DEFAULT_TIME 2 #define DEFAULT_INCREMENT 12 #define DEFAULT_MAX_SOUGHT 1000 -#define DEFAULT_IDLE_TIMEOUT 3600 +#define DEFAULT_IDLE_TIMEOUT 36000 #define DEFAULT_LOGIN_TIMEOUT 300 #define DEFAULT_GUEST_PREFIX_ONLY 0 diff --git a/lasker-2.2.3/src/eco.c b/lasker-2.2.3/src/eco.c old mode 100644 new mode 100755 index bc3a115..5d13738 --- a/lasker-2.2.3/src/eco.c +++ b/lasker-2.2.3/src/eco.c @@ -48,63 +48,66 @@ static int ECO_entries, NIC_entries, LONG_entries; void FEN_to_board(char* FENpos, struct game_state_t* gs) { - int f,r; - char next; - - - for (r=7; r >=0; r--) { - f=0; - while (f<8) { - next = *(FENpos++); - if (isalpha(next)) - gs->board[f++][r] = CharToPiece(next); - else if (next != '/') { - int t = (next - '0'); - do - gs->board[f++][r] = NOPIECE; - while (--t); - } - } - } - if (*(FENpos + 1) == 'w') /* the char after the space */ - gs->onMove = WHITE; - else - gs->onMove = BLACK; + int f,r; + char next; +printf("FEN, var='%s'\n", gs->variant); + for (r=gs->ranks-1; r >=0; r--) { + f=0; + while (ffiles) { + 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; - char piece; - - for (r=7; r>=0; r--) { - count = 0; - for (f=0; f<8; f++) { - if ((piece = PieceToChar(gs->board[f][r])) != ' ') { - if (count) { - *(FENpos++) = count + '0'; - count = 0; - } - *(FENpos++) = piece; - } else { - if (f == 7) - *(FENpos++) = count + '0' + 1; - else - count++; - } - } - *(FENpos++) = '/'; - } - - *(--FENpos) = ' '; - - if (gs->onMove == WHITE) - *(++FENpos) = 'w'; - else - *(++FENpos) = 'b'; - *(++FENpos) = '\0'; + int f,r,count; + char piece; + + for (r=gs->ranks-1; r>=0; r--) { + count = 0; + for (f=0; ffiles; 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) diff --git a/lasker-2.2.3/src/gamedb.c b/lasker-2.2.3/src/gamedb.c index 76aed03..666b5ed 100644 --- a/lasker-2.2.3/src/gamedb.c +++ b/lasker-2.2.3/src/gamedb.c @@ -30,7 +30,8 @@ static int game_zero(int g); const char *TypeStrings[NUM_GAMETYPES] = {"untimed", "blitz", "standard", "nonstandard", "wild", "lightning", - "bughouse"}; + "bughouse", "gothic", "knightmate", + "capablanca"}; /* this method is awful! how about allocation as we need it and freeing afterwards! */ @@ -127,7 +128,7 @@ static char *game_time_str(int wt, int winc, int bt, int binc) return tstr; } -const char *bstr[] = {"untimed", "blitz", "standard", "non-standard", "wild", "lightning", "Bughouse"}; +const char *bstr[] = {"untimed", "blitz", "standard", "non-standard", "wild", "lightning", "Bughouse", "Gothic", "Knightmate", "Capablanca"}; const char *rstr[] = {"unrated", "rated"}; @@ -160,6 +161,12 @@ int game_isblitz(int wt, int winc, int bt, int binc, if(cat && cat[0]) { if (!strcmp(cat, "bughouse")) return TYPE_BUGHOUSE; + if (!strcmp(cat, "gothic")) + return TYPE_GOTHIC; + if (!strcmp(cat, "knightmate")) + return TYPE_KNIGHTMATE; + if (!strcmp(cat, "capablanca")) + return TYPE_CAPABLANCA; if (board && board[0]) { if (!strcmp(cat, "wild")) return TYPE_WILD; @@ -247,7 +254,14 @@ void send_boards(int g) if ((game_globals.garray[g].status != GAME_SETUP) && (check_kings(&game_globals.garray[g].game_state))) { - d_printf( "Game has invalid amount of kings. Aborting...\n"); + d_printf( "Game has invalid number of kings. Aborting...\n"); +{ int f, r; +d_printf("files = %d, ranks = %d\n", game_globals.garray[g].game_state.files, game_globals.garray[g].game_state.ranks); +for(r=0; r 0) { // [HGM] computer game, add {score/depth} comment + if ((col += sprintf(tmp, "{%s%.2f/%d} ", moves[i].score > 0 ? "+" : "", + moves[i].score, moves[i].depth)) > 70) { + strcat(gameString, "\n"); + col = 0; + } + strcat(gameString, tmp); + } } strcat(gameString, "\n"); @@ -538,7 +579,8 @@ char *movesToString(int g, int pgn) } else { strcat(gameString, "\nUnrated "); } - strcat (gameString, TypeStrings[game_globals.garray[g].type]); +// strcat (gameString, TypeStrings[game_globals.garray[g].type]); + strcat (gameString, game_globals.garray[g].variant); strcat(gameString, " match, initial time: "); if ((game_globals.garray[g].bInitTime != game_globals.garray[g].wInitTime) || (game_globals.garray[g].wIncrement != game_globals.garray[g].bIncrement)) { /* different starting times */ sprintf(tmp, "%d minutes, increment: %d seconds AND %d minutes, increment: %d seconds.\n\n", game_globals.garray[g].wInitTime / 600, game_globals.garray[g].wIncrement / 10, game_globals.garray[g].bInitTime / 600, game_globals.garray[g].bIncrement / 10); @@ -546,6 +588,45 @@ char *movesToString(int g, int pgn) sprintf(tmp, "%d minutes, increment: %d seconds.\n\n", game_globals.garray[g].wInitTime / 600, game_globals.garray[g].wIncrement / 10); } strcat(gameString, tmp); + if(game_globals.garray[g].game_state.setup) { // [HGM] setup: print the initial position board + char *q; struct game_state_t initial_gs; struct move_t ml[600]; int r, f; + + initial_gs.gameNum = g; + initial_gs.wkrmoved = 0; // [HGM] for some reason calling reset_board_vars() does not work here + initial_gs.wqrmoved = 0; // so I just duplicated the code and pasted it here... + initial_gs.wkmoved = 0; + initial_gs.bkrmoved = 0; + initial_gs.bqrmoved = 0; + initial_gs.bkmoved = 0; + initial_gs.onMove = WHITE; + initial_gs.lastIrreversable = -1; + initial_gs.files = game_globals.garray[g].game_state.files; + initial_gs.ranks = game_globals.garray[g].game_state.ranks; + initial_gs.holdings = game_globals.garray[g].game_state.holdings; + strcpy(initial_gs.variant, game_globals.garray[g].game_state.variant); + for (f = 0; f < 2; f++) { + for (r = 0; r < initial_gs.files; r++) + initial_gs.ep_possible[f][r] = 0; + for (r = PAWN; r <= QUEEN; r++) + initial_gs.holding[f][r-PAWN] = 0; + } + FEN_to_board(game_globals.garray[g].FENstartPos ,&initial_gs); + + kludgeFlag = 1; // [HGM] setup: this is not thread safe. Must it be??? + q = board_to_string( + game_globals.garray[g].white_name, + game_globals.garray[g].black_name, + game_globals.garray[g].wTime, + game_globals.garray[g].bTime, + &initial_gs, + ml, + 11, + WHITE, 0, 0); + kludgeFlag = 0; + + strcat(gameString, q); + strcat(gameString, "\n"); + } sprintf(tmp, "Move %-19s%-19s\n", game_globals.garray[g].white_name, game_globals.garray[g].black_name); strcat(gameString, tmp); strcat(gameString, "---- ---------------- ----------------\n"); @@ -584,8 +665,65 @@ void game_disconnect(int g, int p) game_ended(g, (game_globals.garray[g].white == p) ? WHITE : BLACK, END_LOSTCONNECTION); } -int CharToPiece(char c) +int CharToPiece(char c, char *variant) { + + if(variant) { + if(!strcmp(variant, "shogi")) { + switch(c) { + case 'N': + return W_HONORABLEHORSE; + case 'n': + return B_HONORABLEHORSE; + case 'L': + return W_LANCE; + case 'l': + return B_LANCE; + case 'S': + return W_SILVER; + case 's': + return B_SILVER; + case 'G': + return W_GOLD; + case 'g': + return B_GOLD; + } + } else if(!strcmp(variant, "xiangqi")) { + switch(c) { + case 'A': + return W_MANDARIN; + case 'a': + return B_MANDARIN; + case 'H': + return W_HORSE; + case 'h': + return B_HORSE; + case 'C': + return W_CANNON; + case 'c': + return B_CANNON; + } + } else if(!strcmp(variant, "super")) { + switch(c) { + case 'E': + return W_EMPRESS; + case 'e': + return B_EMPRESS; + case 'S': + return W_PRINCESS; + case 's': + return B_PRINCESS; + case 'Z': + return W_AMAZON; + case 'z': + return B_AMAZON; + case 'V': + return W_CENTAUR; + case 'v': + return B_CENTAUR; + } + } + } switch (c) { case 'P': return W_PAWN; @@ -603,10 +741,26 @@ int CharToPiece(char c) return W_ROOK; case 'r': return B_ROOK; + case 'A': + return W_CARDINAL; + case 'a': + return B_CARDINAL; + case 'C': + return W_MARSHALL; + case 'c': + return B_MARSHALL; + case 'M': + return W_MAN; + case 'm': + return B_MAN; case 'Q': return W_QUEEN; case 'q': return B_QUEEN; + case 'E': + return W_ELEPHANT; + case 'e': + return B_ELEPHANT; case 'K': return W_KING; case 'k': @@ -623,8 +777,10 @@ char PieceToChar(int piece) case B_PAWN: return 'p'; case W_KNIGHT: + case W_HONORABLEHORSE: return 'N'; case B_KNIGHT: + case B_HONORABLEHORSE: return 'n'; case W_BISHOP: return 'B'; @@ -634,14 +790,92 @@ char PieceToChar(int piece) return 'R'; case B_ROOK: return 'r'; + case W_CARDINAL: + case W_MANDARIN: + case W_ALFIL2: + return 'A'; + case B_CARDINAL: + case B_MANDARIN: + case B_ALFIL2: + return 'a'; + case W_CANNON: + case W_MARSHALL: + return 'C'; + case B_CANNON: + case B_MARSHALL: + return 'c'; + case W_MAN: + case W_MINISTER: + return 'M'; + case B_MAN: + case B_MINISTER: + return 'm'; case W_QUEEN: return 'Q'; case B_QUEEN: return 'q'; + case W_ELEPHANT: + case W_EMPRESS: + return 'E'; + case B_ELEPHANT: + case B_EMPRESS: + return 'e'; + case W_ALFIL: + return 'B'; + case B_ALFIL: + return 'b'; + case W_FERZ: + return 'Q'; + case B_FERZ: + return 'q'; + case W_FERZ2: + return 'F'; + case B_FERZ2: + return 'f'; + case W_WAZIR: + case W_WOODY: + return 'W'; + case B_WAZIR: + case B_WOODY: + return 'w'; + case W_HORSE: + case W_PRIESTESS: + case W_NIGHTRIDER: + return 'H'; + case B_HORSE: + case B_PRIESTESS: + case B_NIGHTRIDER: + return 'h'; + case W_SILVER: + case W_PRINCESS: + case W_MAN2: + return 'S'; + case B_SILVER: + case B_PRINCESS: + case B_MAN2: + return 's'; + case W_GOLD: + case W_MASTODON: + return 'G'; + case B_GOLD: + case B_MASTODON: + return 'g'; + case W_AMAZON: + return 'Z'; + case B_AMAZON: + return 'z'; + case W_CENTAUR: + return 'V'; + case B_CENTAUR: + return 'v'; case W_KING: return 'K'; case B_KING: return 'k'; + case W_LANCE: + return 'L'; + case B_LANCE: + return 'l'; default: return ' '; } @@ -779,7 +1013,10 @@ int game_read(int g, int wp, int bp) if (game_globals.garray[g].type == TYPE_BLITZ) { game_globals.garray[g].white_rating = player_globals.parray[wp].b_stats.rating; game_globals.garray[g].black_rating = player_globals.parray[bp].b_stats.rating; - } else if (game_globals.garray[g].type == TYPE_WILD) { + } else if (game_globals.garray[g].type == TYPE_WILD || + game_globals.garray[g].type == TYPE_KNIGHTMATE || + game_globals.garray[g].type == TYPE_CAPABLANCA || + game_globals.garray[g].type == TYPE_GOTHIC) { game_globals.garray[g].white_rating = player_globals.parray[wp].w_stats.rating; game_globals.garray[g].black_rating = player_globals.parray[bp].w_stats.rating; } else if (game_globals.garray[g].type == TYPE_LIGHT) { @@ -797,7 +1034,7 @@ int game_read(int g, int wp, int bp) if (!fp) { return -1; } - for (piece=PAWN; piece <= QUEEN; piece++) { + for (piece=PAWN; piece < KING; piece++) { game_globals.garray[g].game_state.holding[0][piece-PAWN] = game_globals.garray[g].game_state.holding[1][piece-PAWN] = 0; } @@ -977,7 +1214,9 @@ static void write_g_out(int g, char *file, int maxlines, int isDraw, wr = player_globals.parray[wp].b_stats.rating; br = player_globals.parray[bp].b_stats.rating; type[1] = 'b'; - } else if (game_globals.garray[g].type == TYPE_WILD) { + } else if (game_globals.garray[g].type == TYPE_WILD || + game_globals.garray[g].type == TYPE_KNIGHTMATE || + game_globals.garray[g].type == TYPE_GOTHIC) { wr = player_globals.parray[wp].w_stats.rating; br = player_globals.parray[bp].w_stats.rating; type[1] = 'w'; @@ -1458,8 +1697,8 @@ static int check_kings(struct game_state_t *gs) int f, r; - for (f = 0; f < 8; f++) { - for (r = 0; r < 8; r++) { + for (f = 0; f < gs->files; f++) { + for (r = 0; r < gs->ranks; r++) { if (gs->board[f][r] == B_KING) blackking++; if (gs->board[f][r] == W_KING) whiteking++; } diff --git a/lasker-2.2.3/src/gamedb.h b/lasker-2.2.3/src/gamedb.h index 711700c..d0249b7 100644 --- a/lasker-2.2.3/src/gamedb.h +++ b/lasker-2.2.3/src/gamedb.h @@ -36,9 +36,9 @@ GENSTRUCT enum gamestatus {GAME_EMPTY, GAME_NEW, GAME_ACTIVE, GAME_EXAMINE, GAME /* Do not change the order of these - DAV */ GENSTRUCT enum gametype {TYPE_UNTIMED, TYPE_BLITZ, TYPE_STAND, TYPE_NONSTANDARD, - TYPE_WILD, TYPE_LIGHT, TYPE_BUGHOUSE}; + TYPE_WILD, TYPE_LIGHT, TYPE_BUGHOUSE, TYPE_GOTHIC, TYPE_KNIGHTMATE, TYPE_CAPABLANCA}; -#define NUM_GAMETYPES 7 +#define NUM_GAMETYPES 10 /* OK, DAV, I'll try it another way. -- hersco */ enum ratetype {RATE_STAND, RATE_BLITZ, RATE_WILD, RATE_LIGHT, RATE_BUGHOUSE}; @@ -68,7 +68,8 @@ GENSTRUCT enum gameend { END_ADJDRAW, END_ADJWIN, END_ADJABORT, - END_COURTESYADJOURN + END_COURTESYADJOURN, + END_BARE // [HGM] bare king }; struct journal { @@ -138,6 +139,7 @@ GENSTRUCT struct game { char black_name[MAX_LOGIN_NAME]; _NULLTERM int white_rating; int black_rating; + char variant[80]; // [HGM] arbitrary variant name for sending to interface, derived from load-directory name }; extern const char *TypeStrings[NUM_GAMETYPES]; diff --git a/lasker-2.2.3/src/gamedb_old.c b/lasker-2.2.3/src/gamedb_old.c index e9d9306..15b947e 100644 --- a/lasker-2.2.3/src/gamedb_old.c +++ b/lasker-2.2.3/src/gamedb_old.c @@ -155,7 +155,7 @@ static int ReadGameState(FILE * fp, struct game_state_t *gs, int version) for (i = 0; i < 8; i++) for (j = 0; j < 8; j++) { pieceChar = getc(fp); - gs->board[i][j] = CharToPiece(pieceChar); + gs->board[i][j] = CharToPiece(pieceChar, NULL); } } if (fscanf(fp, "%d %d %d %d %d %d", diff --git a/lasker-2.2.3/src/gameproc.c b/lasker-2.2.3/src/gameproc.c index 7e2cd5d..a0dba3f 100644 --- a/lasker-2.2.3/src/gameproc.c +++ b/lasker-2.2.3/src/gameproc.c @@ -139,6 +139,11 @@ void game_ended(int g, int winner, int why) 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_RESIGN: sprintf(tmp, "%s resigns} %s", NameOfLoser, winSymbol); strcpy(EndSymbol, "Res"); @@ -335,7 +340,7 @@ void game_ended(int g, int winner, int why) 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; @@ -547,6 +552,7 @@ void process_move(int p, char *command) } if ((len = strlen(command)) > 1) { if (command[len - 2] == '=') { +printf("promo '%s'\n", command); switch (tolower(command[strlen(command) - 1])) { case 'n': pp->promote = KNIGHT; @@ -557,9 +563,41 @@ void process_move(int p, char *command) 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; default: pprintf(p, "Don't understand that move.\n"); return; @@ -567,6 +605,7 @@ void process_move(int p, char *command) } } } + switch (parse_move(command, &gg->game_state, &move, pp->promote)) { case MOVE_ILLEGAL: pprintf(p, "Illegal move.\n"); @@ -633,13 +672,19 @@ void process_move(int p, char *command) 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 */ + int victim = move.pieceCaptured, partner = gg->link; + // [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(gg->link, colorval(move.pieceCaptured) | PAWN); + update_holding(partner, colorval(victim) | PAWN); // [HGM] todo: for Shogi we would have to demote differently! else - update_holding(gg->link, move.pieceCaptured); + update_holding(partner, victim); } now = tenth_secs(); move.atTime = now; @@ -733,6 +778,22 @@ void process_move(int p, char *command) 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) @@ -1039,8 +1100,8 @@ static int player_has_mating_material(struct game_state_t *gs, int color) 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: diff --git a/lasker-2.2.3/src/help.c b/lasker-2.2.3/src/help.c index 0a8988a..be1c93e 100644 --- a/lasker-2.2.3/src/help.c +++ b/lasker-2.2.3/src/help.c @@ -21,7 +21,7 @@ #include "includes.h" -static const char *help_dir[NUM_LANGS] = {HELP_DIR, HELP_SPANISH, +const char *help_dir[NUM_LANGS] = {HELP_DIR, HELP_SPANISH, HELP_FRENCH, HELP_DANISH}; diff --git a/lasker-2.2.3/src/matchproc.c b/lasker-2.2.3/src/matchproc.c index 35f1937..020be38 100644 --- a/lasker-2.2.3/src/matchproc.c +++ b/lasker-2.2.3/src/matchproc.c @@ -23,7 +23,7 @@ #include "includes.h" const char *colorstr[] = {"", "[black] ", "[white] "}; -static const char *adjustr[] = {"", " (adjourned)"}; +const char *adjustr[] = {"", " (adjourned)"}; static void prepare_match(int g,int wt,int bt,int winc,int binc,int wp, int bp,int rated) { @@ -156,7 +156,8 @@ static void output_match_messages(int wp,int bp,int g, char* mess) player_globals.parray[bp].name, game_globals.garray[g].black_rating, rstr[game_globals.garray[g].rated], - bstr[game_globals.garray[g].type], + //bstr[game_globals.garray[g].type], + game_globals.garray[g].variant, game_globals.garray[g].wInitTime, game_globals.garray[g].wIncrement); pprintf(wp, "%s", outStr); @@ -168,7 +169,8 @@ static void output_match_messages(int wp,int bp,int g, char* mess) player_globals.parray[bp].name, mess, rstr[game_globals.garray[g].rated], - bstr[game_globals.garray[g].type]); + //bstr[game_globals.garray[g].type]); + game_globals.garray[g].variant); pprintf(wp, "%s", outStr); pprintf(bp, "%s", outStr); @@ -265,6 +267,7 @@ int create_new_match(int g, int white_player, int black_player, decline_withdraw_offers(white_player, -1, PEND_SIMUL, DO_WITHDRAW | DO_DECLINE); } + game_globals.garray[g].FENstartPos[0] = 0; // [HGM] new shuffle if (board_init(g,&game_globals.garray[g].game_state, category, board)) { pprintf(white_player, "PROBLEM LOADING BOARD. Game Aborted.\n"); pprintf(black_player, "PROBLEM LOADING BOARD. Game Aborted.\n"); @@ -279,6 +282,15 @@ int create_new_match(int g, int white_player, int black_player, else game_globals.garray[g].type = game_isblitz(wt, winc, bt, binc, category, board); + if(category && category[0]) { // [HGM] set variant string from directory for games loaded from file + if(!strcmp(category, "wild") && board) + sprintf(game_globals.garray[g].variant, "%s/%s", category, board); + else + strcpy(game_globals.garray[g].variant, category); + } + else + strcpy(game_globals.garray[g].variant, bstr[game_globals.garray[g].type]); + prepare_match(g,wt,bt,winc,binc,white_player,black_player,rated); output_match_messages(white_player,black_player,g, "Creating"); @@ -490,10 +502,47 @@ static int parse_match_string(int p, int* wt,int* bt,int* winc,int* binc, } else { strcpy(category,parsebuf); if (!strncmp("bughouse",category, strlen(category)) - && strlen(category) >= 3) { + && strlen(category) >= 3 || !strcmp("bh", category)) { strcpy(category, "bughouse"); bughouse = 1; } + // [HGM] allow some shortcuts for variant names + if(!strcmp("bh", category)) { + strcpy(category, "bughouse"); + } else + if(!strcmp("zh", category)) { + strcpy(category, "crazyhouse"); + } else + if(!strcmp("fr", category)) { + strcpy(category, "fischerandom"); + } else + if(!strcmp("sj", category)) { + strcpy(category, "shatranj"); + } else + if(!strcmp("gc", category)) { + strcpy(category, "gothic"); + } else + if(!strcmp("ca", category)) { + strcpy(category, "capablanca"); + } else + if(!strcmp("cr", category)) { + strcpy(category, "caparandom"); + } else + if(!strcmp("su", category)) { + strcpy(category, "super"); + } else + if(!strcmp("sg", category)) { + strcpy(category, "shogi"); + } else + if(!strcmp("km", category)) { + strcpy(category, "knightmate"); + } else + if(!strcmp("gr", category)) { + strcpy(category, "great"); + } else + if(!strcmp("xq", category)) { + strcpy(category, "xiangqi"); + } } } else confused = 1; @@ -503,6 +552,8 @@ static int parse_match_string(int p, int* wt,int* bt,int* winc,int* binc, pprintf(p, "Can't interpret %s in match command.\n", parsebuf); return 0; } + if(category && (!board || !board[0])) + strcpy(board, "0"); // [HGM] variants: always provide default board return 1; } diff --git a/lasker-2.2.3/src/movecheck.c b/lasker-2.2.3/src/movecheck.c old mode 100644 new mode 100755 index 81f2d37..953298c --- a/lasker-2.2.3/src/movecheck.c +++ b/lasker-2.2.3/src/movecheck.c @@ -20,6 +20,20 @@ #include "includes.h" +// [HGM] some explanation of the parser code: +// The routine parse_move() calls is_move() to recognize some simple cases, +// like OO-castle and long algebraic with or without dash. What does not fall +// in this class is handed to alg_is_move(), whch is really a continuation +// of is_move(), to recognize SAN. +// Depending on the type of move syntax, parse_move can extract from- and to-square +// immediately, or transate the OO-castling to internal from-to representation. +// Only for SAN syntax the routine alg_pars_move() is called to extract the +// given elements, (through get_move_info(), which is the same as alg_is_move(), +// xcept that it does not discard the value of the elements), and disambiguate +// the move (i.e. determines the from-square) by looking for a piece of the given +// type on the board for which the move is pseudo-legal (using legal_move() ). +// Th + /* Simply tests if the input string is a move or not. */ /* If it matches patterns below */ /* Add to this list as you improve the move parser */ @@ -99,14 +113,14 @@ int is_move(const char *mstr) } -int NextPieceLoop(board_t b, int *f, int *r, int color) +int NextPieceLoop(board_t b, int *f, int *r, int color, int w, int h) { for (;;) { (*r) = (*r) + 1; - if (*r > 7) { + if (*r >= h) { *r = 0; *f = *f + 1; - if (*f > 7) + if (*f >= w) break; } if ((b[*f][*r] != NOPIECE) && iscolor(b[*f][*r], color)) @@ -126,22 +140,22 @@ int InitPieceLoop(board_t b, int *f, int *r, int color) /* See legal_move() */ 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) return 0; - if (gs->onMove == WHITE) { - if (tr - fr == 1) return 1; - if ((fr == 1) && (tr - fr == 2) && gs->board[ff][2]==NOPIECE) return 1; - } else { - if (fr - tr == 1) return 1; - if ((fr == 6) && (fr - tr == 2) && gs->board[ff][5]==NOPIECE) return 1; - } - return 0; - } + if (ff == tf) { + if (gs->board[tf][tr] != NOPIECE && !gs->palace) return 0; // [HGM] XQ 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; + } else { + if (fr - tr == 1) return 1; + if ((fr >= gs->ranks - 1 - gs->pawnDblStep) && (fr - tr == 2) && gs->board[ff][fr-1]==NOPIECE) return 1; + } + return 0; + } if (ff != tf) { /* Capture ? */ if ((ff - tf != 1) && (tf - ff != 1)) return 0; - if ((fr - tr != 1) && (tr - fr != 1)) return 0; if (gs->onMove == WHITE) { - if (fr > tr) return 0; + if(gs->palace) return (fr >= gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns + if (tr != fr+1) return 0; if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],BLACK)) return 1; if (gs->ep_possible[0][ff] == 1) { @@ -150,7 +164,8 @@ static int legal_pawn_move( struct game_state_t *gs, int ff, int fr, int tf, int if ((tf==ff-1) && (gs->board[ff-1][fr] == B_PAWN)) return 1; } } else { - if (tr > fr) return 0; + if(gs->palace) return (fr < gs->ranks/2 && fr == tr); // [HGM] XQ promoted pawns + if (tr != fr-1) return 0; if ((gs->board[tf][tr] != NOPIECE) && iscolor(gs->board[tf][tr],WHITE)) return 1; if (gs->ep_possible[1][ff] == 1) { @@ -180,6 +195,36 @@ static int legal_knight_move(struct game_state_t * gs, int ff, int fr, int tf, i return 0; } +static int legal_horse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + int dx, dy; + + dx = ff - tf; + dy = fr - tr; + if (abs(dx) == 2) { + if (abs(dy) == 1 && gs->board[(ff+tf)/2][fr] == NOPIECE) + return 1; + } + if (abs(dy) == 2) { + if (abs(dx) == 1 && gs->board[ff][(fr+tr)/2] == NOPIECE) + return 1; + } + return 0; +} + +static int legal_honorablehorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + int dx, dy; + + dx = ff - tf; + dy = fr - tr; + if (dy == gs->onMove == WHITE ? 2 : -2) { + if (abs(dx) == 1) + return 1; + } + return 0; +} + static int legal_bishop_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) { int dx, dy, x, y; @@ -255,11 +300,82 @@ static int legal_rook_move(struct game_state_t * gs, int ff, int fr, int tf, int } } +static int legal_cannon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + int i, cnt=0; + int start, stop; + + if (ff == tf) { + if (fr < tr) { + start = fr + 1; + stop = tr - 1; + } else { + start = tr + 1; + stop = fr - 1; + } + for (i = start; i <= stop; i++) { + if (gs->board[ff][i] != NOPIECE) cnt++; + } + return (cnt == 0 && gs->board[tf][tr] == NOPIECE) || + (cnt == 1 && gs->board[tf][tr] != NOPIECE); + } else if (fr == tr) { + if (ff < tf) { + start = ff + 1; + stop = tf - 1; + } else { + start = tf + 1; + stop = ff - 1; + } + for (i = start; i <= stop; i++) { + if (gs->board[i][fr] != NOPIECE) cnt++; + } + return (cnt == 0 && gs->board[tf][tr] == NOPIECE) || + (cnt == 1 && gs->board[tf][tr] != NOPIECE); + } else { + return 0; + } +} + +static int legal_lance_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + int i; + int start, stop; + + if (ff == tf) { + if (abs(fr - tr) == 1) + return 1; + if (fr < tr) { + if(gs->onMove != WHITE) return 0; + start = fr + 1; + stop = tr - 1; + } else { + if(gs->onMove == WHITE) return 0; + start = tr + 1; + stop = fr - 1; + } + for (i = start; i <= stop; i++) { + if (gs->board[ff][i] != NOPIECE) + return 0; + } + return 1; + } +} + static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) { return legal_rook_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr); } +static int legal_cardinal_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_knight_move(gs, ff, fr, tf, tr) || legal_bishop_move(gs, ff, fr, tf, tr); +} + +static int legal_marshall_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_rook_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr); +} + /* Ckeck, if square (kf,kr) is attacked by enemy piece. * Used in castling from/through check testing. */ @@ -268,9 +384,10 @@ static int legal_queen_move(struct game_state_t * gs, int ff, int fr, int tf, in static int is_square_attacked (struct game_state_t *gs, int kf, int kr) { struct game_state_t fakeMove; + int oldk = gs->onMove == WHITE ? gs->wkmoved : gs->bkmoved; fakeMove = *gs; - fakeMove.board[4][kr] = NOPIECE; + fakeMove.board[oldk][kr] = NOPIECE; // [HGM] castle: this routine is called only when King has not moved fakeMove.board[kf][kr] = KING | fakeMove.onMove; fakeMove.onMove = CToggle (fakeMove.onMove); if (in_check(&fakeMove)) return 1; @@ -284,7 +401,7 @@ static int is_square_attacked(struct game_state_t * gs, int kf, int kr) gs->onMove = CToggle(gs->onMove); for (InitPieceLoop(gs->board, &f, &r, gs->onMove); - NextPieceLoop(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)) { gs->onMove = CToggle(gs->onMove); return 1; @@ -295,46 +412,201 @@ static int is_square_attacked(struct game_state_t * gs, int kf, int kr) } */ +static int legal_man_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + if (abs(ff - tf) > 1) + return 0; + if (abs(fr - tr) > 1) + return 0; + return 1; +} + +static int legal_wazir_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace || + tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2)) + return 0; + if (abs(ff - tf) == 1 && fr == tr) + return 1; + if (abs(fr - tr) == 1 && ff == tf) + return 1; + return 0; +} + +static int legal_dababba_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + if (abs(ff - tf) == 2 && fr == tr) + return 1; + if (abs(fr - tr) == 2 && ff == tf) + return 1; + return 0; +} + +static int legal_ferz_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + if (abs(ff - tf) != 1) + return 0; + if (abs(fr - tr) != 1) + return 0; + return 1; +} + +static int legal_mandarin_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + if(gs->palace && (tr > gs->palace && tr < gs->ranks - gs->palace || + tf < (gs->files - gs->palace)/2 || tf >= (gs->files + gs->palace)/2)) + return 0; + if (abs(ff - tf) != 1) + return 0; + if (abs(fr - tr) != 1) + return 0; + return 1; +} + +static int legal_alfil_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + if (abs(ff - tf) != 2) + return 0; + if (abs(fr - tr) != 2) + return 0; + return 1; +} + +static int legal_elephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + if (abs(ff - tf) != 2) + return 0; + if (abs(fr - tr) != 2) + return 0; + if(gs->board[(ff+tf)/2][(fr+tr)/2] != NOPIECE) return 0; // blocked + if((tr >= gs->ranks/2) != (fr >= gs->ranks/2)) return 0; // do not cross river + return 1; +} + +static int legal_gold_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_wazir_move(gs, ff, fr, tf, tr) || (abs(ff-tf) == 1 && tr == fr + (gs->onMove==WHITE ? 1 : -1)); +} + +static int legal_silver_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_ferz_move(gs, ff, fr, tf, tr) || (tf == ff && tr == fr + (gs->onMove==WHITE ? 1 : -1) ); +} + +static int legal_woody_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_wazir_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr); +} + +static int legal_squirrel_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_alfil_move(gs, ff, fr, tf, tr) || legal_dababba_move(gs, ff, fr, tf, tr) + || legal_knight_move(gs, ff, fr, tf, tr); +} + +static int legal_mastodon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_man_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr) + || legal_dababba_move(gs, ff, fr, tf, tr); +} + +static int legal_centaur_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_man_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr); +} + +static int legal_amazon_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_queen_move(gs, ff, fr, tf, tr) || legal_knight_move(gs, ff, fr, tf, tr); +} + +static int legal_dragonking_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_rook_move(gs, ff, fr, tf, tr) || legal_ferz_move(gs, ff, fr, tf, tr); +} + +static int legal_dragonhorse_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_bishop_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr); +} + +static int legal_modernelephant_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_ferz_move(gs, ff, fr, tf, tr) || legal_alfil_move(gs, ff, fr, tf, tr); +} + +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) + || legal_alfil_move(gs, ff, fr, tf, tr); +} + +static int legal_minister_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) +{ + return legal_knight_move(gs, ff, fr, tf, tr) || legal_wazir_move(gs, ff, fr, tf, tr) + || legal_dababba_move(gs, ff, fr, tf, tr); +} + static int legal_king_move(struct game_state_t * gs, int ff, int fr, int tf, int tr) { - if (gs->onMove == WHITE) { - /* King side castling */ - if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 6) && !gs->wkmoved - && (!gs->wkrmoved) && (gs->board[5][0] == NOPIECE) && - (gs->board[6][0] == NOPIECE) && (gs->board[7][0] == W_ROOK) && - (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 5, 0))) { - return 1; - } - /* Queen side castling */ - if ((fr == 0) && (tr == 0) && (ff == 4) && (tf == 2) && !gs->wkmoved - && (!gs->wqrmoved) && (gs->board[3][0] == NOPIECE) && - (gs->board[2][0] == NOPIECE) && (gs->board[1][0] == NOPIECE) && - (gs->board[0][0] == W_ROOK) && - (!is_square_attacked(gs, 4, 0)) && (!is_square_attacked(gs, 3, 0))) { - return 1; - } - } else { /* Black */ - /* King side castling */ - if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 6) && !gs->bkmoved - && (!gs->bkrmoved) && (gs->board[5][7] == NOPIECE) && - (gs->board[6][7] == NOPIECE) && (gs->board[7][7] == B_ROOK) && - (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 5, 7))) { - return 1; - } - /* Queen side castling */ - if ((fr == 7) && (tr == 7) && (ff == 4) && (tf == 2) && (!gs->bkmoved) - && (!gs->bqrmoved) && (gs->board[3][7] == NOPIECE) && - (gs->board[2][7] == NOPIECE) && (gs->board[1][7] == NOPIECE) && - (gs->board[0][7] == B_ROOK) && - (!is_square_attacked(gs, 4, 7)) && (!is_square_attacked(gs, 3, 7))) { + int result; + + // [HGM] castle: test first if valid as regular King move; result = 1 or 0 + if(gs->royalKnight) + result = legal_knight_move(gs, ff, fr, tf, tr); + else if(gs->palace) { + result = legal_wazir_move(gs, ff, fr, tf, tr); + if(!result && ff == tf && piecetype(gs->board[tf][tr]) == KING) { // XQ regicide + int i, d = (tr>fr ? 1 : -1); + for(i=fr+d; i!=tr; i+=d) + if(gs->board[ff][i] != NOPIECE) return 0; // line of sight blocked return 1; } + } else + result = legal_man_move(gs, ff, fr, tf, tr); + + if(result) return 1; + // [HGM] castle: orthodox legal castlings given as King move return 2 + + 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) && + (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) && + (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)) && + (!is_square_attacked(gs, gs->files/2, 0)) && (!is_square_attacked(gs, 3, 0))) { + return 2; + } + } 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) && + (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) && + (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)) && + (!is_square_attacked(gs, gs->files/2, gs->ranks-1)) && (!is_square_attacked(gs, 3, gs->ranks-1))) { + return 2; + } } - if (abs(ff - tf) > 1) - return 0; - if (abs(fr - tr) > 1) - return 0; - return 1; + + return 0; // neither regular King move nor castling } static void add_pos(int tof, int tor, int *posf, int *posr, int *numpos) @@ -348,206 +620,371 @@ static void possible_pawn_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) { - if (gs->onMove == WHITE) { - if (gs->board[onf][onr + 1] == NOPIECE) { - add_pos(onf, onr + 1, posf, posr, numpos); - if ((onr == 1) && (gs->board[onf][onr + 2] == NOPIECE)) - add_pos(onf, onr + 2, posf, posr, numpos); - } - if ((onf > 0) && (gs->board[onf - 1][onr + 1] != NOPIECE) && - (iscolor(gs->board[onf - 1][onr + 1], BLACK))) - add_pos(onf - 1, onr + 1, posf, posr, numpos); - if ((onf < 7) && (gs->board[onf + 1][onr + 1] != NOPIECE) && - (iscolor(gs->board[onf + 1][onr + 1], BLACK))) + if (gs->onMove == WHITE) { + if (gs->board[onf][onr + 1] == NOPIECE || gs->palace) { + 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)) + 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)) + 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 (gs->ep_possible[0][onf] == -1) + add_pos(onf - 1, onr + 1, posf, posr, numpos); + if (gs->ep_possible[0][onf] == 1) add_pos(onf + 1, onr + 1, posf, posr, numpos); - if (gs->ep_possible[0][onf] == -1) - add_pos(onf - 1, onr + 1, posf, posr, numpos); - if (gs->ep_possible[0][onf] == 1) - add_pos(onf + 1, onr + 1, posf, posr, numpos); - } else { - if (gs->board[onf][onr - 1] == NOPIECE) { - add_pos(onf, onr - 1, posf, posr, numpos); - if ((onr == 6) && (gs->board[onf][onr - 2] == NOPIECE)) - add_pos(onf, onr - 2, posf, posr, numpos); - } - if ((onf > 0) && (gs->board[onf - 1][onr - 1] != NOPIECE) && - (iscolor(gs->board[onf - 1][onr - 1], WHITE))) - add_pos(onf - 1, onr - 1, posf, posr, numpos); -/* loon: changed what looks like a typo, here's the original line: - add_pos(onf - 1, onr + 1, posf, posr, numpos); -*/ - if ((onf < 7) && (gs->board[onf + 1][onr - 1] != NOPIECE) && - (iscolor(gs->board[onf + 1][onr - 1], WHITE))) - add_pos(onf + 1, onr - 1, posf, posr, numpos); - if (gs->ep_possible[1][onf] == -1) - add_pos(onf - 1, onr - 1, posf, posr, numpos); - if (gs->ep_possible[1][onf] == 1) - add_pos(onf + 1, onr - 1, posf, posr, numpos); - } + } else { + if (gs->board[onf][onr - 1] == NOPIECE || gs->palace) { + 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)) + 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)) + 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 (gs->ep_possible[1][onf] == -1) + add_pos(onf - 1, onr - 1, posf, posr, numpos); + if (gs->ep_possible[1][onf] == 1) + add_pos(onf + 1, onr - 1, posf, posr, numpos); + } } static void possible_knight_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) { - static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1}, - {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}}; - int f, r; - int j; + static int knightJumps[8][2] = {{-1, 2}, {1, 2}, {2, -1}, {2, 1}, + {-1, -2}, {1, -2}, {-2, 1}, {-2, -1}}; + int f, r; + int j; + + for (j = 0; j < 8; j++) { + f = knightJumps[j][0] + onf; + r = knightJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } +} - for (j = 0; j < 8; j++) { - f = knightJumps[j][0] + onf; - r = knightJumps[j][1] + onr; - if ((f < 0) || (f > 7)) - continue; - if ((r < 0) || (r > 7)) - continue; - if ((gs->board[f][r] == NOPIECE) || - (iscolor(gs->board[f][r], CToggle(gs->onMove)))) - add_pos(f, r, posf, posr, numpos); - } +static void possible_horse_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + static int knightJumps[8][4] = {{-1, 2, 0, 1}, {1, 2, 0, 1}, {2, -1, 1, 0}, {2, 1, 1, 0}, + {-1, -2, 0, -1}, {1, -2, 0, -1}, {-2, 1, -1, 0}, {-2, -1, -1, 0}}; + int f, r; + int j; + + for (j = 0; j < 8; j++) { + f = knightJumps[j][0] + onf; + r = knightJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if ((gs->board[knightJumps[j][2] + onf][knightJumps[j][3] + onr] == NOPIECE) && + ((gs->board[f][r] == NOPIECE) || (iscolor(gs->board[f][r], CToggle(gs->onMove))))) + add_pos(f, r, posf, posr, numpos); + } } static void possible_bishop_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) { - int f, r; - - /* Up Left */ - f = onf; - r = onr; - for (;;) { - f--; - r++; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } - /* Up Right */ - f = onf; - r = onr; - for (;;) { - f++; - r++; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } - /* Down Left */ - f = onf; - r = onr; - for (;;) { - f--; - r--; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } - /* Down Right */ - f = onf; - r = onr; - for (;;) { - f++; - r--; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } + int f, r; + + /* Up Left */ + f = onf; + r = onr; + for (;;) { + f--; + r++; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Up Right */ + f = onf; + r = onr; + for (;;) { + f++; + r++; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down Left */ + f = onf; + r = onr; + for (;;) { + f--; + r--; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down Right */ + f = onf; + r = onr; + for (;;) { + f++; + r--; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } } static void possible_rook_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) { - int f, r; + int f, r; + + /* Left */ + f = onf; + r = onr; + for (;;) { + f--; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Right */ + f = onf; + r = onr; + for (;;) { + f++; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Up */ + f = onf; + r = onr; + for (;;) { + r++; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down */ + f = onf; + r = onr; + for (;;) { + r--; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } +} - /* Left */ - f = onf; - r = onr; - for (;;) { - f--; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } - /* Right */ - f = onf; - r = onr; - for (;;) { - f++; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } - /* Up */ - f = onf; - r = onr; - for (;;) { - r++; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } - /* Down */ - f = onf; - r = onr; - for (;;) { - r--; - if ((f < 0) || (f > 7)) - break; - if ((r < 0) || (r > 7)) - break; - if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) - break; - add_pos(f, r, posf, posr, numpos); - if (gs->board[f][r] != NOPIECE) - break; - } +static void possible_cannon_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + int f, r, i; + + /* Left */ + f = onf; + r = onr; + for (i=0;;) { + f--; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue; + if(i == 0) + add_pos(f, r, posf, posr, numpos); // no hop: non-capt + else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) + add_pos(f, r, posf, posr, numpos); // hop: capt + if (gs->board[f][r] != NOPIECE) + break; + } + /* Right */ + f = onf; + r = onr; + for (i=0;;) { + f++; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue; + if(i == 0) + add_pos(f, r, posf, posr, numpos); // no hop: non-capt + else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) + add_pos(f, r, posf, posr, numpos); // hop: capt + if (gs->board[f][r] != NOPIECE) + break; + } + /* Up */ + f = onf; + r = onr; + for (i=0;;) { + r++; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue; + if(i == 0) + add_pos(f, r, posf, posr, numpos); // no hop: non-capt + else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) + add_pos(f, r, posf, posr, numpos); // hop: capt + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down */ + f = onf; + r = onr; + for (i=0;;) { + r--; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && i++ == 0) continue; + if(i == 0) + add_pos(f, r, posf, posr, numpos); // no hop: non-capt + else if(i == 2 && !iscolor(gs->board[f][r], gs->onMove)) + add_pos(f, r, posf, posr, numpos); // hop: capt + if (gs->board[f][r] != NOPIECE) + break; + } } +static void possible_lance_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + int f, r; + + /* Up */ + f = onf; + r = onr; + for (;gs->onMove == WHITE;) { + r++; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } + /* Down */ + f = onf; + r = onr; + for (;gs->onMove == BLACK;) { + r--; + if ((f < 0) || (f >= gs->files)) + break; + if ((r < 0) || (r >= gs->ranks)) + break; + if ((gs->board[f][r] != NOPIECE) && (iscolor(gs->board[f][r], gs->onMove))) + break; + add_pos(f, r, posf, posr, numpos); + if (gs->board[f][r] != NOPIECE) + break; + } +} + +static void possible_cardinal_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_knight_moves(gs, onf, onr, posf, posr, numpos); + possible_bishop_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_marshall_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_rook_moves(gs, onf, onr, posf, posr, numpos); + possible_knight_moves(gs, onf, onr, posf, posr, numpos); +} + static void possible_queen_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) @@ -556,28 +993,295 @@ static void possible_queen_moves(struct game_state_t * gs, possible_bishop_moves(gs, onf, onr, posf, posr, numpos); } +static void possible_alfil_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}}; + int f, r; + int j; + + for (j = 0; j < 4; j++) { + f = 2*kingJumps[j][0] + onf; + r = 2*kingJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } +} + +static void possible_ferz_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}}; + int f, r; + int j; + + for (j = 0; j < 4; j++) { + f = kingJumps[j][0] + onf; + r = kingJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } +} + +static void possible_mandarin_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}}; + int f, r; + int j; + + for (j = 0; j < 4; j++) { + f = kingJumps[j][0] + onf; + r = kingJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace || + f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } +} + +static void possible_wazir_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; + int f, r; + int j; + + for (j = 0; j < 4; j++) { + f = kingJumps[j][0] + onf; + r = kingJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if(gs->palace && (r >= gs->palace && r < gs->ranks - gs->palace || + f < (gs->files - gs->palace)/2 || f >= (gs->files + gs->palace)/2)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } +} + +static void possible_dababba_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + static int kingJumps[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}}; + int f, r; + int j; + + for (j = 0; j < 4; j++) { + f = 2*kingJumps[j][0] + onf; + r = 2*kingJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove)))) + add_pos(f, r, posf, posr, numpos); + } +} + +static void possible_man_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_wazir_moves(gs, onf, onr, posf, posr, numpos); + possible_ferz_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_dragonking_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_rook_moves(gs, onf, onr, posf, posr, numpos); + possible_ferz_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_dragonhorse_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_wazir_moves(gs, onf, onr, posf, posr, numpos); + possible_bishop_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_centaur_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_man_moves(gs, onf, onr, posf, posr, numpos); + possible_knight_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_woody_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_wazir_moves(gs, onf, onr, posf, posr, numpos); + possible_dababba_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_squirrel_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_alfil_moves(gs, onf, onr, posf, posr, numpos); + possible_dababba_moves(gs, onf, onr, posf, posr, numpos); + possible_knight_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_mastodon_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_man_moves(gs, onf, onr, posf, posr, numpos); + possible_alfil_moves(gs, onf, onr, posf, posr, numpos); + possible_dababba_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_amazon_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_queen_moves(gs, onf, onr, posf, posr, numpos); + possible_knight_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_modernelephant_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_ferz_moves(gs, onf, onr, posf, posr, numpos); + possible_alfil_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_priestess_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_ferz_moves(gs, onf, onr, posf, posr, numpos); + possible_alfil_moves(gs, onf, onr, posf, posr, numpos); + possible_knight_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_minister_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_wazir_moves(gs, onf, onr, posf, posr, numpos); + possible_dababba_moves(gs, onf, onr, posf, posr, numpos); + possible_knight_moves(gs, onf, onr, posf, posr, numpos); +} + +static void possible_gold_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_wazir_moves(gs, onf, onr, posf, posr, numpos); + if(gs->onMove == WHITE) { + if(onr < gs->ranks-1) + if(onf > 0 && !iscolor(gs->board[onf-1][onr+1], WHITE)) + add_pos(onf-1, onr+1, posf, posr, numpos); + if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr+1], WHITE)) + add_pos(onf+1, onr+1, posf, posr, numpos); + } else { + if(onr > 0) + if(onf > 0 && !iscolor(gs->board[onf-1][onr-1], BLACK)) + add_pos(onf-1, onr-1, posf, posr, numpos); + if(onf < gs->files-1 && !iscolor(gs->board[onf+1][onr-1], BLACK)) + add_pos(onf+1, onr-1, posf, posr, numpos); + } +} + +static void possible_silver_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + possible_ferz_moves(gs, onf, onr, posf, posr, numpos); + if(gs->onMove == WHITE) { + if(onr < gs->ranks-1 && !iscolor(gs->board[onf][onr+1], WHITE)) + add_pos(onf, onr+1, posf, posr, numpos); + } else { + if(onr > 0 && !iscolor(gs->board[onf][onr-1], BLACK)) + add_pos(onf, onr-1, posf, posr, numpos); + } +} + +static void possible_honorablehorse_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + int f, r = onr + (gs->onMove == WHITE ? 2 : -2); + + if(r < 0 || r >= gs->ranks) return; + if(onf > 0) { + if ((gs->board[onf-1][r] == NOPIECE) || + (iscolor(gs->board[onf-1][r], CToggle(gs->onMove)))) + add_pos(onf - 1, r, posf, posr, numpos); + } + if(onf < gs->files - 1) { + if ((gs->board[onf+1][r] == NOPIECE) || + (iscolor(gs->board[onf+1][r], CToggle(gs->onMove)))) + add_pos(onf + 1, r, posf, posr, numpos); + } +} + static void possible_king_moves(struct game_state_t * gs, int onf, int onr, int *posf, int *posr, int *numpos) { - static int kingJumps[8][2] = {{-1, -1}, {0, -1}, {1, -1}, {-1, 1}, - {0, 1}, {1, 1}, {-1, 0}, {1, 0}}; - int f, r; - int j; - - for (j = 0; j < 8; j++) { - f = kingJumps[j][0] + onf; - r = kingJumps[j][1] + onr; - if ((f < 0) || (f > 7)) - continue; - if ((r < 0) || (r > 7)) - continue; - if ((gs->board[f][r] == NOPIECE) || - (iscolor(gs->board[f][r], CToggle(gs->onMove)))) - add_pos(f, r, posf, posr, numpos); - } + if(gs->royalKnight) + possible_knight_moves(gs, onf, onr, posf, posr, numpos); + else if(gs->palace) + possible_wazir_moves(gs, onf, onr, posf, posr, numpos); + else + possible_man_moves(gs, onf, onr, posf, posr, numpos); } +static void possible_elephant_moves(struct game_state_t * gs, + int onf, int onr, + int *posf, int *posr, int *numpos) +{ + static int kingJumps[4][2] = {{-1, -1}, {1, -1}, {-1, 1}, {1, 1}}; + int f, r; + int j; + + for (j = 0; j < 4; j++) { + f = 2*kingJumps[j][0] + onf; + r = 2*kingJumps[j][1] + onr; + if ((f < 0) || (f >= gs->files)) + continue; + if ((r < 0) || (r >= gs->ranks)) + continue; + if ((gs->board[(f+onf)/2][(r+onr)/2] == NOPIECE) && ((gs->board[f][r] == NOPIECE) || + (iscolor(gs->board[f][r], CToggle(gs->onMove))))) + add_pos(f, r, posf, posr, numpos); + } +} + /* Doesn't check for check */ int legal_move(struct game_state_t * gs, int fFile, int fRank, @@ -588,15 +1292,57 @@ int legal_move(struct game_state_t * gs, if (fFile == ALG_DROP) { move_piece = fRank; + if(!gs->drops) 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) return 0; if (gs->board[tFile][tRank] != NOPIECE) return 0; - if (move_piece == PAWN && (tRank == 0 || tRank == 7)) + if (move_piece == PAWN && (tRank == 0 || tRank == gs->ranks-1)) return 0; return 1; + } else if(fFile == ALG_CASTLE) { + // [HGM] castle: this code can handle any type of free castling + // it does not check if Rook and King from squares correspond to the rights, as the + // user never enters such squares, but they are copied from the rights on entering o-o-o + int backRank, kRook, qRook, fKing, leftEmpty, rightEmpty, leftCheck, rightCheck, f; + if(!gs->castlingStyle) return 0; // no castling in this variant + if(gs->onMove == WHITE) { + if(gs->wkmoved < 0) return 0; // King moved + fKing = gs->wkmoved; + backRank = 0; + kRook = gs->wkrmoved; + qRook = gs->wqrmoved; + } else { + if(gs->bkmoved < 0) return 0; // King moved + fKing = gs->bkmoved; + backRank = gs->ranks-1; + kRook = gs->bkrmoved; + qRook = gs->bqrmoved; + } + if((tRank > tFile ? qRook : kRook) < 0) return 0; // Rook moved + // here we verified rights do exist, so from squares (fRank and fKing) must be valid + if(gs->board[fRank][backRank] != (ROOK | gs->onMove) ) return 0; // only with own Rook + if(gs->board[fKing][backRank] != (KING | gs->onMove) ) return 0; // only with own King + + // by now we know that K and R are in correct position, and still have rights + if(tRank > tFile) { // R ends right of K: q-side + leftEmpty = fRank < tFile ? fRank+1 : tFile+1; + rightEmpty = tRank < fKing ? fKing-1 : tRank-1; + } else { // k-side + leftEmpty = tRank < fKing ? tRank+1 : fKing+1; + rightEmpty = fRank < tFile ? fRank-1 : tFile-1; + } + for(f=leftEmpty; f<=rightEmpty; f++) // check if other pieces block castling + if(f != fRank && f != fKing && gs->board[f][backRank] != NOPIECE) return 0; + + leftCheck = fKing < tFile ? fKing : tFile+1; + rightCheck = fKing < tFile ? tFile-1 : fKing; + for(f=leftCheck; f<=rightCheck; f++) // check if King passes attacked square or was in check + if(is_square_attacked(gs, f, backRank)) return 0; + + return 1; // passed all tests } else { move_piece = piecetype(gs->board[fFile][fRank]); } @@ -622,9 +1368,86 @@ int legal_move(struct game_state_t * gs, case ROOK: legal = legal_rook_move(gs, fFile, fRank, tFile, tRank); break; + case CARDINAL: + case PRINCESS: + legal = legal_cardinal_move(gs, fFile, fRank, tFile, tRank); + break; + case MARSHALL: + case EMPRESS: + legal = legal_marshall_move(gs, fFile, fRank, tFile, tRank); + break; + case MAN: + case MAN2: + legal = legal_man_move(gs, fFile, fRank, tFile, tRank); + break; case QUEEN: legal = legal_queen_move(gs, fFile, fRank, tFile, tRank); break; + case ELEPHANT: + legal = legal_elephant_move(gs, fFile, fRank, tFile, tRank); + break; + case AMAZON: + legal = legal_amazon_move(gs, fFile, fRank, tFile, tRank); + break; + case WOODY: + legal = legal_woody_move(gs, fFile, fRank, tFile, tRank); + break; + case SQUIRREL: + legal = legal_squirrel_move(gs, fFile, fRank, tFile, tRank); + break; + case MASTODON: + legal = legal_mastodon_move(gs, fFile, fRank, tFile, tRank); + break; + case CENTAUR: + legal = legal_centaur_move(gs, fFile, fRank, tFile, tRank); + break; + case HORSE: + legal = legal_horse_move(gs, fFile, fRank, tFile, tRank); + break; + case FERZ: + case FERZ2: + legal = legal_ferz_move(gs, fFile, fRank, tFile, tRank); + break; + case MANDARIN: + legal = legal_mandarin_move(gs, fFile, fRank, tFile, tRank); + break; + case WAZIR: + legal = legal_wazir_move(gs, fFile, fRank, tFile, tRank); + break; + case ALFIL: + case ALFIL2: + legal = legal_alfil_move(gs, fFile, fRank, tFile, tRank); + break; + case MODERNELEPHANT: + legal = legal_modernelephant_move(gs, fFile, fRank, tFile, tRank); + break; + case PRIESTESS: + legal = legal_priestess_move(gs, fFile, fRank, tFile, tRank); + break; + case MINISTER: + legal = legal_minister_move(gs, fFile, fRank, tFile, tRank); + break; + case SILVER: + legal = legal_silver_move(gs, fFile, fRank, tFile, tRank); + break; + case GOLD: + legal = legal_gold_move(gs, fFile, fRank, tFile, tRank); + break; + case LANCE: + legal = legal_lance_move(gs, fFile, fRank, tFile, tRank); + break; + case CANNON: + legal = legal_cannon_move(gs, fFile, fRank, tFile, tRank); + break; + case DRAGONHORSE: + legal = legal_dragonhorse_move(gs, fFile, fRank, tFile, tRank); + break; + case DRAGONKING: + legal = legal_dragonking_move(gs, fFile, fRank, tFile, tRank); + break; + case HONORABLEHORSE: + legal = legal_honorablehorse_move(gs, fFile, fRank, tFile, tRank); + break; case KING: legal = legal_king_move(gs, fFile, fRank, tFile, tRank); break; @@ -641,57 +1464,69 @@ int legal_move(struct game_state_t * gs, * the move is legal. Returns MOVE_ILLEGAL if move leaves you in check */ static int move_calculate(struct game_state_t * gs, struct move_t * mt, int promote) { - struct game_state_t fakeMove; - - mt->pieceCaptured = gs->board[mt->toFile][mt->toRank]; - mt->enPassant = 0; /* Don't know yet, let execute move take care - of it */ - if (mt->fromFile == ALG_DROP) { - mt->piecePromotionTo = NOPIECE; - sprintf(mt->moveString, "%s/%c%c-%c%d", - wpstring[mt->fromRank], - DROP_CHAR, DROP_CHAR, - mt->toFile + 'a', mt->toRank + 1); + struct game_state_t fakeMove; + + mt->pieceCaptured = gs->board[mt->toFile][mt->toRank]; + mt->enPassant = 0; /* Don't know yet, let execute move take care + of it */ + if (mt->fromFile == ALG_DROP) { + mt->piecePromotionTo = NOPIECE; + sprintf(mt->moveString, "%s/%c%c-%c%d", + wpstring[mt->fromRank], + DROP_CHAR, DROP_CHAR, + mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9)); + } 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"); } else { - if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && - ((mt->toRank == 0) || (mt->toRank == 7))) { - mt->piecePromotionTo = promote | - (colorval(gs->board[mt->fromFile][mt->fromRank])); - } else { - mt->piecePromotionTo = NOPIECE; + 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))) { + if(!gs->pawnDblStep && promote == PRINCESS) promote = MAN2; + if(!gs->pawnDblStep && promote != FERZ2 && promote != MAN2) promote = FERZ; // [HGM] kludge to recognize shatranj + mt->piecePromotionTo = promote | + (colorval(gs->board[mt->fromFile][mt->fromRank])); + } else { + mt->piecePromotionTo = NOPIECE; + } + if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && + ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) { + mt->doublePawn = mt->fromFile; + } else { + mt->doublePawn = -1; } - if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == PAWN) && - ((mt->fromRank - mt->toRank == 2) || (mt->toRank - mt->fromRank == 2))) { - mt->doublePawn = mt->fromFile; - } else { - mt->doublePawn = -1; - } - if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) && - (mt->fromFile == 4) && (mt->toFile == 2)) { - sprintf(mt->moveString, "o-o-o"); - } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) && - (mt->fromFile == 4) && (mt->toFile == 6)) { +#if 0 + if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) && + (mt->fromFile == gs->files/2) && (mt->toFile == 2) && + mt->fromRank == mt->toRank) { + sprintf(mt->moveString, "o-o-o"); + } else if ((piecetype(gs->board[mt->fromFile][mt->fromRank]) == KING) && + (mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2) && + mt->fromRank == mt->toRank) { sprintf(mt->moveString, "o-o"); } else { - sprintf(mt->moveString, "%s/%c%d-%c%d", - wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])], - mt->fromFile + 'a', mt->fromRank + 1, - mt->toFile + 'a', mt->toRank + 1); - } - } - /* Replace this with an algabraic de-parser */ - - sprintf(mt->algString, alg_unparse(gs, mt)); - fakeMove = *gs; - /* Calculates enPassant also */ - execute_move(&fakeMove, mt, 0); - - /* Does making this move leave ME in check? */ - if (in_check(&fakeMove)) - return MOVE_ILLEGAL; - /* IanO: bughouse variants: drop cannot be check/checkmate */ - - return MOVE_OK; +#else + { +#endif + sprintf(mt->moveString, "%s/%c%d-%c%d", + wpstring[piecetype(gs->board[mt->fromFile][mt->fromRank])], + mt->fromFile + 'a', mt->fromRank + 1 - (gs->ranks>9), + mt->toFile + 'a', mt->toRank + 1 - (gs->ranks>9)); + } + } + /* Replace this with an algabraic de-parser */ + + sprintf(mt->algString, alg_unparse(gs, mt)); + fakeMove = *gs; + /* Calculates enPassant also */ + execute_move(&fakeMove, mt, 0); + + /* Does making this move leave ME in check? */ + if (in_check(&fakeMove)) + return MOVE_ILLEGAL; + /* IanO: bughouse variants: drop cannot be check/checkmate */ + + return MOVE_OK; } int legal_andcheck_move(struct game_state_t * gs, @@ -717,36 +1552,36 @@ int legal_andcheck_move(struct game_state_t * gs, */ int in_check(struct game_state_t * gs) { - int f, r; - int kf = -1, kr = -1; - - /* Find the king */ - if (gs->onMove == WHITE) { - for (f = 0; f < 8 && kf < 0; f++) - for (r = 0; r < 8 && kf < 0; r++) - if (gs->board[f][r] == B_KING) { - kf = f; - kr = r; - } - } else { - for (f = 0; f < 8 && kf < 0; f++) - for (r = 0; r < 8 && kf < 0; r++) - if (gs->board[f][r] == W_KING) { - kf = f; - kr = r; - } - } - if (kf < 0) { - d_printf( "CHESSD: Error game with no king!\n"); - return 0; - } - for (InitPieceLoop(gs->board, &f, &r, gs->onMove); - NextPieceLoop(gs->board, &f, &r, gs->onMove);) { - if (legal_move(gs, f, r, kf, kr)) { /* In Check? */ - return 1; - } - } - return 0; + int f, r; + int kf = -1, kr = -1; + + /* Find the king */ + if (gs->onMove == WHITE) { + for (f = 0; f < gs->files && kf < 0; f++) + for (r = 0; r < gs->ranks && kf < 0; r++) + if (gs->board[f][r] == B_KING) { + kf = f; + kr = r; + } + } else { + for (f = 0; f < gs->files && kf < 0; f++) + for (r = 0; r < gs->ranks && kf < 0; r++) + if (gs->board[f][r] == W_KING) { + kf = f; + kr = r; + } + } + if (kf < 0) { + d_printf( "CHESSD: Error game with no king!\n"); + return 0; + } + 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? */ + return 1; + } + } + return 0; } int has_legal_move(struct game_state_t * gs) @@ -758,7 +1593,7 @@ int has_legal_move(struct game_state_t * gs) int numpossible = 0; for (InitPieceLoop(gs->board, &f, &r, gs->onMove); - NextPieceLoop(gs->board, &f, &r, gs->onMove);) { + NextPieceLoop(gs->board, &f, &r, gs->onMove, gs->files, gs->ranks);) { switch (piecetype(gs->board[f][r])) { case PAWN: possible_pawn_moves(gs, f, r, possiblef, possibler, &numpossible); @@ -772,9 +1607,86 @@ int has_legal_move(struct game_state_t * gs) case ROOK: possible_rook_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case CARDINAL: + case PRINCESS: + possible_cardinal_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case MARSHALL: + case EMPRESS: + possible_marshall_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case MAN: + case MAN2: + possible_man_moves(gs, f, r, possiblef, possibler, &numpossible); + break; case QUEEN: possible_queen_moves(gs, f, r, possiblef, possibler, &numpossible); break; + case ELEPHANT: + possible_elephant_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case AMAZON: + possible_amazon_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case WOODY: + possible_woody_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case SQUIRREL: + possible_squirrel_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case MASTODON: + possible_mastodon_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case CENTAUR: + possible_centaur_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case HORSE: + possible_horse_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case FERZ: + case FERZ2: + possible_ferz_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case MANDARIN: + possible_mandarin_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case WAZIR: + possible_wazir_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case ALFIL: + case ALFIL2: + possible_alfil_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case MODERNELEPHANT: + possible_modernelephant_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case PRIESTESS: + possible_priestess_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case MINISTER: + possible_minister_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case SILVER: + possible_silver_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case GOLD: + possible_gold_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case CANNON: + possible_cannon_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case LANCE: + possible_lance_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case DRAGONHORSE: + possible_dragonhorse_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case DRAGONKING: + possible_dragonking_moves(gs, f, r, possiblef, possibler, &numpossible); + break; + case HONORABLEHORSE: + possible_honorablehorse_moves(gs, f, r, possiblef, possibler, &numpossible); + break; case KING: kf = f; kr = r; @@ -790,21 +1702,31 @@ int has_legal_move(struct game_state_t * gs) } } - /* IanO: if we got here, then kf and kr must be set */ - if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0) { - /* bughouse: potential drops as check interpositions */ - gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++; - for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) { - if (f>=0 && f<8 && r>=0 && r<8 && gs->board[f][r] == NOPIECE) { - /* try a drop next to the king */ - if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) { + /* IanO: if we got here, then kf and kr must be set */ + if (gs->gameNum >=0 && game_globals.garray[gs->gameNum].link >= 0 + || gs->holdings) { // [HGM] zh: also in 2-player games with drops + /* bughouse: potential drops as check interpositions */ + gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]++; + for (f=kf-1; f<=kf+1; f++) for (r=kr-1; r<=kr+1; r++) { + if (f>=0 && ffiles && r>=0 && rranks && gs->board[f][r] == NOPIECE) { + /* try a drop next to the king */ + if (legal_andcheck_move(gs, ALG_DROP, QUEEN, f, r)) { gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--; - return 1; - } - } - } - gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--; - } + // OK, so we have an interposing drop. But do we have something to drop? + if(game_globals.garray[gs->gameNum].link < 0) { + // we have no partner, so we must have something to drop now + for(i=QUEEN; i>=PAWN; i--) + if(gs->holding[gs->onMove==WHITE ? 0 : 1][i-1]) break; + if(i > PAWN) return 1; // we have a non-Pawn to drop + // We have a Pawn, but check if it legal to drop it + if(i == PAWN && r != 0 && r != gs->ranks-1) return 1; // [HGM] todo: for Shogi there are extra conditions on Pawn drops! + } + return 1; + } + } + } + gs->holding[gs->onMove==WHITE ? 0 : 1][QUEEN - 1]--; + } return 0; } @@ -812,67 +1734,97 @@ int has_legal_move(struct game_state_t * gs) /* This will end up being a very complicated function */ int parse_move(char *mstr, struct game_state_t * gs, struct move_t * mt, int promote) { - int type = is_move(mstr); - int result; - - mt->piecePromotionTo = NOPIECE; - mt->color = gs->onMove; - switch (type) { - case MS_NOTMOVE: - return MOVE_ILLEGAL; - break; - case MS_COMP: - mt->fromFile = mstr[0] - 'a'; - mt->fromRank = mstr[1] - '1'; - mt->toFile = mstr[2] - 'a'; - mt->toRank = mstr[3] - '1'; - break; - case MS_COMPDASH: - mt->fromFile = mstr[0] - 'a'; - mt->fromRank = mstr[1] - '1'; - mt->toFile = mstr[3] - 'a'; - mt->toRank = mstr[4] - '1'; - break; - case MS_KCASTLE: - mt->fromFile = 4; - mt->toFile = 6; - if (gs->onMove == WHITE) { - mt->fromRank = 0; - mt->toRank = 0; - } else { - mt->fromRank = 7; - mt->toRank = 7; - } + int type = is_move(mstr); + int result; + + mt->piecePromotionTo = NOPIECE; + mt->color = gs->onMove; + switch (type) { + case MS_NOTMOVE: + return MOVE_ILLEGAL; + break; + case MS_COMP: + mt->fromFile = mstr[0] - 'a'; + mt->fromRank = mstr[1] - '1' + (gs->ranks>9); + mt->toFile = mstr[2] - 'a'; + mt->toRank = mstr[3] - '1' + (gs->ranks>9); + break; + case MS_COMPDASH: + mt->fromFile = mstr[0] - 'a'; + mt->fromRank = mstr[1] - '1' + (gs->ranks>9); + mt->toFile = mstr[3] - 'a'; + mt->toRank = mstr[4] - '1' + (gs->ranks>9); + break; + case MS_KCASTLE: +#if 0 + mt->fromFile = gs->files/2; + mt->toFile = gs->files-2; + if (gs->onMove == WHITE) { + mt->fromRank = 0; + mt->toRank = 0; + } else { + mt->fromRank = gs->ranks-1; + mt->toRank = gs->ranks-1; + } break; +#endif + // [HGM] castle: for now always assume Fischer-type castling (of which normal castling is a special case). + mt->fromFile = ALG_CASTLE; + mt->toFile = gs->files-2; + mt->fromRank = gs->onMove == WHITE ? gs->wkrmoved : gs->bkrmoved; + mt->toRank = mt->toFile-1; // R next to K + break; case MS_QCASTLE: - mt->fromFile = 4; - mt->toFile = 2; - if (gs->onMove == WHITE) { - mt->fromRank = 0; - mt->toRank = 0; - } else { - mt->fromRank = 7; - mt->toRank = 7; - } - break; - case MS_ALG: - /* Fills in the mt structure */ - if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK) - return result; - break; - default: - return MOVE_ILLEGAL; +#if 0 + mt->fromFile = gs->files/2; + mt->toFile = 2; + if (gs->onMove == WHITE) { + mt->fromRank = 0; + mt->toRank = 0; + } else { + mt->fromRank = gs->ranks-1; + mt->toRank = gs->ranks-1; + } break; +#endif + mt->fromFile = ALG_CASTLE; + mt->toFile = 2; + mt->fromRank = gs->onMove == WHITE ? gs->wqrmoved : gs->bqrmoved; + mt->toRank = mt->toFile+1; + break; + case MS_ALG: + /* Fills in the mt structure */ + if ((result = alg_parse_move(mstr, gs, mt)) != MOVE_OK) + return result; + break; + default: + return MOVE_ILLEGAL; + break; } - if (!legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank)) { - return MOVE_ILLEGAL; - } - - if (mt->piecePromotionTo != NOPIECE) { - promote = piecetype(mt->piecePromotionTo); - } - - return move_calculate(gs, mt, promote); + if((mt->fromRank >= gs->ranks || mt->fromRank < 0 || mt->fromFile >= gs->files) && + mt->fromFile != ALG_DROP && mt->fromFile != ALG_CASTLE + || mt->toRank < 0 || mt->toRank >= gs->ranks || mt->toFile >= gs->files) + return MOVE_ILLEGAL; // [HGM] make sure move stays on board + + if (!(result = legal_move(gs, mt->fromFile, mt->fromRank, mt->toFile, mt->toRank))) + return MOVE_ILLEGAL; + + if(result == 2) { // [HGM] castle: orthodox castling was given as King move; convert it to new format + if(mt->fromFile - mt->toFile > 1) { // Q-side + mt->fromRank = 0; + mt->toRank = mt->toFile+1; + } else if(mt->toFile - mt->fromFile > 1) { // K-side + mt->fromRank = gs->files-1; + mt->toRank = mt->toFile-1; + } + mt->fromFile = ALG_CASTLE; + } + + if (mt->piecePromotionTo != NOPIECE) { + promote = piecetype(mt->piecePromotionTo); + } + + return move_calculate(gs, mt, promote); } /* Returns MOVE_OK, MOVE_NOMATERIAL, MOVE_CHECKMATE, or MOVE_STALEMATE */ @@ -881,7 +1833,7 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st { int movedPiece; int tookPiece; - int i, j, foobar; + int i, j, foobar, wCnt, bCnt, king, rook; if (mt->fromFile == ALG_DROP) { movedPiece = mt->fromRank; @@ -890,6 +1842,23 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st gs->board[mt->toFile][mt->toRank] = movedPiece | gs->onMove; if (gs->gameNum >= 0) gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves; + } else if(mt->fromFile == ALG_CASTLE) { + int backRank, fKing; + // [HGM] castle: perform castling + if(gs->onMove == WHITE) { + backRank = 0; + fKing = gs->wkmoved; + gs->wkmoved = -gs->wkmoved-2; + } else { + backRank = gs->ranks-1; + fKing = gs->bkmoved; + gs->bkmoved = -gs->bkmoved-2; + } + // move Rook & King, in a way that is resistant to ending where they started (for FRC!) + rook = gs->board[mt->fromRank][backRank]; // first remember + king = gs->board[fKing][backRank]; + gs->board[mt->fromRank][backRank] = NOPIECE; // then erase gs->board[fKing][backRank] = NOPIECE; gs->board[mt->toRank][backRank] = rook; // then put back + gs->board[mt->toFile][backRank] = king; } else { movedPiece = gs->board[mt->fromFile][mt->fromRank]; tookPiece = gs->board[mt->toFile][mt->toRank]; @@ -897,16 +1866,18 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st 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; /* Check if irreversable */ - if ((piecetype(movedPiece) == PAWN) || (tookPiece != NOPIECE)) { + if ((piecetype(movedPiece) == PAWN) && (mt->fromRank != mt->toRank) // [HGM] XQ: sideway Pawn move reversible! + || (tookPiece != NOPIECE)) { if (gs->gameNum >= 0) gs->lastIrreversable = game_globals.garray[gs->gameNum].numHalfMoves; } /* Check if this move is en-passant */ if ((piecetype(movedPiece) == PAWN) && (mt->fromFile != mt->toFile) && - (tookPiece == NOPIECE)) { + (tookPiece == NOPIECE) && !gs->palace) { // [HGM] XQ: no e.p. in sideway xiangqi moves if (gs->onMove == WHITE) { mt->pieceCaptured = B_PAWN; } else { @@ -919,11 +1890,11 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st } gs->board[mt->toFile][mt->fromRank] = NOPIECE; } - /* Check en-passant flags for next moves */ - for (i = 0; i < 8; i++) { - gs->ep_possible[0][i] = 0; - gs->ep_possible[1][i] = 0; - } + /* Check en-passant flags for next moves */ + for (i = 0; i < gs->files; i++) { + gs->ep_possible[0][i] = 0; + gs->ep_possible[1][i] = 0; + } /* Added by Sparky 3/16/95 From soso@Viktoria.drp.fmph.uniba.sk Thu Mar 16 13:08:51 1995 @@ -940,94 +1911,105 @@ int execute_move(struct game_state_t * gs, struct move_t * mt, int check_game_st if ((mt->toFile+1 < 7 ) .... should be : (mt->toFile < 7 ) } */ - if ((piecetype(movedPiece) == PAWN) && - ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) { - /* Should turn on enpassent flag if possible */ - if (gs->onMove == WHITE) { - if ((mt->toFile < 7) && gs->board[mt->toFile + 1][3] == B_PAWN) { - gs->ep_possible[1][mt->toFile + 1] = -1; - } - if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][3] == B_PAWN) { - gs->ep_possible[1][mt->toFile - 1] = 1; - } - } else { - if ((mt->toFile < 7) && gs->board[mt->toFile + 1][4] == W_PAWN) { - gs->ep_possible[0][mt->toFile + 1] = -1; - } - if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][4] == W_PAWN) { - gs->ep_possible[0][mt->toFile - 1] = 1; - } - } - } - if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 0)) { - if ((mt->fromRank == 0) && (gs->onMove == WHITE)) - gs->wqrmoved = 1; - if ((mt->fromRank == 7) && (gs->onMove == BLACK)) - gs->bqrmoved = 1; - } - if ((piecetype(movedPiece) == ROOK) && (mt->fromFile == 7)) { - if ((mt->fromRank == 0) && (gs->onMove == WHITE)) - gs->wkrmoved = 1; - if ((mt->fromRank == 7) && (gs->onMove == BLACK)) - gs->bkrmoved = 1; - } - if (piecetype(movedPiece) == KING) { - if (gs->onMove == WHITE) - gs->wkmoved = 1; - else - gs->bkmoved = 1; - } - if ((piecetype(movedPiece) == KING) && - ((mt->fromFile == 4) && ((mt->toFile == 6)))) { /* Check for KS castling */ - gs->board[5][mt->toRank] = gs->board[7][mt->toRank]; - gs->board[7][mt->toRank] = NOPIECE; + if ((piecetype(movedPiece) == PAWN) && + ((mt->fromRank == mt->toRank + 2) || (mt->fromRank + 2 == mt->toRank))) { + /* Should turn on enpassent flag if possible */ + if (gs->onMove == WHITE) { + if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == B_PAWN) { + gs->ep_possible[1][mt->toFile + 1] = -1; + } + if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == B_PAWN) { + gs->ep_possible[1][mt->toFile - 1] = 1; + } + } else { + if ((mt->toFile < gs->files-1) && gs->board[mt->toFile + 1][mt->toRank] == W_PAWN) { + gs->ep_possible[0][mt->toFile + 1] = -1; + } + if ((mt->toFile - 1 >= 0) && gs->board[mt->toFile - 1][mt->toRank] == W_PAWN) { + gs->ep_possible[0][mt->toFile - 1] = 1; + } + } + } + if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == 0) && (gs->onMove == WHITE)) { + if (mt->fromFile == gs->wqrmoved) // [HGM] castle: flip w.r.t. -1 to remember original + gs->wqrmoved = -gs->wqrmoved-2; + if (mt->fromFile == gs->wkrmoved) + gs->wkrmoved = -gs->wkrmoved-2; + } + if ((piecetype(movedPiece) == ROOK) && (mt->fromRank == gs->ranks-1) && (gs->onMove == BLACK)) { + if (mt->fromFile == gs->bqrmoved) + gs->bqrmoved = -gs->bqrmoved-2; + if (mt->fromFile == gs->bkrmoved) + gs->bkrmoved = -gs->bkrmoved-2; + } + if (piecetype(movedPiece) == KING) { + if ((gs->onMove == WHITE) && (mt->fromFile == gs->wkmoved)) + gs->wkmoved = -gs->wkmoved-2; + if ((gs->onMove == BLACK) && (mt->fromFile == gs->bkmoved)) + gs->bkmoved = -gs->bkmoved-2; } - if ((piecetype(movedPiece) == KING) && - ((mt->fromFile == 4) && ((mt->toFile == 2)))) { /* Check for QS castling */ - gs->board[3][mt->toRank] = gs->board[0][mt->toRank]; - gs->board[0][mt->toRank] = NOPIECE; +#if 0 + if ((piecetype(movedPiece) == KING) && + ((mt->fromFile == gs->files/2) && (mt->toFile == gs->files-2)) && + mt->fromRank == mt->toRank) { /* Check for KS castling */ + gs->board[gs->files-3][mt->toRank] = gs->board[gs->files-1][mt->toRank]; + gs->board[gs->files-1][mt->toRank] = NOPIECE; + } + if ((piecetype(movedPiece) == KING) && + ((mt->fromFile == gs->files/2) && (mt->toFile == 2)) && + mt->fromRank == mt->toRank) { /* Check for QS castling */ + gs->board[3][mt->toRank] = gs->board[0][mt->toRank]; + gs->board[0][mt->toRank] = NOPIECE; } - } - if (gs->onMove == BLACK) - gs->moveNum++; - - if (check_game_status) { - /* Does this move result in check? */ - if (in_check(gs)) { - /* Check for checkmate */ - gs->onMove = CToggle(gs->onMove); - if (!has_legal_move(gs)) - return MOVE_CHECKMATE; - } else { - /* Check for stalemate */ - gs->onMove = CToggle(gs->onMove); - if (!has_legal_move(gs)) - return MOVE_STALEMATE; -/* loon: check for insufficient mating material, first try */ - foobar = 0; - for (i=0; i<8; i++) { - for (j=0; j<8; j++) { - switch(piecetype(gs->board[i][j])) { - case KNIGHT: - case BISHOP: - foobar++; - break; - case KING: - case NOPIECE: - break; - default: - foobar = 2; - break; +#endif + } + if (gs->onMove == BLACK) + gs->moveNum++; + + if (check_game_status) { + /* Does this move result in check? */ + if (in_check(gs)) { + /* Check for checkmate */ + gs->onMove = CToggle(gs->onMove); + if (!has_legal_move(gs)) + return MOVE_CHECKMATE; + } else { + /* Check for stalemate */ + gs->onMove = CToggle(gs->onMove); + if (!has_legal_move(gs)) + return gs->stalemate ? MOVE_STALEMATE : MOVE_CHECKMATE; // [HGM] in XQ and shatranj stalemate loses + } +/* loon: check for insufficient mating material, first try */ + foobar = wCnt = bCnt = 0; + for (i=0; ifiles; i++) { + for (j=0; jranks; j++) { + int p = gs->board[i][j]; + switch(piecetype(p)) { + case KNIGHT: + case BISHOP: + foobar++; + break; + case KING: + case NOPIECE: + break; + default: + foobar = 2; + break; } - } + if(p != NOPIECE && iscolor(p, WHITE)) wCnt++; + if(iscolor(p, BLACK)) bCnt++; + } } - if (foobar < 2) - return MOVE_NOMATERIAL; - } - } else { - gs->onMove = CToggle(gs->onMove); - } - return MOVE_OK; + if(gs->bareKingLoses) { // [HGM] with bare-King-loses rule only KK is insuff. material + if(gs->onMove == BLACK && wCnt == 1 && bCnt > 1) return MOVE_BARE; + if(gs->onMove == WHITE && bCnt == 1 && wCnt > 1) return MOVE_BARE; + if(bCnt == 1 && wCnt == 1) return MOVE_NOMATERIAL; + } else if (foobar < 2) + return MOVE_NOMATERIAL; + } else { + gs->onMove = CToggle(gs->onMove); + } + return MOVE_OK; } int backup_move(int g, int mode) @@ -1046,6 +2028,31 @@ int backup_move(int g, int mode) if (m->toFile < 0) { return MOVE_ILLEGAL; } + if(m->fromFile == ALG_CASTLE) { + // [HGM] castling in new format. Derive K and R moves + int rank, kingFromFile; + if(m->color == WHITE) { + rank = 0; + kingFromFile = -gs->wkmoved-2; + if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen? + gs->wkmoved = kingFromFile; + if(m->toRank > m->toFile) gs->wqrmoved = m->fromRank; + else gs->wkrmoved = m->fromRank; + } else { + rank = gs->ranks-1; + kingFromFile = -gs->bkmoved-2; + if(kingFromFile<0) kingFromFile = -kingFromFile-2; // safety catch; should never happen? + gs->bkmoved = kingFromFile; + if(m->toRank > m->toFile) gs->bqrmoved = m->fromRank; + else gs->bkrmoved = m->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 + 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 | @@ -1058,48 +2065,49 @@ int backup_move(int g, int mode) *******************/ if (piecetype(gs->board[m->fromFile][m->fromRank]) == ROOK) { if (m->color == WHITE) { - if ((m->fromFile == 0) && (m->fromRank == 0)) { - for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { - m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; - if ((m1->fromFile == 0) && (m1->fromRank == 0)) - break; - } - if (i == game_globals.garray[g].numHalfMoves - 1) - gs->wqrmoved = 0; - } - if ((m->fromFile == 7) && (m->fromRank == 0)) { + if ((m->fromFile == -gs->wqrmoved-2) && (m->fromRank == 0)) { for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; - if ((m1->fromFile == 7) && (m1->fromRank == 0)) - break; - } - if (i == game_globals.garray[g].numHalfMoves - 1) - gs->wkrmoved = 0; - } - } else { - if ((m->fromFile == 0) && (m->fromRank == 7)) { - for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { - m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; - if ((m1->fromFile == 0) && (m1->fromRank == 0)) + if ((m1->fromFile == -gs->wqrmoved-2) && (m1->fromRank == 0)) break; } if (i == game_globals.garray[g].numHalfMoves - 1) - gs->bqrmoved = 0; + gs->wqrmoved = m->fromFile; } - if ((m->fromFile == 7) && (m->fromRank == 7)) { - for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { - m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; - if ((m1->fromFile == 7) && (m1->fromRank == 0)) - break; - } - if (i == game_globals.garray[g].numHalfMoves - 1) - gs->bkrmoved = 0; - } - } - } + if ((m->fromFile == -gs->wkrmoved-2) && (m->fromRank == 0)) { + for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; + if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == 0)) + break; + } + if (i == game_globals.garray[g].numHalfMoves - 1) + gs->wkrmoved = m->fromFile; + } + } else { + if ((m->fromFile == -gs->bqrmoved-2) && (m->fromRank == gs->ranks-1)) { + for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; + if ((m1->fromFile == -gs->bkrmoved-2) && (m1->fromRank == gs->ranks-1)) + break; + } + if (i == game_globals.garray[g].numHalfMoves - 1) + gs->bqrmoved = m->fromFile; + } + if ((m->fromFile == -gs->bkrmoved-2) && (m->fromRank == gs->ranks-1)) { + for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; + if ((m1->fromFile == -gs->wkrmoved-2) && (m1->fromRank == gs->ranks-1)) + break; + } + if (i == game_globals.garray[g].numHalfMoves - 1) + gs->bkrmoved = m->fromFile; + } + } + } if (piecetype(gs->board[m->fromFile][m->fromRank]) == KING) { gs->board[m->toFile][m->toRank] = m->pieceCaptured; - +#if 0 + /* [HGM] castlings are already intercepted due to new format; this code wrecks knightmate! */ if (m->toFile - m->fromFile == 2) { gs->board[7][m->fromRank] = ROOK | colorval(gs->board[m->fromFile][m->fromRank]); @@ -1136,35 +2144,36 @@ int backup_move(int g, int mode) } goto cleanupMove; } +#endif /****************** When takeback a _first_ move of king (not the castling), the ?kmoved variable must be cleared . To check, if the move is first, we should scan moveList. *******************/ - if (m->color == WHITE) { - - if ((m->fromFile == 4) && (m->fromRank == 0)) { - for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { - m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; - if ((m1->fromFile == 4) && (m1->fromRank == 0)) - break; - } - if (i == game_globals.garray[g].numHalfMoves - 1) - gs->wkmoved = 0; - } - } else { - if ((m->fromFile == 4) && (m->fromRank == 7)) { - for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { - m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; - if ((m1->fromFile == 4) && (m1->fromRank == 7)) - break; - } - if (i == game_globals.garray[g].numHalfMoves - 1) - gs->bkmoved = 0; - } - } - } + if (m->color == WHITE) { + + if ((m->fromFile == -gs->wkmoved-2) && (m->fromRank == 0)) { + for (i = 2; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; + if ((m1->fromFile == gs->wkmoved-2) && (m1->fromRank == 0)) + break; + } + if (i == game_globals.garray[g].numHalfMoves - 1) + gs->wkmoved = m->fromFile; + } + } else { + if ((m->fromFile == -gs->bkmoved-2) && (m->fromRank == gs->ranks-1)) { + for (i = 3; i < game_globals.garray[g].numHalfMoves - 1; i += 2) { + m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[i] : &game_globals.garray[g].examMoveList[i]; + if ((m1->fromFile == -gs->bkmoved-2) && (m1->fromRank == gs->ranks-1)) + break; + } + if (i == game_globals.garray[g].numHalfMoves - 1) + gs->bkmoved = m->fromFile; + } + } + } if (m->enPassant) { /* Do enPassant */ gs->board[m->toFile][m->fromRank] = PAWN | (colorval(gs->board[m->fromFile][m->fromRank]) == WHITE ? BLACK : WHITE); @@ -1243,28 +2252,28 @@ cleanupMove: array. (patch from Soso, added by Sparky 3/17/95) ********/ - if (game_globals.garray[g].numHalfMoves > 0) { - m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : - &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1]; - if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) { - if ((m1->toRank - m1->fromRank) == 2) { - if ((m1->toFile < 7) && gs->board[m1->toFile + 1][3] == B_PAWN) { - gs->ep_possible[1][m1->toFile + 1] = -1; - } - if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][3] == B_PAWN) { - gs->ep_possible[1][m1->toFile - 1] = 1; - } - } - if ((m1->toRank - m1->fromRank) == -2) { - if ((m1->toFile < 7) && gs->board[m1->toFile + 1][4] == W_PAWN) { - gs->ep_possible[0][m1->toFile + 1] = -1; - } - if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][4] == W_PAWN) { - gs->ep_possible[0][m1->toFile - 1] = 1; - } - } - } - } + if (game_globals.garray[g].numHalfMoves > 0) { + m1 = (mode==REL_GAME) ? &game_globals.garray[g].moveList[game_globals.garray[g].numHalfMoves - 1] : + &game_globals.garray[g].examMoveList[game_globals.garray[g].numHalfMoves - 1]; + if (piecetype(gs->board[m1->toFile][m1->toRank]) == PAWN) { + if ((m1->toRank - m1->fromRank) == 2) { + if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == B_PAWN) { + gs->ep_possible[1][m1->toFile + 1] = -1; + } + if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == B_PAWN) { + gs->ep_possible[1][m1->toFile - 1] = 1; + } + } + if ((m1->toRank - m1->fromRank) == -2) { + if ((m1->toFile < gs->files-1) && gs->board[m1->toFile + 1][m1->toRank] == W_PAWN) { + gs->ep_possible[0][m1->toFile + 1] = -1; + } + if ((m1->toFile - 1 >= 0) && gs->board[m1->toFile - 1][m1->toRank] == W_PAWN) { + gs->ep_possible[0][m1->toFile - 1] = 1; + } + } + } + } /************** and here's the end **************/ return MOVE_OK; } diff --git a/lasker-2.2.3/src/movecheck.h b/lasker-2.2.3/src/movecheck.h old mode 100644 new mode 100755 index 8033261..bc06086 --- a/lasker-2.2.3/src/movecheck.h +++ b/lasker-2.2.3/src/movecheck.h @@ -1,41 +1,42 @@ -/* - Copyright (c) 1993 Richard V. Nash. - Copyright (c) 2000 Dan Papasian - Copyright (C) Andrew Tridgell 2002 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#ifndef _MOVECHECK_H -#define _MOVECHECK_H - -#define MOVE_OK 0 -#define MOVE_ILLEGAL 1 -#define MOVE_STALEMATE 2 -#define MOVE_CHECKMATE 3 -#define MOVE_AMBIGUOUS 4 -#define MOVE_NOMATERIAL 5 - -#define MS_NOTMOVE 0 -#define MS_COMP 1 -#define MS_COMPDASH 2 -#define MS_ALG 3 -#define MS_KCASTLE 4 -#define MS_QCASTLE 5 - -#define isrank(c) (((c) <= '8') && ((c) >= '1')) -#define isfile(c) (((c) >= 'a') && ((c) <= 'h')) - -#endif /* _MOVECHECK_H */ +/* + Copyright (c) 1993 Richard V. Nash. + Copyright (c) 2000 Dan Papasian + Copyright (C) Andrew Tridgell 2002 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef _MOVECHECK_H +#define _MOVECHECK_H + +#define MOVE_OK 0 +#define MOVE_ILLEGAL 1 +#define MOVE_STALEMATE 2 +#define MOVE_CHECKMATE 3 +#define MOVE_AMBIGUOUS 4 +#define MOVE_NOMATERIAL 5 +#define MOVE_BARE 6 + +#define MS_NOTMOVE 0 +#define MS_COMP 1 +#define MS_COMPDASH 2 +#define MS_ALG 3 +#define MS_KCASTLE 4 +#define MS_QCASTLE 5 + +#define isrank(c) (((c) <= '9') && ((c) >= '0')) +#define isfile(c) (((c) >= 'a') && ((c) <= 'l')) + +#endif /* _MOVECHECK_H */ diff --git a/lasker-2.2.3/src/obsproc.c b/lasker-2.2.3/src/obsproc.c index 952a6de..3a7a990 100644 --- a/lasker-2.2.3/src/obsproc.c +++ b/lasker-2.2.3/src/obsproc.c @@ -422,7 +422,7 @@ int com_moves(int p, param_list param) g = pp->game; } else if (pp->num_observe) { for (g = 0; g < pp->num_observe; g++) { - pprintf(p, "%s\n", movesToString(pp->observe_list[g], 0)); + pprintf_noformat(p, "%s\n", movesToString(pp->observe_list[g], 0)); } return COM_OK; } else { @@ -444,7 +444,7 @@ int com_moves(int p, param_list param) pprintf(p, "Sorry, that is a private game.\n"); return COM_OK; } - pprintf(p, "%s\n", movesToString(g, 0)); /* pgn may break interfaces? */ + pprintf_noformat(p, "%s\n", movesToString(g, 0)); /* pgn may break interfaces? */ return COM_OK; } @@ -455,8 +455,13 @@ int com_mailmoves(int p, param_list param) int p1; char subj[81]; - if (!CheckPFlag(p, PFLAG_REG)) { - pprintf (p,"Unregistered players cannot use mailmoves.\n"); + if (param[1].type == TYPE_NULL) { + if (!CheckPFlag(p, PFLAG_REG)) { + pprintf (p,"Unregistered players must specify their e-mail address.\n"); + return COM_OK; + } + } else if(!safestring(param[1].val.string)) { + pprintf (p,"Bad e-mail address.\n"); return COM_OK; } @@ -481,7 +486,9 @@ int com_mailmoves(int p, param_list param) return COM_OK; } sprintf(subj, "FICS game report %s vs %s", game_globals.garray[g].white_name, game_globals.garray[g].black_name); - if (mail_string_to_user(p, subj, + if (param[1].type == TYPE_NULL ? mail_string_to_user(p, subj, + movesToString(g, CheckPFlag(p, PFLAG_PGN))) : + mail_string_to_address(param[1].val.string, subj, movesToString(g, CheckPFlag(p, PFLAG_PGN)))) { pprintf(p, "Moves NOT mailed, perhaps your address is incorrect.\n"); } else { @@ -627,6 +634,7 @@ void ExamineScratch(int p, param_list param,int setup) pprintf(p, "Loading from catagory: %s, board: %s.\n", category, board); } + game_globals.garray[g].FENstartPos[0] = 0; // [HGM] new shuffle game if (setup) { board_clear(&game_globals.garray[g].game_state); game_globals.garray[g].status = GAME_SETUP; @@ -667,6 +675,7 @@ static int ExamineStored(FILE * fp, int p, char type) gg = &game_globals.garray[g]; category[0] = '\0'; board[0] = '\0'; + game_globals.garray[g].FENstartPos[0] = 0; // [HGM] make new shuffle for now if (board_init(g,&gg->game_state, category, board)) { pprintf(p, "PROBLEM LOADING BOARD. Examine Aborted.\n"); d_printf( "CHESSD: PROBLEM LOADING BOARD %s %s. Examine Aborted.\n", @@ -683,6 +692,18 @@ static int ExamineStored(FILE * fp, int p, char type) game_remove(g); return -1; } + + // [HGM] OK, we retreived the game info, which includes variant name as "category/board" + // So now we set up the board again, this time for the proper variant (and proper shuffle) + sscanf(gg->variant, "%s/%s", category, board); + if(category[0] && !board[0]) strcpy(board, "0"); + if (board_init(g,&gg->game_state, category, board)) { + pprintf(p, "PROBLEM LOADING BOARD. Examine Aborted.\n"); + d_printf( "CHESSD: PROBLEM LOADING BOARD %s %s. Examine Aborted.\n", + category, board); + game_remove(g); + return -1; + } } else if (ReadGameAttrs(fp, g) < 0) { pprintf(p, "Gamefile is corrupt; please notify an admin.\n"); game_remove(g); @@ -702,7 +723,6 @@ static int ExamineStored(FILE * fp, int p, char type) pp->side = WHITE; /* oh well... */ pp->game = g; - send_boards(g); if (CheckPFlag(p, PFLAG_OPEN)) /* was open */ announce_notavail(p); @@ -1043,9 +1063,14 @@ static void stored_mail_moves(int p, int mail, param_list param) char fileName2[MAX_FILENAME_SIZE]; FILE* fpGame; - if (mail && !CheckPFlag(p, PFLAG_REG)) { - pprintf (p,"Unregistered players cannot use mailstored.\n"); - return; + if (param[2].type == TYPE_NULL) { + if (!CheckPFlag(p, PFLAG_REG)) { + pprintf (p,"Unregistered players must specify their e-mail address.\n"); + return COM_OK; + } + } else if(!safestring(param[2].val.string)) { + pprintf (p,"Bad e-mail address.\n"); + return COM_OK; } if (!FindPlayer(p, param[0].val.word, &wp, &wconnected)) @@ -1125,13 +1150,15 @@ static void stored_mail_moves(int p, int mail, param_list param) } else { sprintf(subj, "FICS adjourned game %s vs %s", game_globals.garray[g].white_name, game_globals.garray[g].black_name); } - if (mail_string_to_user(p, subj, + if (param[2].type == TYPE_NULL ? mail_string_to_user(p, subj, + movesToString(g, CheckPFlag(p, PFLAG_PGN))) : + mail_string_to_address(param[2].val.string, subj, movesToString(g, CheckPFlag(p, PFLAG_PGN)))) pprintf(p, "Moves NOT mailed, perhaps your address is incorrect.\n"); else pprintf(p, "Moves mailed.\n"); } else { - pprintf(p, "%s\n", movesToString(g, 0)); + pprintf_noformat(p, "%s\n", movesToString(g, 0)); } /* Do smoves */ } } diff --git a/lasker-2.2.3/src/setup.c b/lasker-2.2.3/src/setup.c index 4138c63..eb37655 100644 --- a/lasker-2.2.3/src/setup.c +++ b/lasker-2.2.3/src/setup.c @@ -45,8 +45,8 @@ static int validate_position (int p,struct game_state_t *b) int white_k = 0; int black_k = 0; - for (f = 0; (f < 8); f++) { - for (r = 0; (r < 8); r++) { + for (f = 0; (f < b->files); f++) { + for (r = 0; (r < b->ranks); r++) { if (b->board[f][r] == W_KING) { white_k += 1; if (white_k == 2) { @@ -62,7 +62,7 @@ static int validate_position (int p,struct game_state_t *b) } } if (((b->board[f][r] == W_PAWN) || (b->board[f][r] == B_PAWN)) && - ((r == 0) || (r == 7))) { + ((r == 0) || (r == b->ranks-1))) { pprintf (p,"Pawns cannot be placed on the first or eighth rank.\n"); return 0; } @@ -151,17 +151,23 @@ int com_setup (int p,param_list param) pprintf(p,"The position is not valid - staying in setup mode.\n"); return COM_OK; } else { /* try to load a category of board */ - if (param[1].type != TYPE_NULL) { - if (!board_init (pp->game,&(game_globals.garray[pp->game].game_state),param[0].val.word,param[1].val.word)) { + char *board = param[1].val.word; + if (param[1].type == TYPE_NULL) board = "0"; + game_globals.garray[pp->game].FENstartPos[0] = 0; // [HGM] new shuffle + if (!board_init (pp->game,&(game_globals.garray[pp->game].game_state),param[0].val.word,board)) { game_globals.garray[pp->game].game_state.gameNum = gamenum; + if(!strcmp(board,"0")) + sprintf(game_globals.garray[pp->game].variant, "%s",param[0].val.word); + else + sprintf(game_globals.garray[pp->game].variant, "%s/%s",param[0].val.word,board); send_board_to(pp->game, p); - pprintf (p,"Board set up as %s %s.\n",param[0].val.word,param[1].val.word); + pprintf (p,"Board set up as %s %s.\n",param[0].val.word,board); } else { - pprintf (p,"Board %s %s is unavailable.\n",param[0].val.word,param[1].val.word); + pprintf (p,"Board %s %s is unavailable.\n",param[0].val.word,board); game_globals.garray[pp->game].game_state.gameNum = gamenum; } return COM_OK; - } + } } pprintf (p, "You have supplied an incorrect parameter to setup.\n"); @@ -302,7 +308,7 @@ int attempt_drop(int p,int g,char* dropstr) /*check wp@e3 */ } else if (dropstr[0] == 'w') { - piece = CharToPiece(dropstr[1]) & 0x07; + piece = CharToPiece(dropstr[1], game_globals.garray[g].game_state.variant) & 0x7F; color = WHITE; getsquare(dropstr+3,&f,&r); @@ -310,7 +316,7 @@ int attempt_drop(int p,int g,char* dropstr) } else if (len == 5) { /* check length to avoid b@e2 and bb@e2 being confused */ if (dropstr[0] == 'b') { - piece = CharToPiece(dropstr[1]) | BLACK; + piece = CharToPiece(dropstr[1], game_globals.garray[g].game_state.variant) | BLACK; getsquare(dropstr+3,&f,&r); } @@ -320,7 +326,7 @@ int attempt_drop(int p,int g,char* dropstr) if (!((dropstr[1] == '@') || (dropstr[1] == '*'))) return 0; else { - piece = CharToPiece(dropstr[0]); + piece = CharToPiece(dropstr[0], game_globals.garray[g].game_state.variant); getsquare(dropstr+2,&f,&r); } } diff --git a/lasker-2.2.3/src/talkproc.c b/lasker-2.2.3/src/talkproc.c index 1016fc5..34283b5 100644 --- a/lasker-2.2.3/src/talkproc.c +++ b/lasker-2.2.3/src/talkproc.c @@ -472,6 +472,19 @@ int com_kibitz(int p, param_list param) g = pp->game; else g = pp->observe_list[0]; + if(pp->game == g) { // [HGM] capture engine kibitz of player + float score; int depth; + if(sscanf(param[0].val.string, "!!! %f/%d", &score, &depth) == 2) { + struct game *gg = &game_globals.garray[g]; + if(gg->numHalfMoves && gg->status == GAME_ACTIVE) { + int n = gg->numHalfMoves-1; + if(n && (gg->game_state.onMove == WHITE && gg->black != p || + gg->game_state.onMove == BLACK && gg->white != p )) n--; + gg->moveList[n].score = score; + gg->moveList[n].depth = depth; + } + } + } for (p1 = 0; p1 < player_globals.p_num; p1++) { if ((p1 == p) || (player_globals.parray[p1].status != PLAYER_PROMPT)) continue; diff --git a/lasker-2.2.3/src/utils.c b/lasker-2.2.3/src/utils.c index d6245ca..d4c1da7 100644 --- a/lasker-2.2.3/src/utils.c +++ b/lasker-2.2.3/src/utils.c @@ -21,7 +21,7 @@ #include "includes.h" -static int safestring(char *str); +int safestring(char *str); char *eatword(char *str) { @@ -362,7 +362,7 @@ static int safechar(int c) return (isprint(c) && !strchr(">!&*?/<|`$;", c)); } -static int safestring(char *str) +int safestring(char *str) { int i; diff --git a/lasker-2.2.3/src/variable.c b/lasker-2.2.3/src/variable.c index 487b420..0278f3e 100644 --- a/lasker-2.2.3/src/variable.c +++ b/lasker-2.2.3/src/variable.c @@ -793,7 +793,7 @@ static int set_formula(int p, char *var, char *val) #endif } -static var_list variables[] = { +var_list variables[] = { {"ads", set_ads}, {"availinfo", set_availinfo}, {"availmax", set_availmax},