File Coverage

blib/lib/Game/Life/NDim/Board.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Game::Life::NDim::Board;
2              
3             # Created on: 2010-01-04 18:52:38
4             # Create by: Ivan Wills
5             # $Id$
6             # $Revision$, $HeadURL$, $Date$
7             # $Revision$, $Source$, $Date$
8              
9 2     2   40479 use Moose;
  0            
  0            
10             use warnings;
11             use feature qw/:5.10/;
12             use version;
13             use Carp qw/croak cluck confess/;
14             use List::Util qw/max/;
15             use Data::Dumper qw/Dumper/;
16             use English qw/ -no_match_vars /;
17             use Game::Life::NDim::Life;
18             use Game::Life::NDim::Dim;
19             use Params::Coerce ();
20              
21             use overload '""' => \&to_string;
22              
23             our $VERSION = version->new('0.0.2');
24             our @EXPORT_OK = qw//;
25             our %EXPORT_TAGS = ();
26              
27             has items => (
28             is => 'rw',
29             isa => 'ArrayRef',
30             lazy_build => 1,
31             );
32              
33             has dims => (
34             is => 'ro',
35             isa => 'Game::Life::NDim::Dim',
36             required => 1,
37             );
38              
39             has cursor => (
40             is => 'rw',
41             isa => 'Game::Life::NDim::Dim',
42             );
43              
44             has types => (
45             is => 'rw',
46             isa => 'HashRef',
47             default => sub {{ 0 => 0.6, 1 => 0.4 }},
48             );
49              
50             has wrap => (
51             is => 'rw',
52             isa => 'Bool',
53             default => 0,
54             );
55              
56             has verbose => (
57             is => 'rw',
58             isa => 'Bool',
59             default => 0,
60             );
61              
62             around new => sub {
63             my ($new, $class, %params) = @_;
64              
65             if (ref $params{dims} eq 'ARRAY') {
66             $params{dims} = Game::Life::NDim::Dim->new($params{dims});
67             }
68              
69             my $self = $new->($class, %params);
70              
71             $self->reset;
72             $self->seed(%params) if $params{rand};
73             #$self->cursor(Game::Life::NDim::Dim->new([]));
74             for (@{ $self->dims }) {
75             push @{ $self->cursor }, 0;
76             }
77              
78             return $self;
79             };
80              
81             sub _build_items {
82             my ($self, %params) = @_;
83              
84             $self->types = $params{types} if $params{types};
85              
86             my $items = [];
87             my $lives = 0;
88              
89             my $builder;
90             $builder = sub {
91             my ($items, $dims, $pos) = @_;
92             my $count = $dims->[0];
93              
94             for my $i ( 0 .. $count - 1 ) {
95             if ( @{$dims} == 1 ) {
96             $items->[$i] = Game::Life::NDim::Life->new(
97             position => Game::Life::NDim::Dim->new([ @{ $pos }, $i ]),
98             board => $self
99             );
100             $lives++;
101             }
102             else {
103             $items->[$i] = [];
104             my $sub_dims = [ @{ $dims }[ 1 .. @{ $dims } - 1 ] ];
105             my $sub_pos = [ @{ $pos }, $i ];
106             my $sub_items = $items->[$i];
107             $builder->($sub_items, $sub_dims, $sub_pos);
108             }
109             }
110             };
111             $builder->($items, $self->dims, []);
112              
113             return $items;
114             }
115              
116             sub seed {
117             my ($self, %params) = @_;
118              
119             $self->types = $params{types} if $params{types};
120              
121             my $i = 0;
122             while ( ref (my $life = $self->next_life()) ) {
123             $life->seed($self->types);
124             }
125             $self->reset;
126              
127             return $self;
128             }
129              
130             sub reset {
131             my ($self) = @_;
132             my @cursor;
133              
134             for (@{ $self->dims }) {
135             push @cursor, 0;
136             }
137              
138             confess "Empty cursor!" if !@cursor;
139              
140             $cursor[-1] = -1;
141              
142             $self->cursor(Game::Life::NDim::Dim->new(\@cursor));
143              
144             return $self;
145             }
146              
147             sub next_life {
148             my ($self) = @_;
149             my $max_dim;
150              
151             return if !$self->cursor->increment($self->dims);
152              
153             my $life = $self->items;
154              
155             my @pos;
156             for my $i ( 0 .. @{ $self->dims } - 1 ) {
157             if ( ! exists $self->cursor->[$i] ) {
158             die "here?\n";
159             $self->cursor->[$i] = 0;
160             }
161             my $pos = $self->cursor->[$i];
162             push @pos, $pos;
163             if ( ref $life eq 'ARRAY' && @{ $life } < $pos + 1 ) {
164             $life->[$pos] =
165             $i < @{ $self->cursor } - 1 ? []
166             : Game::Life::NDim::Life->new(board => $self, position => $self->cursor);
167             }
168             $life = $life->[$pos];
169             }
170              
171             return $life;
172             }
173              
174             sub set_life {
175             my ($self, $life) = @_;
176              
177             my $curr = $self->items;
178              
179             for my $i ( @{ $self->cursor } ) {
180             if ( ref $curr->[$i] eq 'ARRAY' ) {
181             $curr = $curr->[$i];
182             }
183             else {
184             $curr->[$i] = $life;
185             }
186             }
187              
188             return $self;
189             }
190              
191             sub get_life {
192             my ($self, $position) = @_;
193              
194             my $item = $self->items;
195             my $min = $self->wrap ? -1 : 0;
196             die if !defined $min;
197              
198             for my $i (@{ $position } ) {
199             croak "Cannot get game position from $position $i >= $min " if $i < $min || !exists $item->[$i];
200             $item = $item->[$i];
201             }
202              
203             return $item;
204             }
205              
206             sub to_string {
207             my ($self) = @_;
208              
209             die "The dimension of this game is to large to sensibly convert to a string\n" if @{ $self->dims } > 3;
210              
211             my $spacer = ( 10 >= max (@{$self->dims}, scalar @{$self->dims}) ) ? ' ' : '';
212              
213             my $out = '';
214             my @outs;
215             $self->reset;
216             my $i = 0;
217             my $level = 0;
218             while ( ref ( my $life = $self->next_life() ) ) {
219             if ( @{$self->cursor} > 2 && $self->cursor->[0] != $level) {
220             $out .= "\n";
221             $level = $self->cursor->[0];
222             push @outs, $out;
223             $out = '';
224             }
225             $out .= $life;
226             $out .= $self->cursor->[-1] == $self->dims->[-1] ? "\n" : $spacer;
227             $i++;
228             }
229             $self->reset;
230              
231             if (@outs) {
232             $out .= "\n";
233             $level = $self->cursor->[0];
234             push @outs, $out;
235             $out = '';
236             my @lines;
237             for my $level (@outs) {
238             my $i = 0;
239             for my $line (split /\n/, $level) {
240             $lines[$i] ||= '';
241             $lines[$i] .= " $line";
242             $i++;
243             }
244             }
245             return join "\n", @lines, '';
246             }
247              
248             #return "Board:\n" . $out . "\nCount = $i\n";
249             return $out;
250             }
251              
252             1;
253              
254             __END__
255              
256             =head1 NAME
257              
258             Game::Life::NDim::Board - Object representing the board
259              
260             =head1 VERSION
261              
262             This documentation refers to Game::Life::NDim::Board version 0.0.2.
263              
264              
265             =head1 SYNOPSIS
266              
267             use Game::Life::NDim::Board;
268              
269             # Brief but working code example(s) here showing the most common usage(s)
270             # This section will be as far as many users bother reading, so make it as
271             # educational and exemplary as possible.
272              
273              
274             =head1 DESCRIPTION
275              
276             =head1 SUBROUTINES/METHODS
277              
278             =head2 C<seed ( )>
279              
280             =head2 C<reset ( )>
281              
282             =head2 C<next_life ( )>
283              
284             =head2 C<get_life ( )>
285              
286             =head2 C<set_life ( )>
287              
288             =head2 C<to_string ( )>
289              
290             =head2 C<_build_items ( )>
291              
292             =head1 DIAGNOSTICS
293              
294             =head1 CONFIGURATION AND ENVIRONMENT
295              
296             =head1 DEPENDENCIES
297              
298             =head1 INCOMPATIBILITIES
299              
300             =head1 BUGS AND LIMITATIONS
301              
302             There are no known bugs in this module.
303              
304             Please report problems to Ivan Wills (ivan.wills@gmail.com).
305              
306             Patches are welcome.
307              
308             =head1 AUTHOR
309              
310             Ivan Wills - (ivan.wills@gmail.com)
311              
312             =head1 LICENSE AND COPYRIGHT
313              
314             Copyright (c) 2010 Ivan Wills (14 Mullion Close, Hornsby Heights, NSW Australia 2077).
315             All rights reserved.
316              
317             This module is free software; you can redistribute it and/or modify it under
318             the same terms as Perl itself. See L<perlartistic>. This program is
319             distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
320             without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
321             PARTICULAR PURPOSE.
322              
323             =cut