summaryrefslogtreecommitdiff
path: root/src/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/command.c')
-rwxr-xr-xsrc/command.c2655
1 files changed, 2655 insertions, 0 deletions
diff --git a/src/command.c b/src/command.c
new file mode 100755
index 0000000..d528994
--- /dev/null
+++ b/src/command.c
@@ -0,0 +1,2655 @@
+/**
+
+Copyright (c) Scott Gasch
+
+Module Name:
+
+ command.c
+
+Abstract:
+
+ Process commands received by the input thread. Note: the COMMAND
+ macro is defined in chess.h and used heavily in this module to
+ build function declarations. It hides four parameters:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Author:
+
+ Scott Gasch ([email protected]) 13 May 2004
+
+Revision History:
+
+ $Id: command.c 354 2008-06-30 05:10:08Z scott $
+
+**/
+
+#include "chess.h"
+
+#define MAX_ARGS 32
+int g_eModeBeforeAnalyze = -1;
+
+typedef void (COMMAND_PARSER_FUNCTION)(CHAR *szInput,
+ ULONG argc,
+ CHAR *argv[],
+ POSITION *pos);
+typedef struct _COMMAND_PARSER_ENTRY
+{
+ CHAR *szOpcode;
+ COMMAND_PARSER_FUNCTION *pFunction;
+ FLAG fHandleOnTheFly;
+ FLAG fInvisible;
+ FLAG fWinBoard;
+ CHAR *szSimpleHelp;
+}
+COMMAND_PARSER_ENTRY;
+
+
+COMMAND(AnalyzeCommand)
+/**
+
+Routine description:
+
+ This function implements the 'analyze' engine command.
+
+ Usage:
+
+ analyze
+
+ This command takes no arguments and causes the engine to enter
+ analyze mode. See also: exit
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (g_Options.ePlayMode != ANALYZE_MODE)
+ {
+ g_eModeBeforeAnalyze = g_Options.ePlayMode;
+ g_Options.ePlayMode = ANALYZE_MODE;
+ }
+}
+
+COMMAND(AnalyzeProgressCommand)
+/**
+
+Routine description:
+
+ This function implements the 'analyzeprogressreport' engine
+ command.
+
+ Usage:
+
+ analyzeprogressreport
+
+ This command takes no arguments and causes the engine to dump
+ the current analysis.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (g_Options.ePlayMode == ANALYZE_MODE)
+ {
+ Trace("%s\n", g_Options.szAnalyzeProgressReport);
+ }
+}
+
+COMMAND(BlackCommand)
+/**
+
+Routine description:
+
+ This function implements the 'black' engine command.
+
+ Usage:
+
+ black
+
+ This command takes no arguments and causes the engine to play
+ white and set black to move.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ TellGamelistThatIPlayColor(WHITE);
+ g_Options.ePlayMode = I_PLAY_WHITE;
+ pos->uToMove = BLACK;
+ pos->u64NonPawnSig = ComputeSig(pos);
+}
+
+
+COMMAND(BoardCommand)
+/**
+
+Routine description:
+
+ This function implements the 'board' engine command.
+
+ Usage:
+
+ board
+
+ This command takes no arguments and displays the current board
+ position on stdout and in the log.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ DumpPosition(pos);
+}
+
+COMMAND(ComputerCommand)
+/**
+
+Routine description:
+
+ This function implements the 'computer' engine command.
+
+ Usage:
+
+ computer
+
+ This command takes no argument and informs the engine that it
+ is playing against another computer.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ g_Options.fOpponentIsComputer = TRUE;
+ Trace("tellics +alias whisper kib\n");
+}
+
+COMMAND(DrawCommand)
+{
+ //if (g_iNumDrawScoresInARow > 4)
+ //{
+ // ToXboard("tellopponent I accept your draw offer.\n");
+ // ToXboard("tellics draw\n");
+ //}
+ //else
+ //{
+ //Trace("tellopponent Sorry I do not accept your draw offer at "
+ // "this time.\n");
+ //Trace("tellics decline draw\n");
+ //}
+}
+
+
+//
+// TODO: timestamp command
+//
+
+void
+DumpSizes(void)
+/**
+
+Routine description:
+
+ Dump the sizes of some internal data structures on stdout.
+
+Parameters:
+
+ void
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("sizeof(PAWN_HASH_ENTRY). . . . . . . . . %u bytes\n"
+ "sizeof(HASH_ENTRY) . . . . . . . . . . . %u bytes\n"
+ "sizeof(MOVE) . . . . . . . . . . . . . . %u bytes\n"
+ "sizeof(ATTACK_BITV). . . . . . . . . . . %u bytes\n"
+ "sizeof(SQUARE) . . . . . . . . . . . . . %u bytes\n"
+ "sizeof(POSITION) . . . . . . . . . . . . %u bytes\n"
+ "sizeof(MOVE_STACK) . . . . . . . . . . . %u bytes\n"
+ "sizeof(PLY_INFO) . . . . . . . . . . . . %u bytes\n"
+ "sizeof(COUNTERS) . . . . . . . . . . . . %u bytes\n"
+ "sizeof(SEARCHER_THREAD_CONTEXT). . . . . %u bytes\n"
+ "sizeof(GAME_OPTIONS) . . . . . . . . . . %u bytes\n"
+ "sizeof(MOVE_TIMER) . . . . . . . . . . . %u bytes\n"
+ "sizeof(PIECE_DATA) . . . . . . . . . . . %u bytes\n"
+ "sizeof(VECTOR_DELTA) . . . . . . . . . . %u bytes\n"
+ "sizeof(GAME_PLAYER). . . . . . . . . . . %u bytes\n"
+ "sizeof(GAME_HEADER). . . . . . . . . . . %u bytes\n"
+ "sizeof(GAME_MOVE). . . . . . . . . . . . %u bytes\n"
+ "sizeof(GAME_DATA). . . . . . . . . . . . %u bytes\n"
+ "sizeof(SEE_LIST) . . . . . . . . . . . . %u bytes\n"
+ "sizeof(BOOK_ENTRY) . . . . . . . . . . . %u bytes\n"
+ "-------------------------------------------------\n"
+ "Current main hash table size . . . . . . %u bytes (~%u Mb)\n",
+ sizeof(PAWN_HASH_ENTRY), sizeof(HASH_ENTRY), sizeof(MOVE),
+ sizeof(ATTACK_BITV), sizeof(SQUARE), sizeof(POSITION),
+ sizeof(MOVE_STACK), sizeof(PLY_INFO), sizeof(COUNTERS),
+ sizeof(SEARCHER_THREAD_CONTEXT), sizeof(GAME_OPTIONS),
+ sizeof(MOVE_TIMER), sizeof(PIECE_DATA), sizeof(VECTOR_DELTA),
+ sizeof(GAME_PLAYER), sizeof(GAME_HEADER), sizeof(GAME_MOVE),
+ sizeof(GAME_DATA), sizeof(SEE_LIST), sizeof(BOOK_ENTRY),
+ (g_uHashTableSizeEntries * sizeof(HASH_ENTRY)),
+ ((g_uHashTableSizeEntries * sizeof(HASH_ENTRY)) / MB));
+ ASSERT_ASM_ASSUMPTIONS;
+}
+
+
+COMMAND(DumpCommand)
+/**
+
+Routine description:
+
+ This function implements the 'dump' engine command.
+
+ Usage:
+
+ dump board
+ dump moves
+ dump pgn
+ dump sizes
+ dump eval [optional coor]
+ dump evaldna
+
+ This command is used to dump internal information to the
+ stdout.
+
+ When used with the 'board' argument, a dump of the internal
+ representation of the current board position is produced.
+
+ When used with the 'moves' argument, a list of the moves played
+ thus far in the current game is produced in list format.
+
+ When used with the 'pgn' argument, a list of the moves played
+ thus far in the current game is produced in PGN format.
+
+ When used with the 'sizes' argument, a dump of internal data
+ structure sizes is produced.
+
+ When used with the 'eval' argument and no optional coordinate
+ a dump of all eval terms from the last time the eval function
+ was invoked is produced. If the optional coordinate is
+ provided then the eval terms DIRECTLY affected by the piece at
+ the supplied coordinate is produced. Note: to use dump eval
+ the engine must have been built with -DEVAL_DUMP.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+#ifdef EVAL_DUMP
+ COOR c;
+#endif
+
+ if (argc < 2)
+ {
+ Trace("Error (missing argument)\n");
+ return;
+ }
+ if (!STRCMPI(argv[1], "board"))
+ {
+ DumpPosition(pos);
+ }
+ else if (!STRCMPI(argv[1], "moves"))
+ {
+ DumpGameList();
+ }
+ else if (!STRCMPI(argv[1], "pgn"))
+ {
+ DumpPgn();
+ }
+ else if (!STRCMPI(argv[1], "sizes"))
+ {
+ DumpSizes();
+ }
+ else if (!STRCMPI(argv[1], "evaldna"))
+ {
+ char *p = ExportEvalDNA();
+ Trace("EvalDNA: %s\n", p);
+ free(p);
+ }
+#ifdef EVAL_DUMP
+ else if (!STRCMPI(argv[1], "eval"))
+ {
+ if (argc < 3)
+ {
+ EvalTraceReport();
+ }
+ else
+ {
+ if (!STRCMPI(argv[2], "terms"))
+ {
+ EvalTraceReport();
+ } else {
+ if (LooksLikeCoor(argv[2]))
+ {
+ c = FILE_RANK_TO_COOR((tolower(argv[2][0]) - 'a'),
+ (tolower(argv[2][1]) - '0'));
+ (void)EvalSigmaForPiece(pos, c);
+ } else {
+ (void)EvalSigmaForPiece(pos, ILLEGAL_COOR);
+ }
+ }
+ }
+ }
+#endif
+}
+
+COMMAND(EasyCommand)
+/**
+
+Routine description:
+
+ This function implements the 'easy' engine command.
+
+ Usage:
+
+ easy
+
+ This command takes no arguments and causes the engine not to
+ think on the opponent's time (i.e. not to ponder)
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ g_Options.fShouldPonder = FALSE;
+}
+
+COMMAND(EditCommand)
+/**
+
+Routine description:
+
+ This function implements the 'edit' engine command.
+
+ Usage:
+
+ This command is deprecated and should not be used.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("Error (obsolete command): %s\n", argv[0]);
+ Trace("\nPlease upgrade your version of xboard at "
+ "http://www.timmann.org/\n");
+}
+
+COMMAND(EvalCommand)
+/**
+
+Routine description:
+
+ This function implements the 'eval' engine command.
+
+ Usage:
+
+ eval
+
+ This command takes no arguments and causes the engine to print
+ out a static evaluation of the current board position.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ SEARCHER_THREAD_CONTEXT *ctx;
+ SCORE i;
+
+ ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
+ if (NULL != ctx)
+ {
+ InitializeSearcherContext(pos, ctx);
+ i = Eval(ctx, -INFINITY, +INFINITY);
+ Trace("Static eval: %s\n", ScoreToString(i));
+ SystemFreeMemory(ctx);
+ } else {
+ Trace("Out of memory.\n");
+ }
+}
+
+
+COMMAND(EvalDnaCommand)
+/**
+
+Routine description:
+
+ This function implements the 'evaldna' engine command.
+
+ Usage:
+
+ evaldna write <filename>
+ evaldna read <filename>
+ evaldna dump
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ char *p;
+ if (argc < 2)
+ {
+ Trace("Usage: evaldna <read | write> <filename>\n"
+ " evaldna dump\n");
+ return;
+ }
+ if (!STRCMPI(argv[1], "write"))
+ {
+ if (argc < 3) {
+ Trace("Error (missing argument)\n");
+ return;
+ }
+ if (!WriteEvalDNA(argv[2]))
+ {
+ Trace("Error writing dna file.\n");
+ } else {
+ Trace("DNA file written.\n");
+ }
+ }
+ else if (!STRCMPI(argv[1], "read") ||
+ !STRCMPI(argv[1], "load"))
+ {
+ if (argc < 3) {
+ Trace("Error (missing argument)\n");
+ return;
+ }
+ if (!ReadEvalDNA(argv[2]))
+ {
+ Trace("Error reading dna file.\n");
+ } else {
+ Trace("Loaded dna file \"%s\"\n", argv[2]);
+ p = ExportEvalDNA();
+ Log("(New) dna: %s\n", p);
+ free(p);
+ }
+ }
+ else if (!STRCMPI(argv[1], "dump"))
+ {
+ p = ExportEvalDNA();
+ Trace("EvalDNA: %s\n", p);
+ free(p);
+ }
+}
+
+
+COMMAND(ExitCommand)
+/**
+
+Routine description:
+
+ This function implements the 'exit' engine command.
+
+ Usage:
+
+ exit
+
+ This command takes no arguments and causes the engine to leave
+ analyze mode. The engine reverts to the mode it was in prior
+ to entering analyze mode. See also: analyze
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (g_Options.ePlayMode == ANALYZE_MODE)
+ {
+ ASSERT(g_eModeBeforeAnalyze != ANALYZE_MODE);
+ g_Options.ePlayMode = g_eModeBeforeAnalyze;
+ }
+}
+
+COMMAND(ForceCommand)
+/**
+
+Routine description:
+
+ This function implements the 'force' engine command.
+
+ Usage:
+
+ force
+
+ This command takes no arguments and causes the engine to enter
+ 'force mode'. In this mode it will play neither side.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ TellGamelistThatIPlayColor(BLACK);
+ g_Options.ePlayMode = FORCE_MODE;
+}
+
+COMMAND(GenerateCommand)
+/**
+
+Routine description:
+
+ This function is not directly callable. See 'test generate'
+ instead.
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ SEARCHER_THREAD_CONTEXT *ctx;
+ MOVE mv;
+ ULONG u, uLegal = 0;
+
+ ctx = SystemAllocateMemory(sizeof(SEARCHER_THREAD_CONTEXT));
+ if (NULL != ctx)
+ {
+ memcpy(&(ctx->sPosition), pos, sizeof(POSITION));
+ mv.uMove = 0;
+ GenerateMoves(ctx, mv, (InCheck(pos, pos->uToMove) ? GENERATE_ESCAPES :
+ GENERATE_ALL_MOVES));
+ ASSERT(ctx->uPly == 0);
+ for (u = ctx->sMoveStack.uBegin[0];
+ u < ctx->sMoveStack.uEnd[0];
+ u++)
+ {
+ mv = ctx->sMoveStack.mvf[u].mv;
+ if (MakeMove(ctx, mv))
+ {
+ ASSERT(!InCheck(&(ctx->sPosition), GET_COLOR(mv.pMoved)));
+ uLegal++;
+ UnmakeMove(ctx, mv);
+ Trace("%2u. %s (%d)\t",
+ uLegal,
+ MoveToSan(mv, &(ctx->sPosition)),
+ ctx->sMoveStack.mvf[u].iValue);
+ if (uLegal % 3 == 0)
+ {
+ Trace("\n");
+ }
+ }
+ }
+ Trace("\n%u legal move(s).\n", uLegal);
+ SystemFreeMemory(ctx);
+ }
+}
+
+COMMAND(PlayOtherCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (pos->uToMove == WHITE)
+ {
+ TellGamelistThatIPlayColor(BLACK);
+ g_Options.ePlayMode = I_PLAY_BLACK;
+ } else {
+ ASSERT(pos->uToMove == BLACK);
+ TellGamelistThatIPlayColor(WHITE);
+ g_Options.ePlayMode = I_PLAY_WHITE;
+ }
+}
+
+
+COMMAND(GoCommand)
+/**
+
+Routine description:
+
+ This function implements the 'go' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (pos->uToMove == WHITE)
+ {
+ TellGamelistThatIPlayColor(WHITE);
+ g_Options.ePlayMode = I_PLAY_WHITE;
+ } else {
+ ASSERT(pos->uToMove == BLACK);
+ TellGamelistThatIPlayColor(BLACK);
+ g_Options.ePlayMode = I_PLAY_BLACK;
+ }
+}
+
+COMMAND(HardCommand)
+{
+ g_Options.fShouldPonder = TRUE;
+}
+
+COMMAND(HelpCommand);
+
+COMMAND(HintCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("Error (not implemented): %s\n", argv[0]);
+}
+
+CHAR *OnlyDigits(CHAR *sz)
+{
+ static CHAR out[SMALL_STRING_LEN_CHAR];
+ CHAR *p = out;
+ ULONG uCount = 0;
+
+ while((*sz) && (uCount < SMALL_STRING_LEN_CHAR))
+ {
+ if (isdigit(*sz))
+ {
+ uCount++;
+ *p++ = *sz++;
+ }
+ }
+ *p++ = '\0';
+ return(out);
+}
+
+COMMAND(LevelCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG x;
+
+ if (argc < 4)
+ {
+ Trace("Error (syntax): %s\n", argv[0]);
+ } else {
+ g_Options.uMovesPerTimePeriod = atoi(OnlyDigits(argv[1]));
+ g_Options.uMyClock = atoi(OnlyDigits(argv[2]));
+ g_Options.uMyIncrement = atoi(OnlyDigits(argv[3]));
+
+ g_Options.eClock = CLOCK_NORMAL;
+ if (g_Options.uMyIncrement)
+ {
+ g_Options.eClock = CLOCK_INCREMENT;
+ }
+
+ x = (g_Options.uMyClock + ((g_Options.uMyIncrement * 2) / 3));
+ g_Options.uMyClock *= 60;
+
+ Trace("etime = %u (clock %u and inc %u)\n", x,
+ g_Options.uMyClock, g_Options.uMyIncrement);
+ if (x <= 6)
+ {
+ Trace("bullet game\n");
+ g_Options.eGameType = GAME_BULLET;
+ }
+ else if (x < 15)
+ {
+ Trace("blitz game\n");
+ g_Options.eGameType = GAME_BLITZ;
+ } else {
+ Trace("standard game\n");
+ g_Options.eGameType = GAME_STANDARD;
+ }
+ }
+}
+
+COMMAND(MoveNowCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("MOVE NOW COMMAND --> stop searching now\n");
+ g_MoveTimer.bvFlags |= TIMER_STOPPING;
+}
+
+COMMAND(MovesCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ DumpGameList();
+}
+
+COMMAND(XboardCommand);
+COMMAND(NameCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (argc < 2)
+ {
+ XboardCommand(szInput, argc, argv, pos);
+ } else {
+ SetOpponentsName(argv[1]);
+ }
+}
+
+COMMAND(NewCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("tellics -alias whisp*\n");
+ PreGameReset(TRUE);
+ TellGamelistThatIPlayColor(BLACK);
+ g_Options.ePlayMode = I_PLAY_BLACK;
+ g_Options.uMaxDepth = MAX_PLY_PER_SEARCH - 1;
+}
+
+COMMAND(NoPostCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ g_Options.fShouldPost = FALSE;
+}
+
+COMMAND(OtimCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG x;
+
+ if (argc < 2)
+ {
+ Trace("My opponent's clock stands at %u sec remaining.\n",
+ g_Options.uOpponentsClock);
+
+ switch (g_Options.eClock)
+ {
+ case CLOCK_FIXED:
+ Trace("The move timer is fixed, %u sec / move.\n",
+ g_Options.uMyIncrement);
+ break;
+ case CLOCK_NORMAL:
+ if (g_Options.uMovesPerTimePeriod != 0)
+ {
+ Trace("The move timer is normal, %u moves / time "
+ "period.\n",
+ g_Options.uMovesPerTimePeriod);
+ } else {
+ Trace("The move timer is normal, finish entire "
+ "game in allotted time.\n");
+ }
+ break;
+ case CLOCK_INCREMENT:
+ Trace("The move timer is increment, additional %u sec "
+ "/ move.\n",
+ g_Options.uMyIncrement);
+ break;
+ case CLOCK_NONE:
+ default:
+ Trace("The clock and move timer are disabled.\n");
+ break;
+ }
+ } else {
+ x = atoi(argv[1]);
+ if (x >= 0)
+ {
+ g_Options.uOpponentsClock = x / 100; // convert to seconds
+ } else {
+ Trace("Error (invalid time): %d\n", x);
+ }
+ }
+}
+
+COMMAND(PingCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (argc > 1)
+ {
+ Trace("pong %s\n", argv[1]);
+ }
+}
+
+COMMAND(PostCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ g_Options.fShouldPost = TRUE;
+}
+
+COMMAND(ProtoverCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("feature sigint=0 sigterm=0 myname=\"typhoon %s\" ping=1 "
+ "setboard=1 playother=1 colors=0 time=1 analyze=1 pause=1 "
+ "reuse=1 done=1\n", VERSION);
+}
+
+COMMAND(QuitCommand)
+/**
+
+Routine description:
+
+ This function implements the 'quit' engine command.
+
+ Usage: quit
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+#ifdef MP
+ ULONG u = 0;
+#endif
+
+ //
+ // Stop searching; if we are on an MP box wait until all helper
+ // threads return to the idle state and exit.
+ //
+ g_MoveTimer.bvFlags |= TIMER_STOPPING;
+#ifdef MP
+ u = 0;
+ do
+ {
+ SystemDeferExecution(100);
+ if (++u == 5) break;
+ }
+ while(g_uNumHelpersAvailable != g_uNumHelperThreads);
+#endif
+
+ //
+ // We should be the last thread in the process now.
+ //
+}
+
+COMMAND(RatedCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ g_Options.fGameIsRated = TRUE;
+}
+
+COMMAND(RatingCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG x;
+
+ if (argc < 3)
+ {
+ Trace("Error (bad usage): %s\n", argv[0]);
+ } else {
+ x = atoi(argv[1]);
+ if (x >= 0)
+ {
+ SetMyRating(x);
+ }
+ x = atoi(argv[2]);
+ if (x >= 0)
+ {
+ SetOpponentsRating(x);
+ }
+ }
+}
+
+COMMAND(RandomCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("%u\n", rand());
+}
+
+COMMAND(RemoveCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (TRUE == OfficiallyTakebackMove())
+ {
+ if (TRUE == OfficiallyTakebackMove())
+ {
+ return;
+ }
+ }
+ Trace("Error (unable to takeback move)\n");
+}
+
+COMMAND(ResultCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ GAME_RESULT result;
+ result.eResult = RESULT_UNKNOWN;
+ result.szDescription[0] = '\0';
+
+ if (argc < 2)
+ {
+ Trace("Argc was %u\n", argc);
+ Trace("Usage: result <result> [optional comment]\n");
+ } else {
+ if (!STRNCMPI("1-0", argv[1], 3))
+ {
+ result.eResult = RESULT_WHITE_WON;
+ }
+ else if (!STRNCMPI("0-1", argv[1], 3))
+ {
+ result.eResult = RESULT_BLACK_WON;
+ }
+ else if ((!STRNCMPI("1/2", argv[1], 3)) ||
+ (!STRNCMPI("=", argv[1], 1)))
+ {
+ result.eResult = RESULT_DRAW;
+ }
+ if (argc < 2) {
+ strncpy(result.szDescription, argv[2], 256);
+ }
+ SetGameResultAndDescription(result);
+ if (g_Options.ePlayMode != FORCE_MODE)
+ {
+ DumpPgn();
+ TellGamelistThatIPlayColor(BLACK);
+ g_Options.ePlayMode = FORCE_MODE;
+ }
+ }
+}
+
+COMMAND(SearchDepthCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG x;
+
+ if (argc < 2)
+ {
+ Trace("Current maximum depth limit is %u ply.\n"
+ "The largest depth the engine can search to is %u ply.\n",
+ g_Options.uMaxDepth,
+ MAX_PLY_PER_SEARCH);
+ } else {
+ x = atoi(argv[1]);
+ if (x <= 0)
+ {
+ Trace("Error (illegal depth): %d\n", x);
+ }
+ else if (x >= MAX_PLY_PER_SEARCH)
+ {
+ Trace("Error (my max depth is %u): %u\n",
+ MAX_PLY_PER_SEARCH - 1, x);
+ } else {
+ g_Options.uMaxDepth = x;
+ }
+ }
+}
+
+COMMAND(SearchNodesCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ UINT64 x;
+
+ if (argc < 2)
+ {
+ g_Options.u64MaxNodeCount = 0;
+ Trace("Search nodecount limit disabled.\n");
+ } else {
+ x = strtoull(argv[1], NULL, 10);
+ if (x >= 0)
+ {
+ g_Options.u64MaxNodeCount = x;
+ Trace("Search node limit set to %llu.\n", x);
+ } else {
+ g_Options.u64MaxNodeCount = 0;
+ Trace("Search nodecount limit disabled.\n");
+ }
+ }
+}
+
+
+COMMAND(SearchTimeCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG x;
+
+ if (argc < 2)
+ {
+ Trace("My clock stands at %u sec remaining.\n",
+ g_Options.uMyClock);
+ switch (g_Options.eClock)
+ {
+ case CLOCK_FIXED:
+ Trace("The move timer is fixed, %u sec / move.\n",
+ g_Options.uMyIncrement);
+ break;
+ case CLOCK_NORMAL:
+ if (g_Options.uMovesPerTimePeriod != 0)
+ {
+ Trace("The move timer is normal, %u moves / "
+ "time period.\n",
+ g_Options.uMovesPerTimePeriod);
+ } else {
+ Trace("The move timer is normal, finish entire game in "
+ "allotted time.\n");
+ }
+ break;
+ case CLOCK_INCREMENT:
+ Trace("The move timer is increment, additional %u sec "
+ "/ move.\n",
+ g_Options.uMyIncrement);
+ break;
+ case CLOCK_NONE:
+ default:
+ Trace("The clock and move timer are disabled.\n");
+ break;
+ }
+ } else {
+ x = atoi(argv[1]);
+ if (x >= 0)
+ {
+ g_Options.uMyIncrement = x;
+ g_Options.eClock = CLOCK_FIXED;
+ } else {
+ Trace("Error (illegal time per move): %u\n", x);
+ }
+ }
+}
+
+COMMAND(SetBoardCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ char *p;
+
+ if (argc < 2)
+ {
+ if (NULL != (p = PositionToFen(pos)))
+ {
+ Trace("Current board FEN is: %s\n", p);
+ SystemFreeMemory(p);
+ }
+ } else {
+ p = szInput + (argv[1] - argv[0]);
+ if (FALSE == SetRootPosition(p))
+ {
+ Trace("Error (malformed FEN): %s\n", p);
+ return;
+ }
+ VERIFY(PreGameReset(FALSE));
+ g_Options.ePlayMode = FORCE_MODE;
+ }
+}
+
+COMMAND(SEECommand)
+{
+ MOVE mv;
+ SCORE s;
+
+ if (argc < 3)
+ {
+ Trace("Usage: test see <required-move>\n");
+ return;
+ }
+ switch(LooksLikeMove(argv[2]))
+ {
+ case MOVE_SAN:
+ mv = ParseMoveSan(argv[2], pos);
+ break;
+ case MOVE_ICS:
+ mv = ParseMoveIcs(argv[2], pos);
+ break;
+ default:
+ mv.uMove = 0;
+ }
+ if (!mv.uMove)
+ {
+ Trace("Error (invalid move): '%s'\n", argv[2]);
+ return;
+ }
+ s = SEE(pos, mv);
+ Trace("SEE says that the value of move '%s' is %d\n", argv[2], s);
+}
+
+
+COMMAND(TestCommand)
+/**
+
+Routine description:
+
+ This function implements the 'test' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (argc < 2)
+ {
+ Trace("Error (missing argument)\n");
+ return;
+ }
+
+ if (!STRCMPI(argv[1], "generate"))
+ {
+ GenerateCommand(szInput, argc, argv, pos);
+ }
+ else if (!STRCMPI(argv[1], "draw"))
+ {
+ Trace("drawcount = %u\n",
+ CountOccurrancesOfSigInOfficialGameList(pos->u64NonPawnSig ^
+ pos->u64PawnSig));
+ }
+ else if (!STRCMPI(argv[1], "see"))
+ {
+ SEECommand(szInput, argc, argv, pos);
+ }
+#ifdef EVAL_DUMP
+ else if (!STRCMPI(argv[1], "eval"))
+ {
+ TestEvalWithSymmetry();
+ }
+#endif
+
+ //
+ // TODO: #ifdef TEST allow individual tests to be run here.
+ //
+}
+
+COMMAND(TimeCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ ULONG x;
+
+ if (argc < 2)
+ {
+ Trace("My clock stands at %u sec remaining.\n",
+ g_Options.uMyClock);
+
+ switch (g_Options.eClock)
+ {
+ case CLOCK_FIXED:
+ Trace("The move timer is fixed, %u sec / move.\n",
+ g_Options.uMyIncrement);
+ break;
+ case CLOCK_NORMAL:
+ if (g_Options.uMovesPerTimePeriod != 0)
+ {
+ Trace("The move timer is normal, %u moves / time "
+ "period.\n",
+ g_Options.uMovesPerTimePeriod);
+ } else {
+ Trace("The move timer is normal, finish entire "
+ "game in allotted time.\n");
+ }
+ break;
+ case CLOCK_INCREMENT:
+ Trace("The move timer is increment, additional %u sec "
+ "/ move.\n",
+ g_Options.uMyIncrement);
+ break;
+ case CLOCK_NONE:
+ default:
+ Trace("The clock and move timer are disabled.\n");
+ break;
+ }
+ } else {
+ x = atoi(argv[1]);
+ if (x >= 0)
+ {
+ g_Options.uMyClock = x / 100; // convert to seconds
+ } else {
+ Trace("Error (illegal time): %d\n", x);
+ }
+ }
+}
+
+COMMAND(UndoCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ if (FALSE == OfficiallyTakebackMove())
+ {
+ Trace("Error (can't undo): %s\n", argv[0]);
+ }
+}
+
+COMMAND(UnratedCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ g_Options.fGameIsRated = FALSE;
+}
+
+
+COMMAND(VariantCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Trace("Error (not implemented): %s\n", argv[0]);
+ Trace("tellics abort\n");
+ ASSERT(FALSE);
+}
+
+COMMAND(VersionCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ Banner();
+}
+
+COMMAND(WhiteCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ TellGamelistThatIPlayColor(BLACK);
+ g_Options.ePlayMode = I_PLAY_BLACK;
+ pos->uToMove = WHITE;
+ pos->u64NonPawnSig = ComputeSig(pos);
+}
+
+
+COMMAND(XboardCommand)
+/**
+
+Routine description:
+
+ This function implements the '' engine command.
+
+ Usage:
+
+Parameters:
+
+ The COMMAND macro hides four arguments from the input parser:
+
+ CHAR *szInput : the full line of input
+ ULONG argc : number of argument chunks
+ CHAR *argv[] : array of ptrs to each argument chunk
+ POSITION *pos : a POSITION pointer to operate on
+
+Return value:
+
+ void
+
+**/
+{
+ g_Options.fRunningUnderXboard = TRUE;
+ Trace("\n\n");
+}
+
+COMMAND(AcceptedCommand)
+{
+ ;;
+}
+
+
+// HEREHERE
+COMMAND_PARSER_ENTRY g_ParserTable[] =
+{
+ { "?",
+ MoveNowCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Stop thinking and move immediately" },
+ { ".",
+ AnalyzeProgressCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Show engine's current best line when in analyze mode" },
+ { "accepted",
+ AcceptedCommand,
+ TRUE,
+ TRUE,
+ TRUE,
+ "Internal, part of the WinBoard protocol" },
+ { "analyze",
+ AnalyzeCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Enter analyze mode" },
+ { "avoid",
+ AvoidCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Set a move to avoid (up to three)" },
+ { "bench",
+ BenchCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Run a crafty benchmark and show results" },
+ { "bestmove",
+ GeneratePositionAndBestMoveSuite,
+ FALSE,
+ TRUE,
+ FALSE,
+ "Generate a best move suite from a PGN file" },
+ { "black",
+ BlackCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Sets black to move and computer to play white" },
+ { "book",
+ BookCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Manage the opening book" },
+ { "computer",
+ ComputerCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Informs the engine that it is playing another computer" },
+ { "dump",
+ DumpCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Dumps a structure, position, moves, or pgn" },
+ { "easy",
+ EasyCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Disable pondering" },
+ { "draw",
+ DrawCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Offer the engine a draw" },
+ { "edit",
+ EditCommand,
+ FALSE,
+ TRUE,
+ TRUE,
+ "Depreciated command, do not use" },
+ { "eval",
+ EvalCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Run a static eval" },
+ { "evaldna",
+ EvalDnaCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Read or write the DNA from the eval code." },
+ { "exit",
+ ExitCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Leave analyze mode" },
+ { "force",
+ ForceCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Enter force mode, engine plays neither side" },
+ { "go",
+ GoCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Sets engine to play side on move, begin thinking" },
+ { "hard",
+ HardCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Enable pondering" },
+ { "help",
+ HelpCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Show a list of commands available" },
+ { "hint",
+ HintCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Ask the engine for a hint" },
+ { "id",
+ IdCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Set a problem id name" },
+ { "level",
+ LevelCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Sets game time controls" },
+ { "name",
+ NameCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Tell the engine your name" },
+ { "new",
+ NewCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Start a new game" },
+ { "nopost",
+ NoPostCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Do not show thinking" },
+ { "otim",
+ OtimCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Inform the engine about opponent's clock" },
+ { "perft",
+ PerftCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Run a perft test on the move generator code." },
+ { "ping",
+ PingCommand,
+ TRUE,
+ TRUE,
+ TRUE,
+ "Internal part of the WinBoard protocol" },
+ { "playother",
+ PlayOtherCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Play the other side" },
+ { "post",
+ PostCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Show thinking" },
+ { "protover",
+ ProtoverCommand,
+ TRUE,
+ TRUE,
+ TRUE,
+ "Internal part of the WinBoard protocol" },
+ { "psqt",
+ LearnPsqtFromPgn,
+ FALSE,
+ TRUE,
+ FALSE,
+ "Learn a set of PSQT settings from a PGN file" },
+ { "quit",
+ QuitCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Exit the engine" },
+ { "random",
+ RandomCommand,
+ TRUE,
+ TRUE,
+ TRUE,
+ "no-op" },
+ { "rated",
+ RatedCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Inform the engine that this is a rated game" },
+ { "rating",
+ RatingCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Inform the engine ratings" },
+ { "remove",
+ RemoveCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Take back a full move" },
+ { "result",
+ ResultCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Inform the engine about a game result" },
+ { "script",
+ ScriptCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Run a script" },
+ { "sd",
+ SearchDepthCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Set engine maximum search depth" },
+ { "set",
+ SetCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "View or change an engine variable" },
+ { "setboard",
+ SetBoardCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Load a board position" },
+ { "solution",
+ SolutionCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Set a solution move (up to three)" },
+ { "sn",
+ SearchNodesCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Set the engine max nodes per search limit" },
+ { "st",
+ SearchTimeCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Set the engine search time" },
+ { "test",
+ TestCommand,
+ FALSE,
+ FALSE,
+ FALSE,
+ "Run an internal debugging command" },
+ { "time",
+ TimeCommand,
+ TRUE,
+ FALSE,
+ TRUE,
+ "Tell the engine how its clock stands" },
+ { "undo",
+ UndoCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Take back a halfmove" },
+ { "unrated",
+ UnratedCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Tell the engine that the game is unrated" },
+ { "variant",
+ VariantCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Tell the engine what variant the game is" },
+ { "version",
+ VersionCommand,
+ TRUE,
+ FALSE,
+ FALSE,
+ "Display current version number and build options" },
+ { "white",
+ WhiteCommand,
+ FALSE,
+ FALSE,
+ TRUE,
+ "Sets white to move, engine plays black" },
+ { "winboard",
+ XboardCommand,
+ TRUE,
+ TRUE,
+ TRUE,
+ "Internal part of the WinBoard protocol" },
+ { "xboard",
+ XboardCommand,
+ TRUE,
+ TRUE,
+ TRUE,
+ "Internal part of the WinBoard protocol" },
+};
+
+
+COMMAND(HelpCommand)
+{
+ char *command = NULL;
+ ULONG u;
+
+ //
+ // If passed an argument, give help only about that command.
+ // TODO: divert to a more specific help page here if available.
+ //
+ if (argc > 1)
+ {
+ command = argv[1];
+ for (u = 0; u < ARRAY_LENGTH(g_ParserTable); u++)
+ {
+ if ((!g_ParserTable[u].fInvisible) &&
+ (!STRCMPI(command, g_ParserTable[u].szOpcode)))
+ {
+ Trace("%-13s: %s\n",
+ g_ParserTable[u].szOpcode,
+ g_ParserTable[u].szSimpleHelp);
+ }
+ }
+ return;
+ }
+
+ //
+ // Otherwise general help about all commands.
+ //
+ Trace("xboard/WinBoard protocol support commands:\n"
+ "------------------------------------------\n");
+ for (u = 0; u < ARRAY_LENGTH(g_ParserTable); u++)
+ {
+ if ((g_ParserTable[u].fWinBoard) && (!g_ParserTable[u].fInvisible)) {
+ Trace("%-13s: %s\n",
+ g_ParserTable[u].szOpcode,
+ g_ParserTable[u].szSimpleHelp);
+ }
+ }
+ Trace("\nInternal engine commands:\n"
+ "-------------------------\n");
+ for (u = 0; u < ARRAY_LENGTH(g_ParserTable); u++)
+ {
+ if ((!g_ParserTable[u].fWinBoard) && (!g_ParserTable[u].fInvisible)) {
+ Trace("%-13s: %s\n",
+ g_ParserTable[u].szOpcode,
+ g_ParserTable[u].szSimpleHelp);
+ }
+ }
+}
+
+
+void
+ParseUserInput(FLAG fSearching)
+/**
+
+Routine description:
+
+Parameters:
+
+ FLAG fSearching
+
+Return value:
+
+ void
+
+**/
+{
+ CHAR *pCapturedInput = NULL;
+ CHAR *pFreeThis = NULL;
+ CHAR *pDontFree;
+ CHAR *p, *q;
+ ULONG u;
+ CHAR *argv[MAX_ARGS];
+ ULONG argc = 0;
+ FLAG fInQuote = FALSE;
+ MOVE mv;
+ POSITION *pos = GetRootPosition();
+#if 0
+ static ULONG uHeapAllocated = 0;
+
+ if (0 == uHeapAllocated)
+ {
+ uHeapAllocated = GetHeapMemoryUsage();
+ } else {
+ ASSERT(uHeapAllocated == GetHeapMemoryUsage());
+ uHeapAllocated = GetHeapMemoryUsage();
+ }
+#endif
+ //
+ // If we are in batch mode and there is no waiting input, exit.
+ //
+ if (g_Options.fNoInputThread && (0 == NumberOfPendingInputEvents()))
+ {
+ Trace("Exhausted input in batch mode, exiting...\n");
+ exit(-1);
+ }
+
+ //
+ // By the time we see this the input thread is likely already
+ // exited so don't try to read from the queue...
+ //
+ if (g_fExitProgram == TRUE)
+ {
+ QuitCommand("quit", 1, NULL, pos);
+ return;
+ }
+
+ //
+ // If we are searching, don't actually read the input event yet.
+ // Just peek and leave it there until we know whether we can do
+ // it or not.
+ //
+ if (TRUE == fSearching)
+ {
+ ASSERT(g_Options.fPondering || g_Options.fThinking);
+ p = pDontFree = PeekNextInput();
+ } else {
+ p = pFreeThis = BlockingReadInput();
+ }
+ if (NULL == p)
+ {
+ goto end;
+ }
+
+ //
+ // Skip over leading whitespace and do not parse comment lines
+ //
+ while((*p) && (isspace(*p))) p++;
+ if (((*p) && (*p == '#')) ||
+ ((*p) && (*(p+1)) && (*p == '/') && (*(p+1) == '/')))
+ {
+ goto consume_if_searching;
+ }
+
+ //
+ // Chop the last \n out of the string
+ //
+ q = p;
+ while(*q)
+ {
+ if (*q == '\n')
+ {
+ *q = '\0';
+ break;
+ }
+ q++;
+ }
+
+ //
+ // Break it up into chunks for the COMMAND functions.
+ //
+ pCapturedInput = STRDUP(p);
+ memset(argv, 0, sizeof(argv));
+ do
+ {
+ while(*p && isspace(*p)) p++;
+ if (!*p) break;
+ argv[argc++] = p;
+ fInQuote = FALSE;
+ while (*p)
+ {
+ if (*p == '"')
+ {
+ fInQuote = !fInQuote;
+ }
+ else if (*p == '{')
+ {
+ fInQuote = TRUE;
+ }
+ else if (*p == '}')
+ {
+ fInQuote = FALSE;
+ }
+ else if (isspace(*p) && (FALSE == fInQuote))
+ {
+ break;
+ }
+ p++;
+ }
+ if (!*p) break;
+ *p = '\0';
+ p++;
+ }
+ while(argc < MAX_ARGS);
+ if (argc == 0)
+ {
+ goto consume_if_searching;
+ }
+
+ //
+ // Does it look like a move?
+ //
+ mv.uMove = 0;
+ switch(LooksLikeMove(argv[0]))
+ {
+ case MOVE_SAN:
+ mv = ParseMoveSan(argv[0], pos);
+ break;
+ case MOVE_ICS:
+ mv = ParseMoveIcs(argv[0], pos);
+ break;
+ case NOT_MOVE:
+ for (u = 0; u < ARRAY_LENGTH(g_ParserTable); u++)
+ {
+ if (!STRCMPI(g_ParserTable[u].szOpcode, argv[0]))
+ {
+ if (TRUE == fSearching)
+ {
+ if (TRUE == g_ParserTable[u].fHandleOnTheFly)
+ {
+ //
+ // We can do that command on the fly in
+ // the middle of the search. Note: these
+ // commands MUST NOT affect anything that
+ // the search is doing or you'll get
+ // corruption.
+ //
+ (*g_ParserTable[u].pFunction)
+ (pCapturedInput, argc, argv, pos);
+ goto consume_if_searching;
+ } else {
+ //
+ // We can't handle that input without
+ // unrolling the search first.
+ //
+ Trace("COMPLEX INPUT --> stop searching now\n");
+ ASSERT(pDontFree);
+ strcpy(pDontFree, pCapturedInput);
+ g_MoveTimer.bvFlags |= TIMER_STOPPING;
+ goto end;
+ }
+ } else {
+ //
+ // We were called from the main loop or from
+ // the script parser. No one is searching.
+ // Just do the command.
+ //
+ (*g_ParserTable[u].pFunction)
+ (pCapturedInput, argc, argv, pos);
+ goto end;
+ }
+ }
+ }
+ if ((TRUE == LooksLikeFen(pCapturedInput)) &&
+ (TRUE == SetRootPosition(pCapturedInput)))
+ {
+ goto end;
+ }
+ break;
+#ifdef DEBUG
+ default:
+ UtilPanic(SHOULD_NOT_GET_HERE,
+ NULL, NULL, NULL, NULL,
+ __FILE__, __LINE__);
+ break;
+#endif
+ }
+
+ //
+ // Was it a move?
+ //
+ if (mv.uMove)
+ {
+ if (fSearching == TRUE)
+ {
+ //
+ // No one should move (my pieces) while I'm thinking!
+ //
+ ASSERT(g_Options.fPondering == TRUE);
+ ASSERT(g_Options.fThinking == FALSE);
+ if (IS_SAME_MOVE(mv, g_Options.mvPonder))
+ {
+ Trace("PREDICTED MOVE PLAYED --> converting to search\n");
+ g_Options.fSuccessfulPonder = TRUE;
+ g_Options.fPondering = FALSE;
+ g_Options.fThinking = TRUE;
+ SetMoveTimerForSearch(TRUE, FLIP(GET_COLOR(mv.pMoved)));
+ goto consume_if_searching;
+ } else {
+ g_MoveTimer.bvFlags |= TIMER_STOPPING;
+ if (TRUE == OfficiallyMakeMove(mv, 0, FALSE))
+ {
+ Trace("NONPREDICTED MOVE PLAYED --> stop pondering now\n");
+ goto end;
+ } else {
+ UtilPanic(GOT_ILLEGAL_MOVE_WHILE_PONDERING,
+ GetRootPosition(),
+ (void *)mv.uMove,
+ NULL,
+ NULL,
+ __FILE__, __LINE__);
+ }
+ }
+ } else {
+ if (FALSE == OfficiallyMakeMove(mv, 0, FALSE))
+ {
+ UtilPanic(CANNOT_OFFICIALLY_MAKE_MOVE,
+ GetRootPosition(),
+ (void *)mv.uMove,
+ NULL,
+ NULL,
+ __FILE__, __LINE__);
+ }
+ }
+ } else {
+ Trace("Unknown/illegal move/command: \"%s\"\n", pCapturedInput);
+ }
+
+ consume_if_searching:
+ if (TRUE == fSearching)
+ {
+ ASSERT(NULL == pFreeThis);
+ ASSERT(NumberOfPendingInputEvents() > 0);
+ pFreeThis = BlockingReadInput();
+ }
+ // fall through
+
+ end:
+ if (NULL != pFreeThis)
+ {
+ SystemFreeMemory(pFreeThis);
+ pFreeThis = NULL;
+ }
+ if (NULL != pCapturedInput)
+ {
+ SystemFreeMemory(pCapturedInput);
+ pCapturedInput = NULL;
+ }
+// ASSERT(uHeapAllocated == GetHeapMemoryUsage());
+}