Games-Go-SimpleBoard
view release on metacpan or search on metacpan
SimpleBoard.pm view on Meta::CPAN
[] # also pass (deprecated!)
It changes the board or executes a move, by first clearing the bits
specified in C<$clr>, then setting bits specified in C<$set>.
If C<$set> includes C<MARK_LABEL>, the label text must be given in
C<$label>.
If C<$set> contains C<MARK_MOVE> then surrounded stones will be removed
from the board and (simple) Kos are detected and marked with square
symbols and C<MARK_KO>, after removing other marking symbols. The
markings are also removed with the next next update structure that uses
C<MARK_MOVE>, so this flag is suited well for marking, well, moves. Note
that you can make invalid "moves" (such as suicide) and C<update> will
try to cope with it. You can use C<is_valid_move> to avoid making illegal
moves.
For handicap "moves", currently only board sizes 9, 13 and 19 are
supported and only handicap values from 2 to 9. The placement follows the
IGS rules, if you want other placements, you have to set it up yourself.
This function modifies the C<$hint> member of the specified structure
to speed up repeated board generation and updates with the same update
structures.
If the hint member is a reference the scalar pointed to by the reference
is updated instead.
If all this hint member thing is confusing, just ignore it and specify
it as C<undef> or leave it out of the array entirely. Do make sure that
you keep your update structures around as long as previous updates don't
change, however, as regenerating a full board position from hinted
update structures is I<much> faster then recreating it from fresh update
structures.
Example, make two silly moves:
$board->update ([[0, 18, -1, MARK_B | MARK_MOVE],
[0, 17, -1, MARK_W | MARK_MOVE]]);
=cut
our %HANDICAP_COORD = (
9 => [2, 4, 6],
13 => [3, 6, 9],
19 => [3, 9, 15],
);
our %HANDICAP_XY = (
2 => [qw(0,2 2,0 )],
3 => [qw(0,2 2,0 0,0 )],
4 => [qw(0,2 2,0 0,0 2,2 )],
5 => [qw(0,2 2,0 0,0 2,2 1,1)],
6 => [qw(0,2 2,0 0,0 2,2 0,1 2,1 )],
7 => [qw(0,2 2,0 0,0 2,2 0,1 2,1 1,1)],
8 => [qw(0,2 2,0 0,0 2,2 0,1 2,1 1,0 1,2 )],
9 => [qw(0,2 2,0 0,0 2,2 0,1 2,1 1,0 1,2 1,1)],
);
our $mark_symbols = MARK_CIRCLE | MARK_SQUARE | MARK_TRIANGLE | MARK_CROSS | MARK_KO;
sub update {
my ($self, $path) = @_;
my $board = $self->{board};
for (@$path) {
my ($x, $y, $clr, $set, $label) = @$_;
if (!defined $x) {
$$_ &= ~$mark_symbols for @{ delete $self->{unmark} || [] };
# pass
} elsif ($x == MOVE_HANDICAP) {
$$_ &= ~$mark_symbols for @{ delete $self->{unmark} || [] };
# $y = #handicap stones
my $c = $HANDICAP_COORD{$self->{size}}
or Carp::croak "$self->{size}: illegal board size for handicap";
my $h = $HANDICAP_XY{$y}
or Carp::croak "$y: illegal number of handicap stones";
for (@$h) {
my ($x, $y) = map $c->[$_], split /,/;
$board->[$x][$y] = MARK_B | MARK_MOVE;
}
} else {
my $space = \$board->[$x][$y];
$$space = $$space & ~$clr | $set;
$self->{label}[$x][$y] = $label if $set & MARK_LABEL;
if ($set & MARK_MOVE) {
$$_ &= ~$mark_symbols for @{ $self->{unmark} || [] };
@{ $self->{unmark} } = $space;
# remark the space, in case the move was on the same spot as the
# old mark
$$space |= $set;
unless (${ $_->[5] ||= \my $hint }) {
my ($own, $opp) =
$set & MARK_B
? (MARK_B, MARK_W)
: (MARK_W, MARK_B);
my (@capture, @suicide);
push @capture, $self->capture ($opp, $x-1, $y) if $x > 0 && $board->[$x-1][$y] & $opp;
push @capture, $self->capture ($opp, $x+1, $y) if $x < $self->{max} && $board->[$x+1][$y] & $opp;
push @capture, $self->capture ($opp, $x, $y-1) if $y > 0 && $board->[$x][$y-1] & $opp;
push @capture, $self->capture ($opp, $x, $y+1) if $y < $self->{max} && $board->[$x][$y+1] & $opp;
# keep only unique coordinates
@capture = do { my %seen; grep !$seen{"$_->[0],$_->[1]"}++, @capture };
# remove captured stones
$self->{captures}[$own == MARK_B ? COLOUR_BLACK : COLOUR_WHITE] += @capture;
$self->{board}[$_->[0]][$_->[1]] = 0
for @capture;
( run in 2.496 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )