ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/kgsueme/bin/igsueme
Revision: 1.3
Committed: Tue Jun 21 10:36:47 2005 UTC (18 years, 11 months ago) by root
Branch: MAIN
Changes since 1.2: +4 -4 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 elmex 1.1 #!/opt/bin/perl
2     package util;
3    
4     sub format_time($) {
5     my ($time) = @_;
6    
7     $time > 60*60
8     ? sprintf "%d:%02d:%02d", $time / (60 * 60), $time / 60 % 60, $time % 60
9     : sprintf "%d:%02d", $time / 60 % 60, $time % 60;
10     }
11    
12    
13     package goclock;
14    
15     use Time::HiRes ();
16    
17     use Gtk2;
18     use Glib::Object::Subclass Gtk2::Label;
19    
20     sub INIT_INSTANCE {
21     my $self = shift;
22    
23     $self->signal_connect (destroy => sub { $_[0]->stop });
24    
25     $self->{format} = sub {
26 elmex 1.2
27     if ($_[0] < 0 || $self->{interval} < 0 || $self->{moves} < 0) {
28 elmex 1.1 util::format_time $_[0];
29 elmex 1.2
30 elmex 1.1 } else {
31 elmex 1.2 my $time = int $_[0];
32    
33     if ($self->{interval} != 0) {
34     $time = int (($_[0] - 1) % $self->{interval} + 1);
35     }
36 elmex 1.1
37 elmex 1.2 sprintf "%s/%d = %d [s/mv]",
38 elmex 1.1 util::format_time $time,
39     $self->{moves},
40 elmex 1.2 $self->{moves} >= 1 ? $time / $self->{moves} : $self->{interval};
41 elmex 1.1 }
42     }
43    
44     }
45    
46     sub FINALIZE_INSTANCE {
47     my $self = shift;
48    
49     $self->stop;
50     }
51    
52     sub refresh {
53     my ($self) = @_;
54    
55     my $timer = $self->{time};
56     print "TIM: $self->{time} $self->{moves} $self->{interval}\n";
57    
58     $self->set_text ($self->{format}->($timer));
59     }
60    
61     sub set_time {
62     my ($self, $start, $time, $moves, $interval) = @_;
63    
64     $self->{interval} = $interval;
65     $self->{time} = $time;
66     $self->{moves} = $moves;
67    
68     $self->refresh;
69     if ($start) {
70     $self->start;
71     } else {
72     $self->stop;
73     }
74     }
75    
76     sub start {
77     my ($self, $interval) = @_;
78    
79     $self->stop;
80    
81     my $timeout; $timeout = sub {
82     $self->{timeout} = add Glib::Timeout 1000, $timeout;
83     $self->{time}--;
84     $self->refresh;
85     0;
86     };
87    
88     $self->{time}++;
89     $timeout->();
90     }
91    
92     sub stop {
93     my ($self) = @_;
94    
95     remove Glib::Source delete $self->{timeout} if $self->{timeout};
96     }
97    
98    
99     package main;
100 root 1.3
101 elmex 1.1 use Glib;
102     use Gtk2 -init;
103     use Gtk2::Helper;
104     use Gtk2::SimpleList;
105     use Gtk2::GoBoard;
106     use Games::Go::SimpleBoard;
107     use IO::Socket::INET;
108 root 1.3 use Net::IGS;
109 elmex 1.1 use strict;
110 root 1.3
111 elmex 1.1 require Data::Dumper;
112    
113     my %games;
114    
115     my @timers;
116    
117     my %alphmap = (
118     A => 1,
119     B => 2,
120     C => 3,
121     D => 4,
122     E => 5,
123     F => 6,
124     G => 7,
125     H => 8,
126     J => 9,
127     K => 10,
128     L => 11,
129     M => 12,
130     N => 13,
131     O => 14,
132     P => 15,
133     Q => 16,
134     R => 17,
135     S => 18,
136     T => 19,
137     U => 20,
138     V => 21,
139     W => 22,
140     );
141    
142     sub dump($) {
143     print Data::Dumper::Dumper ([$_[0]]);
144     }
145    
146     sub con {
147     my ($host, $port) = @_;
148    
149     my $socket = new IO::Socket::INET PeerAddr => $host, PeerPort => $port
150     or die "cannot connect to $host:$port: $!";
151    
152     $socket->autoflush (1);
153     return $socket;
154     }
155    
156     sub spawn_game_view {
157     my ($igs, $gamenr) = @_;
158    
159     my $game = $games{$gamenr};
160     my $size = $game->{size};
161    
162     return if not defined $game;
163    
164     my $w = Gtk2::Window->new;
165     $w->set_default_size (600, 700);
166    
167     $w->add (my $v = new Gtk2::VBox);
168     $v->pack_start ((new Gtk2::Label
169     "Game $gamenr: White: $game->{white} [$game->{white_rank}] vs. Black: $game->{black} [$game->{black_rank}]"), 0, 1, 0);
170     $v->pack_start ((new Gtk2::Label
171     "Size: $game->{size} Handicap: $game->{handicap}"), 0, 1, 0);
172     $v->pack_start ((my $clock1 = new goclock), 0, 1, 0);
173     $v->pack_start ((my $clock2 = new goclock), 0, 1, 0);
174     $v->pack_start ((my $msg = new Gtk2::Label), 0, 1, 0);
175     $v->pack_start ((my $mv_lbl = new Gtk2::Label), 0, 1, 0);
176    
177     $v->pack_start ((my $board = new Gtk2::GoBoard size => $size), 1, 1, 0);
178    
179    
180     $msg->set_text ($game->{title});
181    
182     my $p3 = $igs->set_ev_cb ('game_title' => sub {
183     my ($s, $gnr, $t) = @_;
184     $gnr == $gamenr or return;
185     $msg->set_text ($t);
186     $game->{title} = $t;
187     });
188    
189     my $pos = $igs->set_ev_cb ('game_over' => sub {
190     my ($self, $gnr, $result) = @_;
191     $gnr == $gamenr or return;
192     $clock1->stop;
193     $clock2->stop;
194     $msg->set_text ($game->{title} . ": Game Over: $result");
195     });
196    
197     my $pos2 = $igs->set_ev_cb ('game_move' => sub {
198     my $self = shift;
199     my $gnr = shift;
200    
201     $gnr == $gamenr or return;
202    
203     my $move = shift;
204    
205     my $mnr = $move->{number};
206     $move->{coords} =~ m/^(.)(\d+)/;
207     my $x = $alphmap{$1} - 1;
208     my $y = $size - $2;
209    
210     my $white_mv = $move->{color} eq 'white';
211    
212     $game->{moves}->[$mnr] = $move;
213     my $mv = $game->{moves_struct}->[$mnr]
214     = [ $x, $y, ~MARK_CIRCLE, MARK_CIRCLE | MARK_MOVE | ($white_mv ? MARK_W : MARK_B), '' ];
215    
216     print "MOVE $gamenr | $mnr | $gnr : $x, $y $move->{color} = $move->{white_time} <=> $move->{black_time} | $move->{white_stones} <-> $move->{black_stones} | $game->{byo}\n";
217    
218     $mv_lbl->set_text ("Move " . ($mnr + 1));
219     $clock1->set_time ((not $white_mv), $move->{white_time}, $move->{white_stones}, $game->{byo} * 60);
220     $clock2->set_time ($white_mv, $move->{black_time}, $move->{black_stones}, $game->{byo} * 60);
221     if ($move->{white_time} == 0 && $move->{white_stones} == -1 && $move->{black_time} == 0 && $move->{black_stones} == -1) {
222     $clock1->stop ();
223     $clock2->stop ();
224     }
225    
226     my $board_state = new Games::Go::SimpleBoard $size;
227     $board_state->update ($game->{moves_struct});
228     $board->set_board ($board_state);
229     });
230    
231     $w->signal_connect (destroy => sub {
232     $igs->unset_ev_cb ('game_over', $pos);
233     $igs->unset_ev_cb ('game_move', $pos2);
234     $igs->unset_ev_cb ('game_title', $p3);
235     $igs->feed_event ('req_unobserve', $gamenr);
236     });
237    
238     $w->show_all;
239     }
240    
241     sub build_ui {
242     my $igs = shift;
243    
244     my $win = Gtk2::Window->new;
245     $win->set_default_size (600, 800);
246    
247     my $slist = Gtk2::SimpleList->new (
248     'N' => 'int', # game number
249     'White' => 'text',
250     'W Rank' => 'text',
251     'Black' => 'text',
252     'B Rank' => 'text',
253     'Move' => 'int',
254     'Size' => 'int',
255     'Hand' => 'int',
256     'Komi' => 'double',
257     'Byo' => 'int',
258     'F' => 'text',
259     'R' => 'text',
260     );
261    
262     my $plist = Gtk2::SimpleList->new (
263     'Name' => 'text',
264     'Rank' => 'text',
265     'Obs' => 'int',
266     'Pla' => 'int',
267     'Idle' => 'text',
268     'Flags' => 'text',
269     );
270    
271     $win->add (my $p = Gtk2::VPaned->new);
272     $p->add1 (my $sw = Gtk2::ScrolledWindow->new);
273     $sw->add ($slist);
274     $p->add2 (my $hp = Gtk2::HPaned->new);
275     $hp->add1 (my $sw = Gtk2::ScrolledWindow->new);
276     $sw->add_with_viewport (my $v = Gtk2::VBox->new);
277     $v->pack_start (my $txt = Gtk2::TextView->new, 1, 1, 0);
278     $v->pack_start (my $b1 = Gtk2::Button->new ('sort'), 0, 1, 0);
279     $hp->add2 (my $sw = Gtk2::ScrolledWindow->new);
280     $sw->add ($plist);
281    
282     $b1->signal_connect (clicked => sub {
283     @{$slist->{data}} =
284     map { my %g = %{$games{$_}}; print "$g{number}\n"; [ @g{qw/number white white_rank black black_rank move size handicap komi byo Fflag Rflag/} ] }
285     sort { $a <=> $b } keys %games;
286     });
287     $slist->signal_connect (row_activated => sub {
288     my ($sl, $path, $column) = @_;
289     my $row_ref = $sl->get_row_data_from_path ($path);
290    
291     spawn_game_view ($igs, $row_ref->[0]);
292    
293     $igs->feed_event ("req_observe", $row_ref->[0]);
294     $igs->feed_event ("req_moves", $row_ref->[0]);
295     });
296    
297     $p->set_position (400);
298     $hp->set_position (300);
299    
300     $igs->set_ev_cb ('game_list' => sub {
301     my %game = %{$_[1]};
302     $games{$game{number}} = { %game };
303     push @{$slist->{data}}, [ @game{qw/number white white_rank black black_rank move size handicap komi byo Fflag Rflag/} ];
304     });
305    
306     $igs->set_ev_cb ('player_list' => sub {
307     my %player = %{$_[1]};
308     push @{$plist->{data}}, [ @player{qw/name rank obs playing idle flags/} ];
309     # @{$plist->{data}} = sort { $a->[0] cmp $b->[0] } @{$plist->{data}};
310     });
311    
312     $win->show_all ();
313     }
314    
315     #################################################################################
316     #################################################################################
317     #################################################################################
318    
319 root 1.3 my $igs = new Net::IGS;
320 elmex 1.1
321     $igs->init ("elmex", "lolfe123");
322    
323     my $sck = con ("igs.joyjoy.net", 6969);
324    
325     $igs->set_writer (sub { $sck->syswrite ($_[0]) });
326    
327     $igs->set_ev_cb ('recv_file' => sub {
328     print "FILE [ $_[1] ]\n";
329     });
330    
331     $igs->sendline ('games');
332     $igs->sendline ('players');
333     my $buffer;
334    
335     my $pos = $igs->set_ev_cb ('game_over' => sub {
336     my ($self, $gnr, $result) = @_;
337     delete $games{$gnr};
338     });
339    
340     Gtk2::Helper->add_watch (fileno($sck), 'in', sub {
341     my $data;
342    
343     my $r = $sck->sysread ($data, 4096);
344    
345     if (not $r) {
346     # check $r == 0 or undef # FIXME
347     die "eof from server";
348     }
349    
350     $buffer .= $data;
351     $igs->feed_data (\$buffer);
352    
353     1;
354     });
355    
356     build_ui ($igs);
357    
358     Gtk2->main;