use strict; use English; use Tk; require Tk::LabEntry; use Expect; $|++; my $gnugo = "/bin/gnugo"; my ( $mw, $white, $black, $canvas, @taken, ); my $boardSize = $ARGV[0]; my $squareSize = 15; my $borderSize = 17; die "How big is the board?\n" unless (($boardSize > 4) && ($boardSize < 16)); my $exp = Expect->spawn("$gnugo --boardsize $boardSize") or die "Cannot spawn $gnugo: $!\n"; my $patidx = $exp->expect(1,'-re', qr'black(1):'); $mw = MainWindow->new(-title=>"GNU Go"); $mw->optionAdd('*font'=>"Fixed 10"); $canvas =$mw->Canvas(-relief=>"raised", -width=>($boardSize-1)*$squareSize+$borderSize*2, -height=>($boardSize-1)*$squareSize+$borderSize*2, )->pack(); $mw->LabEntry(-label=>"White", -labelAnchor=>'w', -labelWidth=>4, -labelPack=>[-side=>"left"], -textvariable=>\$white)->pack(); $mw->LabEntry(-label=>"Black", -labelAnchor=>'w', -labelWidth=>4, -labelPack=>[-side=>"left"], -textvariable=>\$black)->pack(); $mw->Button(-text=>"Pass", -command=>sub{ send_and_receive("pass\n"); } )->pack(); for(0 .. $boardSize-1){ $canvas->createLine($borderSize, $borderSize+$_*$squareSize, ($boardSize-1)*$squareSize+$borderSize, $borderSize+$_*$squareSize, ); $canvas->createLine($borderSize+$_*$squareSize, $borderSize, $borderSize+$_*$squareSize, ($boardSize-1)*$squareSize+$borderSize, ); $canvas->createText($borderSize+$_*$squareSize, $borderSize-10, -text=>chr(ord('A')+$_)); $canvas->createText($borderSize-10,$borderSize+$_*$squareSize,-text=>$boardSize-$_); for my $y(0 .. $boardSize-1){ $taken[$_][$y]{state} = 0; } } $canvas->bind("all",'', [\&click, Tk::Ev('x'), Tk::Ev('y')]); MainLoop; sub click { my $x = $ARG[1]; my $y = $ARG[2]; $canvas->bind("all",''); my $gridx = sprintf("%.0f",($x-$borderSize)/$squareSize); my $gridy = sprintf("%.0f",($y-$borderSize)/$squareSize); return if $taken[$gridx][$gridy]{state}; draw_piece($gridx, $gridy, "#000000"); $gridy = $boardSize-$gridy; send_and_receive(chr(ord('A')+$gridx) . $gridy . "\n"); } sub send_and_receive { $exp->send(shift); $exp->clear_accum(); $exp->expect(undef,'-re', qr'\d+[.+XO() ]{11,33}\d+', sub { my $self = shift; my $match = $self->match; $match =~ /(\d+)(.*?)\d+/; my $x = 0; my $y = $boardSize-$1; $match = $2; foreach(split(//,$match)){ next if (/ / || /\(/ || /\)/); if ((/\./ || /\+/) && $taken[$x][$y]{state}){ $canvas->delete($taken[$x][$y]{piece}); $taken[$x][$y]{state} = 0; } if (/X/ && !$taken[$x][$y]{state}){ draw_piece($x,$y,"#000000"); } if (/O/ && !$taken[$x][$y]{state}){ draw_piece($x,$y,"#FFFFFF"); } $x++; } $self->set_accum($self->after()); exp_continue; }, '-re', qr'pieces', sub { print "Found Pieces entry\n"; my $self = shift; my $match = $self->match; if ($match =~ /White.*?(\d+)/){ $white->configure(-text=>$1); print "found $1\n"; } if ($match =~ /Black.*?(\d+)/){ $black->configure(-text=>$1); print "found $1\n"; } $self->set_accum($self->after()); exp_continue; }, '-re', qr'black\(\d+\)', sub { $canvas->bind("all",'', [\&click, Tk::Ev('x'), Tk::Ev('y')]); }, '-re', qr'Result.*', sub { my $self = shift; $mw->Label(-text=>$self->match)->pack(); } ); } sub draw_piece{ my $x = shift; my $y = shift; my $color = shift; $taken[$x][$y]{state}++; $taken[$x][$y]{piece} = $canvas->createOval($borderSize+$x*$squareSize-$squareSize/2+2, $borderSize+$y*$squareSize-$squareSize/2+2, $borderSize+$x*$squareSize+$squareSize/2-2, $borderSize+$y*$squareSize+$squareSize/2-2, -fill=>$color, ); $mw->update(); }