File Coverage

blib/lib/Games/Worms/Base.pm
Criterion Covered Total %
statement 6 104 5.7
branch 0 42 0.0
condition 0 9 0.0
subroutine 2 17 11.7
pod 0 15 0.0
total 8 187 4.2


line stmt bran cond sub pod time code
1             package Games::Worms::Base;
2             # base class for worms
3 1     1   6810 use strict;
  1         2  
  1         50  
4              
5             =head1 NAME
6              
7             Games::Worms::Base -- base class for worms
8              
9             =head1 SYNOPSIS
10              
11             package Spunky;
12             use Games::Worms::Random;
13             @ISA = ('Games::Worms::Random');
14             ...stuff...
15              
16             =head1 DESCRIPTION
17              
18             This is the base class for all worms in Worms.
19              
20             =cut
21              
22 1     1   5 use vars qw($Debug $VERSION @Colors $Color_counter $Directions);
  1         2  
  1         1385  
23             $Debug = 0;
24             $VERSION = "0.60";
25             $Directions = 6; # number of directions in this universe
26              
27             my $uid = 0;
28              
29             $Color_counter = 0;
30             @Colors = qw(red green blue yellow white orange);
31              
32             #--------------------------------------------------------------------------
33              
34             sub default_color {
35 0     0 0   my $color = $Color_counter++;
36 0 0         $Color_counter = 0 if $Color_counter > $#Colors;
37 0           return $Colors[$color];
38             }
39              
40             #--------------------------------------------------------------------------
41              
42             sub init {
43 0     0 0   return;
44             }
45              
46             #--------------------------------------------------------------------------
47              
48             sub initial_move {
49 0     0 0   return int(rand($Directions));
50             }
51              
52 0     0 0   sub can_zombie { 0 }
53             # override with sub can_zombie { 1 } in a class that can be zombies
54              
55             #--------------------------------------------------------------------------
56              
57             sub try_move {
58 0     0 0   my $worm = $_[0];
59 0 0         return unless $worm->is_alive;
60 0 0         if($Debug > 2) {
61 0           sleep 1;
62             }
63              
64 0           my $current_node = $worm->{'current_node'};
65              
66 0           my(%dir_2_uneaten_seg);
67             my $i;
68 0           foreach my $seg ($current_node->segments_away) {
69 0           $dir_2_uneaten_seg{$i++} = $seg;
70             }
71             # was: @dir_2_uneaten_seg{0,1,2,3,4,5} = $current_node->segments_away;
72              
73 0           my $origin_direction = 0;
74              
75 0           foreach my $d (sort keys %dir_2_uneaten_seg) {
76             # Is this the direction I got here by?
77 0 0         if($dir_2_uneaten_seg{$d} eq $worm->{'last_segment_eaten'}) {
78 0           $origin_direction = $d;
79             }
80              
81 0 0         if($dir_2_uneaten_seg{$d}->is_eaten) {
82             # print " Direction $d is no good ($dir_2_uneaten_seg{$d} is eaten)\n" if $Debug;
83 0           delete $dir_2_uneaten_seg{$d};
84             } else {
85             # print " Direction $d is okay\n" if $Debug;
86             }
87             }
88              
89 0 0         unless(keys(%dir_2_uneaten_seg)) {
90 0 0         print
91             " worm $worm->{'name'} is stuck, from direction $origin_direction\n"
92             if $Debug;
93 0           $worm->die;
94 0           return 0;
95             }
96              
97 0           my %rel_dir_2_uneaten_seg;
98 0           my @rel_directions = (0) x $Directions;
99 0           @rel_dir_2_uneaten_seg{ map {($_ - $origin_direction) % $Directions}
  0            
100             keys(%dir_2_uneaten_seg)
101             }
102             = values(%dir_2_uneaten_seg);
103 0           foreach my $rd (keys(%rel_dir_2_uneaten_seg)) {
104 0           $rel_directions[$rd] = 1;
105             } # a 1 in this list means a FREE (uneaten) node
106              
107 0 0         if($Debug > 1) {
108 0           my $adirs = join '', keys %dir_2_uneaten_seg;
109 0           my $rdirs = join '', keys %rel_dir_2_uneaten_seg;
110 0 0         print " worm $worm->{'name'} can go ",
111             scalar(keys(%dir_2_uneaten_seg)),
112             " ways (R$rdirs A$adirs), from dir $origin_direction\n"
113             if $Debug > 1;
114             }
115              
116 0           my $context = join('', @rel_directions);
117              
118 0           my $rel_dir_to_move;
119 0 0 0       if($worm->{'memoize'} && defined($worm->{'memory'}{$context})) {
120 0           $rel_dir_to_move = $worm->{'memory'}{$context};
121             } else {
122 0 0         if(keys(%dir_2_uneaten_seg) == $Directions) { # new worm
    0          
123 0           $rel_dir_to_move =
124             $worm->initial_move(\%rel_dir_2_uneaten_seg, \@rel_directions, $context);
125             } elsif(keys(%dir_2_uneaten_seg) == 1) {
126 0           $rel_dir_to_move = (keys(%rel_dir_2_uneaten_seg))[0];
127             } else {
128 0           $rel_dir_to_move =
129             $worm->which_way(\%rel_dir_2_uneaten_seg, \@rel_directions, $context);
130             }
131 0 0         $worm->{'memory'}{$context} = $rel_dir_to_move if $worm->{'memoize'};
132             }
133              
134             # now unrelativize
135 0           my $dir_to_move = ($rel_dir_to_move + $origin_direction) % $Directions;
136 0 0         print
137             " worm $worm->{'name'} goes in R$rel_dir_to_move (D$dir_to_move)\n"
138             if $Debug > 1;
139              
140 0           my $segment_to_eat = $dir_2_uneaten_seg{$dir_to_move};
141 0           my $destination_node = $current_node->toward('node', $dir_to_move);
142            
143 0           $worm->eat_segment($segment_to_eat);
144              
145 0           $current_node = $worm->{'current_node'} = $destination_node;
146              
147 0           return 1;
148             }
149              
150             #--------------------------------------------------------------------------
151             #
152             # You probably don't want to mess with the methods below here.
153             #
154              
155             sub is_undead { # read-only method
156 0     0 0   my $it = $_[0];
157 0           return $it->{'is_undead'};
158             }
159              
160             sub be_undead { # set the undead attrib to 1
161 0     0 0   my $it = $_[0];
162 0           $it->{'last_segment_eaten'} = 0;
163 0           $it->{'is_undead'} = 1;
164             }
165              
166             sub be_not_undead { # set the undead attrib to 0
167 0     0 0   my $it = $_[0];
168 0           $it->{'last_segment_eaten'} = 0;
169 0           $it->{'is_undead'} = 0;
170             }
171              
172             #--------------------------------------------------------------------------
173              
174             sub new {
175 0     0 0   my $c = shift;
176 0   0       $c = ref($c) || $c;
177 0           my $it = bless { @_ }, $c;
178              
179 0           $it->{'uid'} = $uid++; # per-session unique, if we need it
180 0 0         $it->{'is_alive'} = 1 unless defined $it->{'is_alive'};
181 0   0       $it->{'color'} ||= $it->default_color;
182 0           $it->{'segments_eaten'} = 0;
183 0           $it->{'last_segment_eaten'} = 0;
184 0           $it->{'memoize'} = $it->am_memoized;
185 0           $it->{'can_zombie'} = $it->can_zombie;
186 0 0         $it->{'is_undead'} = 1 unless defined $it->{'is_undead'};
187 0           $it->{'memory'} = {};
188              
189 0           $it->init;
190              
191 0 0         push @{$it->{'board'}{'worms'}}, $it if $it->{'board'};
  0            
192             # if I have a board set, put me in that board's worms list.
193 0 0         print "New worm $it ($it->{'name'})\n" if $Debug;
194              
195 0           return $it;
196             }
197              
198 0     0 0   sub am_memoized { 1; }
199             # to block memoization, override with: sub am_memoized { 0; }
200              
201             sub segments_eaten {
202 0     0 0   my $it = $_[0];
203 0           return $it->{'segments_eaten'};
204             }
205              
206             sub is_alive { # regardless of whether undead or not
207 0     0 0   my $it = $_[0];
208 0           return $it->{'is_alive'};
209             }
210              
211             #sub current_node {
212             # my $it = $_[0];
213             # return $it->{'current_node'};
214             #}
215              
216             sub die { # kill this worm.
217 0     0 0   my $worm = $_[0];
218 0 0         print " worm $worm dies\n" if $Debug;
219 0           $worm->{'is_alive'} = 0;
220 0           $worm->{'is_undead'} = 0;
221             }
222              
223             sub really_die { # kill this worm DEAD.
224 0     0 0   my $worm = $_[0];
225 0 0         print " worm $worm really dies\n" if $Debug;
226 0           $worm->{'is_alive'} = 0;
227 0           $worm->{'is_undead'} = 0;
228             }
229              
230              
231             sub eat_segment {
232 0     0 0   my($worm, $segment) = @_[0,1];
233 0           $worm->{'segments_eaten'}++;
234 0           $worm->{'last_segment_eaten'} = $segment;
235              
236 0 0         if($worm->{'is_undead'}) {
237 0           $segment->{'color'} = $worm->{'color'};
238 0           $segment->be_eaten;
239 0           $segment->draw;
240             } else {
241 0           $segment->{'color'} = $worm->{'color'};
242 0           $segment->refresh;
243             }
244              
245             # make a SEG->be_eaten_by(WORM) and SEG->be_restored_by(WORM)
246              
247             # print " worm $worm eats segment $segment\n" if $Debug;
248              
249 0           return;
250             }
251              
252             #--------------------------------------------------------------------------
253              
254             1;
255              
256             __END__