how to make a chess interface

Discussion of chess software programming and technical issues.

Moderator: Ras

Chan Rasjid
Posts: 588
Joined: Thu Mar 09, 2006 4:47 pm
Location: Singapore

Re: how to make a chess interface

Post by Chan Rasjid »

hgm wrote:
Chan Rasjid wrote:My complaint is that the look and feel and the ease of use of xboard cannot be compared to the newer graphics programs; eg the graphics linux terminal, gedit or even pychess. They are a breeze to use and configure. A new xboard done from scratch would be a different story.
Are you sure that this is not merely because of the way you use it? From the commands you posted I noticed that you explicitly invoke Polyglot, and configure it by using a fruit.ini file. I imagine that configuring gedit would also be an extreme pain if you would try to locate the hidden user preference files for it, and edit those. But no one in his right mind would try to configure gedit that way, of course.

What seems needed is not so much re-doing XBoard from scratch, as well as re-doing its users from scratch. :wink:
Accepted. Thounsands of ...apol..

I find it makes one's life easier by making assumption and sticking to it than to find out the truth or facts... like it's easy to write a 3200 elo chess program - just discover the few tricks the ippolit authors know and embedded somewhere in their obfuscated code.

I am a Linux newbie till perpetuity and don't even know what really is "echo $PATH" . I will make a huge effort to re-invent myself from scratch :D

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

Re: how to make a chess interface

Post by ilari »

hgm wrote:
Chan Rasjid wrote:My complaint is that the look and feel and the ease of use of xboard cannot be compared to the newer graphics programs; eg the graphics linux terminal, gedit or even pychess. They are a breeze to use and configure. A new xboard done from scratch would be a different story.
Are you sure that this is not merely because of the way you use it? From the commands you posted I noticed that you explicitly invoke Polyglot, and configure it by using a fruit.ini file. I imagine that configuring gedit would also be an extreme pain if you would try to locate the hidden user preference files for it, and edit those. But no one in his right mind would try to configure gedit that way, of course.

What seems needed is not so much re-doing XBoard from scratch, as well as re-doing its users from scratch. :wink:
When it comes to usability and UI design, the customer is always right. It's extremely difficult to know what the users find intuitive or counter-intuitive without actually listening to them.
User avatar
hgm
Posts: 28446
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: how to make a chess interface

Post by hgm »

ilari wrote:When it comes to usability and UI design, the customer is always right. It's extremely difficult to know what the users find intuitive or counter-intuitive without actually listening to them.
Sure. But if people are stuck in the stone age, there is just no improvement that will satisfy them. It is like someone saying "I don't like these Ferrari cars. It is very difficult to tie my horses to the front bumper, and the windscreen gets in the way of my whip, so that I have to stand up all the time to flog my horses over it, when I want to make any speed".

I don't think Mr. Ferrari would take such complaints seriously, and consider to drop the windscreen from the design. In the same spirit, I don't think it would be a good idea to listen to people that complain XBoard is user-unfriendly "because you need to edit ini files".

I happen to think XBoard does configure 'like a breeze', and am open to suggestions from people that have felt the breeze, and have ideas to make that breeze blow even smoother. But criticism from people that are using version 4.6.2 like it was 4.2.7, and then criticize its 4.2.7-ness, is really not relevant.
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: how to make a chess interface

Post by lucasart »

ilari wrote: 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 (pipe(readpipe) < 0 || pipe(writepipe) < 0)
	fatal_perror("Couldn't create pipes");

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

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

	if(execv(cmd, NULL) == -1) {
		my_perror("Couldn't Execute %s", cmd);
		_exit(EXIT_FAILURE);
	}
} else { /* in the parent process */
	int ret;
		
	close(CHILD_READ);
	close(CHILD_WRITE);

	in = fdopen(PARENT_READ, "r");
	if (in == NULL)
		fatal_perror("Engine %d: Opening input stream", id);

}

waitpid(pid, NULL, 0); /* wait for the child to be ready */

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

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

fclose(in);
in = NULL;
close(PARENT_WRITE);
close(PARENT_READ);
Your code essentially works. I encapsulated that into a class Process, which is basically used in this manner:

Code: Select all

  try {
    Process P("/home/lucas/DC");
  catch (ProcessErr &perr) {
    ...
  }
  P.readln(...);
  P.writeln(..);
There were just two little errors I noticed:
* the execv call sends argc = 0, and argv = NULL to the program which isn't what we want (we need argc = 1), so execlp(cmd, cmd, NULL) seems more appropriate
* waitpid is blocking, so removed it. instead i'll start writing to the process and listening to the pipe until there's sth to read.

I need to play around with this stuff until it's rock solid. Then I'll derive an Engine class from the Position class, which will contain an Options object (also a class), and provide some high level way of talking to an UCI engine.

It's really a fascinating project. From a programming perspective that is, because from a user perspective, my program does nothing usefull for the moment (and for a long time to come).
User avatar
hgm
Posts: 28446
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: how to make a chess interface

Post by hgm »

lucasart wrote:There were just two little errors I noticed:
* the execv call sends argc = 0, and argv = NULL to the program which isn't what we want (we need argc = 1), so execlp(cmd, cmd, NULL) seems more appropriate
* waitpid is blocking, so removed it. instead i'll start writing to the process and listening to the pipe until there's sth to read.
The example from UCI2WB wouldn't have had that problem. And would also work with Windows API... :P
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: how to make a chess interface

Post by lucasart »

OK, I think I now have the first stone. A Process "class" (written in C99, because C++ is already irritating me now)

process.h

Code: Select all

#pragma once
#include <stdbool.h>
#include <stdio.h>
#include "unistd.h"

typedef struct {
	pid_t pid;
	FILE *in, *out;
} Process;

bool process_create(Process *p, const char *cmd);
bool process_destroy(Process *p);

bool process_readln(const Process *p, char *buf, size_t n);
bool process_writeln(const Process *p, char *buf);
process.c

Code: Select all

#include "process.h"
#include <sys/types.h>
#include <signal.h>

bool process_create(Process *p, const char *cmd)
{
	int readpipe[2], writepipe[2];
	#define PARENT_READ		readpipe[0]
	#define CHILD_WRITE		readpipe[1]
	#define CHILD_READ		writepipe[0]
	#define PARENT_WRITE	writepipe[1]

	if (pipe(readpipe) < 0 || pipe(writepipe) < 0)
		return false;

	p->pid = fork();
	
	if (p->pid == 0) {
		// in the child process
		close(PARENT_WRITE);
		close(PARENT_READ);

		if (dup2(CHILD_READ, STDIN_FILENO) == -1)
			return false;
		close(CHILD_READ);

		if (dup2(CHILD_WRITE, STDOUT_FILENO) == -1)
			return false;
		close(CHILD_WRITE);

		if (execlp(cmd, cmd, NULL) == -1)
			return false;
	}
	else if (p->pid > 0) {
		// in the parent process
		close(CHILD_READ);
		close(CHILD_WRITE);

		if (!(p->in = fdopen(PARENT_READ, "r")))
			return false;

		if (!(p->out = fdopen(PARENT_WRITE, "w")))
			return false;
		
		setvbuf(p->in, NULL, _IONBF, 0);
		setvbuf(p->out, NULL, _IONBF, 0);
	} else
		// fork failed
		return false;
	
	return true;
}

bool process_destroy(Process *p)
{
	// close the parent side of the pipes
	fclose(p->in);
	fclose(p->out);
	
	// kill the child process
	return kill(p->pid, SIGKILL) >= 0;
}

bool process_readln(const Process *p, char *buf, size_t n)
{
	return fgets(buf, n, p->in) >= 0;
}

bool process_writeln(const Process *p, char *buf)
{
	return fputs(buf, p->out) >= 0;
}
Now we can spawn and kill processes and talk to them in a high level manner:

Code: Select all

#include <process.h>
#include <string.h>

int main(int argc, char **argv)
{
	Process p;
	process_create(&p, "/home/lucas/Chess/DC/DC");
	
	char buf[0x100];
	process_writeln(&p, "uci\n");
	
	while (true) {
		process_readln(&p, buf, sizeof(buf));
		printf(buf);
		if (!strcmp(buf, "uciok\n"))
			break;
	}
	
	process_destroy(&p);
}
And the output is just as expected:

Code: Select all

id name DiscoCheck 3.7.1
id author Lucas Braesch
option name Hash type spin default 32 min 1 max 8192
option name Verbose type check default true
option name AutoClearHash type check default false
option name TimeBuffer type spin default 100 min 0 max 5000
uciok
PS: functions returning a bool return false on error. I don't think any calling function of the process machinery needs to have more info on why the pipes could not be created, the process couldn't be forked etc. they just need to know if all is good or not.
lucasart
Posts: 3243
Joined: Mon May 31, 2010 1:29 pm
Full name: lucasart

Re: how to make a chess interface

Post by lucasart »

hgm wrote: And would also work with Windows API... :P
The fact that my code won't work on Windows is a bonus :wink:
User avatar
hgm
Posts: 28446
Joined: Fri Mar 10, 2006 10:06 am
Location: Amsterdam
Full name: H G Muller

Re: how to make a chess interface

Post by hgm »

Oh? What happened to the "as portable as possible" from your original post? :shock:
kbhearn
Posts: 411
Joined: Thu Dec 30, 2010 4:48 am

Re: how to make a chess interface

Post by kbhearn »

Well the difference here is editing ini files or needing to supply commandline arguments is the stoneage when it comes to a gui. nice options to be available, but ultimately everything that can be configured should be configurable within the ui once it loads, and it should be done in a way that is consistent with the operating system you're on (i.e. menus and standard dialogs like opening a file should feel native). xboard fails on both counts with many things that aren't configurable inside the ui, and the dialogs that do exist being clunky and dated.
User avatar
Evert
Posts: 2929
Joined: Sat Jan 22, 2011 12:42 am
Location: NL

Re: how to make a chess interface

Post by Evert »

kbhearn wrote:Well the difference here is editing ini files or needing to supply commandline arguments is the stoneage when it comes to a gui. nice options to be available, but ultimately everything that can be configured should be configurable within the ui once it loads,
Not that I've looked too closely (preferring commandline arguments because I can specify them from a script), but my impression is that with recent versions of XBoard, you can.
and it should be done in a way that is consistent with the operating system you're on (i.e. menus and standard dialogs like opening a file should feel native).
So tell me, what does "native" mean for an X11 application? GTK? Qt? Motif? When you get down to it the answer depends on your preferred window manager. They're all native. As is Athena (although I agree it's quite dated now).