gnome-chess/src/chess-engine.vala

174 lines
4.3 KiB
Vala
Raw Normal View History

2014-01-07 02:19:07 +00:00
/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
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 ();
public signal void error ();
public signal void claim_draw ();
public signal void offer_draw ();
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)
{
warning ("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)
{
warning ("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)
{
Process.close_pid (pid);
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 ()
{
2014-01-07 01:51:03 +00:00
// FIXME sometimes this source does not exist...
if (stdout_watch_id > 0)
Source.remove (stdout_watch_id);
if (pid != 0)
Posix.kill (pid, Posix.SIGTERM);
}
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)
{
warning ("Failed to read from engine: %s", e.message);
return false;
}
2011-01-01 01:42:50 +00:00
catch (IOChannelError e)
{
warning ("Failed to read from engine: %s", e.message);
return false;
}
2011-01-01 01:42:50 +00:00
if (status == IOStatus.EOF)
{
debug ("EOF");
return false;
}
2011-01-01 01:42:50 +00:00
if (status == IOStatus.NORMAL)
{
buf.resize ((int) n_read);
process_input (buf);
}
return true;
}
protected void write (char[] data)
{
size_t offset = 0;
size_t n_written = 0;
do
{
n_written = Posix.write(stdin_fd, &data[offset], data.length - offset);
offset += n_written;
} while (n_written > 0 && offset < data.length);
}
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);
}
}