I don't have access to a 64-bit perl. However, this is a 32-bit version
of combining two 16 bit integers into a 32 bit number. While this runs
as long as the coordinates are within range, I can't test it in the 64-bit version.
I like it because all offsets are found with a simple addition inside tick.
All the encode/decode mess is in the input and output routines.
In theory (completely untested), all that's needed is to change the line
my $half = 16; # make 32 for 64-bit perls
to
my $half = 32; # make 32 for 64-bit perls
to make it use the full range of two 32 bit numbers.
So here's the code
package Organism;
use strict;
use warnings;
sub count {
return scalar keys %{ shift->{Cells} };
}
# Input a list of [ x, y ] coords
sub insert_cells {
my $self = shift;
my $cells = $self->{Cells};
for my $r (@_) { $cells->{
(($r->[0] + $self->{fudge}) << $self->{half}) |
($r->[1] + $self->{fudge})
} = undef }
}
# Return sorted list of cells in the Organism.
# Used for verification and testing the state of the organism.
sub get_live_cells {
my $self = shift;
sort { $a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] }
map { [
($_ >> $self->{half}) - $self->{fudge},
($_ & (1 << $self->{half}) - 1) - $self->{fudge}
] } keys %{ $self->{Cells} };
}
sub tick {
my $self = shift;
my $cells = $self->{Cells};
my @deltas = @{ $self->{deltas} };
my ( %new_cells, %dead_cells );
for my $c (keys %{ $cells }) {
# Get the (up to 8) dead cells surrounding the cell
$dead_cells{$_}++ for my @zcells =
grep !exists $cells->{$_}, map $c + $_, @deltas;
# Check the live cell
# Note: next line equivalent to nlive == 2 || nlive == 3
@zcells == 5 || @zcells == 6 and $new_cells{$c} = undef;
}
$dead_cells{$_} == 3 and $new_cells{$_} = undef for keys %dead_cell
+s;
$self->{Cells} = \%new_cells;
}
sub new {
my $class = shift;
my $half = 16; # make 32 for 64-bit perls
my $base = 1 << $half;
my $fudge = $base >> 1;
my @deltas = ($base-1, $base, $base+1,
-1, 1, -$base-1, -$base, -$base+1);
my %init_self = ( Cells => {},
fudge => $fudge, half => $half, deltas => \@deltas );
bless \%init_self, $class;
}
1;
Preliminary testing with 16 bit numbers seemed to show it's about 10% slower than the pack version :(