Algorithm-Gutter
view release on metacpan or search on metacpan
lib/Algorithm/Gutter.pm view on Meta::CPAN
# -*- Perl -*-
#
# Algorithm::Gutter - cellular automata to simulate rain in a gutter,
# or, "the hundred and forty-second worst drum machine in the West".
package Algorithm::Gutter;
use 5.26.0;
use Object::Pad 0.66;
our $VERSION = '0.02';
class Algorithm::Gutter::Cell {
field $amount :mutator :param = 0;
field $context :mutator;
field $enabled :mutator :param = 0;
field $id :reader :param = 0;
field $threshold :mutator :param = ~0;
field $update :mutator :param = undef;
method drain ( $index, $all = 1, $stash = undef ) {
if ( $enabled and $amount >= $threshold ) {
my $drained;
if ($all) {
$drained = $amount;
$amount = 0;
} else {
$drained = $threshold;
$amount -= $threshold;
}
die "no update callback" unless defined $update;
return $update->( $self, $index, $drained, $stash );
}
return;
}
}
class Algorithm::Gutter {
field $gutter :reader :param = [];
field $rain :writer :param = undef;
# Try to drain cells, possibly triggering cell update functions.
method drain ( $all = 1, $stash = undef ) {
my $index = 0;
map { $_->drain( $index++, $all, $stash ) } @$gutter;
}
# Adding water to the cells left as an exercise to the caller.
method rain ( $stash = undef ) {
die "no rain callback supplied" unless defined $rain;
$rain->( $gutter, $stash );
}
# Redistribute imbalances in the water level between adjacent cells.
# There are doubtless more complicated or more efficient ways to do
# this, but those would take time to figure out.
method slosh ( $max = ~0, $dmax = 1 ) {
return if @$gutter < 2;
my $iterations = 0;
my $end = @$gutter - 1;
while ( $max-- > 0 ) {
$iterations++;
my $done = 1;
for my $i ( 0 .. $end - 1 ) {
my $delta = $gutter->[$i]->amount - $gutter->[ $i + 1 ]->amount;
if ( $delta > $dmax ) {
( run in 0.535 second using v1.01-cache-2.11-cpan-39bf76dae61 )