File Coverage

blib/lib/Algorithm/Gutter.pm
Criterion Covered Total %
statement 74 76 97.3
branch 14 16 87.5
condition 2 3 66.6
subroutine 13 14 92.8
pod 5 5 100.0
total 108 114 94.7


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             #
3             # Algorithm::Gutter - cellular automata to simulate rain in a gutter,
4             # or, "the hundred and forty-second worst drum machine in the West".
5              
6             package Algorithm::Gutter;
7 2     2   678977 use 5.26.0;
  2         7  
8 2     2   1387 use Object::Pad 0.66;
  2         19503  
  2         114  
9             our $VERSION = '0.02';
10              
11             class Algorithm::Gutter::Cell {
12 43     43   126 field $amount :mutator :param = 0;
13 43     3   137 field $context :mutator;
  3         19  
  3         14  
14 2     2   5 field $enabled :mutator :param = 0;
15 2     0   6 field $id :reader :param = 0;
  0         0  
16 0     1   0 field $threshold :mutator :param = ~0;
  1         3  
17 1         4 field $update :mutator :param = undef;
18              
19 9     9   15 method drain ( $index, $all = 1, $stash = undef ) {
  9     1   21  
  9         14  
  9         14  
  9         15  
  9         11  
  1         3  
  1         3  
20 9 100 66     32 if ( $enabled and $amount >= $threshold ) {
21 2         4 my $drained;
22 2 100       7 if ($all) {
23 1         16 $drained = $amount;
24 1         4 $amount = 0;
25             } else {
26 1         4 $drained = $threshold;
27 1         2 $amount -= $threshold;
28             }
29 2 50       7 die "no update callback" unless defined $update;
30 2         8 return $update->( $self, $index, $drained, $stash );
31             }
32 7         34 return;
33             }
34             }
35              
36             class Algorithm::Gutter {
37 21     21 1 98 field $gutter :reader :param = [];
38 21         117 field $rain :writer :param = undef;
39              
40             # Try to drain cells, possibly triggering cell update functions.
41 3     3 1 10 method drain ( $all = 1, $stash = undef ) {
  3     2 1 9  
  3         7  
  3         6  
  3         5  
  2         24  
  2         16  
42 3         5 my $index = 0;
43 3         9 map { $_->drain( $index++, $all, $stash ) } @$gutter;
  9         24  
44             }
45              
46             # Adding water to the cells left as an exercise to the caller.
47 7     7 1 23 method rain ( $stash = undef ) {
  7         28  
  7         20  
  7         10  
48 7 50       26 die "no rain callback supplied" unless defined $rain;
49 7         24 $rain->( $gutter, $stash );
50             }
51              
52             # Redistribute imbalances in the water level between adjacent cells.
53             # There are doubtless more complicated or more efficient ways to do
54             # this, but those would take time to figure out.
55 4     4 1 13 method slosh ( $max = ~0, $dmax = 1 ) {
  4         16  
  4         9  
  4         8  
  4         5  
56 4 100       23 return if @$gutter < 2;
57 2         4 my $iterations = 0;
58 2         5 my $end = @$gutter - 1;
59 2         8 while ( $max-- > 0 ) {
60 3         6 $iterations++;
61 3         6 my $done = 1;
62 3         9 for my $i ( 0 .. $end - 1 ) {
63 4         11 my $delta = $gutter->[$i]->amount - $gutter->[ $i + 1 ]->amount;
64 4 100       11 if ( $delta > $dmax ) {
65 2         6 $gutter->[$i]->amount--;
66 2         7 $gutter->[ $i + 1 ]->amount++;
67 2         6 $done = 0;
68             }
69             }
70 3         10 for my $i ( reverse 1 .. $end ) {
71 4         36 my $delta = $gutter->[$i]->amount - $gutter->[ $i - 1 ]->amount;
72 4 100       12 if ( $delta > $dmax ) {
73 1         5 $gutter->[$i]->amount--;
74 1         4 $gutter->[ $i - 1 ]->amount++;
75 1         3 $done = 0;
76             }
77             }
78 3 100       14 last if $done;
79             }
80 2         10 return $iterations;
81             }
82             }
83              
84             1;
85             __END__