File Coverage

blib/lib/AI/Termites.pm
Criterion Covered Total %
statement 21 85 24.7
branch 0 14 0.0
condition 0 19 0.0
subroutine 7 20 35.0
pod 0 13 0.0
total 28 151 18.5


line stmt bran cond sub pod time code
1             package AI::Termites;
2              
3 1     1   22069 use 5.010;
  1         5  
  1         49  
4              
5             our $VERSION = '0.02';
6              
7 1     1   6 use strict;
  1         2  
  1         45  
8 1     1   4 use warnings;
  1         14  
  1         31  
9              
10 1     1   975 use Math::Vector::Real;
  1         14964  
  1         61  
11 1     1   788 use Math::Vector::Real::Random;
  1         9738  
  1         41  
12              
13 1     1   12 use List::Util;
  1         2  
  1         112  
14 1     1   6 use Carp;
  1         2  
  1         1094  
15              
16             sub new {
17 0     0 0   my ($class, %opts) = @_;
18 0           my ($dim, $box);
19 0           $box = delete $opts{box};
20 0 0         if (defined $box) {
21 0           $box = V(@$box);
22 0           $dim = @$box;
23             }
24             else {
25 0   0       $dim = delete $opts{dim} // 3;
26 0   0       my $size = delete $opts{world_size} // 1000;
27 0           $box = Math::Vector::Real->cube($dim, $size);
28             }
29              
30 0           my $box_vol = 1;
31 0           $box_vol *= $_ for @$box;
32              
33 0   0       my $n_termites = delete $opts{n_termites} // 50;
34 0   0       my $n_wood = delete $opts{n_wood} // 200;
35 0   0       my $iterations = delete $opts{iterations} // 0;
36 0   0       my $termite_speed = delete $opts{termite_speed} // abs($box)/10;
37 0   0       my $near = delete $opts{near} // abs($box)/50;
38 0 0         %opts and croak "unknown parameter(s) ". join(", ", keys %opts);
39              
40 0           my @wood;
41             my @termites;
42              
43 0           my $self = { wood => \@wood,
44             termites => \@termites,
45             iteration => 0,
46             speed => $termite_speed,
47             box => $box,
48             box_vol => $box_vol,
49             wood_density => $n_wood/$box_vol,
50             near => $near,
51             inear2 => 1/($near * $near),
52             near_dim => $near ** $dim,
53             taken => 0,
54             dim => $dim };
55              
56 0           bless $self, $class;
57              
58 0           push @wood, $self->new_wood for (1..$n_wood);
59 0           push @termites, $self->new_termite for (1..$n_termites);
60 0           $self->iterate for (1..$iterations);
61 0           $self;
62             }
63              
64 0     0 0   sub dim { shift->{dim} }
65              
66 0     0 0   sub box { shift->{box} }
67              
68             sub new_wood {
69 0     0 0   my $self = shift;
70 0           my $wood = { pos => $self->{box}->random_in_box,
71             taken => 0 };
72             }
73              
74             sub new_termite {
75 0     0 0   my $self = shift;
76 0           my $termite = { pos => $self->{box}->random_in_box };
77             }
78              
79             sub iterate {
80 0     0 0   my $self = shift;
81              
82 0           $self->before_termites_move;
83              
84 0           for my $term (@{$self->{termites}}) {
  0            
85 0           $self->termite_move($term);
86             }
87 0           $self->before_termites_action;
88 0           for my $term (@{$self->{termites}}) {
  0            
89 0           $self->termite_action($term);
90             }
91 0           $self->after_termites_action;
92             }
93              
94             sub termite_move {
95 0     0 0   my ($self, $termite) = @_;
96 0           $termite->{pos} = $self->{box}->wrap( $termite->{pos} +
97             Math::Vector::Real->random_normal($self->{dim},
98             $self->{speed}));
99             }
100              
101 0     0 0   sub before_termites_move {}
102 0     0 0   sub before_termites_action {}
103 0     0 0   sub after_termites_action {}
104              
105             sub termite_action {
106 0     0 0   my ($self, $termite) = @_;
107 0 0         if (defined $termite->{wood_ix}) {
108 0 0         if ($self->termite_leave_wood_p($termite)) {
109 0           $self->termite_leave_wood($termite);
110             }
111             }
112             else {
113 0           my $wood_ix = $self->termite_take_wood_p($termite);
114 0 0         defined $wood_ix and $self->termite_take_wood($termite, $wood_ix);
115             }
116             }
117              
118             sub termite_take_wood {
119 0     0 0   my ($self, $termite, $wood_ix) = @_;
120 0           my $wood = $self->{wood}[$wood_ix];
121 0 0         return if $wood->{taken};
122 0           $wood->{taken} = 1;
123 0           $self->{taken}++;
124             # print "taken: $self->{taken}\n";
125 0 0         defined $termite->{wood_ix} and die "termite is already carrying some wood";
126 0           $termite->{wood_ix} = $wood_ix;
127             }
128              
129             sub termite_leave_wood {
130 0     0 0   my ($self, $termite) = @_;
131 0   0       my $wood_ix = delete $termite->{wood_ix} //
132             croak "termite can not leave wood because it is carrying nothing";
133 0           $self->{taken}--;
134 0           my $wood = $self->{wood}[$wood_ix];
135 0           $wood->{taken} = 0;
136 0           $wood->{pos}->set($termite->{pos});
137             }
138              
139              
140             1;
141             __END__