UCI Chess Engine Protocol

I really like the UCI protocol.  I know there are diehard fans of Winboard out there, but for me I like the cleanness of UCI.  One of the aim I have for Maverick is to support as much of the protocol as possible.  In Monarch the UCI code was stable but it was a bit messy.  So I put some thought into how I could simplify the implementation.  Here’s what I came up with for Maverick:

There are two threads.  The first thread just listens for user / GUI input.  We’ll call this the listening thread. The second thread runs the engine’s search and reports back with it’s findings.  We’ll call this the thinking thread.  Most, if not all, problems with this type of implementation crop up when one thread gets out of sync with the other thread’s state. This usually results in the thinking thread being sent unexpected commands which are either ignored or processed incorrectly.

The insight I had was by using the UCI protocol there are only two commands which change the state of the thinking thread.  These are “go” and “stop”, (there is also “quit”, which I handle as a special form of “stop”).  So the “go” command needs to change the state of the thinking thread from “waiting” to “thinking”.  And the stop command needs to change the state back from “thinking” to “waiting”.  In Maverick’s implementation I’ve also added “Start_Thinking” as another state for the thinking thread.  This is needed when there is rapid fire changes and the GUI is blasting commands at the engine.  Under the rapid fire scenario the engine can receive a stop command before the engine starts to think.  By having the “Start_Thinking” state the engine can wait for the search to start before taking any more input from the GUI.

Here’s the code:

void uci_stop()
{
uci.stop = TRUE;
while (uci.engine_state != UCI_ENGINE_WAITING)
Sleep(1);
}

void uci_go(char *s)
{
search_start_time = time_now();
last_display_update = search_start_time;
set_uci_level(s, position->to_move);
uci.engine_state = UCI_ENGINE_START_THINKING;
while (uci.engine_state == UCI_ENGINE_START_THINKING)
Sleep(1);
}

It seems to work well and be rock-solid stable!

Maverick is almost ready to start playing chess.  A few more clean-ups needed!

US Citizenship & x5 Speed-up!

It’s been a while since I last posted.  I’ve been busy getting all of the UCI plumbing in place.  Maverick is almost at the stage it can play a game of chess.  I’ve created the basic search routines – complete with alpha-beta, quiescent search and root search. 

Some early tests show quite a speed-up compared to my old Monarch letterbox framework.  On my 2.8 GHz i7 4900MQ the old Monarch 1.7 engine is doing about 1.7 million nodes per second.  On the same positions Maverick is doing about 8.6 million.  I expect this will come down once I add hash tables and beef up the evaluation but this is better than I expected.  It’s about a five times speed-up.  I think quite a bit is due to the 64 bit GCC 4.8 compiler but I’m happy with the result.

I’m hoping Maverick will play its first game this weekend.

On another note – I became a US citizen today!

UCI Protocol – Capturing User Input

I found the Monarch’s source code in a corner of my hard disk.  One of the strong points of Monarch was its stability.  Users reported running thousands and thousand of games without it crashing.  I put this down to defensive programming (hat tip Fabian!) and a solid implementation of the UCI protocol. So since Monarch was so stable I’ll reuse as much of the UCI code as possible.  This is not intended as a lesson on the UCI protocol, so if you want ot find out more I suggest you read Shredder’s Page or UCI Chess Engine:

Listening for the Input:

There are basically two ways to listen for input in console mode.  One way is to check for the data in the standard pipes (Fruit uses this approach).  The other is to use a separate Thread for the engine and use the main thread to get the user input.  Monarch used the second approach.  It seemed to work well.

So here’s the main loop.  This sets the buffer to zero (highly recommended to avoid any timing delays) and initializes the engine:

int main(int argc, char *argv[])
{
setbuf(stdout, NULL);
setbuf(stdin, NULL);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stdin, NULL, _IONBF, 0);

//uci.engine_initialized = FALSE;
//uci.mode = UCI_STARTING;

create_uci_engine_thread();

uci_set_author();
listen_for_uci_input();
//destroy_hash();

return TRUE;
}

Creating the engine thread is relatively straightforward:

void create_uci_engine_thread()
{
thread_handle = (HANDLE)_beginthreadex( NULL, 0, &engine_loop, NULL, 0, &threadID );
SetThreadPriority(thread_handle, THREAD_PRIORITY_NORMAL); // needed for Fritz GUI! :-))
}

Now the engine just needs to respond to changes in the UCI mode.

unsigned __stdcall engine_loop(void* pArguments)
{
uci.mode = UCI_WAITING;
while(TRUE){
if (uci.mode == UCI_START_THINKING){
//root_search(position);
if (uci.mode != UCI_QUIT)
uci.mode = UCI_WAITING;
}
if (uci.mode == UCI_QUIT){
_endthreadex(0);
return 0;
}
else{
Sleep(1);
}
}
}

Now I have a working console application I can start to write the basic building blocks of the engine and test them with the “test” command.

Tomorrow, I’ll work on the chess board data structure.