File Coverage

blib/lib/Game/Life.pm
Criterion Covered Total %
statement 81 105 77.1
branch 14 20 70.0
condition 28 64 43.7
subroutine 13 20 65.0
pod 12 12 100.0
total 148 221 66.9


line stmt bran cond sub pod time code
1             #!/usr/bin/perl -w
2              
3             package Game::Life;
4              
5             #=============================================================================
6             #
7             # $Id: Life.pm,v 0.06 2013/05/16 08:55:32 ltp Exp $
8             # $Revision: 0.06 $
9             # $Author: ltp $
10             # $Date: 2013/05/16 08:55:32 $
11             # $Log: Life.pm,v $
12             #
13             # Revision 0.06 2013/05/16 08:55:32 ltp
14             #
15             # Improved test coverage.
16             #
17             # Revision 0.05 2013/05/15 21:18:29 ltp
18             #
19             # Modified constructor to allow arbitrary sized game board.
20             #
21             # Revision 0.04 2001/07/04 02:49:29 mneylon
22             #
23             # Fixed distribution problem
24             #
25             # Revision 0.03 2001/07/04 02:27:55 mneylon
26             #
27             # Updated README for distribution
28             #
29             # Revision 0.02 2001/07/04 02:23:13 mneylon
30             #
31             # Added test cases
32             # Added set_text_points, get_text_grid
33             # Added set_rules, get_breeding_rules, get_living_rules, and set default
34             # values for these as Conway's rules
35             # Modifications from code as posted on Perlmonks.org
36             #
37             #
38             #=============================================================================
39              
40 4     4   25038 use strict;
  4         9  
  4         137  
41 4     4   21 use Exporter;
  4         5  
  4         169  
42 4     4   3157 use Clone qw( clone );
  4         22648  
  4         317  
43              
44             BEGIN {
45 4     4   34 use Exporter ();
  4         5  
  4         86  
46 4     4   21 use vars qw($VERSION @ISA @EXPORT %EXPORT_TAGS);
  4         5  
  4         465  
47 4     4   47 $VERSION = sprintf( "%d.%02d", q($Revision: 0.06 $) =~ /\s(\d+)\.(\d+)/ );
48 4         93 @ISA = qw(Exporter);
49 4         10 @EXPORT = qw();
50 4         7701 %EXPORT_TAGS = ( );
51             }
52              
53              
54             my $default_size = 100;
55              
56             sub new {
57 6     6 1 2335 my $class = shift;
58 6         13 my $self = {} ;
59            
60             # No args, set up a blank one
61 6   33     41 $self->{ size } = shift || $default_size;
62 6 100       29 if ( ref( $self->{ size } ) ) {
63 3         9 ( $self->{ size_y }, $self->{ size_x } ) = @{ $self->{ size } };
  3         16  
64             }
65             else {
66             $self->{ size_y } = $self->{ size_x } = $self->{ size }
67 3         14 }
68              
69 234         2226 $self->{ grid } = [ map
70 35         69 { [ map { 0 } (1..$self->{ size_y } ) ] }
71 6         31 (1..$self->{ size_x } ) ];
72              
73 6         26 bless $self, $class;
74            
75 6         12 my ( $breedlife, $keeplife ) = @_;
76             # Default values for Conway's game
77 6   50     43 $breedlife ||= [ 3 ];
78 6   50     67 $keeplife ||= [ 2,3 ];
79              
80 6         23 $self->set_rules( $breedlife, $keeplife );
81              
82 6         22 return $self;
83             }
84              
85             sub set_rules {
86 6     6 1 17 my $self = shift;
87 6         12 my ( $breedlife, $keeplife ) = @_;
88              
89 6 50 33     81 die "Life rules must be arrayrefs if used"
      33        
      33        
90             unless ( defined ( $breedlife ) && ref( $breedlife ) eq "ARRAY" &&
91             defined ( $keeplife ) && ref( $keeplife ) eq "ARRAY" );
92            
93             # Force a duplication so we don't rely on the passed version
94 6         18 my @temp1 = @$breedlife;
95 6         15 my @temp2 = @$keeplife;
96              
97 6         37 $self->{ breed_criteria } = \@temp1;
98 6         22 $self->{ keep_criteria } = \@temp2;
99             }
100              
101             sub get_breeding_rules {
102 0     0 1 0 my $self = shift;
103 0         0 return @{ $self->{ breed_criteria } };
  0         0  
104             }
105              
106             sub get_living_rules {
107 0     0 1 0 my $self = shift;
108 0         0 return @{ $self->{ keep_criteria } };
  0         0  
109             }
110              
111             sub toggle_point {
112 0     0 1 0 my ( $self, $x, $y ) = @_;
113 0         0 return ( $self->{ grid }->[$x]->[$y] = !$self->{ grid }->[$x]->[$y] );
114             }
115              
116             sub set_point {
117 0     0 1 0 my ( $self, $x, $y ) = @_;
118 0         0 $self->{ grid }->[$x]->[$y] = 1;
119             }
120              
121             sub unset_point {
122 0     0 1 0 my ( $self, $x, $y ) = @_;
123 0         0 $self->{ grid }->[$x]->[$y] = 0;
124             }
125              
126             sub place_points {
127 0     0 1 0 my ( $self, $x, $y, $array ) = @_;
128             return if ( $x < 0 || $x >= $self->{ size_x } ||
129 0 0 0     0 $y < 0 || $y >= $self->{ size_y } );
      0        
      0        
130 0         0 my ($i, $j);
131 0         0 my $array_x = @$array;
132 0         0 my $array_y = @{$$array[0]};
  0         0  
133 0   0     0 for ( $i = 0 ; $i < $array_x && $i+$x < $self->{ size_x }; $i++ ) {
134 0   0     0 for ( $j = 0 ; $j < $array_y && $j+$y < $self->{ size_y }; $j++ ) {
135 0 0       0 $self->{ grid }->[ $x + $i ]->[ $y + $j ] =
136             ($array->[ $i ]->[ $j ] > 0) ? 1 : 0;
137             }
138             }
139 0         0 return 1;
140             }
141              
142             sub place_text_points {
143 6     6 1 119 my ( $self, $x, $y, $living, @array ) = @_;
144             return if ( $x < 0 || $x >= $self->{ size_x } ||
145 6 50 33     86 $y < 0 || $y >= $self->{ size_y } );
      33        
      33        
146 6         9 my ($i, $j);
147 6         10 my $array_x = @array;
148 6         15 my $array_y = length $array[0];
149 6   66     49 for ( $i = 0 ; $i < $array_x && $i+$x < $self->{ size_x }; $i++ ) {
150 35   66     149 for ( $j = 0 ; $j < $array_y && $j+$y < $self->{ size_y }; $j++ ) {
151 234 100       1255 $self->{ grid }->[ $x + $i ]->[ $y + $j ] =
152             (substr($array[ $i ], $j, 1 ) eq $living) ? 1 : 0;
153             }
154             }
155 6         24 return 1;
156             }
157            
158              
159             sub get_grid {
160 0     0 1 0 my ( $self ) = @_;
161 0         0 return clone( $self->{ grid } );
162             }
163              
164             sub get_text_grid {
165 8     8 1 73 my ( $self, $filled, $empty ) = @_;
166 8   50     34 $filled ||= 'X';
167 8   50     24 $empty ||= '.';
168              
169 8         18 my @array;
170 8         33 for my $i ( 0..$self->{ size_x }-1 ) {
171 45         62 my $string = '';
172 45         100 for my $j ( 0..$self->{ size_y }-1 ) {
173 309 100       650 $string .= $self->{ grid }->[ $i ]->[ $j ] ? $filled : $empty;
174             }
175 45         121 push @array, $string;
176             }
177 8         77 return @array;
178             }
179              
180             sub process {
181 8     8 1 107 my $self = shift;
182 8   50     28 my $times = shift || 1;
183            
184 8         20 for (1..$times) {
185 80         4584 my $new_grid = clone( $self->{ grid } );
186 4     4   4705 use Data::Dumper;
  4         45188  
  4         1297  
187            
188 80         279 for my $i ( 0..$self->{ size_x }-1 ) {
189 436         885 for my $j ( 0..$self->{ size_y }-1 ) {
190 3002         6222 $new_grid->[$i]->[$j] =
191             $self->_determine_life_status( $i, $j );
192             }
193             }
194 80         545 $self->{ grid } = $new_grid;
195             }
196             }
197              
198             sub _determine_life_status {
199 3002     3002   3790 my ( $self, $x , $y ) = @_;
200 3002         2939 my $n = 0;
201 3002         4861 for my $i ( $x-1, $x, $x+1 ) {
202 9006         13742 for my $j ( $y-1, $y, $y+1 ) {
203             $n++ if ( $i >= 0 && $i < $self->{ size_x } &&
204             $j >= 0 && $j < $self->{ size_y } ) &&
205 27018 100 100     305950 ( $self->{ grid }->[ $i ]->[ $j ] );
      100        
      100        
      100        
206             }
207             }
208             # here's the deterministic part; force return of 0 or 1.
209 3002 100       7258 $n-- if $self->{ grid }->[ $x ]->[ $y ];
210 3002         3129 return ( 0 != grep { $_ == $n } @{ $self->{
  3294         13860  
211 3002 100       14008 $self->{ grid }->[ $x ]->[ $y ]
212             ? 'keep_criteria' : 'breed_criteria' } } );
213             }
214              
215             42;
216              
217             __END__