#endif
#include "backendz.h"
#include "evalgraph.h"
+#include "engineoutput.h"
#include "gettext.h"
#ifdef ENABLE_NLS
#endif
ChessProgramState *WhitePlayer();
-void InsertIntoMemo P((int which, char *text)); // [HGM] kibitz: in engineo.c
int VerifyDisplayMode P(());
char *GetInfoFromComment( int, char * ); // [HGM] PV time: returns stripped comment
char marker[BOARD_RANKS][BOARD_FILES]; /* [HGM] marks for target squares */
char legal[BOARD_RANKS][BOARD_FILES]; /* [HGM] legal target squares */
char lastMsg[MSG_SIZ];
+char lastTalker[MSG_SIZ];
ChessSquare pieceSweep = EmptySquare;
ChessSquare promoSweep = EmptySquare, defaultPromoChoice;
int promoDefaultAltered;
default:
break;
}
+ if(appData.fischerCastling) flags |= F_FRC_TYPE_CASTLING, flags &= ~F_ALL_CASTLE_OK; // [HGM] fischer
return flags;
}
ExitAnalyzeMode();
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", cps);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(cps->pr, cps->useSigterm);
+ DestroyChildProcess(cps->pr, 4 + cps->useSigterm);
}
cps->pr = NoProc;
if(appData.debugMode) fprintf(debugFP, "Unload %s\n", cps->which);
int backup; /* [DM] For zippy color lines */
char *p;
char talker[MSG_SIZ]; // [HGM] chat
- int channel;
+ int channel, collective=0;
connectionAlive = TRUE; // [HGM] alive: I think, therefore I am...
char mess[MSG_SIZ];
snprintf(mess, MSG_SIZ, "%s%s", talker, parse);
OutputChatMessage(chattingPartner, mess);
+ if(collective == 1) { // broadcasted talk also goes to private chatbox of talker
+ int p;
+ talker[strlen(talker+1)-1] = NULLCHAR; // strip closing delimiter
+ for(p=0; p<MAX_CHAT; p++) if(!StrCaseCmp(talker+1, chatPartner[p])) {
+ snprintf(mess, MSG_SIZ, "%s: %s", chatPartner[chattingPartner], parse);
+ OutputChatMessage(p, mess);
+ break;
+ }
+ }
chattingPartner = -1;
- next_out = i+1; // [HGM] suppress printing in ICS window
+ if(collective != 3) next_out = i+1; // [HGM] suppress printing in ICS window
+ collective = 0;
} else
if(!suppressKibitz) // [HGM] kibitz
AppendComment(forwardMostMove, StripHighlight(parse), TRUE);
looking_at(buf, &i, "*(*)(*)(*)(*):") && sscanf(star_match[4], "%d", &channel) == 1 )) {
int p;
sscanf(star_match[0], "%[^(]", talker+1); // strip (C) or (U) off ICS handle
- chattingPartner = -1;
+ chattingPartner = -1; collective = 0;
if(channel >= 0) // channel broadcast; look if there is a chatbox for this channel
for(p=0; p<MAX_CHAT; p++) {
+ collective = 1;
if(chatPartner[p][0] >= '0' && chatPartner[p][0] <= '9' && channel == atoi(chatPartner[p])) {
talker[0] = '['; strcat(talker, "] ");
- Colorize(channel == 1 ? ColorChannel1 : ColorChannel, FALSE);
+ Colorize((channel == 1 ? ColorChannel1 : ColorChannel), FALSE);
chattingPartner = p; break;
}
} else
if(buf[i-3] == 'e') // kibitz; look if there is a KIBITZ chatbox
for(p=0; p<MAX_CHAT; p++) {
+ collective = 1;
if(!strcmp("kibitzes", chatPartner[p])) {
talker[0] = '['; strcat(talker, "] ");
chattingPartner = p; break;
} else
if(buf[i-3] == 'r') // whisper; look if there is a WHISPER chatbox
for(p=0; p<MAX_CHAT; p++) {
+ collective = 1;
if(!strcmp("whispers", chatPartner[p])) {
talker[0] = '['; strcat(talker, "] ");
chattingPartner = p; break;
if(buf[i-3] == 't' || buf[oldi+2] == '>') {// shout, c-shout or it; look if there is a 'shouts' chatbox
if(buf[i-8] == '-' && buf[i-3] == 't')
for(p=0; p<MAX_CHAT; p++) { // c-shout; check if dedicatesd c-shout box exists
+ collective = 1;
if(!strcmp("c-shouts", chatPartner[p])) {
talker[0] = '('; strcat(talker, ") "); Colorize(ColorSShout, FALSE);
chattingPartner = p; break;
}
if(chattingPartner < 0)
for(p=0; p<MAX_CHAT; p++) {
+ collective = 1;
if(!strcmp("shouts", chatPartner[p])) {
if(buf[oldi+2] == '>') { talker[0] = '<'; strcat(talker, "> "); Colorize(ColorShout, FALSE); }
else if(buf[i-8] == '-') { talker[0] = '('; strcat(talker, ") "); Colorize(ColorSShout, FALSE); }
}
if(chattingPartner<0) // if not, look if there is a chatbox for this indivdual
for(p=0; p<MAX_CHAT; p++) if(!StrCaseCmp(talker+1, chatPartner[p])) {
- talker[0] = 0; Colorize(ColorTell, FALSE);
+ talker[0] = 0;
+ Colorize(ColorTell, FALSE);
+ if(collective) safeStrCpy(talker, "broadcasts: ", MSG_SIZ);
+ collective |= 2;
chattingPartner = p; break;
}
- if(chattingPartner<0) i = oldi; else {
+ if(chattingPartner<0) i = oldi, safeStrCpy(lastTalker, talker+1, MSG_SIZ); else {
Colorize(curColor, TRUE); // undo the bogus colorations we just made to trigger the souds
- if(oldi > 0 && buf[oldi-1] == '\n') oldi--;
- if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out);
started = STARTED_COMMENT;
parse_pos = 0; parse[0] = NULLCHAR;
savingComment = 3 + chattingPartner; // counts as TRUE
- suppressKibitz = TRUE;
- continue;
+ if(collective == 3) i = oldi; else {
+ suppressKibitz = TRUE;
+ if(oldi > 0 && buf[oldi-1] == '\n') oldi--;
+ if (oldi > next_out) SendToPlayer(&buf[next_out], oldi - next_out);
+ continue;
+ }
}
} // [HGM] chat: end of patch
parse[parse_pos] = NULLCHAR;
started = STARTED_COMMENT;
savingComment = TRUE;
- } else {
+ } else if(collective != 3) {
started = STARTED_CHATTER;
savingComment = FALSE;
}
/* Added by Tord: Send castle moves in "O-O" in FRC games if required by
* the engine. It would be nice to have a better way to identify castle
* moves here. */
- if((gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom)
- && cps->useOOCastle) {
+ if(appData.fischerCastling && cps->useOOCastle) {
int fromX = moveList[moveNum][0] - AAA;
int fromY = moveList[moveNum][1] - ONE;
int toX = moveList[moveNum][2] - AAA;
} else if(strstr(buf+lineStart, "exclude:") == buf+lineStart) { // exclude moves clicked
ExcludeClick(origIndex - lineStart);
return FALSE;
+ } else if(!strncmp(buf+lineStart, "dep\t", 4)) { // column headers clicked
+ Collapse(origIndex - lineStart);
+ return FALSE;
}
ParsePV(buf+startPV, FALSE, gameMode != AnalyzeMode);
*start = startPV; *end = index-1;
oldh = gameInfo.holdingsWidth;
static int oldv;
- if(appData.icsActive) shuffleOpenings = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request
+ if(appData.icsActive) shuffleOpenings = appData.fischerCastling = FALSE; // [HGM] shuffle: in ICS mode, only shuffle on ICS request
/* [AS] Initialize pv info list [HGM] and game status */
{
switch (gameInfo.variant) {
case VariantFischeRandom:
shuffleOpenings = TRUE;
+ appData.fischerCastling = TRUE;
default:
break;
case VariantShatranj:
break;
case VariantCapaRandom:
shuffleOpenings = TRUE;
+ appData.fischerCastling = TRUE;
case VariantCapablanca:
pieces = CapablancaArray;
gameInfo.boardWidth = 10;
promotionZoneSize = 3;
}
- // Treat Lance as Pawn when it is not representing Amazon
- if(gameInfo.variant != VariantSuper) {
+ // Treat Lance as Pawn when it is not representing Amazon or Lance
+ if(gameInfo.variant != VariantSuper && gameInfo.variant != VariantChu) {
if(piece == WhiteLance) piece = WhitePawn; else
if(piece == BlackLance) piece = BlackPawn;
}
char lastLoadGameTitle[MSG_SIZ], lastLoadPositionTitle[MSG_SIZ];
ChessMove lastLoadGameStart = EndOfFile;
int doubleClick;
+Boolean addToBookFlag;
void
UserMoveEvent(int fromX, int fromY, int toX, int toY, int promoChar)
return;
}
+ if(addToBookFlag) { // adding moves to book
+ char buf[MSG_SIZ], move[MSG_SIZ];
+ CoordsToAlgebraic(boards[currentMove], PosFlags(currentMove), fromY, fromX, toY, toX, promoChar, move);
+ snprintf(buf, MSG_SIZ, " 0.0%% 1 %s\n", move);
+ AddBookMove(buf);
+ addToBookFlag = FALSE;
+ ClearHighlights();
+ return;
+ }
+
FinishMove(moveType, fromX, fromY, toX, toY, promoChar);
}
/* Check if clicking again on the same color piece */
fromP = boards[currentMove][fromY][fromX];
toP = boards[currentMove][y][x];
- frc = gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess;
+ frc = appData.fischerCastling || gameInfo.variant == VariantSChess;
if( (killX < 0 || x != fromX || y != fromY) && // [HGM] lion: do not interpret igui as deselect!
((WhitePawn <= fromP && fromP <= WhiteKing &&
WhitePawn <= toP && toP <= WhiteKing &&
GameEnds(machineWhite ? BlackWins : WhiteWins,
buf1, GE_XBOARD);
return;
- } else if(gameInfo.variant != VariantFischeRandom && gameInfo.variant != VariantCapaRandom)
+ } else if(!appData.fischerCastling)
/* [HGM] Kludge to handle engines that send FRC-style castling
when they shouldn't (like TSCP-Gothic) */
switch(moveType) {
}
/* [AS] Adjudicate game if needed (note: remember that forwardMostMove now points past the last move) */
- if( gameMode == TwoMachinesPlay && adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {
+ if( gameMode == TwoMachinesPlay && appData.adjudicateLossThreshold != 0 && forwardMostMove >= adjudicateLossPlies ) {
int count = 0;
while( count < adjudicateLossPlies ) {
if( count & 1 ) {
score = -score; /* Flip score for winning side */
}
-
- if( score > adjudicateLossThreshold ) {
+printf("score=%d count=%d\n",score,count);
+ if( score > appData.adjudicateLossThreshold ) {
break;
}
(unsigned int)programStats.nodes / (10*abs(programStats.time) + 1.),
programStats.movelist);
SendToICS(buf);
-if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats.nodes, programStats.nodes);
}
}
#endif
int dummy, w, h, hand, s=6; char buf[MSG_SIZ], varName[MSG_SIZ];
if(appData.icsActive || forwardMostMove != 0 || cps != &first) return;
*buf = NULLCHAR;
- if(sscanf(message, "setup (%s", buf) == 1) s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
+ if(sscanf(message, "setup (%s", buf) == 1) {
+ s = 8 + strlen(buf), buf[s-9] = NULLCHAR, SetCharTable(pieceToChar, buf);
+ ASSIGN(appData.pieceToCharTable, buf);
+ }
if(startedFromSetupPosition) return;
dummy = sscanf(message+s, "%dx%d+%d_%s", &w, &h, &hand, varName);
if(dummy >= 3) {
}
piece = board[toY][toX] = (ChessSquare) fromX;
} else {
- ChessSquare victim;
+// ChessSquare victim;
int i;
if( killX >= 0 && killY >= 0 ) // [HGM] lion: Lion trampled over something
- victim = board[killY][killX],
+// victim = board[killY][killX],
board[killY][killX] = EmptySquare,
board[EP_STATUS] = EP_CAPTURE;
SendToProgram(buf, cps);
}
+ setboardSpoiledMachineBlack = FALSE;
SendToProgram(cps->initString, cps);
if (gameInfo.variant != VariantNormal &&
gameInfo.variant != VariantLoadable
ExitAnalyzeMode();
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &first);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(first.pr, first.useSigterm);
+ DestroyChildProcess(first.pr, 4 + first.useSigterm);
first.reload = TRUE;
}
first.pr = NoProc;
if (second.pr != NoProc) {
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &second);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(second.pr, second.useSigterm);
+ DestroyChildProcess(second.pr, 4 + second.useSigterm);
second.reload = TRUE;
}
second.pr = NoProc;
return;
}
+ if (appData.icsActive) printf("\n"); // [HGM] end on new line after closing XBoard
if (appData.icsActive && appData.colorize) Colorize(ColorNone, FALSE);
if (telnetISR != NULL) {
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &first);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(first.pr, 10 /* [AS] first.useSigterm */ );
+ DestroyChildProcess(first.pr, 4 + first.useSigterm /* [AS] first.useSigterm */ );
}
if (second.pr != NoProc) {
DoSleep( appData.delayBeforeQuit );
SendToProgram("quit\n", &second);
- DoSleep( appData.delayAfterQuit );
- DestroyChildProcess(second.pr, 10 /* [AS] second.useSigterm */ );
+ DestroyChildProcess(second.pr, 4 + second.useSigterm /* [AS] second.useSigterm */ );
}
if (first.isr != NULL) {
RemoveInputSource(first.isr);
first.maybeThinking = FALSE; /* avoid killing GNU Chess */
EngineOutputPopUp();
}
- if (!appData.icsEngineAnalyze) gameMode = AnalyzeMode;
+ if (!appData.icsEngineAnalyze) {
+ gameMode = AnalyzeMode;
+ ClearEngineOutputPane(0); // [TK] exclude: to print exclusion/multipv header
+ }
pausing = FALSE;
ModeHighlight();
SetGameInfo();
} else {
if(nrCastlingRights) {
q = p;
- if(gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom) {
+ if(appData.fischerCastling) {
/* [HGM] write directly from rights */
if(boards[move][CASTLING][2] != NoRights &&
boards[move][CASTLING][0] != NoRights )
Boolean
ParseFEN (Board board, int *blackPlaysFirst, char *fen, Boolean autoSize)
{
- int i, j, k, w=0;
+ int i, j, k, w=0, subst=0, shuffle=0;
char *p, c;
int emptycount, virgin[BOARD_FILES];
ChessSquare piece;
if (j + emptycount > gameInfo.boardWidth) return FALSE;
while (emptycount--)
board[i][(j++)+gameInfo.holdingsWidth] = EmptySquare;
+ } else if (*p == '<') {
+ if(i == BOARD_HEIGHT-1) shuffle = 1;
+ else if (i != 0 || !shuffle) return FALSE;
+ p++;
+ } else if (shuffle && *p == '>') {
+ p++; // for now ignore closing shuffle range, and assume rank-end
+ } else if (*p == '?') {
+ if (j >= gameInfo.boardWidth) return FALSE;
+ if (i != 0 && i != BOARD_HEIGHT-1) return FALSE; // only on back-rank
+ board[i][(j++)+gameInfo.holdingsWidth] = ClearBoard; p++; subst++; // placeHolder
} else if (*p == '+' || isalpha(*p)) {
if (j >= gameInfo.boardWidth) return FALSE;
if(*p=='+') {
/* [HGM] look for Crazyhouse holdings here */
while(*p==' ') p++;
if( gameInfo.holdingsWidth && p[-1] == '/' || *p == '[') {
+ int swap=0, wcnt=0, bcnt=0;
if(*p == '[') p++;
+ if(*p == '<') swap++, p++;
if(*p == '-' ) p++; /* empty holdings */ else {
if( !gameInfo.holdingsWidth ) return FALSE; /* no room to put holdings! */
/* if we would allow FEN reading to set board size, we would */
if( i >= gameInfo.holdingsSize ) return FALSE;
board[BOARD_HEIGHT-1-i][0] = piece; /* black holdings */
board[BOARD_HEIGHT-1-i][1]++; /* black counts */
+ bcnt++;
} else {
i = (int)piece - (int)WhitePawn;
i = PieceToNumber((ChessSquare)i);
if( i >= gameInfo.holdingsSize ) return FALSE;
board[i][BOARD_WIDTH-1] = piece; /* white holdings */
board[i][BOARD_WIDTH-2]++; /* black holdings */
+ wcnt++;
+ }
+ }
+ if(subst) { // substitute back-rank question marks by holdings pieces
+ for(j=BOARD_LEFT; j<BOARD_RGHT; j++) {
+ int k, m, n = bcnt + 1;
+ if(board[0][j] == ClearBoard) {
+ if(!wcnt) return FALSE;
+ n = rand() % wcnt;
+ for(k=0, m=n; k<gameInfo.holdingsSize; k++) if((m -= board[k][BOARD_WIDTH-2]) < 0) {
+ board[0][j] = board[k][BOARD_WIDTH-1]; wcnt--;
+ if(--board[k][BOARD_WIDTH-2] == 0) board[k][BOARD_WIDTH-1] = EmptySquare;
+ break;
+ }
+ }
+ 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;
+ break;
+ }
+ }
}
+ subst = 0;
}
}
if(*p == ']') p++;
}
+ if(subst) return FALSE; // substitution requested, but no holdings
+
while(*p == ' ') p++;
/* Active color */
board[EP_STATUS] = EP_UNKNOWN;
for(i=0; i<nrCastlingRights; i++ ) {
board[CASTLING][i] =
- gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom ? NoRights : initialRights[i];
+ appData.fischerCastling ? NoRights : initialRights[i];
} /* assume possible unless obviously impossible */
if(initialRights[0]!=NoRights && board[castlingRank[0]][initialRights[0]] != WhiteRook) board[CASTLING][0] = NoRights;
if(initialRights[1]!=NoRights && board[castlingRank[1]][initialRights[1]] != WhiteRook) board[CASTLING][1] = NoRights;
while(*p==' ') p++;
if(nrCastlingRights) {
+ int fischer = 0;
if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) virgin[i] = 0;
if(*p >= 'A' && *p <= 'Z' || *p >= 'a' && *p <= 'z' || *p=='-') {
/* castling indicator present, so default becomes no castlings */
}
}
while(*p=='K' || *p=='Q' || *p=='k' || *p=='q' || *p=='-' ||
- (gameInfo.variant == VariantFischeRandom || gameInfo.variant == VariantCapaRandom || gameInfo.variant == VariantSChess) &&
+ (appData.fischerCastling || gameInfo.variant == VariantSChess) &&
( *p >= 'a' && *p < 'a' + gameInfo.boardWidth) ||
( *p >= 'A' && *p < 'A' + gameInfo.boardWidth) ) {
int c = *p++, whiteKingFile=NoRights, blackKingFile=NoRights;
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][0] != NoRights) virgin[board[CASTLING][0]] |= VIRGIN_W;
if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= VIRGIN_W;
+ if(whiteKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1;
break;
case'Q':
for(i=BOARD_LEFT; i<BOARD_RGHT && board[0][i]!=WhiteRook && i<whiteKingFile; i++);
board[CASTLING][2] = whiteKingFile;
if(board[CASTLING][1] != NoRights) virgin[board[CASTLING][1]] |= VIRGIN_W;
if(board[CASTLING][2] != NoRights) virgin[board[CASTLING][2]] |= VIRGIN_W;
+ if(whiteKingFile != BOARD_WIDTH>>1|| i != BOARD_LEFT) fischer = 1;
break;
case'k':
for(i=BOARD_RGHT-1; board[BOARD_HEIGHT-1][i]!=BlackRook && i>blackKingFile; i--);
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][3] != NoRights) virgin[board[CASTLING][3]] |= VIRGIN_B;
if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B;
+ if(blackKingFile != BOARD_WIDTH>>1|| i != BOARD_RGHT-1) fischer = 1;
break;
case'q':
for(i=BOARD_LEFT; i<BOARD_RGHT && board[BOARD_HEIGHT-1][i]!=BlackRook && i<blackKingFile; i++);
board[CASTLING][5] = blackKingFile;
if(board[CASTLING][4] != NoRights) virgin[board[CASTLING][4]] |= VIRGIN_B;
if(board[CASTLING][5] != NoRights) virgin[board[CASTLING][5]] |= VIRGIN_B;
+ if(blackKingFile != BOARD_WIDTH>>1|| i != BOARD_LEFT) fischer = 1;
case '-':
break;
default: /* FRC castlings */
}
for(i=0; i<nrCastlingRights; i++)
if(board[CASTLING][i] != NoRights) initialRights[i] = board[CASTLING][i];
- if(gameInfo.variant == VariantSChess) for(i=0; i<BOARD_FILES; i++) board[VIRGIN][i] = virgin[i];
+ if(gameInfo.variant == VariantSChess)
+ for(i=0; i<BOARD_FILES; i++) board[VIRGIN][i] = shuffle ? VIRGIN_W | VIRGIN_B : virgin[i]; // when shuffling assume all virgin
+ if(fischer && shuffle) appData.fischerCastling = TRUE;
if (appData.debugMode) {
fprintf(debugFP, "FEN castling rights:");
for(i=0; i<nrCastlingRights; i++)
while(*p==' ') p++;
}
+ if(shuffle) SetUpShuffle(board, appData.defaultFrcPosition);
+
/* read e.p. field in games that know e.p. capture */
if(gameInfo.variant != VariantShogi && gameInfo.variant != VariantXiangqi &&
gameInfo.variant != VariantShatranj && gameInfo.variant != VariantCourier &&