File Coverage

blib/lib/AI/Evolve/Befunge/Blueprint.pm
Criterion Covered Total %
statement 63 64 98.4
branch 22 22 100.0
condition 2 2 100.0
subroutine 14 15 93.3
pod 6 6 100.0
total 107 109 98.1


line stmt bran cond sub pod time code
1             package AI::Evolve::Befunge::Blueprint;
2 3     3   145657 use strict;
  3         7  
  3         177  
3 3     3   15 use warnings;
  3         6  
  3         85  
4 3     3   16 use Carp;
  3         6  
  3         353  
5 3     3   2899 use Language::Befunge::Vector;
  3         17767  
  3         105  
6 3     3   3324 use Perl6::Export::Attrs;
  3         35867  
  3         25  
7              
8 3     3   219 use base 'Class::Accessor::Fast';
  3         7  
  3         2503  
9             __PACKAGE__->mk_accessors(qw(code dims size id host fitness name));
10 3     3   11532 use AI::Evolve::Befunge::Util;
  3         25  
  3         47  
11              
12             # FIXME: consolidate "host" and "id" into a single string
13              
14             =head1 NAME
15              
16             AI::Evolve::Befunge::Blueprint - code storage object
17              
18             =head1 SYNOPSIS
19              
20             my $blueprint = Blueprint->new(code => $codestring, dimensions => 4);
21             my $name = $blueprint->name;
22             my $string = $blueprint->as_string;
23              
24             =head1 DESCRIPTION
25              
26             Blueprint is a container object for a befunge creature's code. It gives
27             new blueprints a unique name, so that we can keep track of them and
28             tell critters apart. One or more Critter objects may be created from
29             the Befunge source code contained within this object, so that it may
30             compete with other critters. As the critter(s) compete, the fitness
31             score of this object is modified, for use as sort criteria later on.
32              
33              
34             =head1 METHODS
35              
36             =head2 new
37              
38             my $blueprint = Blueprint->new(code => $codestring, dimensions => 4);
39              
40             Create a new Blueprint object. Two attributes are mandatory:
41              
42             code - a Befunge code string. This must be exactly the right
43             length to fill a hypercube of the given dimensions.
44             dimensions - The number of dimensions we will operate in.
45              
46             Other arguments are optional, and will be determined automatically if
47             not specified:
48              
49             fitness - assign it a fitness score, default is 0.
50             id - assign it an id, default is to call new_popid() (see below).
51             host - the hostname, default is $ENV{HOST}.
52              
53             =cut
54              
55             sub new {
56 31     31 1 31348 my $self = bless({}, shift);
57 31         130 my %args = @_;
58 31         67 my $usage = 'Usage: AI::Evolve::Befunge::Blueprint->new(code => "whatever", dimensions => 4, [, id => 2, host => "localhost", fitness => 5]);\n';
59 31 100       127 croak $usage unless exists $args{code};
60 30 100       97 croak $usage unless exists $args{dimensions};
61 29         234 $$self{code} = $args{code};
62 29         76 $$self{dims} = $args{dimensions};
63 29 100       102 if($$self{dims} > 1) {
64 13         127 $$self{size} = int((length($$self{code})+1)**(1/$$self{dims}));
65             } else {
66 16         53 $$self{size} = length($$self{code});
67             }
68 29 100       137 croak("code has a non-orthogonal size!")
69             unless ($$self{size}**$$self{dims}) == length($$self{code});
70 28         235 $$self{size} = Language::Befunge::Vector->new(map { $$self{size} } (1..$$self{dims}));
  53         356  
71 28   100     182 $$self{fitness} = $args{fitness} // 0;
72 28 100       94 $$self{id} = $args{id} if exists $args{id};
73 28 100       321 $$self{host} = $args{host} if exists $args{host};
74 28 100       135 $$self{id} = $self->new_popid() unless defined $$self{id};
75 28 100       153 $$self{host} = $ENV{HOST} unless defined $$self{host};
76 28         233 $$self{name} = "$$self{host}-$$self{id}";
77 28         130 return $self;
78             }
79              
80              
81             =head2 new_from_string
82              
83             my $blueprint = Blueprint->new_from_string($string);
84              
85             Parses a text representation of a blueprint, returns a Blueprint
86             object. The text representation was likely created by L,
87             below.
88              
89             =cut
90              
91             sub new_from_string {
92 4     4 1 2601 my ($package, $line) = @_;
93 4 100       15 return undef unless defined $line;
94 3         8 chomp $line;
95 3 100       18 if($line =~ /^\[I(-?\d+) D(\d+) F(\d+) H([^\]]+)\](.+)/) {
96 2         11 my ($id, $dimensions, $fitness, $host, $code) = ($1, $2, $3, $4, $5);
97 2         17 return AI::Evolve::Befunge::Blueprint->new(
98             id => $id,
99             dimensions => $dimensions,
100             fitness => $fitness,
101             host => $host,
102             code => $code,
103             );
104             }
105 1         4 return undef;
106             }
107              
108              
109             =head2 new_from_file
110              
111             my $blueprint = Blueprint->new_from_file($file);
112              
113             Reads a text representation (single line of text) of a blueprint from
114             a results file (or a migration file), returns a Blueprint object.
115             Calls L to do the dirty work.
116              
117             =cut
118              
119             sub new_from_file {
120 1     1 1 104 my ($package, $file) = @_;
121 1         77 return $package->new_from_string($file->getline);
122             }
123              
124              
125             =head2 as_string
126              
127             print $blueprint->as_string();
128              
129             Return a text representation of this blueprint. This is suitable for
130             sticking into a results file, or migrating to another node. See
131             L above.
132              
133             =cut
134              
135             sub as_string {
136 3     3 1 5719 my $self = shift;
137 3         14 my $rv =
138             "[I$$self{id} D$$self{dims} F$$self{fitness} H$$self{host}]";
139 3         8 $rv .= $$self{code};
140 3         5 $rv .= "\n";
141 3         19 return $rv;
142             }
143              
144              
145             =head1 STANDALONE FUNCTIONS
146              
147             These functions are exported by default.
148              
149             =cut
150              
151             {
152             my $_popid;
153              
154             =head2 new_popid
155              
156             my $id = new_popid();
157              
158             Return a unique identifier.
159              
160             =cut
161              
162             sub new_popid :Export(:DEFAULT) {
163 28 100   28 1 91 $_popid = 0 unless defined $_popid;
164 28         88 return $_popid++;
165 3     3   52426 }
  3         8  
  3         57  
166              
167              
168             =head2 set_popid
169              
170             set_popid($id);
171              
172             Initialize the iterator to the given value. This is typically done
173             when a new process reads a results file, to keep node identifiers
174             unique across runs.
175              
176             =cut
177              
178             sub set_popid :Export(:DEFAULT) {
179 0     0 1 0 $_popid = shift;
180 3     3   1831 }
  3         7  
  3         14  
181             }
182              
183             new_popid();
184              
185              
186             =head1 AUTHOR
187              
188             Mark Glines
189              
190              
191             =head1 COPYRIGHT AND LICENSE
192              
193             This software is copyright (c) 2008 Mark Glines.
194              
195             It is distributed under the terms of the Artistic License 2.0. For details,
196             see the "LICENSE" file packaged alongside this module.
197              
198             =cut
199              
200              
201             1;