}
-/* FIXME! This is truly the function from hell! */
-
/*
* Process the user's command. If easy mode is OFF (the computer is thinking
* on opponents time) and the program is out of book, then make the 'hint'
* the hint move, then set Sdepth to zero.
*/
-int
-InputCommand(char *command, int root)
+static char ponderString[20];
+
+void
+PonderOnHintMove(void)
{
#ifdef QUIETBACKGROUND
short have_shown_prompt = false;
#endif
- short ok, done, is_move = false;
unsigned short mv;
- char s[200], sx[200];
- static char backlog[200];
- ok = flag.quit = done = false;
- player = opponent;
-
-#if ttblsz
- if (TTadd > ttbllimit)
- ZeroTTable();
-#endif
-
- if ((hint > 0) && !flag.easy && !flag.force && !command && !backlog[0] && root)
- {
/*
* A hint move for the player is available. Compute a move for the
* opponent in background mode assuming that the hint move will be
ft = time0; /* Save reference time for the player. */
fflush(stdout);
algbr((short) hint >> 8, (short) hint & 0xff, false);
- strcpy(s, mvstr[0]);
+ strcpy(ponderString, mvstr[0]);
if (flag.post)
dsp->GiveHint();
/* do the hint move */
- if (VerifyMove(s, VERIFY_AND_TRY_MODE, &mv))
+ if (VerifyMove(ponderString, VERIFY_AND_TRY_MODE, &mv))
{
Sdepth = 0;
}
#endif
- /* undo the hint and carry on */
- VerifyMove(s, UNMAKE_MODE, &mv);
+ if (strcmp(ponderString, "hit"))
+ { /* undo the hint and carry on */
+ VerifyMove(ponderString, UNMAKE_MODE, &mv);
+ }
+ else
+ { /* otherwise SelectMove will have played the computer's reply */
+ /* update ponder-move stats, which was skipped in TRY_MODE */
+ GameList[GameCnt-1].depth = GameList[GameCnt].score = 0;
+ GameList[GameCnt-1].nodes = 0;
+ ElapsedTime(COMPUTE_AND_INIT_MODE);
+ GameList[GameCnt-1].time = (short) (et + 50)/100; /* FIXME: this is wrong */
+
+ RenewTimeControl(computer); /* add time for next session */
+ }
Sdepth = 0;
}
time0 = ft; /* Restore reference time for the player. */
- }
-
- while(!(ok || flag.quit || done))
- {
- player = opponent;
-
- if (flag.analyze && !command && !backlog[0] && root) {
- SelectMove(opponent, BACKGROUND_MODE);
- }
-
-#ifdef QUIETBACKGROUND
- if (!have_shown_prompt)
- {
-#endif /* QUIETBACKGROUND */
-
- dsp->ShowPrompt();
-
-#ifdef QUIETBACKGROUND
- }
-
- have_shown_prompt = false;
-#endif /* QUIETBACKGROUND */
-
- if (!command && backlog[0]) command = backlog; /* pick up backlogged command */
-
- if (command == NULL) {
- int eof = dsp->GetString(sx);
- if (eof)
- dsp->ExitShogi();
- } else {
- strcpy(sx, command);
- backlog[0]= '\0'; /* make sure no backlog is left */
- done = true;
- }
-
- /* extract first word */
- if (sscanf(sx, "%s", s) < 1)
- continue;
+ ponderString[0] = '\0';
+}
- if (!root && strcmp(s, "."))
- { /* during search most commands can only be done after abort */
- strcpy(backlog, sx); /* backlog the command */
- return true; /* and order search abort */
- }
+/*
+ * Recognize the command s from input line sx, and perform the action it specifies.
+ * Returns whether the command could cause it to be out turn to move.
+ */
+int
+ParseAndExecuteCommand(char *s, char *sx)
+{
+ short ok;
+ unsigned short mv;
if (strcmp(s, "bd") == 0) /* bd -- display board */
{
"shogi"
#endif
);
- printf("debug=1 setboard=1 sigint=0 memory=1 done=1\n");
+ printf("debug=1 setboard=1 sigint=0 memory=1 usermove=1 done=1\n");
}
else if (strcmp(s, ".") == 0)
{ // periodic update request of analysis info: send stat01 info
}
else
{
+ if (strcmp(s, "usermove") == 0)
+ sscanf(sx + 9, "%s", s);
+
if (flag.mate)
{
ok = true;
flag.mate = true;
}
- else
+ else if (XSHOGI)
{
- is_move = true;
- }
+ /* add remaining time in milliseconds for xshogi */
+ printf("%d. %s %ld\n",
+ ++mycnt2, s, TimeControl.clock[player] * 10);
+ }
}
Sdepth = 0;
}
+
+ return ok;
+}
+
+/*
+ * Read commands from input, and execute them, until it becomes our turn to move.
+ * When called during a background search (root = false) it just backlogs the
+ * input command without executing it, and returns immediately. Unless the command
+ * was the move on which the search was pondering. In that case we turn the ongoing
+ * search into a foreground search. To judge this, it is also necessary to process
+ * the 'time' and 'otim' commands that preceed the move. The '.' command is also
+ * always processed, to prevent it from aborting an analysis search.
+ * The time spent waiting for input can be filled with background searches for
+ * pondering or analysis. (In !root mode input is guaranteed to be pending already!)
+ */
+int
+InputCommand(int root)
+{
+#ifdef QUIETBACKGROUND
+ short have_shown_prompt = false;
+#endif
+ short ok;
+ char s[200], sx[200], s2[200];
+ static char backlog[200];
+
+ ok = flag.quit = false;
+ player = opponent;
+
+#if ttblsz
+ /* CHECKME: should this also be done in the following while loop? */
+ if (TTadd > ttbllimit)
+ ZeroTTable();
+#endif
+
+ while ((hint > 0) && !flag.easy && !flag.force && !backlog[0] && root)
+ {
+ /*
+ * A hint move for the player is available. Compute a move for the
+ * opponent in background mode assuming that the hint move will be
+ * selected by the player.
+ * Terminate this search on input, which will then be saved in backlog[].
+ * Unless the input was the hint move ('ponder hit'). Then that move will
+ * be played (after the search times out) in addition to the hint. There
+ * will then be no backlog, and we start pondering on the new hint move.
+ */
+
+ PonderOnHintMove();
+ }
+
+ while(!(ok || flag.quit))
+ { /* process input commands until our it becomes our turn to move */
+ player = opponent;
+
+ /* in analysis mode we do a background search while waiting for input */
+ if (flag.analyze && !backlog[0] && root) {
+ SelectMove(opponent, BACKGROUND_MODE);
+ }
+
+#ifdef QUIETBACKGROUND
+ if (!have_shown_prompt)
+ {
+#endif /* QUIETBACKGROUND */
+
+ dsp->ShowPrompt();
+
+#ifdef QUIETBACKGROUND
+ }
+
+ have_shown_prompt = false;
+#endif /* QUIETBACKGROUND */
+
+ if (!backlog[0]) { /* read new input line */
+ int eof = dsp->GetString(sx);
+ if (eof)
+ dsp->ExitShogi();
+ } else { /* or use backlogged input line */
+ strcpy(sx, backlog);
+ backlog[0]= '\0'; /* make sure no backlog is left */
+ }
+
+ /* extract first word */
+ if (sscanf(sx, "%s %s", s, s2) < 1)
+ continue;
+
+ if (!root && (strcmp(s, "usermove") == 0)
+ && (strcmp(s2, ponderString) == 0))
+ { /* ponder hit; switch to normal search */
+ background = false;
+ hint = 0;
+ if (TCflag)
+ { /* account opponent time and moves */
+ TimeControl.clock[opponent] -= et;
+ timeopp[oppptr] = et;
+ if (--TimeControl.moves[opponent] == 0)
+ TimeControl.moves[opponent] = TCmoves; /* assumes uni-TC! */
+ }
+ SetResponseTime(computer);
+ strcpy(ponderString, "hit");
+ return false; /* no search abort */
+ }
+
+ if (!root && strcmp(s, ".") && strcmp(s, "time") && strcmp(s, "otim"))
+ { /* during search most commands can only be done after abort */
+ strcpy(backlog, sx); /* backlog the command */
+ return true; /* and order search abort */
+ }
+
+ ok = ParseAndExecuteCommand(s, sx); /* returns whether turn changed */
}
ElapsedTime(COMPUTE_AND_INIT_MODE);
+ /* kludge alert: change the side we play to prevent starting a search */
if (flag.force)
{
computer = opponent;
opponent = computer ^ 1;
}
- if (XSHOGI)
- {
- /* add remaining time in milliseconds for xshogi */
- if (is_move)
- {
- printf("%d. %s %ld\n",
- ++mycnt2, s, TimeControl.clock[player] * 10);
- }
- }
-
return true;
}