File Coverage

lib/Games/PMM/Monster.pm
Criterion Covered Total %
statement 46 60 76.6
branch 7 14 50.0
condition 2 2 100.0
subroutine 14 16 87.5
pod 9 12 75.0
total 78 104 75.0


line stmt bran cond sub pod time code
1             package Games::PMM::Monster;
2              
3 3     3   36507 use strict;
  3         7  
  3         130  
4 3     3   1380 use Games::PMM::Monster::Commands;
  3         7  
  3         2218  
5              
6             my $id;
7              
8             my %charge_dirs =
9             (
10             north => [qw( y x )],
11             south => [qw( y x )],
12             east => [qw( x y )],
13             west => [qw( x y )],
14             );
15              
16             my %directions =
17             (
18             north => {
19             x => 0,
20             y => +1,
21             left => 'west',
22             right => 'east',
23             },
24             south => {
25             x => 0,
26             y => -1,
27             left => 'east',
28             right => 'west',
29             },
30             west => {
31             x => -1,
32             y => 0,
33             left => 'south',
34             right => 'north',
35             },
36             east => {
37             x => +1,
38             y => 0,
39             left => 'north',
40             right => 'south',
41             },
42             );
43              
44             my %turns =
45             (
46             north =>
47             {
48             smaller => 'left',
49             larger => 'right',
50             },
51             south =>
52             {
53             smaller => 'right',
54             larger => 'left',
55             },
56             east =>
57             {
58             smaller => 'right',
59             larger => 'left',
60             },
61             west =>
62             {
63             smaller => 'left',
64             larger => 'right',
65             },
66             );
67              
68             sub new
69             {
70 8     8 1 2321 my ($class, %args) = @_;
71 8   100     58 $args{commands} ||= [];
72              
73 8         12 my $commands = Games::PMM::Monster::Commands->new( @{ $args{commands} } );
  8         49  
74 8         70 bless
75             {
76             id => ++$id,
77             index => 0,
78             commands => $commands,
79             facing => 'north',
80             seen => [],
81             health => 3,
82             }, $class;
83             }
84              
85             sub id
86             {
87 171     171 1 1154 my $self = shift;
88 171         582 $self->{id};
89             }
90              
91             sub health
92             {
93 6     6 1 1837 my $self = shift;
94 6         31 $self->{health};
95             }
96              
97             sub damage
98             {
99 3     3 1 7 my $self = shift;
100 3         11 --$self->{health};
101             }
102              
103             sub commands
104             {
105 5     5 1 8 my $self = shift;
106 5         18 $self->{commands};
107             }
108              
109             sub facing
110             {
111 108     108 1 569 my $self = shift;
112 108 100       254 $self->{facing} = shift if @_;
113 108         305 $self->{facing};
114             }
115              
116             sub seen
117             {
118 20     20 0 26 my $self = shift;
119 20 100       46 $self->{seen} = shift if @_;
120 20         59 $self->{seen};
121             }
122              
123             sub next_command
124             {
125 4     4 1 7 my $self = shift;
126 4         10 $self->commands->next();
127             }
128              
129             sub direction
130             {
131 10     10 0 15 my ($self, $value) = @_;
132              
133 10         18 my $facing = $self->facing();
134 10         23 my $dir = $directions{ $facing };
135              
136 10         15 return { map { $_ => $dir->{$_} * $value } qw( x y ) };
  20         102  
137             }
138              
139             sub turn
140             {
141 15     15 1 38 my ($self, $turn_dir) = @_;
142              
143 15         33 my $facing = $self->facing();
144 15         656 my $new_facing = $directions{ $facing }{$turn_dir};
145 15         31 $self->facing( $new_facing );
146             }
147              
148             sub closest
149             {
150 14     14 1 20 my $self = shift;
151 14         15 my $closest;
152              
153 14         17 for my $seen (@{ $self->seen() })
  14         31  
154             {
155 15 100       37 $closest = $seen unless $closest;
156 15 50       52 $closest = $seen if $seen->{distance} < $closest->{distance};
157             }
158              
159 14         40 return $closest;
160             }
161              
162             for my $method (
163             {
164             name => 'charge',
165             forward => -1,
166             backward => 1,
167             },
168             {
169             name => 'retreat',
170             forward => 1,
171             backward => -1,
172             })
173             {
174 3     3   20 no strict 'refs';
  3         6  
  3         860  
175             *{ $method->{name} } = sub
176             {
177 0     0     my ($self, %args) = @_;
178 0           my $facing = $self->facing();
179 0           my $prefer_axis = $charge_dirs{ $facing };
180 0           my $pos = $args{current};
181            
182 0           my %delta =
183             (
184             x => 0,
185             y => 0,
186             );
187              
188 0           for my $axis (@$prefer_axis)
189             {
190             # turning
191 0 0         if ($pos->{$axis} == $args{$axis})
192             {
193 0           $self->turn( $self->get_turn_direction(
194             $axis, $facing, $pos->{$axis}, $args{$axis}
195             ));
196 0           return 'turned';
197             }
198              
199 0 0         $delta{ $axis } = $pos->{$axis} > $args{$axis} ?
200             $method->{forward} :
201             $method->{backward};
202 0           last;
203             }
204              
205 0           return \%delta;
206             };
207             }
208              
209             sub get_turn_direction
210             {
211 0     0 0   my ($self, $axis, $facing, $current, $dest) = @_;
212              
213 0 0         return $turns{ $facing }->{ $current < $dest ? 'larger' : 'smaller' };
214             }
215              
216             1;
217             __END__