how to make a chess interface

Discussion of chess software programming and technical issues.

Moderators: bob, hgm, Harvey Williamson

Forum rules
This textbox is used to restore diagrams posted with the [d] tag before the upgrade.
Post Reply
User avatar
lucasart
Posts: 3041
Joined: Mon May 31, 2010 11:29 am
Full name: lucasart
Contact:

how to make a chess interface

Post by lucasart » Sun Aug 26, 2012 9:08 am

In the most basic form, how do you write, in C++, a chess interface. Really the basics I'd like to understand how to do are:

1/ how to launch an instance of an executable file, and get a file handler for its stdin and stdout
2/ talk to this program by sending stuff to its stdin
3/ receive responses. should I do an infinite loop that constantly tries to read the stdout of the program ? Or is there a better way ?

If anyone could show me a sketch of such a program, just the fundamental lines of code to do these things, that would be perfect.

In the meantime, I'm trying to learn GTKmm. My dream would be to do a chess GUI for Linux primarly, but ideally as portable as possible.

Thank you!

kbhearn
Posts: 411
Joined: Thu Dec 30, 2010 3:48 am

Re: how to make a chess interface

Post by kbhearn » Sun Aug 26, 2012 9:28 am

Setting up a child process differs between operating systems. You can use a library to get a common interface to the differing underlying function calls, i know QT provides a child process object, i'd guess the other major gui libraries might as well. Once you get the process setup with its stdin and stdout mapped to pipes you (or your library) have defined, you write to those pipes with standard io functions.

As for receiving from the programs, ways to do nonblocking reads/check for input are again, operating system specific. A seperate thread in an infinite read loop may just be simpler.

User avatar
lucasart
Posts: 3041
Joined: Mon May 31, 2010 11:29 am
Full name: lucasart
Contact:

Re: how to make a chess interface

Post by lucasart » Sun Aug 26, 2012 9:50 am

kbhearn wrote:Setting up a child process differs between operating systems. You can use a library to get a common interface to the differing underlying function calls, i know QT provides a child process object, i'd guess the other major gui libraries might as well. Once you get the process setup with its stdin and stdout mapped to pipes you (or your library) have defined, you write to those pipes with standard io functions.

As for receiving from the programs, ways to do nonblocking reads/check for input are again, operating system specific. A seperate thread in an infinite read loop may just be simpler.
OK. For spawning a process asynchronously, it seems that GTKmm gives me a very nice and portable wrapper:
http://developer.gnome.org/glibmm/unsta ... Spawn.html

I'm still wondering (just for my understanding) if it's not possible to write this in standard C++ without using Qt or GTKmm, in a portable way. Basically I'm looking for a version of the exec() system call that is asynchronous, and gives me file handles for stdin/stdout.

Now, for reading responses from the program. I know one way (a loop that looks into the stdout without flushing it, I've got the code for POSIX and Windows in my chess engine). I'll have a look at the GTKmm documentation for a way to read a pipe without flushing it, as it will allow me to have portable code for that. But should I do a loop ? Or is there a way to connect a function to stuff appearing in a pipe, in the same way as you connect a function to a button being clicked for example in a GUI ?

Problem with a loop, is that I'll have to run it in a separate thread as you mentionned (otherwise the GUI will be irresponsive), and that I find it somewhat inelegant.
Last edited by lucasart on Sun Aug 26, 2012 9:52 am, edited 1 time in total.

User avatar
hgm
Posts: 23772
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: how to make a chess interface

Post by hgm » Sun Aug 26, 2012 9:52 am

lucasart wrote:In the most basic form, how do you write, in C++, a chess interface. Really the basics I'd like to understand how to do are:

1/ how to launch an instance of an executable file, and get a file handler for its stdin and stdout
2/ talk to this program by sending stuff to its stdin
3/ receive responses. should I do an infinite loop that constantly tries to read the stdout of the program ? Or is there a better way ?

If anyone could show me a sketch of such a program, just the fundamental lines of code to do these things, that would be perfect.
Perhaps it is an idea to take a look at the UCI2WB source code. This is not a GUI, so you would not be distracted by all kind of graphics stuff, but it does everything you ask about, and hardly anything more, as what to send to the engine is what it receives from its own stdin, after a simple translation, and what it receives from the engine is similarly forwards to its own stdout. So it is a really small (single-file) source code.

UCI2WB compiles both for Windows and Linux, with the aid of some #if conditionals. It is written in plain C, but it seems that is also C++. It does not use any intermediate platform such as GTK or Qt, just raw Windows API or the pthreads library.

Polling for input is bad (wasteful on CPU, and causing delays). Good GUIs use a separate input thread for each engine they connect to (or make use of an event handler of the supporting platform to make input event-driven, which basically simulates such threads). UCI2WB uses one thread to process engine input, and another thread to process GUI input. Normally both threads are blocked in an input call, and as soon as input arise they fall through to process it.

In rare cases the two threads need to be synchronized (e.g. to handle UCI engines in 'SyncStop' mode, i.e. wait sending other stuff after having send 'stop' until after the engine has acknowledged the 'stop' with 'bestmove'). There I avoid polling by using an 'internal' pipe, from which the GUI->engine thread reads a byte (and thus blocks) after sending 'stop', so that it wakes up as soon as the engine->GUI thread receives 'bestmove' and writes a byte to the pipe.

User avatar
lucasart
Posts: 3041
Joined: Mon May 31, 2010 11:29 am
Full name: lucasart
Contact:

Re: how to make a chess interface

Post by lucasart » Sun Aug 26, 2012 10:03 am

On second thought, I might have somewhat underestimated the complexity of this task... Maybe I'll start by learning GTKmm on really stupid examples, and write something like the Notepad program in Windows. I think that should teachme some basics of GUI programming on a practical example.

I've never done any GUI programming in C or C++. Although I much prefer plain C for writing a chess engine, I have to admit that C++ is more appropriate for GUI stuff, and GTKmm is a great example of the power of complex object designs, when used appropriately.

The only GUI programming I ever did was in Visual Basic, in the "old days" (DOS 6.22/Windows 3.11/VB 5). That was so much easier, it's not even comparable.

User avatar
hgm
Posts: 23772
Joined: Fri Mar 10, 2006 9:06 am
Location: Amsterdam
Full name: H G Muller
Contact:

Re: how to make a chess interface

Post by hgm » Sun Aug 26, 2012 10:25 am

Well, writing a full-fledged GUI from scratch is between 10 and 100 times as much work as writing an engine.

For the real GUI stuff you will typically use some widget-set library, which then usually also provides an event handler, where input (from any source) simply generates an event. So there is no reason then to create threads yourself, you just supply the handlers for the input. (This is how XBoard does it).

Setting up pipes and spawn a process for the engine you typically have to do yourself, though.

User avatar
stegemma
Posts: 859
Joined: Mon Aug 10, 2009 8:05 pm
Location: Italy
Full name: Stefano Gemma
Contact:

Re: how to make a chess interface

Post by stegemma » Sun Aug 26, 2012 10:30 am

Maybe you can take a look to wxWidgets. I'm developing my new programs with this ambient:

GUI: wxWidgets + wxFormBuilder
IDE: CodeLite
Compiler: GCC

In Windows, you can use mingw. In MAC you just have to install xCode to have gcc available. In Linux, gcc should already be available or you can install it.

To configure all the ambient requires some time but you can develop very portable applications.

User avatar
lucasart
Posts: 3041
Joined: Mon May 31, 2010 11:29 am
Full name: lucasart
Contact:

Re: how to make a chess interface

Post by lucasart » Sun Aug 26, 2012 10:36 am

My dream come true! No more reinventing wheels !
http://carlo17.home.xs4all.nl/cwchessboard/index.html

kbhearn
Posts: 411
Joined: Thu Dec 30, 2010 3:48 am

Re: how to make a chess interface

Post by kbhearn » Sun Aug 26, 2012 10:39 am

you'd just wind up writing the same code the library writers are doing for you anyways, but yes, you could do it yourself. on linux you use pipe(), fork() and exec(). on windows none of these functions exist. you instead use CreatePipe, and CreateProcess. Once the process is created, the rest of the code to interact with it can be portable.

User avatar
ilari
Posts: 750
Joined: Mon Mar 27, 2006 5:45 pm
Location: Finland
Contact:

Re: how to make a chess interface

Post by ilari » Sun Aug 26, 2012 10:52 am

lucasart wrote:In the most basic form, how do you write, in C++, a chess interface. Really the basics I'd like to understand how to do are:

1/ how to launch an instance of an executable file, and get a file handler for its stdin and stdout
2/ talk to this program by sending stuff to its stdin
3/ receive responses. should I do an infinite loop that constantly tries to read the stdout of the program ? Or is there a better way ?

If anyone could show me a sketch of such a program, just the fundamental lines of code to do these things, that would be perfect.

In the meantime, I'm trying to learn GTKmm. My dream would be to do a chess GUI for Linux primarly, but ideally as portable as possible.

Thank you!
1 and 2) If you want to use the POSIX API directly, you should basically create a subprocess with fork(), create input and output pipes with pipe(), and call execv() in the child process to set the chess engine as its process image. Then you can write() on the parent process' write pipe to send commands to the engine and read() to read input from it... or you can read input normally if you get a file handle to the read pipe with fdopen().

Here's some example code that may or may not work because I grabbed it from an old project of mine:

Code: Select all

#define PARENT_READ readpipe[0]
#define CHILD_WRITE readpipe[1]
#define CHILD_READ writepipe[0]
#define PARENT_WRITE writepipe[1]

pid_t pid;
int readpipe[2];
int writepipe[2];
const char *cmd = "./engine_executable";
FILE *in;

if &#40;pipe&#40;readpipe&#41; < 0 || pipe&#40;writepipe&#41; < 0&#41;
	fatal_perror&#40;"Couldn't create pipes");

if (&#40;pid = fork&#40;)) < 0&#41;
	fatal_perror&#40;"Couldn't fork child");
else if &#40;pid == 0&#41; &#123; /* in the child process */
	close&#40;PARENT_WRITE&#41;;
	close&#40;PARENT_READ&#41;;

	if &#40;dup2&#40;CHILD_READ, STDIN_FILENO&#41; == -1&#41;
		fatal_perror&#40;"Couldn't map read pipe to stdin");
	close&#40;CHILD_READ&#41;;
	if &#40;dup2&#40;CHILD_WRITE, STDOUT_FILENO&#41; == -1&#41;
		fatal_perror&#40;"Couldn't map write pipe to stdout");
	close&#40;CHILD_WRITE&#41;;

	if&#40;execv&#40;cmd, NULL&#41; == -1&#41; &#123;
		my_perror&#40;"Couldn't Execute %s", cmd&#41;;
		_exit&#40;EXIT_FAILURE&#41;;
	&#125;
&#125; else &#123; /* in the parent process */
	int ret;
		
	close&#40;CHILD_READ&#41;;
	close&#40;CHILD_WRITE&#41;;

	in = fdopen&#40;PARENT_READ, "r");
	if &#40;in == NULL&#41;
		fatal_perror&#40;"Engine %d&#58; Opening input stream", id&#41;;

&#125;

waitpid&#40;pid, NULL, 0&#41;; /* wait for the child to be ready */

/* Now you can read from <in> or write to the child with write&#40;PARENT_WRITE, "text\n", 5&#41;; */

/* Once you're done close the child process */
if &#40;waitpid&#40;pid, NULL, 0&#41; == -1 && errno != ECHILD&#41;
	my_perror&#40;"Couldn't join process %d", pid&#41;;

fclose&#40;in&#41;;
in = NULL;
close&#40;PARENT_WRITE&#41;;
close&#40;PARENT_READ&#41;;
3) Like HGM said, definitely use an infinite loop of blocking read calls in a separate thread. If you use a framework that has signals and slots (like Qt, Gtkmm, Boost) you can send to signal from the reading thread every time it receives a new line of input, and catch that signal in the main thread.

Post Reply