File Coverage

blib/lib/Games/Mastermind.pm
Criterion Covered Total %
statement 50 50 100.0
branch 10 10 100.0
condition 3 3 100.0
subroutine 9 9 100.0
pod 4 4 100.0
total 76 76 100.0


line stmt bran cond sub pod time code
1             package Games::Mastermind;
2             {
3             $Games::Mastermind::VERSION = '0.06';
4             }
5              
6 4     4   137770 use warnings;
  4         9  
  4         168  
7 4     4   24 use strict;
  4         11  
  4         145  
8 4     4   22 use Carp;
  4         13  
  4         969  
9              
10             sub new {
11 3     3 1 2183 my $class = shift;
12 3         32 my $self = bless {
13             # blacK Blue Green Red Yellow White
14             pegs => [qw( K B G R Y W )],
15             holes => 4,
16             @_,
17             history => [],
18             }, $class;
19 3         18 $self->reset;
20              
21 3         12 return $self;
22             }
23              
24             # some quick accessors
25             for my $attr (qw( pegs holes code history )) {
26 4     4   25 no strict 'refs';
  4         8  
  4         1878  
27             *$attr = sub {
28 194 100   194   21916 if( @_ > 1 ) {
29 34         120 $_[0]->reset;
30 34         95 $_[0]->{$attr} = $_[1];
31             }
32 194         621 $_[0]->{$attr};
33             };
34             }
35              
36 5     5 1 25 sub turn { scalar @{$_[0]->history}; }
  5         12  
37              
38             sub reset {
39 38     38 1 670 my $self = shift;
40 38         87 my $pegs = $self->pegs;
41 38         79 $self->{history} = []; # don't use the accessors here
42 38         138 $self->{code} = [ map { $pegs->[ rand @$pegs ] } 1 .. $self->holes ];
  152         557  
43             }
44              
45             sub play {
46 37     37 1 1734 my $self = shift;
47 37         84 my @guess = @_;
48 37         40 my @code = @{ $self->code };
  37         64  
49              
50 37 100       291 croak "Not enough pegs in guess (@guess)"
51             if( @guess != @code );
52              
53 36         70 my $marks = [ 0, 0 ];
54              
55             # black marks
56 36         76 for my $i ( 0 .. @code - 1 ) {
57 144 100       326 if( $guess[$i] eq $code[$i] ) {
58 40         49 $marks->[0]++;
59 40         75 $guess[$i] = $code[$i] = undef;
60             }
61             }
62              
63             # white marks
64 36         185 @guess = sort grep defined, @guess;
65 36         131 @code = sort grep defined, @code;
66 36   100     194 while( @guess && @code ) {
67 110 100       195 if( $guess[0] eq $code[0] ) {
68 50         58 $marks->[1]++;
69 50         52 shift @guess;
70 50         199 shift @code;
71             }
72             else {
73 60 100       89 if ( $guess[0] lt $code[0] ) { shift @guess }
  32         116  
74 28         114 else { shift @code }
75             }
76             }
77              
78             # copy data into history
79 36         54 push @{$self->history}, [ [ @_ ], [ @$marks ] ];
  36         66  
80              
81 36         179 return $marks;
82             }
83              
84             1;
85              
86              
87              
88             =pod
89              
90             =encoding iso-8859-1
91              
92             =head1 NAME
93              
94             Games::Mastermind - A simple framework for Mastermind games
95              
96             =head1 VERSION
97              
98             version 0.06
99              
100             =head1 SYNOPSIS
101              
102             use Games::Mastermind;
103              
104             # the classic game
105             $mm = Games::Mastermind->new;
106              
107             # make a guess
108             $marks = $game->play(qw( Y C W R ));
109              
110             # results
111             print "You win!\n" if $marks->[0] == $mm->holes();
112              
113             # the game history is available at all times
114             $history = $mm->history();
115             $last_turn = $mm->history()->[-1];
116              
117             # reset the game
118             $mm->reset();
119              
120             =head1 DESCRIPTION
121              
122             Games::Mastermind is a very simple framework for running Mastermind
123             games.
124              
125             =head1 METHODS
126              
127             The Games::Mastermind class provides the following methods:
128              
129             =over 4
130              
131             =item new( %args )
132              
133             Constructor. Valid parameters are C, a reference to the list
134             of available pegs and C, the number of holes in the game.
135              
136             The default game is the original Mastermind:
137              
138             pegs => [qw( B C G R Y W )]
139             holes => 4
140              
141             =item play( @guess )
142              
143             Give the answer to C<@guess> as a reference to an array of two numbers:
144             the number of black marks (right colour in the right position) and
145             the number of white marks (right colour in the wrong position).
146              
147             The winning combination is C<< [ $mm->holes(), 0 ] >>.
148              
149             =item reset()
150              
151             Start a new game: clear the history and compute a new code.
152              
153             =item turn()
154              
155             Return the move number. C<0> if the game hasn't started yet.
156              
157             =back
158              
159             =head2 Accessors
160              
161             Accessors are available for most of the game parameters:
162              
163             =over 4
164              
165             =item pegs()
166              
167             The list of pegs (as a reference to a list of strings).
168              
169             =item holes()
170              
171             The number of holes.
172              
173             =item history()
174              
175             Return a reference to the game history, as an array of C<[ guess, answer ]>
176             arrays.
177              
178             =item code()
179              
180             The hidden code, as a reference to the list of hidden pegs.
181              
182             =back
183              
184             All these getters are also setters. Note that setting any of these
185             parameters will automatically C the game.
186              
187             =head1 GAME API
188              
189             This section describes how to interface the game with a player.
190              
191             Once the game is created, for each turn, it is given a guess
192             and returns the outcome of this turn.
193              
194             This example script show a very dumb player program:
195              
196             use Games::Mastermind;
197              
198             my $game = Games::Mastermind->new(); # standard game
199             my $holes = $game->holes();
200             my @pegs = @{ $game->pegs() };
201              
202             # simply play at random
203             my $result = [ 0, 0 ];
204             while ( $result->[0] != $holes ) {
205             $result =
206             $game->play( my @guess = map { $pegs[ rand @pegs ] } 1 .. $holes );
207             print "@guess | @$result\n";
208             }
209              
210             The flow of control is in the hand of the player program or object,
211             which asks the game if the guess was good. The count of turns must
212             be handled by the controlling program.
213              
214             =head1 BUGS
215              
216             Please report any bugs or feature requests to
217             C, or through the web interface at
218             L.
219             I will be notified, and then you'll automatically be notified of progress on
220             your bug as I make changes.
221              
222             =head1 ACKNOWLEDGEMENTS
223              
224             Sébastien Aperghis-Tramoni opened his old Super Mastermind game to
225             check out what the black markers meant.
226              
227             =head1 BUGS
228              
229             Please report any bugs or feature requests on the bugtracker website
230             http://rt.cpan.org/NoAuth/Bugs.html?Dist=Games-Mastermind or by email to
231             bug-games-mastermind@rt.cpan.org.
232              
233             When submitting a bug or request, please include a test-file or a
234             patch to an existing test-file that illustrates the bug or desired
235             feature.
236              
237             =head1 AUTHOR
238              
239             Philippe Bruhat (BooK)
240              
241             =head1 COPYRIGHT
242              
243             Copyright 2005-2013 Philippe Bruhat (BooK), All Rights Reserved.
244              
245             =head1 LICENSE
246              
247             This program is free software; you can redistribute it and/or modify it
248             under the same terms as Perl itself.
249              
250             =cut
251              
252              
253             __END__