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
|
2014-02-16 20:06:54 +00:00
|
|
|
* Copyright (C) 2013-2014 Michael Catanzaro
|
2013-07-07 21:14:29 +00:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
public class ChessEngineCECP : ChessEngine
|
|
|
|
{
|
|
|
|
private char[] buffer;
|
|
|
|
private bool moving = false;
|
2011-01-09 21:36:38 +00:00
|
|
|
private string[] options;
|
2010-12-08 07:18:30 +00:00
|
|
|
|
2014-02-16 20:06:54 +00:00
|
|
|
public ChessEngineCECP (string binary, string[] args, uint delay_seconds, string[] options)
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
2014-02-16 20:06:54 +00:00
|
|
|
base (binary, args, delay_seconds);
|
2011-01-09 21:36:38 +00:00
|
|
|
this.options = options;
|
2010-12-08 07:18:30 +00:00
|
|
|
starting.connect (start_cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void start_cb ()
|
|
|
|
{
|
|
|
|
write_line ("xboard");
|
2013-07-28 02:16:34 +00:00
|
|
|
write_line ("random");
|
2011-01-09 21:36:38 +00:00
|
|
|
foreach (var o in options)
|
|
|
|
write_line (o);
|
2010-12-08 07:18:30 +00:00
|
|
|
ready = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void process_input (char[] data)
|
|
|
|
{
|
|
|
|
/* Copy new data */
|
|
|
|
int current = buffer.length;
|
|
|
|
buffer.resize ((int) (buffer.length + data.length));
|
|
|
|
for (int i = 0; i < data.length; i++)
|
|
|
|
buffer[current + i] = data[i];
|
|
|
|
|
|
|
|
/* Parse lines */
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
for (offset = 0; offset < buffer.length && buffer[offset] != '\n'; offset++);
|
|
|
|
if (offset >= buffer.length)
|
|
|
|
return;
|
|
|
|
|
|
|
|
buffer[offset] = '\0';
|
|
|
|
string line = (string) buffer;
|
|
|
|
|
2011-01-01 01:42:50 +00:00
|
|
|
debug ("Read from engine: '%s'", line);
|
2010-12-08 07:18:30 +00:00
|
|
|
|
2012-05-18 20:15:39 +00:00
|
|
|
string[] move_prefixes = { "My move is: ", "My move is : ", "my move is ", "move " };
|
2010-12-08 07:18:30 +00:00
|
|
|
foreach (string prefix in move_prefixes)
|
|
|
|
{
|
|
|
|
if (line.has_prefix (prefix))
|
|
|
|
{
|
|
|
|
string move = line[prefix.length:line.length];
|
2011-01-01 01:42:50 +00:00
|
|
|
debug ("Engine moves %s", move);
|
2010-12-08 07:18:30 +00:00
|
|
|
moving = true;
|
2014-10-21 10:43:02 +00:00
|
|
|
moved (move.strip ());
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-25 18:01:15 +00:00
|
|
|
if (line == "resign" || line == "tellics resign" ||
|
2014-10-21 10:43:02 +00:00
|
|
|
(line.has_prefix ("1-0 {") && line.contains ("resign")) ||
|
|
|
|
(line.has_prefix ("0-1 {") && line.contains ("resign")))
|
2010-12-08 07:18:30 +00:00
|
|
|
{
|
2013-08-25 15:02:22 +00:00
|
|
|
resigned ();
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
2013-10-13 18:28:58 +00:00
|
|
|
else if (line.has_prefix ("Illegal move: "))
|
2013-08-25 18:01:15 +00:00
|
|
|
{
|
|
|
|
stop ();
|
|
|
|
error ();
|
|
|
|
}
|
2013-10-13 18:28:58 +00:00
|
|
|
else if (line.has_prefix ("1-0") || line.has_prefix ("0-1"))
|
|
|
|
{
|
|
|
|
/* The engine thinks the game is over and will not play on. */
|
|
|
|
stop ();
|
|
|
|
}
|
2013-08-25 17:49:23 +00:00
|
|
|
else if (line == "game is a draw" ||
|
|
|
|
line == "draw" ||
|
|
|
|
line == "Draw" ||
|
|
|
|
line.has_prefix ("1/2-1/2"))
|
|
|
|
{
|
|
|
|
claim_draw ();
|
|
|
|
}
|
2010-12-08 07:18:30 +00:00
|
|
|
else if (line == "offer draw")
|
|
|
|
{
|
2013-08-25 17:49:23 +00:00
|
|
|
offer_draw ();
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
buffer = buffer[offset+1:buffer.length];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void start_game ()
|
|
|
|
{
|
|
|
|
}
|
2011-01-25 11:44:15 +00:00
|
|
|
|
2010-12-08 07:18:30 +00:00
|
|
|
public override void request_move ()
|
|
|
|
{
|
|
|
|
write_line ("go");
|
|
|
|
}
|
|
|
|
|
|
|
|
public override void report_move (ChessMove move)
|
|
|
|
{
|
|
|
|
/* Don't repeat the engines move back to it */
|
|
|
|
if (!moving)
|
|
|
|
{
|
|
|
|
/* Stop the AI from automatically moving in response to this one */
|
|
|
|
write_line ("force");
|
2011-01-18 21:00:37 +00:00
|
|
|
write_line (move.get_engine ());
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|
|
|
|
moving = false;
|
|
|
|
}
|
2011-01-25 11:44:15 +00:00
|
|
|
|
2014-06-25 15:20:03 +00:00
|
|
|
public override void do_undo ()
|
2011-01-25 11:44:15 +00:00
|
|
|
{
|
2013-07-28 02:17:50 +00:00
|
|
|
/*
|
|
|
|
* We're undoing only the most recent move here, so there's no need to
|
|
|
|
* call Undo twice, or to use fanciness like the remove command. This
|
|
|
|
* function will be called twice if we need to undo two moves in a row.
|
|
|
|
*
|
|
|
|
* force is not necessary for GNUChess or Phalanx, but it's required by
|
|
|
|
* CECP and most other engines will move again immediately without it
|
|
|
|
* (leading to an apparent AI hang).
|
|
|
|
*/
|
|
|
|
write_line ("force");
|
2011-01-25 11:44:15 +00:00
|
|
|
write_line ("undo");
|
|
|
|
}
|
2010-12-08 07:18:30 +00:00
|
|
|
}
|