File Coverage

blib/lib/Wx/App/Mastermind/Board.pm
Criterion Covered Total %
statement 9 9 100.0
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 12 12 100.0


line stmt bran cond sub pod time code
1             package Wx::App::Mastermind::Board;
2              
3 1     1   1910 use strict;
  1         1  
  1         35  
4 1     1   7 use warnings;
  1         2  
  1         33  
5 1     1   6 use base qw(Wx::Panel Class::Accessor::Fast Class::Publisher);
  1         2  
  1         843  
6              
7             use Wx qw(:sizer :textctrl);
8             use Wx::Event qw(EVT_TEXT_ENTER EVT_PAINT EVT_LEFT_UP EVT_BUTTON);
9              
10             use Wx::App::Mastermind::Board::PegStrip;
11             use Wx::App::Mastermind::Board::Editor;
12              
13             __PACKAGE__->mk_accessors( qw(position) );
14             __PACKAGE__->mk_ro_accessors( qw(player editor button_go) );
15              
16             use constant
17             { PEG_WIDTH => 20,
18             PEG_HEIGHT => 20,
19             PEG_PADDING => 5,
20             };
21              
22             sub reset {
23             my( $self ) = @_;
24              
25             $self->{moves} = [];
26             $self->{answers} = [];
27             $self->{position} = 0;
28             $self->show_code( 0 );
29             $self->Refresh;
30             }
31              
32             sub new {
33             my( $class, $parent, $player ) = @_;
34             my $self = $class->SUPER::new( $parent );
35              
36             $self->{player} = $player;
37              
38             $player->board( $self );
39              
40             if( $self->player->moves_editable ) {
41             my $editor_top = ( PEG_HEIGHT + PEG_PADDING ) * ( $self->tries + 1 )
42             + 3 * PEG_PADDING;
43             $self->{editor} = Wx::App::Mastermind::Board::Editor->new
44             ( { position => [ PEG_PADDING, $editor_top ],
45             board => $self,
46             } );
47              
48             my $go_top = $editor_top + PEG_HEIGHT + PEG_PADDING;
49             my $go = Wx::Button->new( $self, -1, 'Go!',
50             [ PEG_PADDING, $go_top ] );
51             $self->{button_go} = $go;
52             $self->start;
53              
54             EVT_LEFT_UP( $self, sub { $self->editor->on_click( $_[1] ) } );
55             EVT_BUTTON( $self, $self->button_go, sub { $self->editor->on_move } );
56             }
57             $self->add_subscriber( 'move', $player->listener, 'on_move' );
58             $self->add_subscriber( 'answer', $player->listener, 'on_answer' );
59              
60             EVT_PAINT( $self, \&on_paint );
61              
62             $self->SetSize( $self->get_size );
63             $self->reset;
64              
65             return $self;
66             }
67              
68             sub _create_strip {
69             my $strip = Wx::App::Mastermind::Board::PegStrip->new
70             ( { peg_width => PEG_WIDTH,
71             peg_height => PEG_HEIGHT,
72             peg_padding => PEG_PADDING,
73             } );
74              
75             return $strip;
76             }
77              
78             sub on_paint {
79             my( $self, $event ) = @_;
80             my $dc = Wx::PaintDC->new( $self );
81              
82             my( $x, $y ) = ( PEG_PADDING, PEG_PADDING );
83             my $strip = $self->_create_strip;
84             my( $sx, $sy ) = $strip->get_size( $self->holes );
85              
86             if( $self->show_code ) {
87             $strip->draw( $dc, $x, $y, $self->player->listener->game->code );
88             }
89             $y += PEG_HEIGHT + PEG_PADDING;
90              
91             foreach my $i ( 1 .. $self->tries ) {
92             my $current = $self->editor
93             && $i == $self->position + 1
94             && !$self->show_code;
95             $strip->draw( $dc, $x, $y, $self->moves( $i - 1 ), undef, $current );
96             $strip->draw( $dc, $x + $sx + 2 * PEG_PADDING,
97             $y, $self->answers( $i - 1 ) );
98              
99             $y += PEG_HEIGHT + PEG_PADDING;
100             }
101              
102             $self->editor->draw( $dc ) if $self->editor;
103             }
104              
105             sub add_move {
106             my( $self, $move ) = @_;
107              
108             $self->moves->[ $self->position ] = $move;
109             $self->Refresh;
110             $self->notify_subscribers( 'move',
111             position => $self->position,
112             move => $move,
113             );
114             }
115              
116             sub add_answer {
117             my( $self, $answer ) = @_;
118             my @ans = ( ( 'K' ) x $answer->[0],
119             ( 'W' ) x $answer->[1],
120             ( ' ' ) x ( $self->holes - $answer->[0] - $answer->[1] ) );
121              
122             $self->answers->[ $self->position ] = \@ans;
123             $self->Refresh;
124             $self->notify_subscribers( 'answer',
125             position => $self->position,
126             answer => $answer,
127             );
128             $self->position( $self->position + 1 );
129             }
130              
131             sub turn_finished {
132             my( $self ) = @_;
133              
134             $self->notify_subscribers( 'turn_finished' );
135             }
136              
137             sub start {
138             my( $self ) = @_;
139              
140             return unless $self->editor;
141              
142             $self->editor->enabled( 1 );
143             $self->button_go->Enable;
144             }
145              
146             sub stop {
147             my( $self ) = @_;
148              
149             return unless $self->editor;
150              
151             $self->editor->enabled( 0 );
152             $self->button_go->Disable;
153             }
154              
155             sub get_size {
156             my( $self ) = @_;
157             my $strip = $self->_create_strip;
158             my( $w, $h ) = $strip->get_size( $self->holes );
159             my( $ew ) = 0;
160              
161             return ( 2 * $w + 5 * PEG_PADDING,
162             ( $h + PEG_PADDING ) * ( $self->tries + 1 ) + 50 );
163             }
164              
165             sub hit_test {
166             my( $self, $mx, $my ) = @_;
167             my $strip = $self->_create_strip;
168             my( $x, $y ) = ( PEG_PADDING, 2 * PEG_PADDING + PEG_HEIGHT );
169             foreach my $i ( 1 .. $self->tries ) {
170             my $hit = $strip->hit_test( $x, $y, $self->holes, $mx, $my );
171             return [ 'move', $i - 1, $hit ] if $hit != -1;
172              
173             $y += PEG_HEIGHT + PEG_PADDING;
174             }
175              
176             if( $self->editor ) {
177             my $hit = $self->editor->hit_test( $mx, $my );
178             return [ 'editor', $hit ] if $hit != -1;
179             }
180              
181             return undef;
182             }
183              
184             sub set_peg {
185             my( $self, $x, $y, $peg ) = @_;
186             my $move = $self->{moves}[$x] ||= [ ( ' ' ) x $self->holes ];
187             $move->[$y] = $peg;
188             $self->Refresh;
189             }
190              
191             sub show_code {
192             my( $self, $show ) = @_;
193              
194             return $self->{show_code} if @_ == 1;
195             $self->{show_code} = $show;
196             $self->Refresh;
197             }
198              
199             sub _get {
200             return $_[1] if @_ == 2;
201             if( $_[2] >= @{$_[1]} ) {
202             return [ ( ' ' ) x $_[0]->holes ];
203             } else {
204             return $_[1][$_[2]];
205             }
206             }
207              
208             sub moves { my $self = shift; $self->_get( $self->{moves}, @_ ) }
209             sub answers { my $self = shift; $self->_get( $self->{answers}, @_ ) }
210             sub pegs { $_[0]->player->pegs }
211             sub holes { $_[0]->player->holes }
212             sub tries { $_[0]->player->tries }
213              
214             1;