File Coverage

blib/lib/Games/Go/GTP.pm
Criterion Covered Total %
statement 12 108 11.1
branch 0 26 0.0
condition 0 5 0.0
subroutine 4 26 15.3
pod 3 22 13.6
total 19 187 10.1


line stmt bran cond sub pod time code
1             package Games::Go::GTP;
2              
3 1     1   30912 use strict;
  1         9  
  1         41  
4 1     1   5 use warnings;
  1         1  
  1         40  
5 1     1   4 use Exporter;
  1         5  
  1         47  
6 1     1   4 use vars qw(@ISA @EXPORT $VERSION);
  1         1  
  1         1415  
7             $VERSION = 0.07;
8             @ISA = qw(Exporter);
9             @EXPORT = qw(>pcommand);
10              
11             my %known_commands = (
12             protocol_version => \&protocol_version,
13             name => \&name,
14             version => \&version,
15             known_command => \&known_command,
16             list_commands => \&list_commands,
17             quit => \&quit,
18             boardsize => \&boardsize,
19             clear_board => \&clear_board,
20             komi => \&komi,
21             play => \&play,
22             genmove => \&genmove,
23             place_free_handicap => \&place_free_handicap,
24             set_free_handicap => \&set_free_handicap,
25             final_status_list => \&final_status_list,
26             undo => \&undo,
27             'kgs-genmove_cleanup' => \&kgs_genmove_cleanup,
28             'kgs-game_over' => \&kgs_game_over,
29             );
30              
31             my $PROTOCOL_VERSION_NO = 2;
32             my $ENGINE_NAME = 'my engine';
33             my $ENGINE_VERSION = '0.01';
34              
35             sub engineName {
36 0     0 1   my $ename = shift;
37 0 0         $ENGINE_NAME = $ename if defined $ename;
38 0           return $ENGINE_NAME
39             }
40              
41             sub engineVersion {
42 0     0 1   my $eversion = shift;
43 0 0         $ENGINE_VERSION = $eversion if defined $eversion;
44 0           return $ENGINE_VERSION
45             }
46              
47             sub protocolVersion {
48 0     0 1   my $pversion = shift;
49 0 0         $PROTOCOL_VERSION_NO = $pversion if defined $pversion;
50 0           return $PROTOCOL_VERSION_NO
51             }
52              
53             sub gtpcommand {
54 0     0 0   my ($command, $res, @params);
55 0           my $id = '';
56 0           my $status;
57 0 0         if ($_[0] =~ /^\d/o) {
58 0           $id = shift;
59             }
60 0           $command = shift;
61 0 0         if (exists $known_commands{$command}) {
62 0           my ($result, $output);
63 0           ($result, $output, $status) = $known_commands{$command}->(@_);
64 0   0       $output ||= '';
65 0           $res = join '', $result, $id, ' ', $output, "\n\n";
66             } else {
67 0           $res = join '', '?', $id, ' unknown command', "\n\n" ;
68             }
69 0 0         if ($command eq 'quit') {
70 0           $res = 0;
71             }
72 0           return $res, $status
73             }
74              
75             sub protocol_version {
76 0     0 0   return '=', $PROTOCOL_VERSION_NO;
77             }
78              
79             sub name {
80 0     0 0   return '=', $ENGINE_NAME;
81             }
82              
83             sub version {
84 0     0 0   return '=', $ENGINE_VERSION;
85             }
86              
87             sub known_command {
88 0     0 0   my ($command) = @_;
89 0 0         my $response = (exists $known_commands{$command}) ? 'true' : 'false';
90 0           return '=', $response;
91             }
92              
93             sub list_commands {
94 0     0 0   my $commands = join "\n", keys %known_commands;
95 0           return '=', $commands;
96             }
97              
98             sub quit {
99 0     0 0   return '=';
100             }
101              
102             sub boardsize {
103 0     0 0   my ($size, $referee, $player) = @_;
104 0           eval {$referee->size($size)};
  0            
105 0 0 0       return '?',' unacceptable size' if $@ or $size > 25;
106 0           $player->size($size);
107 0           $referee->restore(0);
108 0           $player->initboard($referee);
109 0           return '=', undef, 1 # so the caller of this module knows we're in a game
110             }
111              
112             sub clear_board {
113 0     0 0   my ($referee, $player) = @_;
114 0           $referee->restore(0);
115 0           $player->initboard($referee);
116 0           return '='
117             }
118              
119             sub komi { # need to tell Referee?
120 0     0 0   my ($komi) = @_;
121 0           return '='
122             }
123              
124             sub play {
125 0     0 0   my ($colour, $GTPpoint, $referee, $player) = @_;
126 0           $colour = convertcolour($colour);
127 0           eval {$referee->play($colour, $GTPpoint)};
  0            
128 0 0         return '?', ' illegal move' if $@;
129 0           return '='
130             }
131              
132             sub genmove {
133 0     0 0   my ($colour, $referee, $player) = @_;
134 0           $colour = convertcolour($colour);
135 0           $player->update($colour, $referee);
136 0           my $move = $player->chooselegalmove($colour, $referee);
137 0           $referee->play($colour, $move);
138 0           return '=', $move;
139             }
140              
141             sub place_free_handicap {
142 0     0 0   my ($handicap, $referee, $player) = @_;
143 0           my @moves;
144 0           for (1..$handicap) {
145 0           $player->update('B', $referee);
146 0           my $move = $player->chooselegalmove('B', $referee);
147 0           $referee->setup('AB', join ',', $move);
148 0           push @moves, $move;
149             }
150 0           return '=', join ' ', @moves
151             }
152              
153             sub set_free_handicap {
154 0     0 0   my $player = pop;
155 0           my $referee = pop;
156 0           $referee->setup('AB', join ',', @_);
157 0           return '='
158             }
159              
160             sub final_status_list {
161 0     0 0   my ($statustype, $referee, $player) = @_;
162 0           my $pref;
163 0           for ($statustype) {
164 0 0         if (lc $_ eq 'alive') {
165 0           $pref = $referee->listallalive;
166             last
167 0           }
168 0 0         if (lc $_ eq 'dead') {
169 0           $pref = $referee->listalldead;
170             last
171 0           }
172 0 0         if (lc $_ eq 'seki') {
173             last
174 0           }
175 0           return '?', ' syntax error'
176             }
177 0           return '=', join ' ', @$pref
178             }
179              
180             sub kgs_genmove_cleanup {
181 0     0 0   my ($colour, $referee, $player) = @_;
182 0           $player->{_KGScleanup} = 1;
183 0           my ($status, $res) = genmove(@_);
184 0           $player->{_KGScleanup} = 0;
185 0           return $status, $res
186             }
187              
188             sub undo {
189 0     0 0   my ($referee, $player) = @_;
190 0           eval { $referee->restore(-1) };
  0            
191 0 0         return '?', ' cannot undo' if $@;
192 0           return '='
193             }
194              
195             sub kgs_game_over {
196 0     0 0   return '=', undef, 0
197             }
198              
199             sub convertcolour {
200 0     0 0   return uc substr shift, 0, 1
201             }
202              
203             1;
204              
205             =head1 NAME
206              
207             Games::Go::GTP - Interact with a server or Go playing program using GTP
208              
209             =head1 SYNOPSIS
210              
211             use Games::Go::GTP;
212             use Games::Go::Player;
213             my $referee = new Games::Go::Referee;
214             my $player = new Games::Go::Player;
215             ...
216             my ($res, $status) = Games::Go::GTP::gtpcommand(@args, $referee, $player);
217              
218             =head1 DESCRIPTION
219              
220             I would like to make this module more abstract, but I'm not sure how.
221             For example, it assumes that Player, which is the code that generates a move (supply your own!),
222             supports the following methods:
223              
224             $player->size($somesize); # eg, $player->size(19), issued following the GTP command boardsize
225             $player->initboard($referee); # following the GTP command clear_board
226             $player->update($colour, $referee); # following GTP play
227             $player->chooselegalmove($colour, $referee); # following GTP genmove
228             $player->{_KGScleanup} = 1; # following the KGS specific kgs_genmove_cleanup
229              
230             =head2 General use
231              
232             An example of a script to run a bot on KGS is given in the example folder.
233              
234              
235             =head1 METHODS
236              
237             =head2 engineName, engineVersion, protocolVersion
238              
239             use Games::Go::GTP;
240             Games::Go::GTP::engineName('MYNAME'); # set MYNAME to anything you like
241             Games::Go::GTP::engineVersion('0.01'); # set '0.01' to anything you like
242             Games::Go::GTP::protocolVersion('2'); # leave this one alone ?
243              
244             =head1 AUTHOR (version 0.01)
245              
246             DG
247              
248             =cut