Ponder

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

outAtime
Posts: 226
Joined: Sun Mar 08, 2009 3:08 pm
Location: Canada

Ponder

Post by outAtime »

Hi all. I've been running "Faile" for a while now and would like to add a ponder feature. I've tried looking at other code, including Sjeng (7.0) but I can't see how it's been implemented (or where). I can't find any instructions online or examples of code for how to do this. I imagine it should be fairly simple once I know what I need to add where. Could anyone please provide some examples or guidance here? I had a look at crafty which has great code, but Im finding it difficult to follow the different parameters back to really get the grasp of it. Maybe there is some fairly simple code I can add somewhere to allow the engine to do this? Any help would be appreciated! Thanks .
outAtime
outAtime
Posts: 226
Joined: Sun Mar 08, 2009 3:08 pm
Location: Canada

Re: Ponder

Post by outAtime »

Just to sort of update where Im at:
I have found these: extern char ponder_input[STR_BUFF];
extern bool is_pondering;
and also in another part:

Code: Select all

 if (!is_pondering && (Variant == Bughouse || Variant == Crazyhouse)) return 0; 
 return 1;
outAtime
User avatar
hgm
Posts: 27808
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: Ponder

Post by hgm »

For pondering it must be possible to abort the (ponder) search. The simplest way to do that is mae a global abort flag, and test it after UnMake(), and return immediately when it is set, so your search unwinds. (You could also use that to implement a move-now command, or put an emergency brake in the engine's time management, so that it would not have to use large safety margins when allocating time.)

Once you have that, you must monitor for input during the search. On Windows this can be done with the call PeekNamedPipe(). You don't want to check that in every node, because that would mean a significant burdon, but you could check it, say, every 1000 nodes. So you would put in your Search() something like:

Code: Select all

if&#40;delay-- < 0&#41; &#123;
    DWORD cnt;
    delay = 1000; 
    if&#40;!PeekNamedPipe&#40;inp, NULL, 0, NULL, &cnt, NULL&#41; || cnt != 0&#41; abort = 1;
&#125;
where during initialization you would have done:

Code: Select all

inp = GetStdHandle&#40;STD_INPUT_HANDLE&#41;;
Then you could start up a search with infinite time limit just before you start reading the input. (Supposing pondering has been switched on.) Arrival of input would cause the search to abort, so you would read and process the input as you would have done when you were not pondering.

Don't forget to clear 'abort' afterwards. That's realy all there is to it.
outAtime
Posts: 226
Joined: Sun Mar 08, 2009 3:08 pm
Location: Canada

Re: Ponder

Post by outAtime »

Code: Select all


int interrupt&#40;void&#41;
&#123;
  int c;

#ifdef HAVE_SELECT
  FD_ZERO&#40;&read_fds&#41;;
  FD_SET&#40;0,&read_fds&#41;;
  timeout.tv_sec = timeout.tv_usec = 0;
  select&#40;1,&read_fds,NULL,NULL,&timeout&#41;;
  if&#40;FD_ISSET&#40;0,&read_fds&#41;) 
    &#123;
      c = getc&#40;stdin&#41;;

      if &#40;c == '?')   /*Move now*/
	&#123;
	  return 1;
	&#125;
      else if &#40;c == '.')     /* Stat request */
	&#123;
	  getc&#40;stdin&#41;;
	  post_stat_thinking&#40;);
	  return 0;
	&#125;

      ungetc&#40;c, stdin&#41;;

      if (!is_pondering && &#40;Variant == Bughouse || Variant == Crazyhouse&#41;) return 0; 

      return 1;
    &#125;
  else return 0;
#else 
  static int init = 0, pipe;
  static HANDLE inh;
  DWORD dw;
  if&#40;xb_mode&#41; &#123;     // winboard interrupt code taken from crafty
    if (!init&#41; &#123;
      init = 1;
      inh = GetStdHandle&#40;STD_INPUT_HANDLE&#41;;
      pipe = !GetConsoleMode&#40;inh, &dw&#41;;
      if (!pipe&#41; &#123;
	SetConsoleMode&#40;inh, dw & ~&#40;ENABLE_MOUSE_INPUT|ENABLE_WINDOW_INPUT&#41;);
	FlushConsoleInputBuffer&#40;inh&#41;;
	FlushConsoleInputBuffer&#40;inh&#41;;
      &#125;
    &#125;
    if&#40;pipe&#41; &#123;
      if&#40;!PeekNamedPipe&#40;inh, NULL, 0, NULL, &dw, NULL&#41;) 
	&#123;
	  c = getc&#40;stdin&#41;;

	  if &#40;c == '?')   /*Move now*/
	    &#123;
	      return 1;
	    &#125;
	  else if &#40;c == '.')     /* Stat request */
	    &#123;
	      getc&#40;stdin&#41;;
	      post_stat_thinking&#40;);
	      return 0;
	    &#125;
	  
	  ungetc&#40;c, stdin&#41;;
	  
	  if (!is_pondering && &#40;Variant == Bughouse || Variant == Crazyhouse&#41;) return 0; 
	  
	  return 1;
	&#125;
      if &#40;dw&#41;
	&#123;
	  c = getc&#40;stdin&#41;;
	  
	  if &#40;c == '?')   /*Move now*/
	    &#123;
	      return 1;
	    &#125;
	  else if &#40;c == '.')     /* Stat request */
	    &#123;
	      getc&#40;stdin&#41;;
	      post_stat_thinking&#40;);
	      return 0;
	    &#125;
	  
	  ungetc&#40;c, stdin&#41;;
	  
	  if (!is_pondering && &#40;Variant == Bughouse || Variant == Crazyhouse&#41;) return 0; 
	  
	  return 1;
	&#125;
      else return 0;
    &#125; else &#123;
      GetNumberOfConsoleInputEvents&#40;inh, &dw&#41;;
      if &#40;dw <= 1&#41;
	&#123; 
	  return 0; 
	&#125;
      else 
	&#123; 
	  c = getc&#40;stdin&#41;;

	  if &#40;c == '?')   /*Move now*/
	    &#123;
	      return 1;
	    &#125;
	  else if &#40;c == '.')     /* Stat request */
	    &#123;
	      getc&#40;stdin&#41;;
	      post_stat_thinking&#40;);
	      return 0;
	    &#125;
	  
	  ungetc&#40;c, stdin&#41;;
	  
	  if (!is_pondering && &#40;Variant == Bughouse || Variant == Crazyhouse&#41;) return 0; 
	  
	  return 1;
	&#125;;
    &#125;
  &#125;
#endif
Obviously, I feel like I don't need all this, and it can be simplified. This is a code example I found in .utils . How much of this will I need or can I just use the code you suggested only? I know I dont need the "Move Now" stuff if I dont want it, Im more curious about what comes after #else .. is that all I will need? I feel like Im just about ready to try it. I dont see the delay-- idea here though.
outAtime
Gian-Carlo Pascutto
Posts: 1243
Joined: Sat Dec 13, 2008 7:00 pm

Re: Ponder

Post by Gian-Carlo Pascutto »

The code is a bit more complicated than needed because:

1) It supports both Unix and Windows (#ifdef HAVE_SELECT...#else...#endif)
2) It duplicates some code needlessly.
3) It handles move immediate (! command in winboard)
4) It handles analysis mode (. command in winboard)

To handle the latter 2, the code gets the first character, checks for a match, and then "ungets" the character so the normal winboard processing code can take care of it.
outAtime
Posts: 226
Joined: Sun Mar 08, 2009 3:08 pm
Location: Canada

Re: Ponder

Post by outAtime »

Great! :) All I'm trying to do is get old Faile to ponder. Aside from adding the
(extern char ponder_input[STR_BUFF]; extern bool is_pondering;) to .extvars do you think I will need to add any of the !is_pondering stuff to search anywhere? Im hoping I wont and that it will work with just the mods to .utils and .extvars.
outAtime
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Ponder

Post by Sven »

Gian-Carlo Pascutto wrote:3) It handles move immediate (! command in winboard)
? command :-)

Sven
outAtime
Posts: 226
Joined: Sun Mar 08, 2009 3:08 pm
Location: Canada

Re: Ponder

Post by outAtime »

OK, I have it compiled fixed a couple errors, but I'm not getting any information about what its pondering...how to output the ponder moves like regular search? I will have a look around and see what I can dig up...
Basically it detects ponder, but I need some way to confirm its working, like some data on the screen :)
outAtime
Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Ponder

Post by Sven »

Gian-Carlo Pascutto wrote:The code is a bit more complicated than needed because:

1) It supports both Unix and Windows (#ifdef HAVE_SELECT...#else...#endif)
2) It duplicates some code needlessly.
3) It handles move immediate (! command in winboard)
4) It handles analysis mode (. command in winboard)

To handle the latter 2, the code gets the first character, checks for a match, and then "ungets" the character so the normal winboard processing code can take care of it.
5) It combines several purposes in one function, while I think it would be better to separate the pure detection of input being available from processing that input.
6) As an implication of 5), it works with engines based on the WB protocol only.
7) It depends on several global variables and constants (read_fds, timeout, xb_mode, is_pondering, Variant, Bughouse, Crazyhouse) and also calls at least one engine-specific function (post_stat_thinking()) so it is not easy to port it to a different engine.

Sven
outAtime
Posts: 226
Joined: Sun Mar 08, 2009 3:08 pm
Location: Canada

Re: Ponder

Post by outAtime »

OK, thanks. I'll see what I can do with that! Much appreciated!
outAtime