… | |
… | |
2 | |
2 | |
3 | #use PApp::Util qw(dumpval); # debug only |
3 | #use PApp::Util qw(dumpval); # debug only |
4 | |
4 | |
5 | use Gtk; |
5 | use Gtk; |
6 | use Gtk::Gdk; |
6 | use Gtk::Gdk; |
7 | use Gtk; |
7 | #use Gtk::Gdk::Pixbuf; |
8 | #use Gtk::Gdk::ImlibImage; |
8 | use Gtk::Gdk::ImlibImage; |
|
|
9 | |
9 | use Gnome; |
10 | use Gnome; |
10 | init Gnome "kgsueme"; |
|
|
11 | |
|
|
12 | |
11 | |
13 | use KGS::Protocol; |
12 | use KGS::Protocol; |
14 | use KGS::Listener::Debug; |
13 | use KGS::Listener::Debug; |
15 | |
14 | |
16 | use IO::Socket::INET; |
15 | use IO::Socket::INET; |
17 | |
16 | |
18 | use Errno; |
17 | use Errno; |
19 | |
18 | |
20 | init Gtk; |
19 | init Gnome "kgsueme"; |
21 | |
20 | |
22 | $HACK = 1; # do NEVER enable. ;) |
21 | $HACK = 1; # do NEVER enable. ;) |
23 | |
22 | |
24 | our $config; |
23 | our $config; |
|
|
24 | our $IMGDIR = "images"; |
|
|
25 | |
|
|
26 | sub load_img { |
|
|
27 | # new_from_file Gtk::Gdk::Pixbuf "$IMGDIR/$_[0]" |
|
|
28 | load_image Gtk::Gdk::ImlibImage "$IMGDIR/$_[0]" |
|
|
29 | or die "$IMGDIR/$_[0]: $!"; |
|
|
30 | } |
|
|
31 | |
|
|
32 | our @black_img = load_img "b01-100x102.png"; |
|
|
33 | our @white_img = map +(load_img "w0$_-100x102_retouched.png"), 1,2,3; |
|
|
34 | our $board_img = load_img "woodgrain-01.jpg"; |
25 | |
35 | |
26 | { |
36 | { |
27 | use Storable (); |
37 | use Storable (); |
28 | use Scalar::Util (); |
38 | use Scalar::Util (); |
29 | |
39 | |
… | |
… | |
34 | |
44 | |
35 | $config = $state->{config} ||= {}; |
45 | $config = $state->{config} ||= {}; |
36 | |
46 | |
37 | # grr... more gtk+ brokenness |
47 | # grr... more gtk+ brokenness |
38 | my %get = ( |
48 | my %get = ( |
39 | hpane_position => sub { ($_[0]->children)[0]->allocation->[2] }, |
|
|
40 | vpane_position => sub { ($_[0]->children)[0]->allocation->[3] }, |
|
|
41 | window_size => sub { [ @{$_[0]->allocation}[2,3] ] }, |
49 | window_size => sub { [ @{$_[0]->allocation}[2,3] ] }, |
42 | #window_pos => sub { die PApp::Util::dumpval [ $_[0]->get_root_origin ] }, |
50 | #window_pos => sub { die PApp::Util::dumpval [ $_[0]->get_root_origin ] }, |
43 | clist_column_widths => sub { |
51 | clist_column_widths => sub { |
44 | $_[0]{column_widths}; |
52 | $_[0]{column_widths}; |
45 | }, |
53 | }, |
… | |
… | |
76 | |
84 | |
77 | sub save_state { |
85 | sub save_state { |
78 | for (@widgets) { |
86 | for (@widgets) { |
79 | if ($_->[0]) { |
87 | if ($_->[0]) { |
80 | my ($widget, $class, $instance, $attr) = @$_; |
88 | my ($widget, $class, $instance, $attr) = @$_; |
|
|
89 | |
|
|
90 | $widget->realize; |
|
|
91 | |
81 | while (my ($k, $v) = each %$attr) { |
92 | while (my ($k, $v) = each %$attr) { |
82 | my ($set, $get) = $k =~ /=/ ? split /=/, $k : ($k, $k); |
93 | my ($set, $get) = $k =~ /=/ ? split /=/, $k : ($k, $k); |
83 | $v = $get{$get} ? $get{$get}->($widget) : $widget->get($get); |
94 | $v = $get{$get} ? $get{$get}->($widget) : $widget->get($get); |
84 | |
95 | |
85 | $state->{$class}{"*"}{$get} = $v; |
96 | $state->{$class}{"*"}{$get} = $v; |
… | |
… | |
147 | $self->{roomlist} = new roomlist conn => $self->{conn}; |
158 | $self->{roomlist} = new roomlist conn => $self->{conn}; |
148 | |
159 | |
149 | $self->{window} = new Gtk::Window 'toplevel'; |
160 | $self->{window} = new Gtk::Window 'toplevel'; |
150 | $self->{window}->set_title('kgsueme'); |
161 | $self->{window}->set_title('kgsueme'); |
151 | ::state $self->{window}, "main::window", undef, window_size => [400, 100]; |
162 | ::state $self->{window}, "main::window", undef, window_size => [400, 100]; |
152 | $self->{window}->signal_connect(delete_event => sub { main_quit Gtk }); |
163 | $self->{window}->signal_connect(delete_event => sub { main_quit Gtk; 1 }); |
153 | |
164 | |
154 | $self->{window}->add(my $vbox = new Gtk::VBox); |
165 | $self->{window}->add(my $vbox = new Gtk::VBox); |
155 | |
166 | |
156 | $vbox->pack_start(($buttonbox = new Gtk::HButtonBox), 0, 1, 0); |
167 | $vbox->pack_start(($buttonbox = new Gtk::HButtonBox), 0, 1, 0); |
157 | $buttonbox->set_spacing(0); |
168 | $buttonbox->set_spacing(0); |
… | |
… | |
223 | |
234 | |
224 | ::status("login", "logged in as '$self->{conn}{name}' with status '$msg->{result}'"); |
235 | ::status("login", "logged in as '$self->{conn}{name}' with status '$msg->{result}'"); |
225 | $::config->{login} = $self->{conn}{name}; |
236 | $::config->{login} = $self->{conn}{name}; |
226 | |
237 | |
227 | if ($msg->{success}) { |
238 | if ($msg->{success}) { |
228 | warn "hiya\n"; |
|
|
229 | for (keys %{$::config->{rooms}}) { |
239 | for (keys %{$::config->{rooms}}) { |
230 | warn "hiya $_\n"; |
|
|
231 | $self->{roomlist}->join_room($_); |
240 | $self->{roomlist}->join_room($_); |
232 | } |
241 | } |
233 | } |
242 | } |
234 | |
243 | |
235 | warn PApp::Util::dumpval($::config); |
244 | warn PApp::Util::dumpval($::config); |
… | |
… | |
251 | |
260 | |
252 | $self->{window} = new Gtk::Window 'toplevel'; |
261 | $self->{window} = new Gtk::Window 'toplevel'; |
253 | $self->{window}->set_title('KGS Rooms'); |
262 | $self->{window}->set_title('KGS Rooms'); |
254 | ::state $self->{window}, "roomlist::window", undef, window_size => [400, 200]; |
263 | ::state $self->{window}, "roomlist::window", undef, window_size => [400, 200]; |
255 | |
264 | |
256 | $self->{window}->signal_connect(delete_event => sub { $self->{window}->hide }); |
265 | $self->{window}->signal_connect(delete_event => sub { $self->{window}->hide; 1 }); |
257 | |
266 | |
258 | $self->{window}->add(my $vbox = new Gtk::VBox); |
267 | $self->{window}->add(my $vbox = new Gtk::VBox); |
259 | |
268 | |
260 | $vbox->pack_start((my $sw = new Gtk::ScrolledWindow), 1, 1, 0); |
269 | $vbox->pack_start((my $sw = new Gtk::ScrolledWindow), 1, 1, 0); |
261 | $sw->set_policy("automatic", "always"); |
270 | $sw->set_policy("automatic", "always"); |
… | |
… | |
327 | |
336 | |
328 | $self->{window} = new Gtk::Window 'toplevel'; |
337 | $self->{window} = new Gtk::Window 'toplevel'; |
329 | $self->{window}->set_title("KGS Room $self->{name}"); |
338 | $self->{window}->set_title("KGS Room $self->{name}"); |
330 | ::state $self->{window}, "room::window", $self->{name}, window_size => [600, 400]; |
339 | ::state $self->{window}, "room::window", $self->{name}, window_size => [600, 400]; |
331 | |
340 | |
332 | $self->{window}->signal_connect(delete_event => sub { $self->part }); |
341 | $self->{window}->signal_connect(delete_event => sub { $self->part; 1 }); |
333 | |
342 | |
334 | $self->{window}->add(my $hpane = new Gtk::HPaned); |
343 | $self->{window}->add(my $hpane = new Gtk::HPaned); |
335 | ::state $hpane, "room::hpane", $self->{name}, hpane_position => 200; |
344 | ::state $hpane, "room::hpane", $self->{name}, hpane_position => 200; |
336 | |
345 | |
337 | $hpane->add(my $vpane = new Gtk::VPaned); |
346 | $hpane->add(my $vpane = new Gtk::VPaned); |
… | |
… | |
449 | } |
458 | } |
450 | |
459 | |
451 | sub event_update_roominfo { |
460 | sub event_update_roominfo { |
452 | my ($self) = @_; |
461 | my ($self) = @_; |
453 | |
462 | |
454 | $self->{text}->insert(undef, undef, undef, "$self->{owner}: $self->{description}\n\n"); |
463 | $self->{text}->insert(undef, undef, undef, "\n$self->{owner}: $self->{description}\n"); |
455 | } |
464 | } |
456 | |
465 | |
457 | sub inject_msg_room { |
466 | sub inject_msg_room { |
458 | my ($self, $msg) = @_; |
467 | my ($self, $msg) = @_; |
459 | return unless $self->{channel} == $msg->{channel}; |
468 | return unless $self->{channel} == $msg->{channel}; |
460 | |
469 | |
461 | $self->{text}->insert(undef, undef, undef, "$msg->{name}: $msg->{message}\n"); |
470 | $self->{text}->insert(undef, undef, undef, "\n$msg->{name}: $msg->{message}"); |
462 | } |
471 | } |
463 | |
472 | |
464 | ############################################################################# |
473 | ############################################################################# |
465 | |
474 | |
466 | package game; |
475 | package game; |
|
|
476 | |
|
|
477 | use KGS::Constants; |
467 | |
478 | |
468 | use base KGS::Listener::Game; |
479 | use base KGS::Listener::Game; |
469 | use base KGS::Game; |
480 | use base KGS::Game; |
470 | |
481 | |
471 | sub new { |
482 | sub new { |
… | |
… | |
476 | |
487 | |
477 | $self->{window} = new Gtk::Window 'toplevel'; |
488 | $self->{window} = new Gtk::Window 'toplevel'; |
478 | $self->{window}->set_title("KGS Game ".$self->user0." ".$self->user1); |
489 | $self->{window}->set_title("KGS Game ".$self->user0." ".$self->user1); |
479 | ::state $self->{window}, "game::window", undef, window_size => [600, 500]; |
490 | ::state $self->{window}, "game::window", undef, window_size => [600, 500]; |
480 | |
491 | |
481 | $self->{window}->signal_connect(delete_event => sub { $self->part }); |
492 | $self->{window}->signal_connect(delete_event => sub { $self->part; 1 }); |
482 | |
493 | |
483 | $self->{window}->add(my $hpane = new Gtk::HPaned); |
494 | $self->{window}->add(my $hpane = new Gtk::HPaned); |
484 | ::state $hpane, "game::hpane", undef, hpane_position => 500; |
495 | ::state $hpane, "game::hpane", undef, hpane_position => 500; |
485 | |
496 | |
486 | $hpane->add(my $canvas = new Gnome::Canvas); |
497 | $::config{aa}++; |
487 | $self->{canvas} = $canvas; |
498 | $self->{canvas} = $::config{aa} ? new_aa Gnome::Canvas : new Gnome::Canvas; |
|
|
499 | $hpane->add($self->{canvas}); |
|
|
500 | |
|
|
501 | $self->{canvas}->signal_connect(size_allocate => sub { |
|
|
502 | warn "@_ @{$_[1]}"; |
|
|
503 | #$self->{canvas}->set_pixels_per_unit( |
|
|
504 | }); |
|
|
505 | |
|
|
506 | my $line_colour = $::config{line_colour} || "darkbrown"; |
|
|
507 | my $border = 0.1; |
|
|
508 | |
488 | # $canvas->set_pixels_per_unit(300); |
509 | $self->{canvas}->set_pixels_per_unit(300); |
489 | $canvas->set_scroll_region(0,0,400,400); |
510 | $self->{canvas}->set_scroll_region(-$border,-$border,1+$border,1+$border); |
490 | $self->{board} = [[]]; |
511 | |
491 | # $canvas->style->bg('normal', $canvas->style->white); |
|
|
492 | { |
512 | { |
493 | my $croot = $canvas->root; |
513 | my $croot = $self->{canvas}->root; |
494 | my $cgroup = $croot->new($croot, "Gnome::CanvasGroup"); |
514 | my $cgroup = $croot; #->new($croot, "Gnome::CanvasGroup"); |
495 | my $w = 400; |
515 | |
496 | my $pad = 26; |
516 | if ($::board_img) { |
|
|
517 | $cgroup->new($cgroup, "Gnome::CanvasImage", |
|
|
518 | x => -$border, y => -$border, |
|
|
519 | width => 1+$border*2, height => 1+$border*2, |
|
|
520 | image => $::board_img, |
|
|
521 | anchor => "nw" |
|
|
522 | ); |
|
|
523 | } else { |
|
|
524 | die; |
497 | my $box = $cgroup->new($cgroup,"Gnome::CanvasRect", |
525 | $cgroup->new($cgroup, "Gnome::CanvasRect", |
498 | x1 => 0, x2 => $w, |
526 | x1 => -$border, x2 => 1+$border, |
499 | y1 => 0, y2 => $w, |
527 | y1 => -$border, y2 => 1+$border, |
500 | outline_color => "green", |
|
|
501 | fill_color => "green", |
|
|
502 | width_pixels => 2, |
|
|
503 | ); |
|
|
504 | my $box2 = $cgroup->new($cgroup,"Gnome::CanvasRect", |
|
|
505 | x1 => $pad, x2 => $w - $pad, |
|
|
506 | y1 => $pad, y2 => $w - $pad, |
|
|
507 | outline_color => "brown", |
528 | outline_color => "black", |
508 | fill_color => "brown", |
529 | fill_color => "brown", |
509 | width_pixels => 2, |
530 | width_pixels => 2, |
510 | ); |
531 | ); |
511 | my @lines; |
532 | } |
|
|
533 | |
512 | my $x1 = $pad * 2; # == my $y1 = 30; |
534 | my $x1 = $pad * 2; # == my $y1 = 30; |
513 | my $x2 = $w - ($pad * 2); # == my $y2 = 270; |
535 | my $x2 = $w - ($pad * 2); # == my $y2 = 270; |
514 | my $w = $x2 - $x1; |
536 | my $w = $x2 - $x1; |
515 | my $s = $self->{size} - 1; |
537 | my $s = $self->{size} - 1; |
|
|
538 | my $ofs = 0.5 / $self->{size}; |
516 | |
539 | |
517 | for (my $i = 0; $i <= $s; $i++) { # one more iteration for the finishing lines |
540 | my $a = "A"; |
518 | push @lines, |
541 | for my $i (1 .. $self->{size}) { # one more iteration for the last lines |
|
|
542 | my $k = $i / $self->{size} - $ofs; |
|
|
543 | |
519 | $cgroup->new($cgroup,"Gnome::CanvasLine", |
544 | $cgroup->new($cgroup, "Gnome::CanvasLine", |
520 | points => [ $x1, $x1 + ($w/$s)*$i, $x1 + $w, $x1 + ($w/$s)*$i ], |
545 | points => [ $k,$ofs, $k,1-$ofs ], |
521 | fill_color => "darkbrown", |
546 | fill_color => $line_colour, |
522 | width_pixels => 1); |
547 | width_pixels => 1); |
523 | push @lines, |
548 | |
524 | $cgroup->new($cgroup,"Gnome::CanvasLine", |
549 | $cgroup->new($cgroup, "Gnome::CanvasLine", |
525 | points => [ $x1 + ($w/$s)*$i, $x1, $x1 + ($w/$s)*$i, $x1 + $w ], |
550 | points => [ $ofs,$k, 1-$ofs,$k ], |
526 | fill_color => "darkbrown", |
551 | fill_color => $line_colour, |
527 | width_pixels => 1); |
552 | width_pixels => 1); |
|
|
553 | |
|
|
554 | for ( [$k,-$border*0.5,$a], [$k,1+$border*0.5,$a], [-$border*0.5,$k,$i], [1+$border*0.5,$k,$i] ) { |
|
|
555 | my ($x, $y, $text) = @$_; |
|
|
556 | |
|
|
557 | my $text = $cgroup->new($cgroup, "Gnome::CanvasText", |
|
|
558 | x => 0, y => 0, text => $text, |
|
|
559 | justification => "center", |
|
|
560 | anchor => "center", |
|
|
561 | font => "-*-helvetica-medium-r-*--34-*", |
|
|
562 | fill_color => $line_colour); |
|
|
563 | |
|
|
564 | $text->affine_relative($border*0.015,0, 0,$border*0.015, $x,$y); |
|
|
565 | } |
|
|
566 | |
|
|
567 | $a++; |
528 | } |
568 | } |
529 | $self->{board_gfx}->{lines} = \@lines; |
569 | |
530 | my $stones = [[]]; |
570 | my $stones = [[]]; |
531 | my $wf = ($w/$s); |
571 | |
532 | for (my $x = 0; $x < $self->{size}; $x++) { |
572 | for my $x (1 .. $self->{size}) { |
533 | for (my $y = 0; $y < $self->{size}; $y++) { |
573 | my $xk = $x / $self->{size} - $ofs; |
534 | $stones->[$x]->[$y]->[0] = # black stone |
574 | for my $y (1 .. $self->{size}) { |
|
|
575 | my $yk = $y / $self->{size} - $ofs; |
|
|
576 | |
|
|
577 | my $col = $stones->[$x-1][$y-1] = []; |
|
|
578 | |
|
|
579 | if (1) { |
|
|
580 | $col->[0] = |
|
|
581 | $cgroup->new($cgroup, "Gnome::CanvasImage", |
|
|
582 | x => $xk, y => $yk, |
|
|
583 | width => $ofs*2, height => $ofs*2, |
|
|
584 | image => $::black_img[int rand @::black_img], |
|
|
585 | anchor => "center"); |
|
|
586 | $col->[1] = |
|
|
587 | $cgroup->new($cgroup, "Gnome::CanvasImage", |
|
|
588 | x => $xk, y => $yk, |
|
|
589 | width => $ofs*2, height => $ofs*2, |
|
|
590 | image => $::white_img[int rand @::white_img], |
|
|
591 | anchor => "center"); |
|
|
592 | } else { |
|
|
593 | # too large, scale has NO effect |
|
|
594 | $col->[0] = |
535 | $cgroup->new($cgroup,"Gnome::CanvasEllipse", |
595 | $cgroup->new($cgroup, "Gnome::CanvasEllipse", |
536 | x1 => $x1 + $wf*$x - ($wf/2.2), x2 => $x1 + $wf*$x + ($wf/2), |
596 | x1 => $xk, x2 => $xk + 0.001, |
537 | y1 => $x1 + $wf*$y - ($wf/2.2), y2 => $x1 + $wf*$y + ($wf/2), |
597 | y1 => $yk, y2 => $yk + 0.001, |
|
|
598 | outline_color => "black", width_pixels => 2, |
538 | fill_color => "black"); |
599 | fill_color => "black"); |
539 | $stones->[$x]->[$y]->[0]->hide; |
600 | $col->[1] = |
540 | $stones->[$x]->[$y]->[1] = # black stone |
|
|
541 | $cgroup->new($cgroup,"Gnome::CanvasEllipse", |
601 | $cgroup->new($cgroup, "Gnome::CanvasEllipse", |
542 | x1 => $x1 + $wf*$x - ($wf/2.2), x2 => $x1 + $wf*$x + ($wf/2), |
602 | x1 => $xk, x2 => $xk + 0.001, |
543 | y1 => $x1 + $wf*$y - ($wf/2.2), y2 => $x1 + $wf*$y + ($wf/2), |
603 | y1 => $yk, y2 => $yk + 0.001, |
|
|
604 | outline_color => "black", width_pixels => 2, |
544 | fill_color => "white"); |
605 | fill_color => "white"); |
545 | $stones->[$x]->[$y]->[1]->hide; |
606 | } |
|
|
607 | } |
546 | } |
608 | } |
547 | } |
609 | |
548 | $self->{board_gfx}->{stones} = $stones; |
610 | $self->{board_gfx}->{stones} = $stones; |
549 | |
611 | } |
550 | # smooth => 1, |
|
|
551 | # spline_steps => 50 |
|
|
552 | # $line->hide; |
|
|
553 | } |
|
|
554 | $canvas->show(); |
|
|
555 | |
|
|
556 | |
612 | |
557 | $hpane->add(my $vpane = new Gtk::VPaned); |
613 | $hpane->add(my $vpane = new Gtk::VPaned); |
558 | ::state $vpane, "game", $self->{name}, vpane_position => 80; |
614 | ::state $vpane, "game", $self->{name}, vpane_position => 80; |
559 | |
615 | |
560 | $vpane->add(my $sw = new Gtk::ScrolledWindow); |
616 | $vpane->add(my $sw = new Gtk::ScrolledWindow); |
… | |
… | |
620 | $self->event_update; |
676 | $self->event_update; |
621 | } |
677 | } |
622 | |
678 | |
623 | sub event_update_tree { |
679 | sub event_update_tree { |
624 | my ($self) = @_; |
680 | my ($self) = @_; |
|
|
681 | |
|
|
682 | my $board = new KGS::Game::Board $self->{size}; |
|
|
683 | $board->interpret_path ($self->get_path); |
625 | |
684 | |
626 | # if (not defined $self->{board_pm}) { |
685 | # if (not defined $self->{board_pm}) { |
627 | # $self->{board_pm} = new Gtk::Gdk::Pixmap ($self->{board}->window, 100, 100, -1); |
686 | # $self->{board_pm} = new Gtk::Gdk::Pixmap ($self->{board}->window, 100, 100, -1); |
628 | # $self->{board_pm}->draw_rectangle($self->{board}->style->white_gc, 1, 0, 0, 100, 100); |
687 | # $self->{board_pm}->draw_rectangle($self->{board}->style->white_gc, 1, 0, 0, 100, 100); |
629 | # } |
688 | # } |
… | |
… | |
633 | # |
692 | # |
634 | # my $px = $self->{board_pm}; |
693 | # my $px = $self->{board_pm}; |
635 | |
694 | |
636 | for my $x (0 .. $self->{size} - 1) { |
695 | for my $x (0 .. $self->{size} - 1) { |
637 | for my $y (0 .. $self->{size} - 1) { |
696 | for my $y (0 .. $self->{size} - 1) { |
638 | # $self->{board}[$x][$y] = 0; |
697 | my $v = $board->{board}[$x][$y]; |
|
|
698 | |
|
|
699 | $v & MARK_B |
|
|
700 | ? $self->{board_gfx}->{stones}->[$x][$y][0]->show |
639 | $self->{board_gfx}->{stones}->[$x]->[$y]->[0]->hide; |
701 | : $self->{board_gfx}->{stones}->[$x][$y][0]->hide; |
|
|
702 | $v & MARK_W |
|
|
703 | ? $self->{board_gfx}->{stones}->[$x][$y][1]->show |
640 | $self->{board_gfx}->{stones}->[$x]->[$y]->[1]->hide; |
704 | : $self->{board_gfx}->{stones}->[$x][$y][1]->hide; |
641 | } |
705 | } |
642 | } |
706 | } |
643 | |
|
|
644 | for (0..$self->{node}) { |
|
|
645 | while (my ($k, $v) = each %{$self->{tree}[$_]}) { |
|
|
646 | if ($k eq "move7") { |
|
|
647 | if ($v->[1] < 255) { |
|
|
648 | # $self->{board_gfx}->{stones}[$x][$y]->[0]->show; |
|
|
649 | ($v->[0] == 0) && |
|
|
650 | $self->{board_gfx}->{stones}->[$v->[1]]->[$v->[2]]->[0]->show; |
|
|
651 | ($v->[0] == 1) && |
|
|
652 | $self->{board_gfx}->{stones}->[$v->[1]]->[$v->[2]]->[1]->show; |
|
|
653 | # $self->{board}[$v->[1]][$v->[2]] = ($v->[0] + 1); # ("X", "O", "-") |
|
|
654 | # 0 1 2 (+1) |
|
|
655 | } |
|
|
656 | } |
|
|
657 | } |
|
|
658 | } |
|
|
659 | } |
707 | } |
660 | |
|
|
661 | package KGS::Game::Board; |
|
|
662 | package KGS::Game::Node; |
|
|
663 | package KGS::Game::Tree; |
|
|
664 | |
708 | |
665 | 1; |
709 | 1; |
666 | |
710 | |
667 | |
711 | |
668 | |
712 | |