Created
October 14, 2012 18:02
-
-
Save zpmorgan/3889344 to your computer and use it in GitHub Desktop.
go game scorable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Basilisk::Scorable; | |
use Moose; | |
# Basilisk::Scorable, | |
# * original Basilisk had death masks & territory masks. | |
# * B::Scorable should encapsulate that, | |
# & have methods to derive score from caps, deads, & territory | |
has rulemap => ( | |
isa => 'Basilisk::Rulemap', | |
is => 'ro', #shouldn't change. | |
required => 1, | |
); | |
has state => ( | |
isa => 'Basilisk::State', | |
is => 'ro', #shouldn't change. | |
required => 1, | |
); | |
has _alive => ( | |
isa => 'HashRef[Basilisk::NodeSet]', | |
is => 'ro', | |
lazy => 1, | |
builder => '_initially_generous_with_life', | |
); | |
has _dead => ( | |
isa => 'HashRef[Basilisk::NodeSet]', | |
is => 'ro', | |
lazy => 1, | |
builder => '_empty_nodesets', | |
); | |
has _known_terr => ( | |
isa => 'HashRef[Basilisk::NodeSet]', | |
is => 'ro', | |
lazy => 1, | |
builder => '_empty_nodesets', | |
); | |
has _derived_terr => ( | |
isa => 'HashRef[Basilisk::NodeSet]', | |
is => 'ro', | |
lazy => 1, | |
builder => '_initial_derived_terr', | |
); | |
has _dame => ( | |
isa => 'Basilisk::NodeSet', | |
is => 'ro', | |
lazy => 1, | |
builder => '_initial_dame', | |
); | |
#has _seki => (); # | |
#based on state, has dame, derived, & alive. that is everything initially. | |
#this is an attribute so we can initialize these 3 categories at the same time, if needed. | |
has _initial_cats => ( | |
is => 'ro', | |
isa => 'HashRef', #dame isn't color-separated; the others are. | |
lazy => 1, | |
builder => '_build_initial_cats', | |
); | |
#crawl entire board, putting each node into one of these 3 categories. | |
sub _build_initial_cats{ | |
my $self = shift; | |
my $remaining_nodes = $self->rulemap->all_nodes_nodeset; | |
my %initial_cats = ( | |
dame => $self->rulemap->nodeset, | |
alive => { | |
w => $self->rulemap->nodeset, | |
b => $self->rulemap->nodeset, | |
}, | |
derived_terr => { | |
w => $self->rulemap->nodeset, | |
b => $self->rulemap->nodeset, | |
}, | |
); | |
my $board = $self->state->board; | |
while($remaining_nodes->count){ | |
my $node = $remaining_nodes->choose; | |
my $stone = $self->state->at_node($node); | |
if($stone){ | |
my $cond = sub{ $_ eq $stone}; | |
my $contiguous = $self->state->floodfill ($cond, $node); | |
$remaining_nodes->remove($contiguous); | |
$initial_cats{alive}{$stone}->add($contiguous); | |
} | |
else { #space. | |
my $cond = sub{ ! $_ }; | |
my $contiguous = $self->state->floodfill ($cond, $node); | |
my $adjacent = $contiguous->adjacent; | |
my @adj_colors = $self->state->colors_in_nodeset($adjacent);; | |
if(@adj_colors != 1){ | |
$initial_cats{dame}->add($contiguous); | |
} | |
else { | |
$initial_cats{derived_terr}{$adj_colors[0]}->add($contiguous); | |
} | |
$remaining_nodes->remove($contiguous); | |
} | |
} | |
return \%initial_cats; | |
} | |
sub _initial_dame{ | |
my $self = shift; | |
return $self->_initial_cats->{dame} | |
} | |
sub _initial_derived_terr { | |
my $self = shift; | |
return $self->_initial_cats->{derived_terr} | |
} | |
sub _initially_generous_with_life{ | |
my $self = shift; | |
return $self->_initial_cats->{alive} | |
} | |
sub _empty_nodesets{ | |
my $self = shift; | |
return { | |
b => $self->rulemap->nodeset, | |
w => $self->rulemap->nodeset, | |
}; | |
} | |
#transanimation -- to toggle the status of life/death, reanimate^deanimate | |
sub transanimate_node{ | |
my ($self, $node) = @_; | |
my $stone = $self->state->stone_at_node($node); | |
return unless $stone; | |
my $deanimate = $self->aliveness_at_node($node); | |
if($deanimate){ | |
#my $nodeset = $self->rulemap->floodfill(sub{0}, $node); | |
} | |
else{ | |
} | |
}; | |
sub reanimate_node{} | |
sub deanimate_node{} | |
# these 4 lines are shtoopid. | |
# a state is used, and a bunch of nodesets are derived. that is all. | |
# inc. floodfill algorithms to reanimate/deanimate certain chains / chain-groups | |
# | |
#sub territory{} | |
# sub dead_stones{} | |
#sub territory_board{} | |
#sub dead_stones_board{} | |
# | |
#->dead(color): return a nodeset of dead stones of color. | |
#->dead: return a hashref of color => nodeset pairs. | |
sub dead{ | |
my ($self,$color) = @_; | |
unless ($color){ | |
return { | |
b => $self->dead('b'), | |
w => $self->dead('w'), | |
}; | |
} | |
#have color. | |
return $self->rulemap->nodeset; | |
} | |
sub territory{ | |
my ($self,$color) = @_; | |
unless ($color){ | |
return { | |
b => $self->territory('b'), | |
w => $self->territory('w'), | |
}; | |
} | |
#have color. | |
# die %{$self->_known_terr}; | |
my $known = $self->_known_terr->{$color}; | |
die unless $known; | |
my $derived = $self->_derived_terr->{$color}; | |
die unless $derived; | |
my $ns = $self->rulemap->nodeset; | |
$ns->add($known); | |
$ns->add($derived); | |
return $ns; | |
} | |
1; | |
__END__ | |
=head1 NAME | |
Basilisk::Scorable - An abstract state of endgame score negotiation | |
=head1 SYNOPSIS | |
my $rulemap = Basilisk::Rulemap::Rect->new( h=>2, w=>5 ); | |
my $board = [ | |
[qw/0 w 0 b b/], | |
[qw/0 w w b 0/], | |
]; | |
my $state_to_score = Basilisk::State->new( | |
rulemap => $rulemap, | |
turn => 'b', | |
board => $board, | |
); | |
my $scorable = $state_to_score->scorable; | |
my %score = $scorable->score; | |
say "black: $score{b}, white: $score{w}"; | |
# black: 1, white: 2 | |
$scorable->transanimate([0,4]); | |
# equivelent: $scorable->deanimate([0,4]); | |
my %dead_stones = $scorable->dead; | |
say "black: $dead_stones{b}, white: $dead_stones{w}"; | |
# black: 3, white: 0 | |
# | |
$scorable->reanimate([0,4]); | |
# equivelent: $scorable->transanimate([0,4]); | |
# score black: 1, white: 2 | |
=head1 DESCRIPTION | |
The status of each node is one of the following categories: | |
categories: | |
=head2 Stone-occupied node categories: | |
=over 4 | |
=item alive | |
The initial state. | |
=item dead | |
A storable must be told what stones are dead. | |
=item seki? | |
not implemented. Maybe the stones are alive in seki? dunno how to mark seki. | |
=back | |
=head2 stoneless node categories: | |
=over 4 | |
=item known_territory | |
considering stones that are known to be dead, this area is known to be alive. | |
=item derived_territory | |
Surrounded by stones that may be deanimated. | |
=item dame | |
the region is bounded by stones of more than one color. | |
=item seki territory? | |
not implemented. Further research is needed. | |
=back | |
I think that this covers all categories related to score negotiation | |
for different scoring regimes. | |
=over 4 | |
=item chinese rules -- alive stones are a point each. | |
=item japanese rules -- no territory in seki. | |
=back | |
head1 TERMINOLOGY | |
=over 4 | |
=item deanimate -- To set as dead, to kill | |
=item reanimate -- To set as alive, to revive | |
=item animation -- the life/death state of a stone, chain, group, or any (in)?animate object | |
=item transanimate -- to animate xor deanimate something, to to toggle the life/death state | |
=back | |
=head1 RULES | |
Empty regions are initially either dame or derived territory. | |
marking a stone as dead has the effect of converting dame/derived to known | |
for the region bounded by stones of the opposite color. | |
reanimating dead stones returns its adjacent empty nodes to dame. | |
alive stones adjacent to known territory can not be deanimated. | |
=head1 REPRESENTATION | |
Each category has a hash attribute in the scorable object. | |
they are divided into colors, where each color of that cat has a B::NodeSet. | |
the cats are named _alive, _dead, _known_terr, _derived_terr, _dame, maybe _seki later. | |
each transanimation initiates a floodfill to discover the boundry of its the region | |
bordered by the opposite color. | |
The dame category is an exception. there is no color specified. | |
=cut |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment