some crafty questions

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: some crafty questions

Post by bob »

adams161 wrote:well more specifically in the iPhone app it looks like there is something wrong with reading the standard input. this code is finding readstat < 0 or something

readstat = Read(1, buffer);
if (log_file)
fprintf(log_file, "%s(%d): %s\n", SideToMove(wtm), move_number,
buffer);
if (readstat < 0 && input_stream == stdin) {
strcpy(buffer, "end");
(void) Option(tree);
}
I would look at Read() in utility.c and see what is happening. It should never get a 0 or -1 return there, because that "1" parameter says "wait until there is input" so a 0/-1 return should never happen.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: some crafty questions

Post by bob »

adams161 wrote:no the program appears to be writing "End" as a result of this line failing:

readstat = Read(1, buffer);
readstat == -1

that happens in main.c in the main method after the do loop. Is the default standard input and output of whatever i print to the console not really working? Maybe i need to define the standard input and output before i call crafty.

mike
Certainly descriptors 0, 1 and 2 MUST exist before Crafty is executed, it depends on those since that is normal unix/windows process initiation behavior. That's the first thing xboard does is to create pipes and then use dup2() to duplicate these pipes on top of stdin/stdout/etc so that any read to stdin will read from the pipe xboard uses to send commands and any writes to stdout will write to the pipe xboard reads to get engine input back.
adams161
Posts: 626
Joined: Sun May 13, 2007 9:55 pm
Location: Bay Area, CA USA
Full name: Mike Adams

Re: some crafty questions

Post by adams161 »

What I did was 3 things:

1) load crafty code into my existing iPhone project and change crafty's main() to mainIphone()

2) in a button click start a task ( not a fork this is not liked by apple for ios and i'm reading grounds for app rejection), or thread, that simply calls mainIphone() like any other function. This is not inter process communication.

3) My experiment was could they both read and write to the standard input and output. This might have been a bit foolish but i saw a post that hinted at it on a programming forum.


I can't run crafty as a second process in my iPhone app. I think what i need to do when i have time is directly call search from a Fen with a set time of like analyze for 15 seconds and the chain of crafty functions has to exit and i read from some variable its analysis. If i need to abort maybe its like set time to 0 and it thinks it's out of time.

This would run it like a chain of in app c function calls ( on another thread to prevent GUI locking).

mike
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: some crafty questions

Post by bob »

adams161 wrote:What I did was 3 things:

1) load crafty code into my existing iPhone project and change crafty's main() to mainIphone()

2) in a button click start a task ( not a fork this is not liked by apple for ios and i'm reading grounds for app rejection), or thread, that simply calls mainIphone() like any other function. This is not inter process communication.

3) My experiment was could they both read and write to the standard input and output. This might have been a bit foolish but i saw a post that hinted at it on a programming forum.


I can't run crafty as a second process in my iPhone app. I think what i need to do when i have time is directly call search from a Fen with a set time of like analyze for 15 seconds and the chain of crafty functions has to exit and i read from some variable its analysis. If i need to abort maybe its like set time to 0 and it thinks it's out of time.

This would run it like a chain of in app c function calls ( on another thread to prevent GUI locking).

mike
The short answer is that if you use threads, you can't have both read/write stdin. does IOS support what unix calls a "fifo file"? This is a pseudo-file that you have to open once for reading and once for writing. Then what ever you write into the write descriptor can be read by reading from the descriptor you used to open the fifo for reading.

In unix we do this with "mkfifo" command which makes something that looks like a file but is really a sort of "pipe" to connect a reader and writer. You could use that to have the threads talk without fear of races when both access stdin.
kinderchocolate
Posts: 454
Joined: Mon Nov 01, 2010 6:55 am
Full name: Ted Wong

Re: some crafty questions

Post by kinderchocolate »

Bob,

I think you over-engineered. Crafty can be easily integrated in an iOS app with only a single character addition. In SmallChess, an engine is communicated to the user interface with dup2(). This system call allows the standard input/output be accessed by inter-thread-communication. I ported your engine with only a single change:

int main() to int main_()

Your engine works perfectly on my phone.
adams161
Posts: 626
Joined: Sun May 13, 2007 9:55 pm
Location: Bay Area, CA USA
Full name: Mike Adams

Re: some crafty questions

Post by adams161 »

This person indicates they got mkfifo to work in objective-c "Write to fifo file" http://stackoverflow.com/questions/2033 ... -fifo-file

There is a little discussion in apple forums https://discussions.apple.com/message/7933372 "Re: Named Pipes using mkfifo and Cocoa"

I'll have to try it. I haven't specifically seen it mentioned with iOS but from the posts it must be working with iOS or OSX or both.

Is there any specific crafty code functions that need changing? I"m a little hazy on the hand shake and if Crafty's pipe functions need to change to fifo file.

Mike
adams161
Posts: 626
Joined: Sun May 13, 2007 9:55 pm
Location: Bay Area, CA USA
Full name: Mike Adams

Re: some crafty questions

Post by adams161 »

So ted something like this?

// replace standard input with input file

dup2(in, 0);

// replace standard output with output file

dup2(out, 1);


where in and out are files i create? How did you deal with the game history issue? Or did that just not come up with dup2? and what was the one character you had to change? did you have to change the main method to be crafty_main or something?

Mike
kinderchocolate
Posts: 454
Joined: Mon Nov 01, 2010 6:55 am
Full name: Ted Wong

Re: some crafty questions

Post by kinderchocolate »

Mike,

I don't have the source code with me, and I forgot exactly how I did it but I do remember the concepts. The only character change was "main" to "main_".

There're two main ways you can integrate your engine within iOS. In the first way, do what something like Tord.R did in his Stockfish app. Here, you mess around the search and the code for reading inputs. If you go this way, you should add a queue because you can't assume the speed how the engine processes the inputs. You'll need a buffer. For example, in Stockfish, you'd search "info depth" and replaced all occurrence with something like:

const std::string str = <the info depth>;
engine_to_my_gui(str);

and do the same thing to "bestmove". If you did this, you'd have already an engine that talks with your user interface. For the inputs, you'll need to do something like:

getline(....) // Old Stockfish code

to

my_get_line(....)

std::string my_get_line(....)
{
// block until there is something in the queue, a condition variable is good here
// read the first entry from the queue and return it
}

So if you want to make a move, you'll get it from the user then put it into the queue and wake up the condition variable.

In the second way, you treat the entire engine as a blackbox. You don't even look at the source code. When you start the engine thread, you can also create a file descriptor and redirect everything the engine prints automatically to the GUI thread. The GUI thread needs a file descriptor. Once it has it, it can just do something like

std::string a_line_from_engine = read(my_file_descriptor)

This approach is easier to port multiple engines but more technical and harder to accomplish the task. I remember I studied the code in Polyglot for it to work. Polyglot has a good example how inputs and outputs should be redirected, as it's really its why it exists.
kinderchocolate
Posts: 454
Joined: Mon Nov 01, 2010 6:55 am
Full name: Ted Wong

Re: some crafty questions

Post by kinderchocolate »

If you prefer the first method. In Crafty, use the text editor to search for everything that prints a PV and the move the engine makes. Get rid of thos prints and assign the contents to a string. Forward those strings to a C function that you can access in your Objective C code.

Likewise, find the line that takes a standard input in the Crafty. Replaces it with your own function that takes a line from the user interface. Once you've done this and start the Crafty engine in a thread, you're done.
adams161
Posts: 626
Joined: Sun May 13, 2007 9:55 pm
Location: Bay Area, CA USA
Full name: Mike Adams

Re: some crafty questions - experimental results

Post by adams161 »

I was more interested in method two, redirection of input output. I thought i'd write the results of my experimenting for anyone else who might be trying this and to show Bob some of this code.

-(IBAction)initializeNewEngineGame:(id)sender
{

FILE *in, *out;
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
bundlePath = [bundlePath stringByAppendingString:@"/crafty_in.txt"];
const char *c = [bundlePath UTF8String];
bundlePath = [[NSBundle mainBundle] resourcePath];
bundlePath = [bundlePath stringByAppendingString:@"/crafty_out.txt"];
const char *c2 = [bundlePath UTF8String];

in = fopen(c, "r+");
out = fopen(c2, "w");
int inDes = fileno(in);
int outDes = fileno(out);
// replace standard input with input file

dup2(inDes, 0);

// replace standard output with output file

dup2(outDes, 1);

// close unused file descriptors

fclose(in);
fclose(out);

// start engine
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

char* dummy_args[] = { "ponder=off", "xboard", NULL };
mainiphone(2, dummy_args);



});

// this below is a very limited concept. its my activity thread.
// in 4 seconds i start the analysis and in 16 seconds my second if i quit

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

fprintf(stderr, "in here");
int a = 0;
while(1)
{
a++;
if(a == 2)
[self startGame]; // writes to in file winboard commands to start
if(a == 8)
{ [self quitGame];// now we use fopen with append and append exit and quit
fprintf(stderr, "sent quit");
}

int c;
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
bundlePath = [bundlePath stringByAppendingString:@"/crafty_out.txt"];
const char *c2 = [bundlePath UTF8String];


FILE *out = fopen(c2, "r");

if (out) {

int i = 0;
while ((c = getc(out)) != EOF)
{
if(i < self->fileMarkCounter)
{ i++;

}
else
{
fprintf(stderr, "%c", c);
self->fileMarkCounter++;
i++;

}
}
}
fclose(out);
sleep(2);
}
}); //fflush(stdout);

}


It produced the following output that i wrote to stderr


in herefeature done=0
unable to open book file [./book.bin].
book is disabled
unable to open book file [./books.bin].

tellicsnoalias set 1 Crafty v23.4 (1 cpus)
tellicsnoalias kibitz Hello from Crafty v23.4! (1 cpus)
tellicsnoalias set 1 Crafty v23.4 (1 cpus)
Analyze Mode: type "exit" to terminate.
13 14 197 399570 1. Nc3 Nc6 2. Nf3 Nf6 3. e4 e6 4. Bb5 Bb4 5. O-O O-O 6. d3 d5 7. Bd2 Bxc3 8. Bxc3 dxe4 9. Bxc6 bxc6
13 14 248 506469 1. Nc3 Nc6 2. Nf3 Nf6 3. e4 e6 4. Bb5 Bb4 5. O-O O-O 6. d3 d5 7. Bd2 Bxc3 8. Bxc3 dxe4 9. Bxc6 bxc6
14 23 369 759902 1. Nc3 Nc6 2. Nf3 Nf6 3. e4 e5 4. d4 exd4 5. Nxd4 Bc5 6. Nxc6 bxc6 7. e5 Qe7
14 23 462 951713 1. Nc3 Nc6 2. Nf3 Nf6 3. e4 e5 4. d4 exd4 5. Nxd4 Bc5 6. Nxc6 bxc6 7. e5 Qe7
15 38 658 1358286 1. Nc3 Nc6 2. Nf3 Nf6 3. e4 e5 4. d4 exd4 5. Nxd4 Bb4 6. Nxc6 Bxc3+ 7. bxc3 dxc6 8. Qxd8+ Kxd8
15 38 721 1492341 1. Nc3 Nc6 2. Nf3 Nf6 3. e4 e5 4. d4 exd4 5. Nxd4 Bb4 6. Nxc6 Bxc3+ 7. bxc3 dxc6 8. Qxd8+ Kxd8
sent quitanalyze complete.
args indicated quitIllegal move: quit


my functions start game and quit below

-(void) startGame
{
FILE *in;
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
bundlePath = [bundlePath stringByAppendingString:@"/crafty_in.txt"];
const char *c = [bundlePath UTF8String];

in = fopen(c, "w");
fprintf(in, "new\n");
fprintf(in, "level 0 1 1\n");
fprintf(in, "post\n");
fprintf(in,"hard\n");
fprintf(in, "force\n");
fprintf(in, "analyze\n");
fclose(in);

}
-(void) quitGame
{
FILE *in;
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
bundlePath = [bundlePath stringByAppendingString:@"/crafty_in.txt"];
const char *c = [bundlePath UTF8String];

in = fopen(c, "a+");

fprintf(in, "exit\n");
fprintf(in, "quit\n");

fclose(in);

}