extern char installDir[MSG_SIZ];
VariantClass startVariant; /* [HGM] nicks: initial variant */
Boolean abortMatch;
-int deadRanks, handSize;
+int deadRanks, handSize, handOffsets;
extern int tinyLayout, smallLayout;
ChessProgramStats programStats;
boards[moveNum][EP_STATUS] = EP_NONE;
if(str[0] == 'P') boards[moveNum][EP_STATUS] = EP_PAWN_MOVE;
if(strchr(move_str, 'x')) boards[moveNum][EP_STATUS] = EP_CAPTURE;
- if(double_push != -1) boards[moveNum][EP_STATUS] = double_push + BOARD_LEFT;
+ if(double_push != -1) {
+ int dir = WhiteOnMove(moveNum) ? 1 : -1, last = BOARD_HEIGHT-1;
+ boards[moveNum][EP_FILE] = // also set new e.p. variables
+ boards[moveNum][EP_STATUS] = double_push + BOARD_LEFT;
+ boards[moveNum][EP_RANK] = (last + 3*dir)/2;
+ boards[moveNum][LAST_TO] = 128*(last + dir) + boards[moveNum][EP_FILE];
+ } else boards[moveNum][EP_FILE] = boards[moveNum][EP_RANK] = 100;
if (ics_getting_history == H_GOT_REQ_HEADER ||
&& gameInfo.variant != VariantGrand&& gameInfo.variant != VariantSChess) // inherit info that ICS does not give from previous board
for(k=0; k<ranks; k++) for(j=BOARD_LEFT; j<BOARD_RGHT; j++) {
ChessSquare old, new = boards[moveNum][k][j];
- if(fromY == DROP_RANK && k==toY && j==toX) continue; // dropped pieces always stand for themselves
+ if(new == EmptySquare || fromY == DROP_RANK && k==toY && j==toX) continue; // dropped pieces always stand for themselves
old = (k==toY && j==toX) ? boards[moveNum-1][fromY][fromX] : boards[moveNum-1][k][j]; // trace back mover
if(old == new) continue;
if(old == PROMOTED(new)) boards[moveNum][k][j] = old;// prevent promoted pieces to revert to primordial ones
if(old < WhiteCannon || old >= BlackPawn && old < BlackCannon)
boards[moveNum][k][j] = PROMOTED(old); // choose correct type of Gold in promotion
else boards[moveNum][k][j] = old; // preserve type of Gold
- } else if((old == WhitePawn || old == BlackPawn) && new != EmptySquare) // Pawn promotions (but not e.p.capture!)
+ } else if(old == WhitePawn || old == BlackPawn) // Pawn promotions (but not e.p.capture!)
boards[moveNum][k][j] = PROMOTED(new); // use non-primordial representation of chosen piece
}
} else {
shuffleOpenings = 1;
break;
case VariantNoCastle:
- pieces = FIDEArray;
- nrCastlingRights = 0;
/* !!?unconstrained back-rank shuffle */
shuffleOpenings = 1;
+ case VariantSuicide:
+ pieces = FIDEArray;
+ nrCastlingRights = 0;
break;
}
}
if(appData.holdingsSize >= 0) {
i = appData.holdingsSize;
- if(i > gameInfo.boardHeight) i = gameInfo.boardHeight;
+// if(i > gameInfo.boardHeight) i = gameInfo.boardHeight;
gameInfo.holdingsSize = i;
}
if(gameInfo.holdingsSize) gameInfo.holdingsWidth = 2;
if(BOARD_HEIGHT > BOARD_RANKS || BOARD_WIDTH > BOARD_FILES)
DisplayFatalError(_("Recompile to support this BOARD_RANKS or BOARD_FILES!"), 0, 2);
- handSize = BOARD_HEIGHT;
+ if(!handSize) handSize = BOARD_HEIGHT;
pawnRow = gameInfo.boardHeight - 7; /* seems to work in all common variants */
if(pawnRow < 1) pawnRow = 1;
if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantASEAN ||
piece = boards[currentMove][fromY][fromX];
if(gameInfo.variant == VariantChu) {
- promotionZoneSize = BOARD_HEIGHT/3;
+ promotionZoneSize = (BOARD_HEIGHT - deadRanks)/3;
if(legal[toY][toX] == 6) return FALSE; // no promotion if highlights deny it
highestPromotingPiece = (PieceToChar(piece) == '+' || PieceToChar(CHUPROMOTED(piece)) != '+') ? WhitePawn : WhiteKing;
} else if(gameInfo.variant == VariantShogi) {
- promotionZoneSize = BOARD_HEIGHT/3 +(BOARD_HEIGHT == 8);
+ promotionZoneSize = (BOARD_HEIGHT- deadRanks)/3 +(BOARD_HEIGHT == 8);
highestPromotingPiece = (int)WhiteAlfil;
+ if(PieceToChar(piece) != '+' || PieceToChar(CHUPROMOTED(piece)) == '+') highestPromotingPiece = piece;
} else if(gameInfo.variant == VariantMakruk || gameInfo.variant == VariantGrand || gameInfo.variant == VariantChuChess) {
promotionZoneSize = 3;
}
if(fromY < promotionZoneSize && gameInfo.variant == VariantChuChess) return FALSE;
highestPromotingPiece = WHITE_TO_BLACK highestPromotingPiece;
} else {
- if( toY < BOARD_HEIGHT - promotionZoneSize &&
- fromY < BOARD_HEIGHT - promotionZoneSize) return FALSE;
- if(fromY >= BOARD_HEIGHT - promotionZoneSize && gameInfo.variant == VariantChuChess)
+ if( toY < BOARD_HEIGHT - deadRanks - promotionZoneSize &&
+ fromY < BOARD_HEIGHT - deadRanks - promotionZoneSize) return FALSE;
+ if(fromY >= BOARD_HEIGHT - deadRanks - promotionZoneSize && gameInfo.variant == VariantChuChess)
return FALSE;
}
return FALSE;
}
} else {
- if(toY == BOARD_HEIGHT-1 && piece == WhitePawn ||
- toY == BOARD_HEIGHT-1 && piece == WhiteQueen ||
- toY >= BOARD_HEIGHT-2 && piece == WhiteKnight) {
+ if(toY == BOARD_HEIGHT-deadRanks-1 && piece == WhitePawn ||
+ toY == BOARD_HEIGHT-deadRanks-1 && piece == WhiteQueen ||
+ toY >= BOARD_HEIGHT-deadRanks-2 && piece == WhiteKnight) {
*promoChoice = '+';
return FALSE;
}
int
PieceForSquare (int x, int y)
{
- if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT)
- return -1;
- else
+ if (x < 0 || x >= BOARD_WIDTH || y < 0 || y >= BOARD_HEIGHT) return -1;
+ if(x == BOARD_RGHT+1 && handOffsets & 1) y += handSize - BOARD_HEIGHT;
+ if(x == BOARD_LEFT-2 && !(handOffsets & 2)) y += handSize - BOARD_HEIGHT;
return boards[currentMove][y][x];
}
+ChessSquare
+More (Board board, int col, int start, int end)
+{
+ int k;
+ for(k=start; k<end; k++) if(board[k][col]) return (col == 1 ? WhiteMonarch : BlackMonarch); // arrow image
+ return EmptySquare;
+}
+
+void
+DrawPosition (int repaint, Board board)
+{
+ Board compactedBoard;
+ if(handSize > BOARD_HEIGHT && board) {
+ int k;
+ CopyBoard(compactedBoard, board);
+ if(handOffsets & 1) {
+ for(k=0; k<BOARD_HEIGHT; k++) {
+ compactedBoard[k][BOARD_WIDTH-1] = board[k+handSize-BOARD_HEIGHT][BOARD_WIDTH-1];
+ compactedBoard[k][BOARD_WIDTH-2] = board[k+handSize-BOARD_HEIGHT][BOARD_WIDTH-2];
+ }
+ compactedBoard[0][BOARD_WIDTH-1] = More(board, BOARD_WIDTH-2, 0, handSize-BOARD_HEIGHT+1);
+ } else compactedBoard[BOARD_HEIGHT-1][BOARD_WIDTH-1] = More(board, BOARD_WIDTH-2, BOARD_HEIGHT-1, handSize);
+ if(!(handOffsets & 2)) {
+ for(k=0; k<BOARD_HEIGHT; k++) {
+ compactedBoard[k][0] = board[k+handSize-BOARD_HEIGHT][0];
+ compactedBoard[k][1] = board[k+handSize-BOARD_HEIGHT][1];
+ }
+ compactedBoard[0][0] = More(board, 1, 0, handSize-BOARD_HEIGHT+1);
+ } else compactedBoard[BOARD_HEIGHT-1][0] = More(board, 1, BOARD_HEIGHT-1, handSize);
+ DrawPositionX(TRUE, compactedBoard);
+ } else DrawPositionX(repaint, board);
+}
+
int
OKToStartUserMove (int x, int y)
{
(gameInfo.variant == VariantShatranj || gameInfo.variant == VariantCourier ||
gameInfo.variant == VariantMakruk) && !*engineVariant) return FALSE;
return (piece == BlackPawn && y <= zone ||
- piece == WhitePawn && y >= BOARD_HEIGHT-1-zone ||
+ piece == WhitePawn && y >= BOARD_HEIGHT-1-deadRanks-zone ||
piece == BlackLance && y <= zone ||
- piece == WhiteLance && y >= BOARD_HEIGHT-1-zone );
+ piece == WhiteLance && y >= BOARD_HEIGHT-1-deadRanks-zone );
}
void
Boolean right; // instructs front-end to use button-1 events as if they were button 3
Boolean deferChoice;
+int createX = -1, createY = -1; // square where we last created a piece in EditPosition mode
void
LeftClick (ClickType clickType, int xPix, int yPix)
x = BOARD_WIDTH - 1 - x;
}
- if(appData.monoMouse && gameMode == EditPosition && fromX < 0 && clickType == Press && boards[currentMove][y][x] == EmptySquare) {
+ // map clicks in offsetted holdings back to true coords (or switch the offset)
+ if(x == BOARD_RGHT+1) {
+ if(handOffsets & 1) {
+ if(y == 0) { handOffsets &= ~1; DrawPosition(TRUE, boards[currentMove]); return; }
+ y += handSize - BOARD_HEIGHT;
+ } else if(y == BOARD_HEIGHT-1) { handOffsets |= 1; DrawPosition(TRUE, boards[currentMove]); return; }
+ }
+ if(x == BOARD_LEFT-2) {
+ if(!(handOffsets & 2)) {
+ if(y == 0) { handOffsets |= 2; DrawPosition(TRUE, boards[currentMove]); return; }
+ y += handSize - BOARD_HEIGHT;
+ } else if(y == BOARD_HEIGHT-1) { handOffsets &= ~2; DrawPosition(TRUE, boards[currentMove]); return; }
+ }
+
+ if(appData.monoMouse && gameMode == EditPosition && fromX < 0 && clickType == Press &&
+ (boards[currentMove][y][x] == EmptySquare || x == createX && y == createY) ) {
static int dummy;
RightClick(clickType, xPix, yPix, &dummy, &dummy);
right = TRUE;
return;
}
+ createX = createY = -1;
+
if(SeekGraphClick(clickType, xPix, yPix, 0)) return;
prevClickTime = lastClickTime; GetTimeMark(&lastClickTime);
if (xSqr == BOARD_LEFT-1 || xSqr == BOARD_RGHT) return -1;
if (xSqr < 0 || ySqr < 0) return -1;
if(appData.pieceMenu) { whichMenu = 0; break; } // edit-position menu
+ if(flipView) xSqr = BOARD_WIDTH - 1 - xSqr; else ySqr = BOARD_HEIGHT - 1 - ySqr;
+ if(xSqr == createX && ySqr == createY && xSqr != BOARD_LEFT-2 && xSqr != BOARD_RGHT+1) {
+ ChessSquare p = boards[currentMove][ySqr][xSqr];
+ do { if(++p == EmptySquare) p = WhitePawn; } while(PieceToChar(p) == '.');
+ boards[currentMove][ySqr][xSqr] = p; DrawPosition(FALSE, boards[currentMove]);
+ return -2;
+ }
pieceSweep = shiftKey ? BlackPawn : WhitePawn; // [HGM] sweep: prepare selecting piece by mouse sweep
- toX = xSqr; toY = ySqr; lastX = x, lastY = y;
- if(flipView) toX = BOARD_WIDTH - 1 - toX; else toY = BOARD_HEIGHT - 1 - toY;
+ createX = toX = xSqr; createY = toY = ySqr; lastX = x, lastY = y;
NextPiece(0);
return 2; // grab
case IcsObserving:
while(message[s] && message[s++] != ' ');
if(BOARD_HEIGHT != h || BOARD_WIDTH != w + 4*(hand != 0) || gameInfo.holdingsSize != hand ||
dummy == 4 && gameInfo.variant != StringToVariant(varName) ) { // engine wants to change board format or variant
- if(hand <= h) deadRanks = 0; else deadRanks = hand - h, h = hand; // adapt board to over-sized holdings
+// if(hand <= h) deadRanks = 0; else deadRanks = hand - h, h = hand; // adapt board to over-sized holdings
+ if(hand > h) handSize = hand; else handSize = h;
appData.NrFiles = w; appData.NrRanks = h; appData.holdingsSize = hand;
if(dummy == 4) gameInfo.variant = StringToVariant(varName); // parent variant
InitPosition(1); // calls InitDrawingSizes to let new parameters take effect
if(mnemonic[n]) { // if somehow the engine with the selected nickname is no longer found in the list, we skip
ReplaceEngine(&first, 0);
FloatToFront(&appData.recentEngineList, command[n]);
+ ASSIGN(currentEngine[0], command[n]);
}
}
}
pieceDefs = FALSE; // [HGM] gen: reset engine-defined piece moves
deadRanks = 0; // assume entire board is used
+ handSize = 0;
for(i=0; i<EmptySquare; i++) { FREE(pieceDesc[i]); pieceDesc[i] = NULL; }
CleanupTail(); // [HGM] vari: delete any stored variations
CommentPopDown(); // [HGM] make sure no comments to the previous game keep hanging on
}
void
-ToggleSecond ()
+StartSecond ()
{
- if(second.analyzing) {
- SendToProgram("exit\n", &second);
- second.analyzing = FALSE;
- } else {
- if (second.pr == NoProc) StartChessProgram(&second);
+ if(WaitForEngine(&second, StartSecond)) return;
InitChessProgram(&second, FALSE);
FeedMovesToProgram(&second, currentMove);
SendToProgram("analyze\n", &second);
second.analyzing = TRUE;
+ ThawUI();
+}
+
+void
+ToggleSecond ()
+{
+ if(second.analyzing) {
+ SendToProgram("exit\n", &second);
+ second.analyzing = FALSE;
+ } else {
+ StartSecond();
}
}
} else {
if(x < BOARD_LEFT || x >= BOARD_RGHT) {
if(x == BOARD_LEFT-2) {
- if(y < BOARD_HEIGHT-1-gameInfo.holdingsSize) break;
+ if(y < handSize-1-gameInfo.holdingsSize) break;
boards[0][y][1] = 0;
} else
if(x == BOARD_RGHT+1) {
opt->type = SaveButton;
} else return FALSE;
*p = 0; // terminate option name
+ *(int*) (opt->name + MSG_SIZ - 104) = opt->value; // hide default values somewhere
+ if(opt->target == &opt->textValue) strncpy(opt->name + MSG_SIZ - 100, opt->textValue, 99);
// now look if the command-line options define a setting for this engine option.
if(cps->optionSettings && cps->optionSettings[0])
p = strstr(cps->optionSettings, opt->name); else p = NULL;
if(!strcmp(((char**)opt->textValue)[n], q+1)) opt->value = n;
break;
case TextBox:
+ case FileName:
+ case PathName:
safeStrCpy(opt->textValue, q+1, MSG_SIZ - (opt->textValue - opt->name));
break;
case Spin:
strcat(buf, "\n");
SendToProgram(buf, cps);
}
- *(int*) (opt->name + MSG_SIZ - 104) = opt->value; // hide default values somewhere
- if(opt->target == &opt->textValue) strncpy(opt->name + MSG_SIZ - 100, opt->textValue, 99);
return TRUE;
}
DelayedEventCallback cb = GetDelayedEvent();
if ((cb == InitBackEnd3 && cps == &first) ||
(cb == SettingsMenuIfReady && cps == &second) ||
- (cb == LoadEngine) ||
+ (cb == LoadEngine) || (cb == StartSecond) ||
(cb == TwoMachinesEventIfReady)) {
CancelDelayedEvent();
ScheduleDelayedEvent(cb, val ? 1 : 3600000);
*p++ = PieceToChar(piece);
}
for(i=0; i<gameInfo.holdingsSize; i++) { /* black holdings */
- piece = boards[move][BOARD_HEIGHT-i-1][0];
+ piece = boards[move][handSize-i-1][0];
if( piece != EmptySquare )
- for(j=0; j<(int) boards[move][BOARD_HEIGHT-i-1][1]; j++)
+ for(j=0; j<(int) boards[move][handSize-i-1][1]; j++)
*p++ = PieceToChar(piece);
}
/* [HGM] by default clear Crazyhouse holdings, if present */
if(gameInfo.holdingsWidth) {
- for(i=0; i<BOARD_HEIGHT; i++) {
+ for(i=0; i<handSize; i++) {
board[i][0] = EmptySquare; /* black holdings */
board[i][BOARD_WIDTH-1] = EmptySquare; /* white holdings */
board[i][1] = (ChessSquare) 0; /* black counts */
if(board[BOARD_HEIGHT-1][j] == ClearBoard) {
if(!bcnt) return FALSE;
if(n >= bcnt) n = rand() % bcnt; // use same randomization for black and white if possible
- for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((n -= board[BOARD_HEIGHT-1-k][1]) < 0) {
- board[BOARD_HEIGHT-1][j] = board[BOARD_HEIGHT-1-k][0]; bcnt--;
- if(--board[BOARD_HEIGHT-1-k][1] == 0) board[BOARD_HEIGHT-1-k][0] = EmptySquare;
+ for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((n -= board[handSize-1-k][1]) < 0) {
+ board[BOARD_HEIGHT-1][j] = board[handSize-1-k][0]; bcnt--;
+ if(--board[handSize-1-k][1] == 0) board[handSize-1-k][0] = EmptySquare;
break;
}
}