gnome-chess/src/chess-engine.vala

180 lines
4.4 KiB
Vala
Raw Normal View History

2013-07-07 21:14:29 +00:00
/*
* Copyright (C) 2010-2013 Robert Ancell
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
2013-05-12 00:35:52 +00:00
public abstract class ChessEngine : Object
{
private string binary;
private string[] args;
2011-01-01 01:42:50 +00:00
private Pid pid;
private int stdin_fd;
private int stderr_fd;
2011-01-01 01:42:50 +00:00
private IOChannel stdout_channel;
private uint stdout_watch_id;
protected virtual void process_input (char[] data) {}
public signal void starting ();
public signal void ready_changed ();
public signal void moved (string move);
public signal void resigned ();
public signal void stopped ();
private bool _ready = false;
public bool ready
{
protected set
{
_ready = value;
ready_changed ();
}
public get
{
return _ready;
}
}
public ChessEngine (string binary, string[] args)
{
this.binary = binary;
this.args = args;
}
public bool start ()
{
string[] argv = {binary};
foreach (var arg in args)
argv += arg;
argv += null;
int stdout_fd;
try
{
2011-01-01 01:42:50 +00:00
Process.spawn_async_with_pipes (null, argv, null,
SpawnFlags.SEARCH_PATH | SpawnFlags.DO_NOT_REAP_CHILD,
null,
out pid, out stdin_fd, out stdout_fd, out stderr_fd);
}
2011-01-01 01:42:50 +00:00
catch (SpawnError e)
{
stderr.printf ("Failed to execute chess engine: %s\n", e.message);
return false;
}
ChildWatch.add (pid, engine_stopped_cb);
2011-01-01 01:42:50 +00:00
stdout_channel = new IOChannel.unix_new (stdout_fd);
try
{
2011-01-01 01:42:50 +00:00
stdout_channel.set_flags (IOFlags.NONBLOCK);
}
2011-01-01 01:42:50 +00:00
catch (IOChannelError e)
{
stderr.printf ("Failed to set input from chess engine to non-blocking: %s", e.message);
}
stdout_watch_id = stdout_channel.add_watch (IOCondition.IN, read_cb);
starting ();
return true;
}
private void engine_stopped_cb (Pid pid, int status)
{
stopped ();
}
2013-05-12 00:35:52 +00:00
public abstract void start_game ();
2013-05-12 00:35:52 +00:00
public abstract void request_move ();
2013-05-12 00:35:52 +00:00
public abstract void report_move (ChessMove move);
2013-05-12 00:35:52 +00:00
public abstract void undo ();
2011-01-25 11:44:15 +00:00
public void stop ()
{
if (stdout_watch_id > 0)
Source.remove (stdout_watch_id);
if (pid != 0)
{
Posix.kill (pid, Posix.SIGTERM);
Process.close_pid (pid);
}
}
2011-01-01 01:42:50 +00:00
private bool read_cb (IOChannel source, IOCondition condition)
{
char[] buf;
size_t n_read;
2011-01-01 01:42:50 +00:00
IOStatus status;
buf = new char[1024];
try
{
status = source.read_chars (buf, out n_read);
}
2011-01-01 01:42:50 +00:00
catch (ConvertError e)
{
return false;
}
2011-01-01 01:42:50 +00:00
catch (IOChannelError e)
{
return false;
}
2011-01-01 01:42:50 +00:00
if (status == IOStatus.EOF)
{
stdout.printf ("EOF\n");
return false;
}
2011-01-01 01:42:50 +00:00
if (status == IOStatus.NORMAL)
{
2011-01-01 01:42:50 +00:00
//debug ("Read %zu octets from engine", n_read);
buf.resize ((int) n_read);
process_input (buf);
}
return true;
}
protected void write (char[] data)
{
size_t offset = 0;
size_t n_written;
while (offset < data.length)
{
/* Unnecessary copying but there seems to be a vala bug here */
char[] d = new char[data.length - offset];
for (int i = 0; i < data.length - offset; i++)
d[i] = data[offset + i];
n_written = Posix.write(stdin_fd, d, d.length);
if (n_written < 0)
return;
2011-01-01 01:42:50 +00:00
//debug ("Wrote %zu octets to engine", n_written);
offset += n_written;
}
}
protected void write_line (string line)
{
string l = line + "\n";
2011-01-01 01:42:50 +00:00
debug ("Writing line to engine: '%s'", line);
char[] d = l.to_utf8 ();
if (d != null)
write (d);
}
}