engine winboard communication & CPW engine

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
Greg Strong
Posts: 388
Joined: Sun Dec 21, 2008 6:57 pm
Location: Washington, DC

engine winboard communication & CPW engine

Post by Greg Strong »

Hello,

I've been working on a winboard-protocol engine, Quadrox, and it works pretty well, but there are some issues with the most basic communication (low-level stdin stuff.)

It works perfectly when being run by a GUI (Winboard, Arena, etc.) but when I try to enter commands manually into the command prompt window for debugging purposes, as soon as the engine has performed any thinking the console window will never respond to input again.

I'm in a pure Windows environment and the relevant code for communication comes straight out of the CPW engine. It seemed reasonable to model it on that but now I wonder - not because I think the code is bad (it's working 99% now) but because it doesn't seem to be complete or directly usable. Please tell me I'm missing something... The chessprogramming wiki does not appear to contain the code in any downloadable archive (nor anywhere else I found.) So, I spend a significant amount of time saving out every file one-by-one with copy and paste, but couldn't get that to build either. The code seems to be incomplete. For example, the main() function calls a function root(). There's a file "root" (marked obsolete) but it doesn't appear to contain a function called root. If I could build this program and debug it that would be a huge help.

Failing that, the general problem seems to be that in the input() function, the condition:

Code: Select all

if( stdin->_cnt > 0 )
	return 1;
never gets triggered no matter what. Probably this is some Windows issue and everyone is using Linux...

Any insight would be greatly appreciated!
User avatar
hgm
Posts: 28478
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: engine winboard communication & CPW engine

Post by hgm »

I don't know anything about the CPW engine, but I can share my experience on testing for input. Which, like yours, seems there is missing something. (Annoying thing is that I vaguely remember the solution was presented here once, but I cannot find the posting anymore.) The problem I am always facing does have work-arounds, though.

In Windows I use PeekNamedPipe() to test for pending input. (I only do that in ponder mode; my engines do not implement the 'move now' command.) I am aware that this does not work when running from the command line (where you would have to use kbhit() or some MS-DOS thing like that), but I arranged it such that when PeekNamedPipe() prodices an error, (e.g. because of not acting on a pipe), it counts as input. So it immediately falls out of ponder when running from the command line, which I did not care about.

The real problem was that when there is input during ponder, when running under WinBoard, it wil always be the time+otim+usermove combination. The main loop of my protocol driver was usually written such that after processing a command, it checks whether it now have to think or ponder before it starts reading (with blocking input) the next.

After processing the 'time' command it thus started a new ponder search, periodically calling PeekNamedPipe() to check for more input. This consistently tells you there is none, however, despite the fact that 'otim' and 'usermove' haven't been processed (or even seen) yet. It seems that the getchar() call I use to read the 'time' command upto and including the first linefeed also makes the 'otim' and 'usermove' command disappear from the pipe. I.e., it seems that reading a single character from the pipe causes everything queued in the pipe at that moment to be transferred to some internal buffer that was hidden from view. You would no doubt get it as soon as you started using more getchar(), but I wouldn't do that during ponder unless the PeekNamedPipe() would tell you there was input (which of course would never come anymore).

The work-around was simply to assume there is input after 'time' and 'otim', (as WinBoard never sends those in isolation, but only just before 'usermove' or 'go') and never start a ponder search after processing these commands, but go reading a new input line immediately. A bit unsatisfactory, but it worked.

It could be that the stdin->_cnt would offer a more fundamental solution to this. If indeed it does report the contents of the buffer where the input data is hidden. The problem is that there are many levels in implementation of input streams, and potentially each of these levels could involve its own buffering. Below the level of streams (fgetc, fputc) there is the level of raw file descriptors (Unix read and write), and below that there is the Windows API level of file handles. So even if a buffer count at one level tells you nothing is buffered (or if you explicitly turned off buffering for that level), this is no guarantee it is not buffered somewhere at some other level...
User avatar
velmarin
Posts: 1600
Joined: Mon Feb 21, 2011 9:48 am

Re: engine winboard communication & CPW engine

Post by velmarin »

This is engine code CPW, perhaps more ancient, I no remember,
but it compiles perfect VisualC + + and Intel compiler.
I hope help you.

http://www.mediafire.com/?egn24emj7nb17uc
jdart
Posts: 4429
Joined: Fri Mar 10, 2006 5:23 am
Location: http://www.arasanchess.org

Re: engine winboard communication & CPW engine

Post by jdart »

As HGM notes, you need different code in Windows to handle the case of connecting to an engine vs. reading from console.

In either case, input should be unbuffered. This is important. My program does this right away:

Code: Select all

    // Must use unbuffered console
    setbuf(stdin,NULL);
    setbuf(stdout, NULL);
    std::cout.rdbuf()->pubsetbuf(NULL, 0);
    std::cin.rdbuf()->pubsetbuf(NULL, 0);
In implementing the Winboard protocol I direct input to a separate command processing routine when pondering. If the command is not one that is processed during pondering I add it to a stack of incoming commands and process it after the search completes. This is complex but works. Probably it can be done more simply. Note that some existing implementations such the one in MSCP are not really complete (no pondering).

--Jon
jdart
Posts: 4429
Joined: Fri Mar 10, 2006 5:23 am
Location: http://www.arasanchess.org

Re: engine winboard communication & CPW engine

Post by jdart »

I used to use PeekNamedPipe but now I use a separate thread that does a blocking read for input. This is the actual input code:

Code: Select all

 if (_isatty(_fileno(stdin))) {
         // we are reading direct from the console, enable echo & control-char
         // processing
         if (!SetConsoleMode(hStdin, ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT |
                         ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT)) {
            cerr << "SetConsoleMode failed" << endl;
         }
         bSuccess = ReadConsole(hStdin, buf, 1024, &dwRead, NULL);
      }
      else {
         bSuccess = ReadFile(hStdin, buf, 1024, &dwRead, NULL);
         if (! bSuccess || dwRead == 0) {
            if (doTrace) cout << "# read error from input pipe" << endl;
#ifdef UCI_LOG
            ucilog << "read error from input pipe" << endl << (flush);
#endif
            break;
	 }
 }