my $telltarget = undef; # undef to be silent
my @tell_intervals = (5, 20, 60, 120, 240, 480, 960); # after each move
my $uci_assume_full_compliance = 0; # dangerous :-)
+my $update_max_interval = 2.0;
my $second_engine_start_depth = 8;
my @masters = (
'Sesse',
# Program starts here
$SIG{ALRM} = sub { output_screen(); };
+my $latest_update = undef;
$| = 1;
select(STDOUT);
# open the chess engine
-my $engine = open_engine($engine_cmdline);
-my $engine2 = open_engine($engine2_cmdline);
+my $engine = open_engine($engine_cmdline, 'E1');
+my $engine2 = open_engine($engine2_cmdline, 'E2');
my ($last_move, $last_tell);
my $last_text = '';
my $last_told_text = '';
# any fun on the UCI channel?
if ($nfound > 0 && vec($rout, fileno($engine->{'read'}), 1) == 1) {
- my $line = read_line($engine->{'read'});
- handle_uci($engine, $line, 1);
+ my @lines = read_lines($engine);
+ for my $line (@lines) {
+ handle_uci($engine, $line, 1);
+ }
$sleep = 0;
- # don't update too often
- Time::HiRes::alarm(0.2);
+ output_screen();
}
if ($nfound > 0 && vec($rout, fileno($engine2->{'read'}), 1) == 1) {
- my $line = read_line($engine2->{'read'});
- handle_uci($engine2, $line, 0);
+ my @lines = read_lines($engine2);
+ for my $line (@lines) {
+ handle_uci($engine2, $line, 0);
+ }
$sleep = 0;
- # don't update too often
- Time::HiRes::alarm(0.2);
+ output_screen();
}
sleep $sleep;
chomp $line;
$line =~ tr/\r//d;
$line =~ s/ / /g; # Sometimes needed for Zappa Mexico
- print UCILOG localtime() . " <= $line\n";
+ print UCILOG localtime() . " $engine->{'tag'} <= $line\n";
if ($line =~ /^info/) {
my (@infos) = split / /, $line;
shift @infos;
sub output_screen {
#return;
-
+
return if (!defined($pos_calculating));
+ # Don't update too often.
+ my $age = Time::HiRes::tv_interval($latest_update);
+ if ($age < $update_max_interval) {
+ Time::HiRes::alarm($update_max_interval + 0.01 - $age);
+ return;
+ }
+ $latest_update = [Time::HiRes::gettimeofday];
+
my $info = $engine->{'info'};
my $id = $engine->{'id'};
for my $move (keys %refutation_moves) {
eval {
my $m = $refutation_moves{$move};
- next if ($m->{'depth'} < $second_engine_start_depth);
+ die if ($m->{'depth'} < $second_engine_start_depth);
my $pretty_move = join('', prettyprint_pv($pos_calculating->{'board'}, $move));
my @pretty_pv = prettyprint_pv($pos_calculating->{'board'}, $move, @{$m->{'pv'}});
if (scalar @pretty_pv > 5) {
sub uciprint {
my ($engine, $msg) = @_;
print { $engine->{'write'} } "$msg\n";
- print UCILOG localtime() . " => $msg\n";
+ print UCILOG localtime() . " $engine->{'tag'} => $msg\n";
}
sub short_score {
}
sub open_engine {
- my $cmdline = shift;
+ my ($cmdline, $tag) = @_;
my ($uciread, $uciwrite);
my $pid = IPC::Open2::open2($uciread, $uciwrite, $cmdline);
my $engine = {
pid => $pid,
read => $uciread,
+ readbuf => '',
write => $uciwrite,
info => {},
- ids => {}
+ ids => {},
+ tag => $tag,
};
uciprint($engine, "uci");
return $engine;
}
-sub read_line {
- my $fh = shift;
+sub read_lines {
+ my $engine = shift;
#
# Read until we've got a full line -- if the engine sends part of
# a line and then stops we're pretty much hosed, but that should
# never happen.
#
- my $line = '';
- while ($line !~ /\n/) {
+ while ($engine->{'readbuf'} !~ /\n/) {
my $tmp;
- my $ret = sysread $fh, $tmp, 1;
+ my $ret = sysread $engine->{'read'}, $tmp, 4096;
if (!defined($ret)) {
next if ($!{EINTR});
die "EOF from UCI engine";
}
- $line .= $tmp;
+ $engine->{'readbuf'} .= $tmp;
}
- $line =~ tr/\r\n//d;
- return $line;
+ # Blah.
+ my @lines = ();
+ while ($engine->{'readbuf'} =~ s/^([^\n]*)\n//) {
+ my $line = $1;
+ $line =~ tr/\r\n//d;
+ push @lines, $line;
+ }
+ return @lines;
}
# Find all possible legal moves.