File Coverage

blib/lib/Games/AIBot.pm
Criterion Covered Total %
statement 12 143 8.3
branch 0 84 0.0
condition 0 28 0.0
subroutine 4 23 17.3
pod 0 8 0.0
total 16 286 5.5


line stmt bran cond sub pod time code
1             # $File: //member/autrijus/AIBots/lib/Games/AIBot.pm $ $Author: autrijus $
2             # $Revision: #2 $ $Change: 692 $ $DateTime: 2002/08/17 09:29:13 $
3              
4             require 5.005;
5             package Games::AIBot;
6             $Games::AIBot::VERSION = '0.01';
7              
8 1     1   11 use strict;
  1         2  
  1         35  
9 1     1   5 use integer;
  1         2  
  1         4  
10              
11             =head1 NAME
12              
13             Games::AIBot - An AI Bot object
14              
15             =head1 VERSION
16              
17             This document describes version 0.01 of Locale::Maketext::Fuzzy.
18              
19             =head1 SYNOPSIS
20              
21             use Games::AIBot;
22             my $bot = Games::AIBot->new($botfile);
23             $bot->tick;
24              
25             =head1 DESCRIPTION
26              
27             This module exists exclusively for the purpose of the F
28             script bundled in the distribution. Please see L for
29             an explanation of the game's mechanics, rules and tips.
30              
31             =cut
32              
33 1         7 use fields qw/max_fuel max_ammo max_life
34             fuel ammo life
35             x y h score
36             enemy_x enemy_y enemy_h enemy_l
37             snode_x snode_y
38             friend_x friend_y friend_h friend_l
39             bumped_x bumped_y
40             shield cloak laymine
41             bumped found burn
42             id dead botcount
43             lastcmd state var pic
44             name author team stack
45             queue missiles cmds line
46 1     1   909 lineidx stateidx condidx/;
  1         1633  
47              
48              
49             # ===========
50             # Constructor
51             # ===========
52              
53             sub new {
54 0     0 0   my $class = shift;
55             my $bot = ($] > 5.00562) ? fields::new($class)
56 1 0   1   263 : do { no strict 'refs';
  1         2  
  1         2687  
  0            
57 0           bless [\%{$class.'::FIELDS'}], $class };
  0            
58 0           $bot->loadfile($_[0]);
59 0           push @{$bot->{'cmds'}}, 'attempt destruct';
  0            
60              
61 0           my $count;
62 0           foreach my $line (@{$bot->{'cmds'}}) {
  0            
63 0           $count++;
64 0           my $condflag = int($line !~ m/^(?:\$|if|else|elsif|unless|print)/);
65 0 0         $line =~ s/\$(\w+)/exists($bot->[0]->{$1}) ? "\${\$bot}{$1}" : "\${\$bot}{'var'}{$1}"/eg;
  0            
66 0           $line =~ s/\&(?=\w+)/\$bot->_/g;
67 0           $bot->{'lineidx'} .= $condflag; # and (index($line, '$') > -1));
68 0 0 0       $bot->{'stateidx'}{$1} = $count
69             if $line =~ /^sub[\s\t]+(.+)[\s\t]+{/ or $line =~ /^(.+):[\s\t]*{/;
70 0           $bot->{'condidx'} .= int($line ne '}') +
71             ($line =~ /^(?:if|unless|elsif|else|sub|.+:)[\s\t]/);
72             }
73              
74 0           $bot->{'queue'} = [];
75 0           $bot->{'missiles'} = [];
76 0           $bot->{'line'} = 0;
77              
78 0           return $bot;
79             }
80              
81             sub loadfile {
82 0     0 0   my ($bot, $file) = @_;
83 0           my @include;
84              
85 0 0         open _, $file or die "Cannot load bot $file: $!";
86              
87 0           while (<_>) {
88 0           chomp;
89 0           s/#[\s\t].+//;
90 0           s/^[\s\t]+//;
91 0           s/[\s\t\;]+$//;
92 0           s/^(.+)[\s\t]+(if|unless)[\s\t]+(.+)$/$2 ($3) {\n$1\n}\n/g;
93 0 0         if (/^require[\s\t]+\'?([^\']+)\'?/) {
94 0           push @include, substr($file, 0, rindex($file, '/')+1).$1;
95             }
96             else {
97 0 0         push (@{$bot->{'cmds'}}, split("\n", $_)) if $_;
  0            
98             }
99             }
100              
101 0           close _;
102              
103 0           $bot->loadfile($_) foreach @include;
104             }
105              
106             sub cond {
107 0     0 0   my $bot = $_[0];
108 0           my $cmd = eval($_[1]);
109 0 0         if ($@) { die "[Cond $_[1] :".$bot->{'name'}.':'.$bot->{'state'}.'] '.$@ };
  0            
110 0           return $cmd;
111             }
112              
113             sub tick {
114 0     0 0   my $bot = shift;
115 0           my $count;
116              
117 0           while (my $line = $bot->nextline()) {
118 0 0         next if $line eq '}';
119 0 0         if ($count++ > 100) {
120 0           warn "recursion too deep";
121 0           return;
122             }
123              
124 0 0 0       if ($line =~ /^\$[{\w]/) {
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
125 0           $bot->cond($line);
126             }
127             elsif ($line =~ /^(?:else|elsif)[\s\t]/) {
128 0           $bot->endif();
129             }
130             elsif ($line =~ /^sub[\s\t]+(.+)[\s\t]+{$/ or $line =~ /^(.+):[\s\t]*{$/) {
131 0           $bot->{'state'} = $1;
132             }
133             elsif ($line =~ /^goto[\s\t]+(.+)/) {
134 0           pop @{$bot->{'stack'}};
  0            
135 0           $bot->gotostate($1);
136             }
137             elsif ($line =~ /^call[\s\t]+(.+)/ or $line =~ /^(.+)\(\)$/) {
138 0           push @{$bot->{'stack'}}, [@{$bot}{'state', 'line'}];
  0            
  0            
139             # print "call from line ",$bot->{'line'},"\n";
140 0           $bot->gotostate($1);
141             }
142             elsif ($line eq 'redo') {
143 0           $bot->gotostate($bot->{'state'});
144             }
145             elsif ($line eq 'return') {
146 0           warn $bot->{'name'}." cannot return from state ".$bot->{'state'}
147 0 0 0       unless ($bot->{'stack'} and @{$bot->{'stack'}});
148 0           eval{@{$bot}{'state', 'line'} = @{pop(@{$bot->{'stack'}})}};
  0            
  0            
  0            
  0            
149             # print "return to line ",$bot->{'line'},"\n";
150             }
151             elsif ($line =~ /^(if|unless)[\s\t]+(.+){$/) {
152 0 0 0       if ($1 eq 'if' xor $bot->cond($2)) {
153 0           while (my $cond = $bot->elseif()) {
154 0 0         ($bot->{'line'}++, last) if ($bot->cond($cond));
155             }
156 0           $bot->{'line'}--; # end all blocks
157             }
158             }
159             elsif ($line =~ /^(e|d)(?:nable|isable)[\s\t]+(\w+)/) {
160 0 0 0       return $line if ($1 eq 'e' xor $bot->{$2});
161             }
162             elsif ($line =~ /^print[\s\t]+/) {
163 0           $bot->cond($line);
164 0           print "\n";
165             }
166             else {
167             # command
168 0 0         my $times = ((int($1) eq $1) ? $1 : $bot->cond($1))
    0          
169             if ($line =~ s/\s*\*\s*(.+)$//);
170 0           my @cmds;
171              
172 0   0       push @cmds, $line for (1..($times || 1));
173 0           return @cmds;
174             }
175             }
176             }
177              
178             sub endif {
179 0     0 0   my $bot = shift;
180 0           my $depth = 1;
181              
182 0           while ($bot->{'line'}++) {
183 0           $depth += substr($bot->{'condidx'}, $bot->{'line'} - 1, 1) - 1;
184 0 0         return unless $depth;
185             }
186              
187 0           die ("Unterminated condition block from ".$bot->{'state'});
188             }
189              
190             sub elseif {
191 0     0 0   my $bot = shift;
192 0           my $depth = 1;
193              
194 0           $bot->endif();
195 0           my $line = $bot->nextline();
196              
197 0 0         if ($line eq 'else {') {
    0          
198 0           return 1;
199             }
200             elsif ($line =~ /^(?:elsif[\s\t])(.+){/) {
201 0           return $1;
202             }
203              
204 0           return;
205             }
206              
207             sub gotostate {
208 0     0 0   my $bot = shift;
209 0           my $state = shift;
210              
211             # print "=>$state\n";
212              
213 0 0         defined($bot->{'line'} = $bot->{'stateidx'}{$state})
214             or die ($bot->{'name'}.": cannot goto state $state");
215              
216 0           $bot->{'state'} = $state;
217             }
218              
219             sub nextline {
220 0     0 0   my $bot = shift;
221 0           my $lineflag = substr($bot->{'lineidx'}, $bot->{'line'}, 1);
222 0           my $line = $bot->{'cmds'}[$bot->{'line'}++];
223 0 0         return $lineflag ? eval("\"$line\"") : $line;
224             }
225              
226              
227             # ===================
228             # Utility Subroutines
229             # ===================
230              
231             sub _nearst {
232 0     0     my ($bot, $rel) = @_;
233              
234 0 0         return 99999 unless defined $bot->{"${rel}_x"};
235 0           return abs($bot->{"${rel}_x"} - $bot->{'x'}) +
236             abs($bot->{"${rel}_y"} - $bot->{'y'});
237             }
238              
239             sub _onnode {
240 0     0     my $bot = shift;
241              
242 0           return not $bot->_nearst('snode');
243             }
244              
245             sub _inperim {
246 0     0     my ($bot, $rel) = @_;
247              
248 0   0       return ($bot->{"${rel}_x"} and $bot->{"${rel}_y"} and
249             abs($bot->{"${rel}_x"} - $bot->{'x'}) <= 1 and
250             abs($bot->{"${rel}_y"} - $bot->{'y'}) <= 1);
251             }
252              
253             sub _distance {
254 0     0     my ($bot, $x, $y) = @_;
255              
256 0           return abs($x - $bot->{'x'}) + abs($y - $bot->{'y'});
257             }
258              
259             sub _ready {
260 0     0     return Games::AIBots::bot_ready(@_);
261             }
262              
263             sub _damaged {
264 0     0     my $bot = shift;
265 0           return 100 - int($bot->{'life'} / $bot->{'max_life'} * 100);
266             }
267              
268             sub _turnto {
269 0     0     my ($bot, $head) = @_;
270 0 0 0       return if !$head or $bot->{'h'} eq $head;
271              
272 0           my $delta = (index('8624', $bot->{'h'})
273             - index('8624', $head) + 4) % 4;
274              
275 0 0         return ('left') if $delta == 1;
276 0 0         return ('left * 2') if $delta == 2;
277 0 0         return ('right') if $delta == 3;
278             }
279              
280             sub _headto {
281 0     0     my ($bot, $rel) = @_;
282              
283 0 0         return unless defined $bot->{"${rel}_x"};
284              
285 0 0         if ($bot->{"${rel}_x"} == $bot->{'x'}) {
    0          
286 0           return ('2', '8')[$bot->{"${rel}_y"} < $bot->{'y'}];
287             }
288             elsif ($bot->{"${rel}_y"} == $bot->{'y'}) {
289 0           return ('6', '4')[$bot->{"${rel}_x"} < $bot->{'x'}];
290             }
291             }
292              
293             sub _toggle {
294 0     0     my $bot = shift;
295 0           $bot->{'var'}{'_'.$bot->{'state'}}
296             = !$bot->{'var'}{'_'.$bot->{'state'}};
297 0           return !$bot->{'var'}{'_'.$bot->{'state'}};
298             }
299              
300             sub _found {
301 0     0     my $bot = shift;
302              
303             return (
304 0 0         @_ ? (index($_[0], '|') > -1)
    0          
305             ? $bot->{'found'} =~ /^(?:$_[0])/
306             : $bot->{'found'} eq $_[0]
307             : $bot->{'found'}
308             );
309             }
310              
311             sub _bumped {
312 0     0     my $bot = shift;
313              
314             return (
315 0 0         @_ ? (index($_[0], '|') > -1)
    0          
316             ? $bot->{'bumped'} =~ /^(?:$_[0])/
317             : $bot->{'bumped'} eq $_[0]
318             : $bot->{'bumped'}
319             );
320             }
321              
322             1;
323              
324             =head1 SEE ALSO
325              
326             L, L
327              
328             =head1 AUTHORS
329              
330             Autrijus Tang Eautrijus@autrijus.orgE
331              
332             Files under the F directory was contributed by students in
333             the autonomous learning experimnetal class, Bei'zheng junior high
334             school, Taipei, Taiwan.
335              
336             =head1 COPYRIGHT
337              
338             Copyright 2001, 2002 by Autrijus Tang Eautrijus@autrijus.orgE.
339              
340             This program is free software; you can redistribute it and/or
341             modify it under the same terms as Perl itself.
342              
343             See L
344              
345             =cut