# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# This program is distributed with GNU Go, a Go program. #
# Write gnugo@gnu.org or see http://www.gnu.org/software/gnugo/ #
# for more information. #
# Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 #
# 2008 and 2009 by the Free Software Foundation. #
# 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 - version 3, #
# or (at your option) any later version. #
# This program is distributed in the hope that it will be #
# useful, but WITHOUT ANY WARRANTY; without even the implied #
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR #
# PURPOSE. See the GNU General Public License in file COPYING #
# You should have received a copy of the GNU General Public #
# License along with this program; if not, write to the Free #
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, #
# Boston, MA 02111, USA. #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# send the command to the GTP program
# parse the response of the GTP program
print STDERR
"$hin 1:$line" if ($debug);
return "ERROR" unless (defined $line);
($repchar, $result) = split(/\s*/, $line, 2);
print STDERR
"$hin 2:repchar $repchar\n" if ($debug);
print STDERR
"$hin 3:result $result\n" if ($debug);
while (!($line =~ /^\s*$/)) {
print STDERR
"$hin 4:$line" if ($debug);
my $board_coords = shift;
$board_coords =~ tr/A-Z/a-z/;
return "" if ($board_coords eq "pass");
my $first = substr($board_coords, 0, 1);
my $number = substr($board_coords, 1);
$sgffirst = chr(ord($first) - 1);
my $sgfsecond = chr(ord('a') + $size - $number);
# print "$board_coords, $sgffirst, $number, $sgfsecond\n";
return $sgffirst . $sgfsecond;
struct
('GTP::Player' => {
my $pid = open2
($self->{out
}, $self->{in}, $cmd);
$self->{gtp_version
} = GTP
::exec_cmd
($self->{in},
$self->{out
}, "protocol_version");
$self->{gtp_version
} eq 1 or $self->{gtp_version
} eq 2 or
die "Unsupported gtp version $self->{gtp_version}\n";
if ($self->{gtp_version
} eq 1) {
} elsif ($color =~ /^w/i) {
die "Illegal color $color\n";
my $move = GTP
::exec_cmd
($self->{in}, $self->{out
}, $cmd);
if ($self->{gtp_version
} eq 1) {
GTP
::exec_cmd
($self->{in}, $self->{out
}, $cmd . $move);
if ($self->{gtp_version
} eq 1) {
GTP
::exec_cmd
($self->{in}, $self->{out
}, $cmd . $move);
GTP
::exec_cmd
($self->{in}, $self->{out
}, "komi $komi");
GTP
::exec_cmd
($self->{in}, $self->{out
}, "boardsize $size");
GTP
::exec_cmd
($self->{in}, $self->{out
}, "clear_board");
$stones = GTP
::exec_cmd
($self->{in}, $self->{out
}, "handicap $handicap");
return split(' ', $stones);
$stones = GTP
::exec_cmd
($self->{in}, $self->{out
}, "fixed_handicap $handicap");
return split(' ', $stones);
$self->{in}->print("quit\n");
$board = GTP
::exec_cmd
($self->{in}, $self->{out
}, "showboard");
if ($self->{gtp_version
} eq 2) {
my $ret = GTP
::exec_cmd
($self->{in}, $self->{out
}, "get_random_seed");
my ($result, $rest) = split(' ', $ret, 2);
my $name = GTP
::exec_cmd
($self->{in}, $self->{out
}, "name");
my $version = GTP
::exec_cmd
($self->{in}, $self->{out
}, "version");
return GTP
::exec_cmd
($self->{in}, $self->{out
}, "score");
my $ret = GTP
::exec_cmd
($self->{in}, $self->{out
}, "final_score");
my ($result, $rest) = split(' ', $ret, 2);
package GTP
::Game
::Result
;
struct
('GTP::Game::Result' => {
'black' => 'GTP::Player',
'white' => 'GTP::Player',
'handicap_stones' => '@',
'result' => 'GTP::Game::Result'
my $handle = new FileHandle
;
$handle->open(">$sgffile") or
die "Can't write to $sgffile\n";
my $black_name = $self->black->get_program_name;
my $white_name = $self->white->get_program_name;
my $black_seed = $self->black->get_random_seed;
my $white_seed = $self->white->get_random_seed;
my $handicap = $self->handicap;
my $result = $self->{result
}->resultw;
print $handle "(;GM[1]FF[4]RU[Japanese]SZ[$size]HA[$handicap]KM[$komi]RE[$result]\n";
print $handle "PW[$white_name (random seed $white_seed)]PB[$black_name (random seed $black_seed)]\n";
for my $stone (@
{$self->handicap_stones}) {
printf $handle "AB[%s]", GTP
::standard_to_sgf
($self->size, $stone);
my $toplay = $self->handicap < 2 ?
'B' : 'W';
for my $move (@
{$self->moves}) {
my $sgfmove = GTP
::standard_to_sgf
($size, $move);
print $handle ";$toplay" . "[$sgfmove]\n";
$toplay = $toplay eq 'B' ?
'W' : 'B';
my $handicap = $self->handicap;
print "Setting boardsize and komi for black\n" if $verbose;
$self->black->boardsize($size);
$self->black->clear_board();
$self->black->komi($komi);
print "Setting boardsize and komi for white\n" if $verbose;
$self->white->boardsize($size);
$self->white->clear_board();
$self->white->komi($komi);
my ($move, $toplay, $sgfmove);
$#{$self->handicap_stones} = -1;
@
{$self->handicap_stones} = $self->white->fixed_handicap($handicap);
for my $stone (@
{$self->handicap_stones}) {
$self->black->black($stone);
while ($pass < 2 and $resign eq 0) {
$move = $self->black->genmove("black");
$self->writesgf($sgffile) if defined $sgffile;
$resign = ($move =~ /resign/i) ?
1 : 0;
print "Black resigns\n" if $verbose;
push @
{$self->moves}, $move;
print "Black plays $move\n" if $verbose;
$pass = ($move =~ /PASS/i) ?
$pass + 1 : 0;
$self->white->black($move);
my $black_seed = $self->black->get_random_seed;
printf "Black seed $black_seed\n";
$move = $self->white->genmove("white");
$self->writesgf($sgffile) if defined $sgffile;
$resign = ($move =~ /resign/i) ?
1 : 0;
print "White resigns\n" if $verbose;
push @
{$self->moves}, $move;
print "White plays $move\n" if $verbose;
$pass = ($move =~ /PASS/i) ?
$pass + 1 : 0;
$self->black->white($move);
my $white_seed = $self->white->get_random_seed;
printf "White seed $white_seed\n";
$resultb = $toplay eq 'B' ?
'B+R' : 'W+R';
$resultw = $self->white->final_score;
$resultb = $self->black->final_score;
if ($resultb eq $resultw) {
print "Result: $resultw\n";
print "Result according to W: $resultw\n";
print "****** according to B: $resultb\n";
$self->{result
} = new GTP
::Game
::Result
;
$self->{result
}->resultw($resultw);
$self->{result
}->resultb($resultb);
$self->writesgf($sgffile) if defined $sgffile;
'black' => 'GTP::Player',
'white' => 'GTP::Player',
my $game = new GTP
::Game
;
$game->size($self->size);
$game->komi($self->komi);
$game->handicap($self->handicap);
$game->black($self->black);
$game->white($self->white);
$game->komi($self->komi);
(my $sgffile_base = $sgffile) =~ s/\.sgf$//;
my $sgffile_game = sprintf "%s%03d.sgf", $sgffile_base, $i;
$game->play($sgffile_game);
my $result = new GTP
::Game
::Result
;
$result->resultb($game->{result
}->resultb);
$result->resultw($game->{result
}->resultw);
my $sgffile = "twogtp.sgf";
"verbose|v=i" => \
$verbose,
"handicap|ha=i" => \
$handicap,
"sgffile|f=s" => \
$sgffile,
"boardsize|size|s=i" => \
$size
GTP
::Game
->verbose($verbose);
twogtp --white \'<path to program 1> --mode gtp [program options]\' \\
--black \'<path to program 2> --mode gtp [program options]\' \\
--verbose 1 (to list moves) or --verbose 2 (to draw board)
--size <board size> (default 19)
--games <number of games to play> (-1 to play forever)
die $helpstring unless defined $white and defined $black;
my $black_pl = new GTP
::Player
;
$black_pl->initialize($black);
print "Created black GTP player\n" if $verbose;
my $white_pl = new GTP
::Player
;
$white_pl->initialize($white);
print "Created white GTP player\n" if $verbose;
my $match = new GTP
::Match
;
$match->white($white_pl);
$match->black($black_pl);
$match->handicap($handicap);
my @results = $match->play($games, $sgffile);
if ($r->resultb eq $r->resultw) {
printf "Game $i: %s\n", $r->resultw;
printf "Game $i: %s %s\n", $r->resultb, $r->resultw;