From 18fe8fec4c8638dccb0c59c781a9ad900ddb3043 Mon Sep 17 00:00:00 2001 From: H.G. Muller Date: Wed, 18 Nov 2009 11:34:22 -0800 Subject: [PATCH] refactoring of engineoutput This refactoring patch separates the back-end part out of xengineoutput.c, and puts it in a separate file engineoutput.c. A new header engineoutput.h included by both defines the routines for cross calling. Similarly wengineo.c will be stripped from its back-end code, (and renamed to wengineoutput.c), so WinBoard and XBoard now both use engineoutput.c rather than maintaining duplicate code in their front-end part. I also let the back-end now call EngineOutputUpdate directly, rather then through a relay in the front-end, by renaming it to SetProgramStats (the former name of the relay in winboard.c / xboard.c). Moved some templates of functions in engineoutput.c from winboard.h to frontend.h --- Makefile.am | 1 + engineoutput.c | 502 +++++++++++++++++++++++++++++++++++++++++++++++ engineoutput.h | 69 +++++++ frontend.h | 5 + winboard/makefile.gcc | 12 +- winboard/makefile.ms | 12 +- winboard/wengineo.c | 517 ++----------------------------------------------- winboard/winboard.c | 5 - winboard/winboard.h | 4 - xboard.c | 11 - xengineoutput.c | 500 ++---------------------------------------------- 11 files changed, 624 insertions(+), 1014 deletions(-) create mode 100755 engineoutput.c create mode 100755 engineoutput.h diff --git a/Makefile.am b/Makefile.am index e105ba4..b9d91cb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,6 +20,7 @@ xboard_SOURCES = backend.c backend.h backendz.h \ uci.c \ xboard.c xboard.h \ xedittags.c xedittags.h \ + engineoutput.c engineoutput.h \ xengineoutput.c \ xgamelist.c xgamelist.h\ xhistory.c xhistory.h \ diff --git a/engineoutput.c b/engineoutput.c new file mode 100755 index 0000000..9c493ad --- /dev/null +++ b/engineoutput.c @@ -0,0 +1,502 @@ +/* + * engineoutput.c - split-off backe-end from Engine output (PV) by HGM + * + * Author: Alessandro Scotti (Dec 2005) + * + * Copyright 2005 Alessandro Scotti + * + * ------------------------------------------------------------------------ + * + * GNU XBoard 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 3 of the License, or (at + * your option) any later version. + * + * GNU XBoard 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, see http://www.gnu.org/licenses/. * + * + *------------------------------------------------------------------------ + ** See the file ChangeLog for a revision history. */ + +#define SHOW_PONDERING + +#include "config.h" + +#include +#include + +#if STDC_HEADERS +# include +# include +#else /* not STDC_HEADERS */ +# if HAVE_STRING_H +# include +# else /* not HAVE_STRING_H */ +# include +# endif /* not HAVE_STRING_H */ +#endif /* not STDC_HEADERS */ + +#include "common.h" +#include "frontend.h" +#include "backend.h" +#include "engineoutput.h" + +typedef struct { + char * name; + int which; + int depth; + u64 nodes; + int score; + int time; + char * pv; + char * hint; + int an_move_index; + int an_move_count; +} EngineOutputData; + +// called by other front-end +void EngineOutputUpdate( FrontEndProgramStats * stats ); +void OutputKibitz(int window, char *text); + +// module back-end routines +static void VerifyDisplayMode(); +static void UpdateControls( EngineOutputData * ed ); + +static int lastDepth[2] = { -1, -1 }; +static int lastForwardMostMove[2] = { -1, -1 }; +static int engineState[2] = { -1, -1 }; + +#define MAX_VAR 400 +static int scores[MAX_VAR], textEnd[MAX_VAR], curDepth[2], nrVariations[2]; + +// back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments +void SetEngineState( int which, int state, char * state_data ) +{ + int x_which = 1 - which; + + if( engineState[ which ] != state ) { + engineState[ which ] = state; + + switch( state ) { + case STATE_THINKING: + SetIcon( which, nStateIcon, nThinking ); + if( engineState[ x_which ] == STATE_THINKING ) { + SetEngineState( x_which, STATE_IDLE, "" ); + } + break; + case STATE_PONDERING: + SetIcon( which, nStateIcon, nPondering ); + break; + case STATE_ANALYZING: + SetIcon( which, nStateIcon, nAnalyzing ); + break; + default: + SetIcon( which, nStateIcon, nClear ); + break; + } + } + + if( state_data != 0 ) { + DoSetWindowText( which, nStateData, state_data ); + } +} + +// back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles. +void SetProgramStats( FrontEndProgramStats * stats ) // now directly called by back-end +{ + EngineOutputData ed; + int clearMemo = FALSE; + int which; + int depth; + + if( stats == 0 ) { + SetEngineState( 0, STATE_IDLE, "" ); + SetEngineState( 1, STATE_IDLE, "" ); + return; + } + + if(gameMode == IcsObserving && !appData.icsEngineAnalyze) + return; // [HGM] kibitz: shut up engine if we are observing an ICS game + + which = stats->which; + depth = stats->depth; + + if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) { + return; + } + + if( !EngineOutputDialogExists() ) { + return; + } + + VerifyDisplayMode(); + + ed.which = which; + ed.depth = depth; + ed.nodes = stats->nodes; + ed.score = stats->score; + ed.time = stats->time; + ed.pv = stats->pv; + ed.hint = stats->hint; + ed.an_move_index = stats->an_move_index; + ed.an_move_count = stats->an_move_count; + + /* Get target control. [HGM] this is moved to front end, which get them from a table */ + if( which == 0 ) { + ed.name = first.tidy; + } + else { + ed.name = second.tidy; + } + + /* Clear memo if needed */ + if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) { + clearMemo = TRUE; + } + + if( lastForwardMostMove[which] != forwardMostMove ) { + clearMemo = TRUE; + } + + if( clearMemo ) { DoClearMemo(which); nrVariations[which] = 0; } + + /* Update */ + lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge + lastForwardMostMove[which] = forwardMostMove; + + if( ed.pv != 0 && ed.pv[0] == ' ' ) { + if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */ + ed.pv = ""; + } + } + + UpdateControls( &ed ); +} + +#define ENGINE_COLOR_WHITE 'w' +#define ENGINE_COLOR_BLACK 'b' +#define ENGINE_COLOR_UNKNOWN ' ' + +// pure back end +static char GetEngineColor( int which ) +{ + char result = ENGINE_COLOR_UNKNOWN; + + if( which == 0 || which == 1 ) { + ChessProgramState * cps; + + switch (gameMode) { + case MachinePlaysBlack: + case IcsPlayingBlack: + result = ENGINE_COLOR_BLACK; + break; + case MachinePlaysWhite: + case IcsPlayingWhite: + result = ENGINE_COLOR_WHITE; + break; + case AnalyzeMode: + case AnalyzeFile: + result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; + break; + case TwoMachinesPlay: + cps = (which == 0) ? &first : &second; + result = cps->twoMachinesColor[0]; + result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; + break; + default: ; // does not happen, but suppresses pedantic warnings + } + } + + return result; +} + +// pure back end +static char GetActiveEngineColor() +{ + char result = ENGINE_COLOR_UNKNOWN; + + if( gameMode == TwoMachinesPlay ) { + result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; + } + + return result; +} + +// pure back end +static int IsEnginePondering( int which ) +{ + int result = FALSE; + + switch (gameMode) { + case MachinePlaysBlack: + case IcsPlayingBlack: + if( WhiteOnMove(forwardMostMove) ) result = TRUE; + break; + case MachinePlaysWhite: + case IcsPlayingWhite: + if( ! WhiteOnMove(forwardMostMove) ) result = TRUE; + break; + case TwoMachinesPlay: + if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) { + if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE; + } + break; + default: ; // does not happen, but suppresses pedantic warnings + } + + return result; +} + +// back end +static void SetDisplayMode( int mode ) +{ + if( windowMode != mode ) { + windowMode = mode; + + ResizeWindowControls( mode ); + } +} + +// pure back end +static void VerifyDisplayMode() +{ + int mode; + + /* Get proper mode for current game */ + switch( gameMode ) { + case IcsObserving: // [HGM] ICS analyze + if(!appData.icsEngineAnalyze) return; + case AnalyzeMode: + case AnalyzeFile: + case MachinePlaysWhite: + case MachinePlaysBlack: + mode = 0; + break; + case IcsPlayingWhite: + case IcsPlayingBlack: + mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz + break; + case TwoMachinesPlay: + mode = 1; + break; + default: + /* Do not change */ + return; + } + + SetDisplayMode( mode ); +} + +// back end. Determine what icon to set in the color-icon field, and print it +void SetEngineColorIcon( int which ) +{ + char color = GetEngineColor(which); + int nicon = 0; + + if( color == ENGINE_COLOR_BLACK ) + nicon = nColorBlack; + else if( color == ENGINE_COLOR_WHITE ) + nicon = nColorWhite; + else + nicon = nColorUnknown; + + SetIcon( which, nColorIcon, nicon ); +} + +#define MAX_NAME_LENGTH 32 + +// [HGM] multivar: sort Thinking Output within one depth on score + +static int InsertionPoint( int len, EngineOutputData * ed ) +{ + int i, offs = 0, newScore = ed->score, n = ed->which; + + if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) + newScore = 1e6; // info lines inserted on top + if(ed->depth != curDepth[n]) { // depth has changed + curDepth[n] = ed->depth; + nrVariations[n] = 0; // throw away everything we had + } + // loop through all lines. Note even / odd used for different panes + for(i=nrVariations[n]-2; i>=0; i-=2) { + // put new item behind those we haven't looked at + offs = textEnd[i+n]; + textEnd[i+n+2] = offs + len; + scores[i+n+2] = newScore; + if(newScore < scores[i+n]) break; + // if it had higher score as previous, move previous in stead + scores[i+n+2] = scores[i+n]; + textEnd[i+n+2] = textEnd[i+n] + len; + } + if(i<0) { + offs = 0; + textEnd[n] = offs + len; + scores[n] = newScore; + } + nrVariations[n] += 2; + return offs; +} + + +// pure back end, now SetWindowText is called via wrapper DoSetWindowText +static void UpdateControls( EngineOutputData * ed ) +{ +// int isPondering = FALSE; + + char s_label[MAX_NAME_LENGTH + 32]; + + char * name = ed->name; + + /* Label */ + if( name == 0 || *name == '\0' ) { + name = "?"; + } + + strncpy( s_label, name, MAX_NAME_LENGTH ); + s_label[ MAX_NAME_LENGTH-1 ] = '\0'; + +#ifdef SHOW_PONDERING + if( IsEnginePondering( ed->which ) ) { + char buf[8]; + + buf[0] = '\0'; + + if( ed->hint != 0 && *ed->hint != '\0' ) { + strncpy( buf, ed->hint, sizeof(buf) ); + buf[sizeof(buf)-1] = '\0'; + } + else if( ed->pv != 0 && *ed->pv != '\0' ) { + char * sep = strchr( ed->pv, ' ' ); + int buflen = sizeof(buf); + + if( sep != NULL ) { + buflen = sep - ed->pv + 1; + if( buflen > sizeof(buf) ) buflen = sizeof(buf); + } + + strncpy( buf, ed->pv, buflen ); + buf[ buflen-1 ] = '\0'; + } + + SetEngineState( ed->which, STATE_PONDERING, buf ); + } + else if( gameMode == TwoMachinesPlay ) { + SetEngineState( ed->which, STATE_THINKING, "" ); + } + else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile + || (gameMode == IcsObserving && appData.icsEngineAnalyze)) { // [HGM] ICS-analyze + char buf[64]; + int time_secs = ed->time / 100; + int time_mins = time_secs / 60; + + buf[0] = '\0'; + + if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) { + char mov[16]; + + strncpy( mov, ed->hint, sizeof(mov) ); + mov[ sizeof(mov)-1 ] = '\0'; + + sprintf( buf, "[%d] %d/%d: %s [%02d:%02d:%02d]", ed->depth, ed->an_move_index, + ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 ); + } + + SetEngineState( ed->which, STATE_ANALYZING, buf ); + } + else { + SetEngineState( ed->which, STATE_IDLE, "" ); + } +#endif + + DoSetWindowText( ed->which, nLabel, s_label ); + + s_label[0] = '\0'; + + if( ed->time > 0 && ed->nodes > 0 ) { + unsigned long nps_100 = ed->nodes / ed->time; + + if( nps_100 < 100000 ) { + sprintf( s_label, "NPS: %lu", nps_100 * 100 ); + } + else { + sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 ); + } + } + + DoSetWindowText( ed->which, nLabelNPS, s_label ); + + /* Memo */ + if( ed->pv != 0 && *ed->pv != '\0' ) { + char s_nodes[24]; + char s_score[16]; + char s_time[24]; + char buf[256]; + int buflen; + int time_secs = ed->time / 100; + int time_cent = ed->time % 100; + + /* Nodes */ + if( ed->nodes < 1000000 ) { + sprintf( s_nodes, u64Display, ed->nodes ); + } + else { + sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 ); + } + + /* Score */ + if( ed->score > 0 ) { + sprintf( s_score, "+%.2f", ed->score / 100.0 ); + } + else { + sprintf( s_score, "%.2f", ed->score / 100.0 ); + } + + /* Time */ + sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent ); + + /* Put all together... */ + if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else + sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time ); + + /* Add PV */ + buflen = strlen(buf); + + strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen ); + + buf[ sizeof(buf) - 3 ] = '\0'; + + strcat( buf + buflen, "\r\n" ); + + /* Update memo */ + InsertIntoMemo( ed->which, buf, InsertionPoint(strlen(buf), ed) ); + } + + /* Colors */ + SetEngineColorIcon( ed->which ); +} + +// [HGM] kibitz: write kibitz line; split window for it if necessary +void OutputKibitz(int window, char *text) +{ + if(!EngineOutputIsUp()) return; + if(!opponentKibitzes) { // on first kibitz of game, clear memos + DoClearMemo(1); + if(gameMode == IcsObserving) DoClearMemo(0); + } + opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes. + VerifyDisplayMode(); + if(gameMode == IcsObserving) { + DoSetWindowText(0, nLabel, gameInfo.white); + SetIcon( 0, nColorIcon, nColorWhite); + SetIcon( 0, nStateIcon, nClear); + } + DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name + SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack); + SetIcon( 1, nStateIcon, nClear); + InsertIntoMemo(window-1, text, 0); // [HGM] multivar: always at top +} diff --git a/engineoutput.h b/engineoutput.h new file mode 100755 index 0000000..febbd34 --- /dev/null +++ b/engineoutput.h @@ -0,0 +1,69 @@ +/* + * wengineo.h -- Clipboard routines for WinBoard + * + * Copyright 2000,2009 Free Software Foundation, Inc. + * + * Enhancements Copyright 2005 Alessandro Scotti + * + * ------------------------------------------------------------------------ + * + * GNU XBoard 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 3 of the License, or (at + * your option) any later version. + * + * GNU XBoard 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, see http://www.gnu.org/licenses/. * + * + *------------------------------------------------------------------------ + ** See the file ChangeLog for a revision history. */ + +// [HGM] define numbers to indicate icons, for referring to them in platform-independent way +#define nColorBlack 1 +#define nColorWhite 2 +#define nColorUnknown 3 +#define nClear 4 +#define nPondering 5 +#define nThinking 6 +#define nAnalyzing 7 + +// [HGM] same for output fields (note that there are two of each type, one per color) +#define nColorIcon 1 +#define nStateIcon 2 +#define nLabel 3 +#define nStateData 4 +#define nLabelNPS 5 +#define nMemo 6 + +/* Module variables */ +#define H_MARGIN 2 +#define V_MARGIN 2 +#define LABEL_V_DISTANCE 1 /* Distance between label and memo */ +#define SPLITTER_SIZE 4 /* Distance between first memo and second label */ + +#define ICON_SIZE 14 + +#define STATE_UNKNOWN -1 +#define STATE_THINKING 0 +#define STATE_IDLE 1 +#define STATE_PONDERING 2 +#define STATE_ANALYZING 3 + +extern int windowMode; + +// back-end called by front-end +void SetEngineState( int which, int state, char * state_data ); + +// front-end called by back-end +void SetIcon( int which, int field, int nIcon ); +void DoSetWindowText(int which, int field, char *s_label); +void InsertIntoMemo( int which, char * text, int where ); +void DoClearMemo(int which); +void ResizeWindowControls( int mode ); +int EngineOutputDialogExists(); + diff --git a/frontend.h b/frontend.h index 865fc48..f4734aa 100644 --- a/frontend.h +++ b/frontend.h @@ -201,4 +201,9 @@ typedef struct FrontEndProgramStats_TAG { void SetProgramStats P(( FrontEndProgramStats * stats )); /* [AS] */ +void EngineOutputPopUp P((void)); +void EngineOutputPopDown P((void)); +int EngineOutputIsUp P((void)); +int EngineOutputDialogExists P((void)); + #endif diff --git a/winboard/makefile.gcc b/winboard/makefile.gcc index 429ed4e..a67f099 100644 --- a/winboard/makefile.gcc +++ b/winboard/makefile.gcc @@ -5,9 +5,9 @@ PROJ=winboard OBJS=backend.o book.o gamelist.o lists.o moves.o pgntags.o uci.o zippy.o\ - parser.o wbres.o wclipbrd.o wedittags.o wengineo.o wevalgraph.o\ + parser.o wbres.o wclipbrd.o wedittags.o wengineoutput.o wevalgraph.o\ wgamelist.o whistory.o winboard.o wlayout.o woptions.o wsnap.o\ - wsockerr.o help.o wsettings.o wchat.o + wsockerr.o help.o wsettings.o wchat.o engineoutput.o # make compiling less spammy @@ -125,8 +125,12 @@ woptions.o: woptions.c config.h ../common.h ../frontend.h ../backend.h ../lists. defaults.h winboard.h resource.h $(call compile, $<) -wengineo.o: wengineo.c config.h ../common.h ../frontend.h ../backend.h \ - ../lists.h winboard.h resource.h wsnap.h +wengineoutput.o: wengineoutput.c ../engineoutput.h config.h ../common.h \ + ../frontend.h ../backend.h ../lists.h winboard.h resource.h wsnap.h + $(call compile, $<) + +engineoutput.o: ../engineoutput.c ../engineoutput.h config.h ../common.h \ + ../frontend.h ../backend.h ../lists.h $(call compile, $<) whistory.o: whistory.c config.h ../common.h ../frontend.h ../backend.h \ diff --git a/winboard/makefile.ms b/winboard/makefile.ms index 6c12cfd..59d3928 100644 --- a/winboard/makefile.ms +++ b/winboard/makefile.ms @@ -13,9 +13,9 @@ PROJ = winboard OBJS=backend.obj book.obj gamelist.obj lists.obj moves.obj pgntags.obj uci.obj\ - zippy.obj parser.obj wclipbrd.obj wedittags.obj wengineo.obj wevalgraph.obj\ + zippy.obj parser.obj wclipbrd.obj wedittags.obj wengineoutput.obj wevalgraph.obj\ wgamelist.obj whistory.obj winboard.obj wlayout.obj woptions.obj wsnap.obj\ - wsockerr.obj help.obj wsettings.obj wchat.obj + wsockerr.obj help.obj wsettings.obj wchat.obj engineoutput.obj # Debugging? @@ -133,9 +133,13 @@ woptions.obj: woptions.c config.h ../common.h ../frontend.h ../backend.h \ ../lists.h defaults.h winboard.h resource.h $(CC) $(CFLAGS) woptions.c -wengineo.obj: wengineo.c config.h ../common.h ../frontend.h ../backend.h \ +wengineoutput.obj: wengineoutput.c config.h ../common.h ../frontend.h ../backend.h \ ../lists.h winboard.h resource.h wsnap.h - $(CC) $(CFLAGS) wengineo.c + $(CC) $(CFLAGS) wengineoutput.c + +engineoutput.obj: ../engineoutput.c ../engineoutput.h config.h ../common.h \ + ../frontend.h ../backend.h ../lists.h + $(CC) $(CFLAGS) ../engineoutput.c whistory.obj: whistory.c config.h ../common.h ../frontend.h ../backend.h \ ../lists.h winboard.h resource.h wsnap.h diff --git a/winboard/wengineo.c b/winboard/wengineo.c index 936fcd8..bb51525 100644 --- a/winboard/wengineo.c +++ b/winboard/wengineo.c @@ -1,5 +1,5 @@ /* - * Engine output (PV) + * wengineoutput.c - split-off front-end of Engine output (PV) by HGM * * Author: Alessandro Scotti (Dec 2005) * @@ -39,73 +39,13 @@ #include "winboard.h" #include "wsnap.h" - -// [HGM] define numbers to indicate icons, for referring to them in platform-independent way -#define nColorBlack 1 -#define nColorWhite 2 -#define nColorUnknown 3 -#define nClear 4 -#define nPondering 5 -#define nThinking 6 -#define nAnalyzing 7 - -HICON icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle - -// [HGM] same for output fields (note that there are two of each type, one per color) -#define nColorIcon 1 -#define nStateIcon 2 -#define nLabel 3 -#define nStateData 4 -#define nLabelNPS 5 -#define nMemo 6 - -HWND outputField[2][7]; // [HGM] front-end array to translate output field to window handle - -#define SHOW_PONDERING +#include "engineoutput.h" /* Module variables */ -#define H_MARGIN 2 -#define V_MARGIN 2 -#define LABEL_V_DISTANCE 1 /* Distance between label and memo */ -#define SPLITTER_SIZE 4 /* Distance between first memo and second label */ - -#define ICON_SIZE 14 - -#define STATE_UNKNOWN -1 -#define STATE_THINKING 0 -#define STATE_IDLE 1 -#define STATE_PONDERING 2 -#define STATE_ANALYZING 3 - -static int windowMode = 1; -static int needInit = TRUE; -static int lastDepth[2] = { -1, -1 }; -static int lastForwardMostMove[2] = { -1, -1 }; -static int engineState[2] = { -1, -1 }; +int windowMode = 1; static BOOLEAN engineOutputDialogUp = FALSE; - -typedef struct { -// HWND hColorIcon; // [HGM] the output-control handles are no loger passed, -// HWND hLabel; // to give better front-end / back-end separation -// HWND hStateIcon; // the front-end routines now get them from a (front-end) -// HWND hStateData; // table, indexed by output-field indicators. -// HWND hLabelNPS; -// HWND hMemo; - char * name; - int which; - int depth; - u64 nodes; - int score; - int time; - char * pv; - char * hint; - int an_move_index; - int an_move_count; -} EngineOutputData; - -static void VerifyDisplayMode(); -static void UpdateControls( EngineOutputData * ed ); -static void SetEngineState( int which, int state, char * state_data ); +HICON icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle +HWND outputField[2][7]; // [HGM] front-end array to translate output field to window handle // front end static HICON LoadIconEx( int id ) @@ -118,7 +58,6 @@ static HICON LoadIconEx( int id ) // This cleanses most other routines of front-end stuff, so they can go into the back end. static void InitializeEngineOutput() { - // if( needInit ) { // needInit was already tested before call // [HGM] made this into a table, rather than separate global variables icons[nColorBlack] = LoadIconEx( IDI_BLACK_14 ); icons[nColorWhite] = LoadIconEx( IDI_WHITE_14 ); @@ -143,8 +82,6 @@ static void InitializeEngineOutput() outputField[1][nStateData] = GetDlgItem( engineOutputDialog, IDC_StateData2 ); outputField[1][nLabelNPS] = GetDlgItem( engineOutputDialog, IDC_Engine2_NPS ); outputField[1][nMemo] = GetDlgItem( engineOutputDialog, IDC_EngineMemo2 ); -// needInit = FALSE; -// } } // front end @@ -228,8 +165,9 @@ static void PositionControlSet( HWND hDlg, int x, int y, int clientWidth, int me } // Also here some of the size calculations should go to the back end, and their actual application to a front-end routine -static void ResizeWindowControls( HWND hDlg, int mode ) +void ResizeWindowControls( int mode ) { + HWND hDlg = engineOutputDialog; // [HGM] used to be parameter, but routine is called from back-end RECT rc; int headerHeight = GetHeaderHeight(); // int labelHeight = GetControlHeight( hDlg, IDC_EngineLabel1 ); @@ -286,7 +224,7 @@ static void ResizeWindowControls( HWND hDlg, int mode ) } // front end. Actual printing of PV lines into the output field -static void InsertIntoMemo( int which, char * text, int where ) +void InsertIntoMemo( int which, char * text, int where ) { SendMessage( outputField[which][nMemo], EM_SETSEL, where, where ); // [HGM] multivar: choose insertion point @@ -295,7 +233,7 @@ static void InsertIntoMemo( int which, char * text, int where ) // front end. Associates an icon with an output field ("control" in Windows jargon). // [HGM] let it find out the output field from the 'which' number by itself -static void SetIcon( int which, int field, int nIcon ) +void SetIcon( int which, int field, int nIcon ) { if( nIcon != 0 ) { @@ -321,7 +259,7 @@ LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARA RestoreWindowPlacement( hDlg, &wpEngineOutput ); /* Restore window placement */ - ResizeWindowControls( hDlg, windowMode ); + ResizeWindowControls( windowMode ); /* Set font */ SendDlgItemMessage( engineOutputDialog, IDC_EngineMemo1, WM_SETFONT, (WPARAM)font[boardSize][MOVEHISTORY_FONT]->hf, MAKELPARAM(TRUE, 0 )); @@ -363,7 +301,7 @@ LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARA break; case WM_SIZE: - ResizeWindowControls( hDlg, windowMode ); + ResizeWindowControls( windowMode ); break; case WM_ENTERSIZEMOVE: @@ -386,6 +324,7 @@ LRESULT CALLBACK EngineOutputProc( HWND hDlg, UINT message, WPARAM wParam, LPARA void EngineOutputPopUp() { FARPROC lpProc; + static int needInit = TRUE; CheckMenuItem(GetMenu(hwndMain), IDM_ShowEngineOutput, MF_CHECKED); @@ -432,438 +371,14 @@ void DoClearMemo(int which) SendMessage( outputField[which][nMemo], WM_SETTEXT, 0, (LPARAM) "" ); } -//------------------------ pure back-end routines ------------------------------- - -#define MAX_VAR 400 -static int scores[MAX_VAR], textEnd[MAX_VAR], curDepth[2], nrVariations[2]; - -// back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments -static void SetEngineState( int which, int state, char * state_data ) -{ - int x_which = 1 - which; - - if( engineState[ which ] != state ) { - engineState[ which ] = state; - - switch( state ) { - case STATE_THINKING: - SetIcon( which, nStateIcon, nThinking ); - if( engineState[ x_which ] == STATE_THINKING ) { - SetEngineState( x_which, STATE_IDLE, "" ); - } - break; - case STATE_PONDERING: - SetIcon( which, nStateIcon, nPondering ); - break; - case STATE_ANALYZING: - SetIcon( which, nStateIcon, nAnalyzing ); - break; - default: - SetIcon( which, nStateIcon, nClear ); - break; - } - } - - if( state_data != 0 ) { - DoSetWindowText( which, nStateData, state_data ); - } -} - -// back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles. -void EngineOutputUpdate( FrontEndProgramStats * stats ) -{ - EngineOutputData ed; - int clearMemo = FALSE; - int which; - int depth; - - if( stats == 0 ) { - SetEngineState( 0, STATE_IDLE, "" ); - SetEngineState( 1, STATE_IDLE, "" ); - return; - } - - if(gameMode == IcsObserving && !appData.icsEngineAnalyze) - return; // [HGM] kibitz: shut up engine if we are observing an ICS game - - which = stats->which; - depth = stats->depth; - - if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) { - return; - } - - if( engineOutputDialog == NULL ) { - return; - } - - VerifyDisplayMode(); - - ed.which = which; - ed.depth = depth; - ed.nodes = stats->nodes; - ed.score = stats->score; - ed.time = stats->time; - ed.pv = stats->pv; - ed.hint = stats->hint; - ed.an_move_index = stats->an_move_index; - ed.an_move_count = stats->an_move_count; - - /* Get target control. [HGM] this is moved to front end, which get them from a table */ - if( which == 0 ) { - ed.name = first.tidy; - } - else { - ed.name = second.tidy; - } - - /* Clear memo if needed */ - if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) { - clearMemo = TRUE; - } - - if( lastForwardMostMove[which] != forwardMostMove ) { - clearMemo = TRUE; - } - - if( clearMemo ) { DoClearMemo(which); nrVariations[which] = 0; } - - /* Update */ - lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge - lastForwardMostMove[which] = forwardMostMove; - - if( ed.pv != 0 && ed.pv[0] == ' ' ) { - if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */ - ed.pv = ""; - } - } - - UpdateControls( &ed ); -} - -#define ENGINE_COLOR_WHITE 'w' -#define ENGINE_COLOR_BLACK 'b' -#define ENGINE_COLOR_UNKNOWN ' ' - -// pure back end -char GetEngineColor( int which ) -{ - char result = ENGINE_COLOR_UNKNOWN; - - if( which == 0 || which == 1 ) { - ChessProgramState * cps; - - switch (gameMode) { - case MachinePlaysBlack: - case IcsPlayingBlack: - result = ENGINE_COLOR_BLACK; - break; - case MachinePlaysWhite: - case IcsPlayingWhite: - result = ENGINE_COLOR_WHITE; - break; - case AnalyzeMode: - case AnalyzeFile: - result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; - break; - case TwoMachinesPlay: - cps = (which == 0) ? &first : &second; - result = cps->twoMachinesColor[0]; - result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; - break; - default: ; // does not happen, but suppresses pedantic warnings - } - } - - return result; -} - -// pure back end -char GetActiveEngineColor() -{ - char result = ENGINE_COLOR_UNKNOWN; - - if( gameMode == TwoMachinesPlay ) { - result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; - } - - return result; -} - -// pure back end -static int IsEnginePondering( int which ) -{ - int result = FALSE; - - switch (gameMode) { - case MachinePlaysBlack: - case IcsPlayingBlack: - if( WhiteOnMove(forwardMostMove) ) result = TRUE; - break; - case MachinePlaysWhite: - case IcsPlayingWhite: - if( ! WhiteOnMove(forwardMostMove) ) result = TRUE; - break; - case TwoMachinesPlay: - if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) { - if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE; - } - break; - default: ; // does not happen, but suppresses pedantic warnings - } - - return result; -} - -// back end -static void SetDisplayMode( int mode ) -{ - if( windowMode != mode ) { - windowMode = mode; - - ResizeWindowControls( engineOutputDialog, mode ); - } -} - -// pure back end -static void VerifyDisplayMode() -{ - int mode; - - /* Get proper mode for current game */ - switch( gameMode ) { - case IcsObserving: // [HGM] ICS analyze - if(!appData.icsEngineAnalyze) return; - case AnalyzeMode: - case AnalyzeFile: - case MachinePlaysWhite: - case MachinePlaysBlack: - mode = 0; - break; - case IcsPlayingWhite: - case IcsPlayingBlack: - mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz - break; - case TwoMachinesPlay: - mode = 1; - break; - default: - /* Do not change */ - return; - } - - SetDisplayMode( mode ); -} - -// back end. Determine what icon to se in the color-icon field, and print it -static void SetEngineColorIcon( int which ) -{ - char color = GetEngineColor(which); - int nicon = 0; - - if( color == ENGINE_COLOR_BLACK ) - nicon = nColorBlack; - else if( color == ENGINE_COLOR_WHITE ) - nicon = nColorWhite; - else - nicon = nColorUnknown; - - SetIcon( which, nColorIcon, nicon ); -} - -#define MAX_NAME_LENGTH 32 - -// [HGM] multivar: sort Thinking Output within one depth on score - -static int InsertionPoint( int len, EngineOutputData * ed ) -{ - int i, offs = 0, newScore = ed->score, n = ed->which; - - if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) - newScore = 1e6; // info lines inserted on top - if(ed->depth != curDepth[n]) { // depth has changed - curDepth[n] = ed->depth; - nrVariations[n] = 0; // throw away everything we had - } - // loop through all lines. Note even / odd used for different panes - for(i=nrVariations[n]-2; i>=0; i-=2) { - // put new item behind those we haven't looked at - offs = textEnd[i+n]; - textEnd[i+n+2] = offs + len; - scores[i+n+2] = newScore; - if(newScore < scores[i+n]) break; - // if it had higher score as previous, move previous in stead - scores[i+n+2] = scores[i+n]; - textEnd[i+n+2] = textEnd[i+n] + len; - } - if(i<0) { - offs = 0; - textEnd[n] = offs + len; - scores[n] = newScore; - } - nrVariations[n] += 2; - return offs; -} - -// pure back end, now SetWindowText is called via wrapper DoSetWindowText -static void UpdateControls( EngineOutputData * ed ) -{ -// int isPondering = FALSE; - - char s_label[MAX_NAME_LENGTH + 32]; - - char * name = ed->name; - - /* Label */ - if( name == 0 || *name == '\0' ) { - name = "?"; - } - - strncpy( s_label, name, MAX_NAME_LENGTH ); - s_label[ MAX_NAME_LENGTH-1 ] = '\0'; - -#ifdef SHOW_PONDERING - if( IsEnginePondering( ed->which ) ) { - char buf[8]; - - buf[0] = '\0'; - - if( ed->hint != 0 && *ed->hint != '\0' ) { - strncpy( buf, ed->hint, sizeof(buf) ); - buf[sizeof(buf)-1] = '\0'; - } - else if( ed->pv != 0 && *ed->pv != '\0' ) { - char * sep = strchr( ed->pv, ' ' ); - int buflen = sizeof(buf); - - if( sep != NULL ) { - buflen = sep - ed->pv + 1; - if( buflen > sizeof(buf) ) buflen = sizeof(buf); - } - - strncpy( buf, ed->pv, buflen ); - buf[ buflen-1 ] = '\0'; - } - - SetEngineState( ed->which, STATE_PONDERING, buf ); - } - else if( gameMode == TwoMachinesPlay ) { - SetEngineState( ed->which, STATE_THINKING, "" ); - } - else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile - || (gameMode == IcsObserving && appData.icsEngineAnalyze)) { // [HGM] ICS-analyze - char buf[64]; - int time_secs = ed->time / 100; - int time_mins = time_secs / 60; - - buf[0] = '\0'; - - if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) { - char mov[16]; - - strncpy( mov, ed->hint, sizeof(mov) ); - mov[ sizeof(mov)-1 ] = '\0'; - - sprintf( buf, "%d/%d: %s [%02d:%02d:%02d]", ed->an_move_index, ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 ); - } - - SetEngineState( ed->which, STATE_ANALYZING, buf ); - } - else { - SetEngineState( ed->which, STATE_IDLE, "" ); - } -#endif - - DoSetWindowText( ed->which, nLabel, s_label ); - - s_label[0] = '\0'; - - if( ed->time > 0 && ed->nodes > 0 ) { - unsigned long nps_100 = ed->nodes / ed->time; - - if( nps_100 < 100000 ) { - sprintf( s_label, "NPS: %lu", nps_100 * 100 ); - } - else { - sprintf( s_label, "NPS: %.1fk", nps_100 / 10.0 ); - } - } - - DoSetWindowText( ed->which, nLabelNPS, s_label ); - - /* Memo */ - if( ed->pv != 0 && *ed->pv != '\0' ) { - char s_nodes[24]; - char s_score[16]; - char s_time[24]; - char buf[256]; - int buflen; - int time_secs = ed->time / 100; - int time_cent = ed->time % 100; - - /* Nodes */ - if( ed->nodes < 1000000 ) { - sprintf( s_nodes, u64Display, ed->nodes ); - } - else { - sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 ); - } - - /* Score */ - if( ed->score > 0 ) { - sprintf( s_score, "+%.2f", ed->score / 100.0 ); - } - else { - sprintf( s_score, "%.2f", ed->score / 100.0 ); - } - - /* Time */ - sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent ); - - /* Put all together... */ - if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else - sprintf( buf, "%3d\t%s\t%s\t%s\t", ed->depth, s_score, s_nodes, s_time ); - - /* Add PV */ - buflen = strlen(buf); - - strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen ); - - buf[ sizeof(buf) - 3 ] = '\0'; - - strcat( buf + buflen, "\r\n" ); - - /* Update memo */ - InsertIntoMemo( ed->which, buf, InsertionPoint(strlen(buf), ed) ); - } - - /* Colors */ - SetEngineColorIcon( ed->which ); -} - -// back end +// front end (because only other front-end wants to know) int EngineOutputIsUp() { return engineOutputDialogUp; } -// [HGM] kibitz: write kibitz line; split window for it if necessary -void OutputKibitz(int window, char *text) +// front end, to give back-end access to engineOutputDialog +int EngineOutputDialogExists() { - if(!EngineOutputIsUp()) return; - if(!opponentKibitzes) { // on first kibitz of game, clear memos - DoClearMemo(1); - if(gameMode == IcsObserving) DoClearMemo(0); - } - opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes. - VerifyDisplayMode(); - if(gameMode == IcsObserving) { - DoSetWindowText(0, nLabel, gameInfo.white); - SetIcon( 0, nColorIcon, nColorWhite); - SetIcon( 0, nStateIcon, nClear); - } - DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name - SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack); - SetIcon( 1, nStateIcon, nClear); - InsertIntoMemo(window-1, text, 0); // [HGM] multivar: always at top + return engineOutputDialog != NULL; } diff --git a/winboard/winboard.c b/winboard/winboard.c index 774d2b7..bdcd19a 100644 --- a/winboard/winboard.c +++ b/winboard/winboard.c @@ -10620,8 +10620,3 @@ HistorySet( char movelist[][2*MOVE_LEN], int first, int last, int current ) EvalGraphSet( first, last, current, pvInfoList ); } - -void SetProgramStats( FrontEndProgramStats * stats ) -{ - EngineOutputUpdate( stats ); -} diff --git a/winboard/winboard.h b/winboard/winboard.h index af8c3f9..443f728 100644 --- a/winboard/winboard.h +++ b/winboard/winboard.h @@ -222,10 +222,6 @@ VOID EvalGraphPopDown(); Boolean EvalGraphIsUp(); extern HWND evalGraphDialog; -VOID EngineOutputPopUp(); -VOID EngineOutputPopDown(); -BOOL EngineOutputIsUp(); -VOID EngineOutputUpdate( FrontEndProgramStats * stats ); extern HWND engineOutputDialog; VOID ShowGameListProc(void); diff --git a/xboard.c b/xboard.c index 0f30640..b18b24b 100644 --- a/xboard.c +++ b/xboard.c @@ -202,8 +202,6 @@ extern char *getenv(); void EngineOutputProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); -void EngineOutputPopDown(); - #ifdef __EMX__ #ifndef HAVE_USLEEP @@ -431,7 +429,6 @@ static void CreateAnimVars P((void)); static void DragPieceMove P((int x, int y)); static void DrawDragPiece P((void)); char *ModeToWidgetName P((GameMode mode)); -void EngineOutputUpdate( FrontEndProgramStats * stats ); void ShuffleMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void EngineMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); void UciMenuProc P((Widget w, XEvent *event, String *prms, Cardinal *nprms)); @@ -9373,14 +9370,6 @@ DrawDragPiece () damage[player.startBoardY][player.startBoardX] = TRUE; } -void -SetProgramStats( FrontEndProgramStats * stats ) -{ - // [HR] TODO - // [HGM] done, but perhaps backend should call this directly? - EngineOutputUpdate( stats ); -} - #include int get_term_width() { diff --git a/xengineoutput.c b/xengineoutput.c index 8ba8a7e..7162631 100644 --- a/xengineoutput.c +++ b/xengineoutput.c @@ -70,7 +70,7 @@ extern char *getenv(); #include "frontend.h" #include "backend.h" #include "xboard.h" -// Add xengineo.h later +#include "engineoutput.h" #include "gettext.h" #ifdef ENABLE_NLS @@ -106,44 +106,19 @@ extern int squareSize; extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap; extern char *layoutName; -// temporary kludge to avoid compile errors untill all Windows code has been replaced -#define HICON int * -#define HWND int * - -// [HGM] define numbers to indicate icons, for referring to them in platform-independent way -#define nColorBlack 1 -#define nColorWhite 2 -#define nColorUnknown 3 -#define nClear 4 -#define nPondering 5 -#define nThinking 6 -#define nAnalyzing 7 - Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle - -// [HGM] same for output fields (note that there are two of each type, one per color) -#define nColorIcon 1 -#define nStateIcon 2 -#define nLabel 3 -#define nStateData 4 -#define nLabelNPS 5 -#define nMemo 6 - Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle void EngineOutputPopDown(); void engineOutputPopUp(); int EngineOutputIsUp(); -static void SetEngineColorIcon( int which ); - -#define SHOW_PONDERING +void SetEngineColorIcon( int which ); /* Imports from backend.c */ char * SavePart(char *str); extern int opponentKibitzes; -/* Imports from winboard.c */ -//extern HWND engineOutputDialog; +/* Imports from xboard.c */ extern Arg layoutArgs[2], formArgs[2], messageArgs[4]; //extern WindowPlacement wpEngineOutput; @@ -151,29 +126,10 @@ extern Arg layoutArgs[2], formArgs[2], messageArgs[4]; Position engineOutputX = -1, engineOutputY = -1; Dimension engineOutputW, engineOutputH; Widget engineOutputShell; -int engineOutputDialogUp; +static int engineOutputDialogUp; /* Module variables */ -#define H_MARGIN 2 -#define V_MARGIN 2 -#define LABEL_V_DISTANCE 1 /* Distance between label and memo */ -#define SPLITTER_SIZE 4 /* Distance between first memo and second label */ - -#define ICON_SIZE 14 - -#define STATE_UNKNOWN -1 -#define STATE_THINKING 0 -#define STATE_IDLE 1 -#define STATE_PONDERING 2 -#define STATE_ANALYZING 3 - -static int windowMode = 1; - -static int needInit = TRUE; - -static int lastDepth[2] = { -1, -1 }; -static int lastForwardMostMove[2] = { -1, -1 }; -static int engineState[2] = { -1, -1 }; +int windowMode = 1; typedef struct { char * name; @@ -188,9 +144,7 @@ typedef struct { int an_move_count; } EngineOutputData; -static void VerifyDisplayMode(); -static void UpdateControls( EngineOutputData * ed ); -static void SetEngineState( int which, int state, char * state_data ); +//static void UpdateControls( EngineOutputData * ed ); void ReadIcon(char *pixData[], int iconNr) { @@ -226,7 +180,7 @@ void DoSetWindowText(int which, int field, char *s_label) XtSetValues(outputField[which][field], &arg, 1); } -static void InsertIntoMemo( int which, char * text, int where ) +void InsertIntoMemo( int which, char * text, int where ) { Arg arg; XawTextBlock t; Widget edit; @@ -237,7 +191,7 @@ static void InsertIntoMemo( int which, char * text, int where ) // XtSetValues(outputField[which][nMemo], &arg, 1); } -static void SetIcon( int which, int field, int nIcon ) +void SetIcon( int which, int field, int nIcon ) { Arg arg; @@ -450,14 +404,14 @@ Widget EngineOutputCreate(name, text) return shell; } -void ResizeWindowControls(shell, mode) - Widget shell; +void ResizeWindowControls(mode) int mode; { Widget form1, form2; Arg args[16]; int j; Dimension ew_height, tmp; + Widget shell = engineOutputShell; form1 = XtNameToWidget(shell, "*form"); form2 = XtNameToWidget(shell, "*form2"); @@ -493,6 +447,7 @@ EngineOutputPopUp() Arg args[16]; int j; Widget edit; + static int needInit = TRUE; static char *title = _("Engine output"), *text = _("This feature is experimental"); if (engineOutputShell == NULL) { @@ -555,417 +510,14 @@ void EngineOutputPopDown() ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output } -//------------------------ pure back-end routines ------------------------------- - - -#define MAX_VAR 400 -static int scores[MAX_VAR], textEnd[MAX_VAR], curDepth[2], nrVariations[2]; - -// back end, due to front-end wrapper for SetWindowText, and new SetIcon arguments -static void SetEngineState( int which, int state, char * state_data ) -{ - int x_which = 1 - which; - - if( engineState[ which ] != state ) { - engineState[ which ] = state; - - switch( state ) { - case STATE_THINKING: - SetIcon( which, nStateIcon, nThinking ); - if( engineState[ x_which ] == STATE_THINKING ) { - SetEngineState( x_which, STATE_IDLE, "" ); - } - break; - case STATE_PONDERING: - SetIcon( which, nStateIcon, nPondering ); - break; - case STATE_ANALYZING: - SetIcon( which, nStateIcon, nAnalyzing ); - break; - default: - SetIcon( which, nStateIcon, nClear ); - break; - } - } - - if( state_data != 0 ) { - DoSetWindowText( which, nStateData, state_data ); - } -} - -// back end, now the front-end wrapper ClearMemo is used, and ed no longer contains handles. -void EngineOutputUpdate( FrontEndProgramStats * stats ) -{ - EngineOutputData ed; - int clearMemo = FALSE; - int which; - int depth; - - if( stats == 0 ) { - SetEngineState( 0, STATE_IDLE, "" ); - SetEngineState( 1, STATE_IDLE, "" ); - return; - } - - if(gameMode == IcsObserving && !appData.icsEngineAnalyze) - return; // [HGM] kibitz: shut up engine if we are observing an ICS game - - which = stats->which; - depth = stats->depth; - - if( which < 0 || which > 1 || depth < 0 || stats->time < 0 || stats->pv == 0 ) { - return; - } - - if( engineOutputShell == NULL ) { - return; - } - - VerifyDisplayMode(); - - ed.which = which; - ed.depth = depth; - ed.nodes = stats->nodes; - ed.score = stats->score; - ed.time = stats->time; - ed.pv = stats->pv; - ed.hint = stats->hint; - ed.an_move_index = stats->an_move_index; - ed.an_move_count = stats->an_move_count; - - /* Get target control. [HGM] this is moved to front end, which get them from a table */ - if( which == 0 ) { - ed.name = first.tidy; - } - else { - ed.name = second.tidy; - } - - /* Clear memo if needed */ - if( lastDepth[which] > depth || (lastDepth[which] == depth && depth <= 1) ) { - clearMemo = TRUE; - } - - if( lastForwardMostMove[which] != forwardMostMove ) { - clearMemo = TRUE; - } - - if( clearMemo ) DoClearMemo(which); - - /* Update */ - lastDepth[which] = depth == 1 && ed.nodes == 0 ? 0 : depth; // [HGM] info-line kudge - lastForwardMostMove[which] = forwardMostMove; - - if( ed.pv != 0 && ed.pv[0] == ' ' ) { - if( strncmp( ed.pv, " no PV", 6 ) == 0 ) { /* Hack on hack! :-O */ - ed.pv = ""; - } - } - - UpdateControls( &ed ); -} - -#define ENGINE_COLOR_WHITE 'w' -#define ENGINE_COLOR_BLACK 'b' -#define ENGINE_COLOR_UNKNOWN ' ' - -// pure back end -char GetEngineColor( int which ) -{ - char result = ENGINE_COLOR_UNKNOWN; - - if( which == 0 || which == 1 ) { - ChessProgramState * cps; - - switch (gameMode) { - case MachinePlaysBlack: - case IcsPlayingBlack: - result = ENGINE_COLOR_BLACK; - break; - case MachinePlaysWhite: - case IcsPlayingWhite: - result = ENGINE_COLOR_WHITE; - break; - case AnalyzeMode: - case AnalyzeFile: - result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; - break; - case TwoMachinesPlay: - cps = (which == 0) ? &first : &second; - result = cps->twoMachinesColor[0]; - result = result == 'w' ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; - break; - } - } - - return result; -} - -// pure back end -char GetActiveEngineColor() -{ - char result = ENGINE_COLOR_UNKNOWN; - - if( gameMode == TwoMachinesPlay ) { - result = WhiteOnMove(forwardMostMove) ? ENGINE_COLOR_WHITE : ENGINE_COLOR_BLACK; - } - - return result; -} - -// pure back end -static int IsEnginePondering( int which ) -{ - int result = FALSE; - - switch (gameMode) { - case MachinePlaysBlack: - case IcsPlayingBlack: - if( WhiteOnMove(forwardMostMove) ) result = TRUE; - break; - case MachinePlaysWhite: - case IcsPlayingWhite: - if( ! WhiteOnMove(forwardMostMove) ) result = TRUE; - break; - case TwoMachinesPlay: - if( GetActiveEngineColor() != ENGINE_COLOR_UNKNOWN ) { - if( GetEngineColor( which ) != GetActiveEngineColor() ) result = TRUE; - } - break; - } - - return result; -} - -// back end -static void SetDisplayMode( int mode ) -{ - if( windowMode != mode ) { - windowMode = mode; - - ResizeWindowControls( engineOutputShell, mode ); - } -} - -// pure back end -void VerifyDisplayMode() -{ - int mode; - - /* Get proper mode for current game */ - switch( gameMode ) { - case IcsObserving: // [HGM] ICS analyze - if(!appData.icsEngineAnalyze) return; - case AnalyzeMode: - case AnalyzeFile: - case MachinePlaysWhite: - case MachinePlaysBlack: - mode = 0; - break; - case IcsPlayingWhite: - case IcsPlayingBlack: - mode = appData.zippyPlay && opponentKibitzes; // [HGM] kibitz - break; - case TwoMachinesPlay: - mode = 1; - break; - default: - /* Do not change */ - return; - } - - SetDisplayMode( mode ); -} - -// back end. Determine what icon to se in the color-icon field, and print it -static void SetEngineColorIcon( int which ) -{ - char color = GetEngineColor(which); - int nicon = 0; - - if( color == ENGINE_COLOR_BLACK ) - nicon = nColorBlack; - else if( color == ENGINE_COLOR_WHITE ) - nicon = nColorWhite; - else - nicon = nColorUnknown; - - SetIcon( which, nColorIcon, nicon ); -} - -#define MAX_NAME_LENGTH 32 - -// [HGM] multivar: sort Thinking Output within one depth on score - -static int InsertionPoint( int len, EngineOutputData * ed ) -{ - int i, offs = 0, newScore = ed->score, n = ed->which; - - if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) - newScore = 1e6; // info lines inserted on top - if(ed->depth != curDepth[n]) { // depth has changed - curDepth[n] = ed->depth; - nrVariations[n] = 0; // throw away everything we had - } - // loop through all lines. Note even / odd used for different panes - for(i=nrVariations[n]-2; i>=0; i-=2) { - // put new item behind those we haven't looked at - offs = textEnd[i+n]; - textEnd[i+n+2] = offs + len; - scores[i+n+2] = newScore; - if(newScore < scores[i+n]) break; - // if it had higher score as previous, move previous in stead - scores[i+n+2] = scores[i+n]; - textEnd[i+n+2] = textEnd[i+n] + len; - } - if(i<0) { - offs = 0; - textEnd[n] = offs + len; - scores[n] = newScore; - } - nrVariations[n] += 2; - return offs; -} - -// pure back end, now SetWindowText is called via wrapper DoSetWindowText -static void UpdateControls( EngineOutputData * ed ) +int EngineOutputIsUp() { - int isPondering = FALSE; - - char s_label[MAX_NAME_LENGTH + 32]; - - char * name = ed->name; - - /* Label */ - if( name == 0 || *name == '\0' ) { - name = "?"; - } - - strncpy( s_label, name, MAX_NAME_LENGTH ); - s_label[ MAX_NAME_LENGTH-1 ] = '\0'; - -#ifdef SHOW_PONDERING - if( IsEnginePondering( ed->which ) ) { - char buf[8]; - - buf[0] = '\0'; - - if( ed->hint != 0 && *ed->hint != '\0' ) { - strncpy( buf, ed->hint, sizeof(buf) ); - buf[sizeof(buf)-1] = '\0'; - } - else if( ed->pv != 0 && *ed->pv != '\0' ) { - char * sep = strchr( ed->pv, ' ' ); - int buflen = sizeof(buf); - - if( sep != NULL ) { - buflen = sep - ed->pv + 1; - if( buflen > sizeof(buf) ) buflen = sizeof(buf); - } - - strncpy( buf, ed->pv, buflen ); - buf[ buflen-1 ] = '\0'; - } - - SetEngineState( ed->which, STATE_PONDERING, buf ); - } - else if( gameMode == TwoMachinesPlay ) { - SetEngineState( ed->which, STATE_THINKING, "" ); - } - else if( gameMode == AnalyzeMode || gameMode == AnalyzeFile - || gameMode == IcsObserving && appData.icsEngineAnalyze) { // [HGM] ICS-analyze - char buf[64]; - int time_secs = ed->time / 100; - int time_mins = time_secs / 60; - - buf[0] = '\0'; - - if( ed->an_move_index != 0 && ed->an_move_count != 0 && *ed->hint != '\0' ) { - char mov[16]; - - strncpy( mov, ed->hint, sizeof(mov) ); - mov[ sizeof(mov)-1 ] = '\0'; - - sprintf( buf, "[%d] %d/%d: %s [%02d:%02d:%02d]", ed->depth, ed->an_move_index, - ed->an_move_count, mov, time_mins / 60, time_mins % 60, time_secs % 60 ); - } - - SetEngineState( ed->which, STATE_ANALYZING, buf ); - } - else { - SetEngineState( ed->which, STATE_IDLE, "" ); - } -#endif - - DoSetWindowText( ed->which, nLabel, s_label ); - - s_label[0] = '\0'; - - if( ed->time > 0 && ed->nodes > 0 ) { - unsigned long nps_100 = ed->nodes / ed->time; - - if( nps_100 < 100000 ) { - sprintf( s_label, _("NPS: %lu"), nps_100 * 100 ); - } - else { - sprintf( s_label, _("NPS: %.1fk"), nps_100 / 10.0 ); - } - } - - DoSetWindowText( ed->which, nLabelNPS, s_label ); - - /* Memo */ - if( ed->pv != 0 && *ed->pv != '\0' ) { - char s_nodes[24]; - char s_score[16]; - char s_time[24]; - char buf[256]; - int buflen; - int time_secs = ed->time / 100; - int time_cent = ed->time % 100; - - /* Nodes */ - if( ed->nodes < 1000000 ) { - sprintf( s_nodes, u64Display, ed->nodes ); - } - else { - sprintf( s_nodes, "%.1fM", u64ToDouble(ed->nodes) / 1000000.0 ); - } - - /* Score */ - if( ed->score > 0 ) { - sprintf( s_score, "+%.2f", ed->score / 100.0 ); - } else - sprintf( s_score, "%.2f", ed->score / 100.0 ); - - /* Time */ - sprintf( s_time, "%d:%02d.%02d", time_secs / 60, time_secs % 60, time_cent ); - - /* Put all together... */ - if(ed->nodes == 0 && ed->score == 0 && ed->time == 0) sprintf( buf, "%3d\t", ed->depth ); else - sprintf( buf, "%3d %s %s\t%s\t", ed->depth, s_score, s_nodes, s_time ); - - /* Add PV */ - buflen = strlen(buf); - - strncpy( buf + buflen, ed->pv, sizeof(buf) - buflen ); - - buf[ sizeof(buf) - 3 ] = '\0'; - - strcat( buf + buflen, "\n" ); - - /* Update memo */ - InsertIntoMemo( ed->which, buf, InsertionPoint(strlen(buf), ed) ); - } - - /* Colors */ - SetEngineColorIcon( ed->which ); + return engineOutputDialogUp; } -// back end -int EngineOutputIsUp() +int EngineOutputDialogExists() { - return engineOutputDialogUp; + return engineOutputShell != NULL; } void @@ -980,26 +532,4 @@ EngineOutputProc(w, event, prms, nprms) } else { EngineOutputPopUp(); } -// ToNrEvent(currentMove); -} - -// [HGM] kibitz: write kibitz line; split window for it if necessary -void OutputKibitz(int window, char *text) -{ - if(!EngineOutputIsUp()) return; - if(!opponentKibitzes) { // on first kibitz of game, clear memos - DoClearMemo(1); - if(gameMode == IcsObserving) DoClearMemo(0); - } - opponentKibitzes = TRUE; // this causes split window DisplayMode in ICS modes. - VerifyDisplayMode(); - if(gameMode == IcsObserving) { - DoSetWindowText(0, nLabel, gameInfo.white); - SetIcon( 0, nColorIcon, nColorWhite); - SetIcon( 0, nStateIcon, nClear); - } - DoSetWindowText(1, nLabel, gameMode == IcsPlayingBlack ? gameInfo.white : gameInfo.black); // opponent name - SetIcon( 1, nColorIcon, gameMode == IcsPlayingBlack ? nColorWhite : nColorBlack); - SetIcon( 1, nStateIcon, nClear); - InsertIntoMemo(window-1, text, 0); } -- 1.7.0.4