X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=bdafe3dfaf934fce7aca7b520b8b18d142b98dea;hb=07713bc9c098f6accb3228d75319256cd1eaef1a;hp=329901efa8b0e5711d966e55e2f72213535639b9;hpb=d6897c980542d3ac3d1e9d47fed19766e4d87b63;p=xboard.git diff --git a/backend.c b/backend.c index 329901e..bdafe3d 100644 --- a/backend.c +++ b/backend.c @@ -848,7 +848,7 @@ InitEngine (ChessProgramState *cps, int n) if(cps->tidy == NULL) cps->tidy = (char*) malloc(MSG_SIZ); TidyProgramName(cps->program, cps->host, cps->tidy); cps->matchWins = 0; - ASSIGN(cps->variants, appData.variant); + ASSIGN(cps->variants, appData.noChessProgram ? "" : appData.variant); cps->analysisSupport = 2; /* detect */ cps->analyzing = FALSE; cps->initDone = FALSE; @@ -1202,7 +1202,7 @@ InitBackEnd1 () return; case VariantNormal: /* definitely works! */ - if(strcmp(appData.variant, "normal") && appData.chessProgram) { // [HGM] hope this is an engine-defined variant + if(strcmp(appData.variant, "normal") && !appData.noChessProgram) { // [HGM] hope this is an engine-defined variant safeStrCpy(engineVariant, appData.variant, MSG_SIZ); return; } @@ -2108,14 +2108,14 @@ StringToVariant (char *e) int wnum = -1; VariantClass v = VariantNormal; int i, found = FALSE; - char buf[MSG_SIZ]; + char buf[MSG_SIZ], c; int len; if (!e) return v; /* [HGM] skip over optional board-size prefixes */ - if( sscanf(e, "%dx%d_", &i, &i) == 2 || - sscanf(e, "%dx%d+%d_", &i, &i, &i) == 3 ) { + if( sscanf(e, "%dx%d_%c", &i, &i, &c) == 3 || + sscanf(e, "%dx%d+%d_%c", &i, &i, &i, &c) == 4 ) { while( *e++ != '_'); } @@ -2125,7 +2125,7 @@ StringToVariant (char *e) } else for (i=0; i= VariantShogi && isalpha(p[strlen(variantNames[i])])) continue; + if(p && i >= VariantShogi && (p != e || isalpha(p[strlen(variantNames[i])]))) continue; v = (VariantClass) i; found = TRUE; break; @@ -5328,6 +5328,7 @@ UploadGameEvent () } int killX = -1, killY = -1; // [HGM] lion: used for passing e.p. capture square to MakeMove +int legNr = 1; void CoordsToComputerAlgebraic (int rf, int ff, int rt, int ft, char promoChar, char move[7]) @@ -6107,7 +6108,7 @@ InitPosition (int redraw) case VariantFalcon: pieces = FalconArray; gameInfo.boardWidth = 10; - SetCharTable(pieceToChar, "PNBRQ.............FKpnbrq.............fk"); + SetCharTable(pieceToChar, "PNBRQ............FKpnbrq............fk"); break; case VariantXiangqi: pieces = XiangqiArray; @@ -6550,7 +6551,7 @@ HasPromotionChoice (int fromX, int fromY, int toX, int toY, char *promoChoice, i int p = piece >= BlackPawn ? BLACK_TO_WHITE piece : piece; promotionZoneSize = BOARD_HEIGHT/3; highestPromotingPiece = (p >= WhiteLion || PieceToChar(piece + 22) == '.') ? WhitePawn : WhiteLion; - } else if(gameInfo.variant == VariantShogi || gameInfo.variant == VariantChuChess) { + } else if(gameInfo.variant == VariantShogi) { promotionZoneSize = BOARD_HEIGHT/3; highestPromotingPiece = (int)WhiteAlfil; } else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) { @@ -7263,7 +7264,7 @@ Mark (Board board, int flags, ChessMove kind, int rf, int ff, int rt, int ft, VO { typedef char Markers[BOARD_RANKS][BOARD_FILES]; Markers *m = (Markers *) closure; - if(rf == fromY && ff == fromX && (killX < 0 && !(rt == rf && ft == ff) || abs(ft-killX) < 2 && abs(rt-killY) < 2)) + if(rf == fromY && ff == fromX && (killX < 0 ? !(rt == rf && ft == ff) && legNr & 1 : rt == killY && ft == killX || legNr & 2)) (*m)[rt][ft] = 1 + (board[rt][ft] != EmptySquare || kind == WhiteCapturesEnPassant || kind == BlackCapturesEnPassant) + 3*(kind == FirstLeg && killX < 0), legal[rt][ft] = 1; @@ -7322,8 +7323,8 @@ CanPromote (ChessSquare piece, int y) gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN) return FALSE; return (piece == BlackPawn && y <= zone || piece == WhitePawn && y >= BOARD_HEIGHT-1-zone || - piece == BlackLance && y == 1 || - piece == WhiteLance && y == BOARD_HEIGHT-2 ); + piece == BlackLance && y <= zone || + piece == WhiteLance && y >= BOARD_HEIGHT-1-zone ); } void @@ -7500,6 +7501,7 @@ LeftClick (ClickType clickType, int xPix, int yPix) toP = boards[currentMove][y][x]; frc = appData.fischerCastling || gameInfo.variant == VariantSChess; if( (killX < 0 || x != fromX || y != fromY) && // [HGM] lion: do not interpret igui as deselect! + legal[y][x] == 0 && // if engine told we can move to here, do it even if own piece ((WhitePawn <= fromP && fromP <= WhiteKing && WhitePawn <= toP && toP <= WhiteKing && !(fromP == WhiteKing && toP == WhiteRook && frc) && @@ -8892,19 +8894,23 @@ FakeBookMove: // [HGM] book: we jump here to simulate machine moves after book h if(startedFromSetupPosition) return; ParseFEN(boards[0], &dummy, message+s, FALSE); DrawPosition(TRUE, boards[0]); + CopyBoard(initialPosition, boards[0]); startedFromSetupPosition = TRUE; return; } if(sscanf(message, "piece %s %s", buf2, buf1) == 2) { ChessSquare piece = WhitePawn; char *p=buf2; + if(*p == '+') piece = CHUPROMOTED WhitePawn, p++; + piece += CharToPiece(*p) - WhitePawn; if(cps != &first || appData.testLegality && *engineVariant == NULLCHAR + /* always accept definition of */ && piece != WhiteFalcon && piece != BlackFalcon + /* wild-card pieces. */ && piece != WhiteCobra && piece != BlackCobra /* For variants we don't have */ && gameInfo.variant != VariantBerolina /* correct rules for, we cannot */ && gameInfo.variant != VariantCylinder /* enforce legality on our own! */ && gameInfo.variant != VariantUnknown + && gameInfo.variant != VariantGreat && gameInfo.variant != VariantFairy ) return; - if(*p == '+') piece = CHUPROMOTED WhitePawn, p++; - piece += CharToPiece(*p) - WhitePawn; if(piece < EmptySquare) { pieceDefs = TRUE; ASSIGN(pieceDesc[piece], buf1); @@ -9884,14 +9890,14 @@ ParseGameHistory (char *game) void ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) { - ChessSquare captured = board[toY][toX], piece, king; int p, oldEP = EP_NONE, berolina = 0; + ChessSquare captured = board[toY][toX], piece, pawn, king, killed; int p, rookX, oldEP, epRank, berolina = 0; int promoRank = gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess ? 3 : 1; /* [HGM] compute & store e.p. status and castling rights for new position */ /* we can always do that 'in place', now pointers to these rights are passed to ApplyMove */ if(gameInfo.variant == VariantBerolina) berolina = EP_BEROLIN_A; - oldEP = (signed char)board[EP_STATUS]; + oldEP = (signed char)board[EP_FILE]; epRank = board[EP_RANK]; board[EP_STATUS] = EP_NONE; board[EP_FILE] = board[EP_RANK] = 100; @@ -9908,6 +9914,7 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something // victim = board[killY][killX], + killed = board[killY][killX], board[killY][killX] = EmptySquare, board[EP_STATUS] = EP_CAPTURE; @@ -9920,15 +9927,18 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) } } - if( board[fromY][fromX] == WhiteLance || board[fromY][fromX] == BlackLance ) { - if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantShogi ) - board[EP_STATUS] = EP_PAWN_MOVE; // Lance is Pawn-like in most variants - } else - if( board[fromY][fromX] == WhitePawn ) { + pawn = board[fromY][fromX]; + if( pawn == WhiteLance || pawn == BlackLance ) { + if( gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu ) { + if(gameInfo.variant == VariantSpartan) board[EP_STATUS] = EP_PAWN_MOVE; // in Spartan no e.p. rights must be set + else pawn += WhitePawn - WhiteLance; // Lance is Pawn-like in most variants, so let Pawn code treat it by this kludge + } + } + if( pawn == WhitePawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers board[EP_STATUS] = EP_PAWN_MOVE; - if( toY-fromY==2) { - board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = (fromY + toY)/2; + if( toY-fromY>=2) { + board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = toY - 1 | 128*(toY - fromY > 2); if(toX>BOARD_LEFT && board[toY][toX-1] == BlackPawn && gameInfo.variant != VariantBerolina || toX < fromX) board[EP_STATUS] = toX | berolina; @@ -9937,11 +9947,11 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) board[EP_STATUS] = toX; } } else - if( board[fromY][fromX] == BlackPawn ) { + if( pawn == BlackPawn ) { if(fromY != toY) // [HGM] Xiangqi sideway Pawn moves should not count as 50-move breakers board[EP_STATUS] = EP_PAWN_MOVE; - if( toY-fromY== -2) { - board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = (fromY + toY)/2; + if( toY-fromY<= -2) { + board[EP_FILE] = (fromX + toX)/2; board[EP_RANK] = toY + 1 | 128*(fromY - toY > 2); if(toX>BOARD_LEFT && board[toY][toX-1] == WhitePawn && gameInfo.variant != VariantBerolina || toX < fromX) board[EP_STATUS] = toX | berolina; @@ -9976,6 +9986,12 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) if(gameInfo.variant == VariantKnightmate) king += (int) WhiteUnicorn - (int) WhiteKing; + if(piece != WhiteKing && piece != BlackKing && pieceDesc[piece] && killX >= 0 && strchr(pieceDesc[piece], 'O') // Betza castling-enabled + && (piece < BlackPawn ? killed < BlackPawn : killed >= BlackPawn)) { // and captures own + board[toY][toX] = piece; board[fromY][fromX] = EmptySquare; + board[toY][toX + (killX < fromX ? 1 : -1)] = killed; + board[EP_STATUS] = EP_NONE; // capture was fake! + } else /* Code added by Tord: */ /* FRC castling assumed when king captures friendly rook. [HGM] or RxK for S-Chess */ if (board[fromY][fromX] == WhiteKing && board[toY][toX] == WhiteRook || @@ -10005,15 +10021,17 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && toY == fromY && toX > fromX+1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX-1] = board[fromY][BOARD_RGHT-1]; - board[fromY][BOARD_RGHT-1] = EmptySquare; + for(rookX=BOARD_RGHT-1; board[toY][rookX] == DarkSquare && rookX > toX + 1; rookX--); + board[toY][toX-1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if (board[fromY][fromX] == king && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1 // [HGM] cylinder */ && toY == fromY && toX < fromX-1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX+1] = board[fromY][BOARD_LEFT]; - board[fromY][BOARD_LEFT] = EmptySquare; + for(rookX=BOARD_LEFT; board[toY][rookX] == DarkSquare && rookX < toX - 1; rookX++); + board[toY][toX+1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if ((board[fromY][fromX] == WhitePawn && gameInfo.variant != VariantXiangqi || board[fromY][fromX] == WhiteLance && gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu) && toY >= BOARD_HEIGHT-promoRank && promoChar // defaulting to Q is done elsewhere @@ -10028,12 +10046,14 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && (toX != fromX) && gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantBerolina - && (board[fromY][fromX] == WhitePawn) + && (pawn == WhitePawn) && (board[toY][toX] == EmptySquare)) { board[fromY][fromX] = EmptySquare; - board[toY][toX] = WhitePawn; - captured = board[toY - 1][toX]; - board[toY - 1][toX] = EmptySquare; + board[toY][toX] = piece; + if(toY == epRank - 128 + 1) + captured = board[toY - 2][toX], board[toY - 2][toX] = EmptySquare; + else + captured = board[toY - 1][toX], board[toY - 1][toX] = EmptySquare; } else if ((fromY == BOARD_HEIGHT-4) && (toX == fromX) && gameInfo.variant == VariantBerolina @@ -10052,15 +10072,17 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && toY == fromY && toX > fromX+1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX-1] = board[fromY][BOARD_RGHT-1]; - board[fromY][BOARD_RGHT-1] = EmptySquare; + for(rookX=BOARD_RGHT-1; board[toY][rookX] == DarkSquare && rookX > toX + 1; rookX--); + board[toY][toX-1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if (board[fromY][fromX] == king && fromX != BOARD_LEFT && fromX != BOARD_RGHT-1 // [HGM] cylinder */ && toY == fromY && toX < fromX-1) { board[fromY][fromX] = EmptySquare; board[toY][toX] = king; - board[toY][toX+1] = board[fromY][BOARD_LEFT]; - board[fromY][BOARD_LEFT] = EmptySquare; + for(rookX=BOARD_LEFT; board[toY][rookX] == DarkSquare && rookX < toX - 1; rookX++); + board[toY][toX+1] = board[fromY][rookX]; + board[fromY][rookX] = EmptySquare; } else if (fromY == 7 && fromX == 3 && board[fromY][fromX] == BlackKing && toY == 7 && toX == 5) { @@ -10089,12 +10111,14 @@ ApplyMove (int fromX, int fromY, int toX, int toY, int promoChar, Board board) && (toX != fromX) && gameInfo.variant != VariantXiangqi && gameInfo.variant != VariantBerolina - && (board[fromY][fromX] == BlackPawn) + && (pawn == BlackPawn) && (board[toY][toX] == EmptySquare)) { board[fromY][fromX] = EmptySquare; - board[toY][toX] = BlackPawn; - captured = board[toY + 1][toX]; - board[toY + 1][toX] = EmptySquare; + board[toY][toX] = piece; + if(toY == epRank - 128 - 1) + captured = board[toY + 2][toX], board[toY + 2][toX] = EmptySquare; + else + captured = board[toY + 1][toX], board[toY + 1][toX] = EmptySquare; } else if ((fromY == 3) && (toX == fromX) && gameInfo.variant == VariantBerolina @@ -12853,7 +12877,7 @@ LoadGame (FILE *f, int gameNumber, char *title, int useList) if (!err) numPGNTags++; /* [HGM] PGNvariant: automatically switch to variant given in PGN tag */ - if(gameInfo.variant != oldVariant) { + if(gameInfo.variant != oldVariant && (gameInfo.variant != VariantNormal || gameInfo.variantName == NULL || *gameInfo.variantName == NULLCHAR)) { startedFromPositionFile = FALSE; /* [HGM] loadPos: variant switch likely makes position invalid */ ResetFrontEnd(); // [HGM] might need other bitmaps. Cannot use Reset() because it clears gameInfo :-( InitPosition(TRUE); @@ -12872,6 +12896,8 @@ LoadGame (FILE *f, int gameNumber, char *title, int useList) return FALSE; } CopyBoard(boards[0], initial_position); + if(*engineVariant) // [HGM] for now, assume FEN in engine-defined variant game is default initial position + CopyBoard(initialPosition, initial_position); if (blackPlaysFirst) { currentMove = forwardMostMove = backwardMostMove = 1; CopyBoard(boards[1], initial_position); @@ -15074,6 +15100,8 @@ EditPositionMenuEvent (ChessSquare selection, int x, int y) switch (selection) { case ClearBoard: + fromX = fromY = killX = killY = -1; // [HGM] abort any move entry in progress + MarkTargetSquares(1); CopyBoard(currentBoard, boards[0]); CopyBoard(menuBoard, initialPosition); if (gameMode == IcsExamining && ics_type == ICS_FICS) { @@ -17864,7 +17892,7 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) q = (boards[move][CASTLING][1] == BOARD_LEFT && boards[move][CASTLING][2] != NoRights ); if(handW) { // for S-Chess with pieces in hand, list virgin pieces between K and Q - for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q && j; i--) + for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q; i--) if((boards[move][0][i] != WhiteKing || k+q == 0) && boards[move][VIRGIN][i] & VIRGIN_W) *p++ = i + AAA + 'A' - 'a'; } @@ -17875,7 +17903,7 @@ PositionToFEN (int move, char *overrideCastling, int moveCounts) q = (boards[move][CASTLING][4] == BOARD_LEFT && boards[move][CASTLING][5] != NoRights ); if(handB) { - for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q && j; i--) + for(i=BOARD_RGHT-1-k; i>=BOARD_LEFT+q; i--) if((boards[move][BOARD_HEIGHT-1][i] != BlackKing || k+q == 0) && boards[move][VIRGIN][i] & VIRGIN_B) *p++ = i + AAA; }