Come for the quick hacks, stay for the epiphanies. PerlMonks

### Re^4: High Performance Game of Life

by marioroy (Prior)
 on Aug 12, 2017 at 17:38 UTC Need Help??

in reply to Re^3: High Performance Game of Life
in thread High Performance Game of Life

Here is Organism.pm modified to use pack/unpack, plus slight optimization applied to insert_cells.

package Organism; use strict; use warnings; use feature 'state'; sub count { return scalar keys %{ shift->{Cells} }; } # Input a list of [ x, y ] coords sub insert_cells { my \$cells = shift->{Cells}; for my \$r (@_) { \$cells->{ pack 'ii', @{\$r} } = undef } } # Return sorted list of cells in the Organism. # Used for verification and testing the state of the organism. sub get_live_cells { sort { \$a->[0] <=> \$b->[0] || \$a->[1] <=> \$b->[1] } map { [ unpack 'ii', \$_ ] } keys %{ shift->{Cells} }; } # Return the list of dead cells surrounding a cell sub get_dead_cells { my ( \$cells, \$x0, \$y0 ) = ( shift->{Cells}, @_ ); my ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); state ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8 ); ( ( \$k1 = pack 'ii', \$x1, \$y1 ) x !( 0 + exists \$cells->{ \$k1 } ), ( \$k2 = pack 'ii', \$x1, \$y0 ) x !( 0 + exists \$cells->{ \$k2 } ), ( \$k3 = pack 'ii', \$x1, \$y2 ) x !( 0 + exists \$cells->{ \$k3 } ), ( \$k4 = pack 'ii', \$x0, \$y1 ) x !( 0 + exists \$cells->{ \$k4 } ), ( \$k5 = pack 'ii', \$x0, \$y2 ) x !( 0 + exists \$cells->{ \$k5 } ), ( \$k6 = pack 'ii', \$x2, \$y1 ) x !( 0 + exists \$cells->{ \$k6 } ), ( \$k7 = pack 'ii', \$x2, \$y0 ) x !( 0 + exists \$cells->{ \$k7 } ), ( \$k8 = pack 'ii', \$x2, \$y2 ) x !( 0 + exists \$cells->{ \$k8 } ) ) +; } sub get_num_live { my ( \$cells, \$x0, \$y0 ) = ( shift->{Cells}, @_ ); my ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); ( 0 + exists \$cells->{ pack 'ii', \$x1, \$y1 } ) + ( 0 + exists \$cells->{ pack 'ii', \$x1, \$y0 } ) + ( 0 + exists \$cells->{ pack 'ii', \$x1, \$y2 } ) + ( 0 + exists \$cells->{ pack 'ii', \$x0, \$y1 } ) + ( 0 + exists \$cells->{ pack 'ii', \$x0, \$y2 } ) + ( 0 + exists \$cells->{ pack 'ii', \$x2, \$y1 } ) + ( 0 + exists \$cells->{ pack 'ii', \$x2, \$y0 } ) + ( 0 + exists \$cells->{ pack 'ii', \$x2, \$y2 } ); } sub tick { my \$self = shift; my %new_cells; for my \$c (keys %{ \$self->{Cells} }) { # Get the (up to 8) dead cells surrounding the cell my @zcells = \$self->get_dead_cells( unpack 'ii', \$c ); # Check the live cell # Note: next line equivalent to nlive == 2 || nlive == 3 @zcells == 5 || @zcells == 6 and \$new_cells{\$c} = undef; # Check the dead cells for my \$z (@zcells) { \$self->get_num_live( unpack 'ii', \$z ) == 3 and \$new_cells{\$z +} = undef; } } \$self->{Cells} = \%new_cells; } sub new { my \$class = shift; my %init_self = ( Cells => {} ); bless \%init_self, \$class; } 1;

Regards, Mario

Replies are listed 'Best First'.
Re^5: High Performance Game of Life
by marioroy (Prior) on Aug 12, 2017 at 22:09 UTC

Update: pack 'i2' is more efficient than pack 'ii'

Organism.pm optimized with pack/unpack 'i2' and inlining critical paths.

package Organism; use strict; use warnings; use feature 'state'; sub count { return scalar keys %{ shift->{Cells} }; } # Input a list of [ x, y ] coords sub insert_cells { my \$cells = shift->{Cells}; for my \$r (@_) { \$cells->{ pack 'i2', @{\$r} } = undef } } # Return sorted list of cells in the Organism. # Used for verification and testing the state of the organism. sub get_live_cells { sort { \$a->[0] <=> \$b->[0] || \$a->[1] <=> \$b->[1] } map { [ unpack 'i2', \$_ ] } keys %{ shift->{Cells} }; } # Return the list of dead cells surrounding a cell sub get_dead_cells { my ( \$cells, \$x0, \$y0 ) = ( shift->{Cells}, @_ ); my ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); state ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8 ); ( ( \$k1 = pack 'i2', \$x1, \$y1 ) x !( 0 + exists \$cells->{ \$k1 } ), ( \$k2 = pack 'i2', \$x1, \$y0 ) x !( 0 + exists \$cells->{ \$k2 } ), ( \$k3 = pack 'i2', \$x1, \$y2 ) x !( 0 + exists \$cells->{ \$k3 } ), ( \$k4 = pack 'i2', \$x0, \$y1 ) x !( 0 + exists \$cells->{ \$k4 } ), ( \$k5 = pack 'i2', \$x0, \$y2 ) x !( 0 + exists \$cells->{ \$k5 } ), ( \$k6 = pack 'i2', \$x2, \$y1 ) x !( 0 + exists \$cells->{ \$k6 } ), ( \$k7 = pack 'i2', \$x2, \$y0 ) x !( 0 + exists \$cells->{ \$k7 } ), ( \$k8 = pack 'i2', \$x2, \$y2 ) x !( 0 + exists \$cells->{ \$k8 } ) ) +; } sub tick { my \$self = shift; my \$cells = \$self->{Cells}; my %new_cells; for my \$c (keys %{ \$cells }) { # Get the (up to 8) dead cells surrounding the cell my @zcells = \$self->get_dead_cells( unpack 'i2', \$c ); # Check the live cell # Note: next line equivalent to nlive == 2 || nlive == 3 @zcells == 5 || @zcells == 6 and \$new_cells{\$c} = undef; # Check the dead cells for my \$z (@zcells) { state ( \$x0, \$x1, \$x2, \$y0, \$y1, \$y2 ); ( \$x0, \$y0 ) = unpack 'i2', \$z; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 + ); # Get num live ( ( 0 + exists \$cells->{ pack 'i2', \$x1, \$y1 } ) + ( 0 + exists \$cells->{ pack 'i2', \$x1, \$y0 } ) + ( 0 + exists \$cells->{ pack 'i2', \$x1, \$y2 } ) + ( 0 + exists \$cells->{ pack 'i2', \$x0, \$y1 } ) + ( 0 + exists \$cells->{ pack 'i2', \$x0, \$y2 } ) + ( 0 + exists \$cells->{ pack 'i2', \$x2, \$y1 } ) + ( 0 + exists \$cells->{ pack 'i2', \$x2, \$y0 } ) + ( 0 + exists \$cells->{ pack 'i2', \$x2, \$y2 } ) ) == 3 and \$new_cells{\$z} = undef; } } \$self->{Cells} = \%new_cells; } sub new { my \$class = shift; my %init_self = ( Cells => {} ); bless \%init_self, \$class; } 1;

Regards, Mario

Thanks Mario! Shaved a couple more seconds:

• Got rid of state (didn't seem to make it any faster)
• Switched off warnings (admittedly this didn't make much, if any, difference)
• Some other minor tweaks
See "Mario improvements" entries in "Benchmark Results" section of root node for speed comparison with original Organism.pm.

Note: The code below is the fastest version of the Perl GOL code in this node.

package Organism; use strict; sub count { scalar keys %{ shift->{Cells} } } # Input a list of [ x, y ] coords sub insert_cells { my \$cells = shift->{Cells}; for my \$r (@_) { \$cells->{ pack 'i2', @{\$r} } = undef } } # Return sorted list of cells in the Organism. # Used for verification and testing the state of the organism. sub get_live_cells { sort { \$a->[0] <=> \$b->[0] || \$a->[1] <=> \$b->[1] } map { [ unpack 'i2', \$_ ] } keys %{ shift->{Cells} }; } sub tick { my \$self = shift; my \$cells = \$self->{Cells}; my ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8, \$x0, \$x1, \$x2, \$y0, \$y1, \$y2, %newcells ); for my \$c (keys %{ \$cells }) { # Get the (up to 8) dead cells surrounding the cell ( \$x0, \$y0 ) = unpack 'i2', \$c; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); my @zcells = ( (\$k1 = pack 'i2', \$x1, \$y1) x !exists(\$cells->{\$k1}), (\$k2 = pack 'i2', \$x1, \$y0) x !exists(\$cells->{\$k2}), (\$k3 = pack 'i2', \$x1, \$y2) x !exists(\$cells->{\$k3}), (\$k4 = pack 'i2', \$x0, \$y1) x !exists(\$cells->{\$k4}), (\$k5 = pack 'i2', \$x0, \$y2) x !exists(\$cells->{\$k5}), (\$k6 = pack 'i2', \$x2, \$y1) x !exists(\$cells->{\$k6}), (\$k7 = pack 'i2', \$x2, \$y0) x !exists(\$cells->{\$k7}), (\$k8 = pack 'i2', \$x2, \$y2) x !exists(\$cells->{\$k8}) ); # Check the live cell (next line equivalent to nlive==2 || nlive +==3) @zcells == 5 || @zcells == 6 and \$newcells{\$c} = undef; # Check the dead cells for my \$z (@zcells) { ( \$x0, \$y0 ) = unpack 'i2', \$z; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 + ); exists(\$cells->{pack 'i2', \$x1, \$y1}) + exists(\$cells->{pack 'i2', \$x1, \$y0}) + exists(\$cells->{pack 'i2', \$x1, \$y2}) + exists(\$cells->{pack 'i2', \$x0, \$y1}) + exists(\$cells->{pack 'i2', \$x0, \$y2}) + exists(\$cells->{pack 'i2', \$x2, \$y1}) + exists(\$cells->{pack 'i2', \$x2, \$y0}) + exists(\$cells->{pack 'i2', \$x2, \$y2}) == 3 and \$newcells{\$z +} = undef; } } \$self->{Cells} = \%newcells; } sub new { my \$class = shift; my %init_self = ( Cells => {} ); bless \%init_self, \$class; } 1;

Update: Minor stylistic edits were made to Organism.pm above.

Note that changing the main loop above from:

for my \$c (keys %{ \$cells }) {
to:
while ( my (\$c) = each %{ \$cells } ) {
uses less memory - though I couldn't measure any difference in speed.

Update: This one is shorter, but a bit slower:

sub tick { my \$self = shift; my \$cells = \$self->{Cells}; my ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8, \$x0, \$x1, \$x2, \$y0, \$y1, \$y2 ); %{\$cells} = map { ( \$x0, \$y0 ) = unpack 'i2', \$_; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); my @zcells = ( (\$k1 = pack 'i2', \$x1, \$y1) x !exists(\$cells->{\$k1}), (\$k2 = pack 'i2', \$x1, \$y0) x !exists(\$cells->{\$k2}), (\$k3 = pack 'i2', \$x1, \$y2) x !exists(\$cells->{\$k3}), (\$k4 = pack 'i2', \$x0, \$y1) x !exists(\$cells->{\$k4}), (\$k5 = pack 'i2', \$x0, \$y2) x !exists(\$cells->{\$k5}), (\$k6 = pack 'i2', \$x2, \$y1) x !exists(\$cells->{\$k6}), (\$k7 = pack 'i2', \$x2, \$y0) x !exists(\$cells->{\$k7}), (\$k8 = pack 'i2', \$x2, \$y2) x !exists(\$cells->{\$k8}) ); (\$_, undef) x (@zcells == 5 || @zcells == 6), map { ( \$x0, \$y0 ) = unpack 'i2', \$_; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + +1 ); (\$_, undef) x ( exists(\$cells->{pack 'i2', \$x1, \$y1}) + exists(\$cells->{pack 'i2', \$x1, \$y0}) + exists(\$cells->{pack 'i2', \$x1, \$y2}) + exists(\$cells->{pack 'i2', \$x0, \$y1}) + exists(\$cells->{pack 'i2', \$x0, \$y2}) + exists(\$cells->{pack 'i2', \$x2, \$y1}) + exists(\$cells->{pack 'i2', \$x2, \$y0}) + exists(\$cells->{pack 'i2', \$x2, \$y2}) == 3 ) } @zcells } keys %{\$cells}; }
as is this one:
sub tick { my \$self = shift; my \$cells = \$self->{Cells}; my ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8, \$x0, \$x1, \$x2, \$y0, \$y1, \$y2 ); my %newcells; @newcells{map { ( \$x0, \$y0 ) = unpack 'i2', \$_; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); my @zcells = ( (\$k1 = pack 'i2', \$x1, \$y1) x !exists(\$cells->{\$k1}), (\$k2 = pack 'i2', \$x1, \$y0) x !exists(\$cells->{\$k2}), (\$k3 = pack 'i2', \$x1, \$y2) x !exists(\$cells->{\$k3}), (\$k4 = pack 'i2', \$x0, \$y1) x !exists(\$cells->{\$k4}), (\$k5 = pack 'i2', \$x0, \$y2) x !exists(\$cells->{\$k5}), (\$k6 = pack 'i2', \$x2, \$y1) x !exists(\$cells->{\$k6}), (\$k7 = pack 'i2', \$x2, \$y0) x !exists(\$cells->{\$k7}), (\$k8 = pack 'i2', \$x2, \$y2) x !exists(\$cells->{\$k8}) ); (\$_) x (@zcells == 5 || @zcells == 6), map { ( \$x0, \$y0 ) = unpack 'i2', \$_; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + +1 ); (\$_) x ( exists(\$cells->{pack 'i2', \$x1, \$y1}) + exists(\$cells->{pack 'i2', \$x1, \$y0}) + exists(\$cells->{pack 'i2', \$x1, \$y2}) + exists(\$cells->{pack 'i2', \$x0, \$y1}) + exists(\$cells->{pack 'i2', \$x0, \$y2}) + exists(\$cells->{pack 'i2', \$x2, \$y1}) + exists(\$cells->{pack 'i2', \$x2, \$y0}) + exists(\$cells->{pack 'i2', \$x2, \$y2}) == 3 ) } @zcells } keys %{\$cells} } = undef; \$self->{Cells} = \%newcells; }
I'm guessing they are slower because the list of cells used in the hash slice contains many duplicate dead cells.

Update: Changing:

my @zcells = ( (\$k1 = pack 'i2', \$x1, \$y1) x !exists(\$cells->{\$k1}), (\$k2 = pack 'i2', \$x1, \$y0) x !exists(\$cells->{\$k2}), (\$k3 = pack 'i2', \$x1, \$y2) x !exists(\$cells->{\$k3}), (\$k4 = pack 'i2', \$x0, \$y1) x !exists(\$cells->{\$k4}), (\$k5 = pack 'i2', \$x0, \$y2) x !exists(\$cells->{\$k5}), (\$k6 = pack 'i2', \$x2, \$y1) x !exists(\$cells->{\$k6}), (\$k7 = pack 'i2', \$x2, \$y0) x !exists(\$cells->{\$k7}), (\$k8 = pack 'i2', \$x2, \$y2) x !exists(\$cells->{\$k8}) );
to:
my @zcells = grep( !exists(\$cells->{\$_}), pack('i2', \$x1, \$y1), pack('i2', \$x1, \$y0), pack('i2', \$x1, \$y2), pack('i2', \$x0, \$y1), pack('i2', \$x0, \$y2), pack('i2', \$x2, \$y1), pack('i2', \$x2, \$y0), pack('i2', \$x2, \$y2) );
was slightly slower.

This one was also slower:

sub tick { my \$self = shift; my \$cells = \$self->{Cells}; my ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8, \$x0, \$x1, \$x2, \$y0, \$y1, \$y2, \$z, %newcells ); for my \$c (keys %{ \$cells }) { # Get the (up to 8) dead cells surrounding the cell ( \$x0, \$y0 ) = unpack 'i2', \$c; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); my @zcells = ( (\$x1, \$y1, \$k1 = pack 'i2', \$x1, \$y1) x !exists(\$cells->{\$k1} +), (\$x1, \$y0, \$k2 = pack 'i2', \$x1, \$y0) x !exists(\$cells->{\$k2} +), (\$x1, \$y2, \$k3 = pack 'i2', \$x1, \$y2) x !exists(\$cells->{\$k3} +), (\$x0, \$y1, \$k4 = pack 'i2', \$x0, \$y1) x !exists(\$cells->{\$k4} +), (\$x0, \$y2, \$k5 = pack 'i2', \$x0, \$y2) x !exists(\$cells->{\$k5} +), (\$x2, \$y1, \$k6 = pack 'i2', \$x2, \$y1) x !exists(\$cells->{\$k6} +), (\$x2, \$y0, \$k7 = pack 'i2', \$x2, \$y0) x !exists(\$cells->{\$k7} +), (\$x2, \$y2, \$k8 = pack 'i2', \$x2, \$y2) x !exists(\$cells->{\$k8} +) ); # Check the live cell (next line equivalent to nlive==2 || nlive +==3) @zcells == 15 || @zcells == 18 and \$newcells{\$c} = undef; # Check the dead cells while (@zcells) { ( \$x0, \$y0, \$z ) = splice @zcells, 0, 3; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 + ); exists(\$cells->{pack 'i2', \$x1, \$y1}) + exists(\$cells->{pack 'i2', \$x1, \$y0}) + exists(\$cells->{pack 'i2', \$x1, \$y2}) + exists(\$cells->{pack 'i2', \$x0, \$y1}) + exists(\$cells->{pack 'i2', \$x0, \$y2}) + exists(\$cells->{pack 'i2', \$x2, \$y1}) + exists(\$cells->{pack 'i2', \$x2, \$y0}) + exists(\$cells->{pack 'i2', \$x2, \$y2}) == 3 and \$newcells{\$z +} = undef; } } \$self->{Cells} = \%newcells; }

Try this. Notably faster on my machine that is horribly slower than yours.

package Organism; use strict; # use warnings; sub count { return scalar keys %{ shift->{Cells} }; } # Input a list of [ x, y ] coords sub insert_cells { my \$cells = shift->{Cells}; for my \$r (@_) { \$cells->{ pack 'i2', @{\$r} } = undef } } # Return sorted list of cells in the Organism. # Used for verification and testing the state of the organism. sub get_live_cells { sort { \$a->[0] <=> \$b->[0] || \$a->[1] <=> \$b->[1] } map { [ unpack 'i2', \$_ ] } keys %{ shift->{Cells} }; } sub tick { my \$self = shift; my \$cells = \$self->{Cells}; my ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8, \$x0, \$x1, \$x2, \$y0, \$y1, \$y2, %new_cells, %dead_cells ); for my \$c (keys %{ \$cells }) { # Get the (up to 8) dead cells surrounding the cell ( \$x0, \$y0 ) = unpack 'i2', \$c; ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); \$dead_cells{\$_}++ for my @zcells = ( (\$k1 = pack 'i2', \$x1, \$y1) x !(exists \$cells->{\$k1}), (\$k2 = pack 'i2', \$x1, \$y0) x !(exists \$cells->{\$k2}), (\$k3 = pack 'i2', \$x1, \$y2) x !(exists \$cells->{\$k3}), (\$k4 = pack 'i2', \$x0, \$y1) x !(exists \$cells->{\$k4}), (\$k5 = pack 'i2', \$x0, \$y2) x !(exists \$cells->{\$k5}), (\$k6 = pack 'i2', \$x2, \$y1) x !(exists \$cells->{\$k6}), (\$k7 = pack 'i2', \$x2, \$y0) x !(exists \$cells->{\$k7}), (\$k8 = pack 'i2', \$x2, \$y2) x !(exists \$cells->{\$k8}) ); # 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 %init_self = ( Cells => {} ); bless \%init_self, \$class; } 1;

Update 1: Bit-manipulation will not work when \$y is negative. See this post. I assumed that \$y was always positive from testing using the initial test script.

Update 2: See this post for a version that maps two integers into one integer successfully.

For a last attempt in reaching 10x, I tried combining two integers into one via bit-manipulation. Having to support (\$x) being negative made bit-manipulation more complicated. However, it runs as fast as pack('ii').

This was an exercise and nothing more. I thought why not try bit-shifting the two integers into one.

package Organism; use strict; # use warnings; sub _pack { my ( \$x, \$y ) = @_; \$x < 0 ? -(abs(\$x) << 32 | \$y) : \$x << 32 | \$y; } sub _unpack { my ( \$n ) = @_; return \$n < 0 ? ( -( abs(\$n) >> 32 ), abs(\$n) & 0xFFFFFFFF ) : ( \$n >> 32 , \$n & 0xFFFFFFFF ); } sub count { return scalar keys %{ shift->{Cells} }; } # Input a list of [ x, y ] coords sub insert_cells { my \$cells = shift->{Cells}; for my \$r (@_) { \$cells->{ _pack @{\$r} } = undef } } # Used for verification and testing the state of the organism. sub get_live_cells { sort { \$a->[0] <=> \$b->[0] || \$a->[1] <=> \$b->[1] } map { [ _unpack \$_ ] } keys %{ shift->{Cells} }; } sub tick { my \$self = shift; my \$cells = \$self->{Cells}; my ( \$k1, \$k2, \$k3, \$k4, \$k5, \$k6, \$k7, \$k8, \$x0, \$x1, \$x2, \$y0, \$y1, \$y2, %new_cells ); for my \$c (keys %{ \$cells }) { # Get the (up to 8) dead cells surrounding the cell ( \$x0, \$y0 ) = \$c < 0 ? ( -( abs(\$c) >> 32 ), abs(\$c) & 0xFFFFFFFF ) : ( \$c >> 32 , \$c & 0xFFFFFFFF ); ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 ); my @zcells = ( (\$k1 = \$x1 < 0 ? -(abs(\$x1) << 32 | \$y1) : \$x1 << 32 | \$y1) x + !(exists \$cells->{\$k1}), (\$k2 = \$x1 < 0 ? -(abs(\$x1) << 32 | \$y0) : \$x1 << 32 | \$y0) x + !(exists \$cells->{\$k2}), (\$k3 = \$x1 < 0 ? -(abs(\$x1) << 32 | \$y2) : \$x1 << 32 | \$y2) x + !(exists \$cells->{\$k3}), (\$k4 = \$x0 < 0 ? -(abs(\$x0) << 32 | \$y1) : \$x0 << 32 | \$y1) x + !(exists \$cells->{\$k4}), (\$k5 = \$x0 < 0 ? -(abs(\$x0) << 32 | \$y2) : \$x0 << 32 | \$y2) x + !(exists \$cells->{\$k5}), (\$k6 = \$x2 < 0 ? -(abs(\$x2) << 32 | \$y1) : \$x2 << 32 | \$y1) x + !(exists \$cells->{\$k6}), (\$k7 = \$x2 < 0 ? -(abs(\$x2) << 32 | \$y0) : \$x2 << 32 | \$y0) x + !(exists \$cells->{\$k7}), (\$k8 = \$x2 < 0 ? -(abs(\$x2) << 32 | \$y2) : \$x2 << 32 | \$y2) x + !(exists \$cells->{\$k8}) ); # Check the live cell # Note: next line equivalent to nlive == 2 || nlive == 3 @zcells == 5 || @zcells == 6 and \$new_cells{\$c} = undef; # Check the dead cells for my \$z (@zcells) { ( \$x0, \$y0 ) = \$z < 0 ? ( -( abs(\$z) >> 32 ), abs(\$z) & 0xFFFFFFFF ) : ( \$z >> 32 , \$z & 0xFFFFFFFF ); ( \$x1, \$x2, \$y1, \$y2 ) = ( \$x0 - 1, \$x0 + 1, \$y0 - 1, \$y0 + 1 + ); # Get num live ( ( exists \$cells->{ \$x1 < 0 ? -(abs(\$x1) << 32 | \$y1) : \$x +1 << 32 | \$y1 } ) + ( exists \$cells->{ \$x1 < 0 ? -(abs(\$x1) << 32 | \$y0) : \$x +1 << 32 | \$y0 } ) + ( exists \$cells->{ \$x1 < 0 ? -(abs(\$x1) << 32 | \$y2) : \$x +1 << 32 | \$y2 } ) + ( exists \$cells->{ \$x0 < 0 ? -(abs(\$x0) << 32 | \$y1) : \$x +0 << 32 | \$y1 } ) + ( exists \$cells->{ \$x0 < 0 ? -(abs(\$x0) << 32 | \$y2) : \$x +0 << 32 | \$y2 } ) + ( exists \$cells->{ \$x2 < 0 ? -(abs(\$x2) << 32 | \$y1) : \$x +2 << 32 | \$y1 } ) + ( exists \$cells->{ \$x2 < 0 ? -(abs(\$x2) << 32 | \$y0) : \$x +2 << 32 | \$y0 } ) + ( exists \$cells->{ \$x2 < 0 ? -(abs(\$x2) << 32 | \$y2) : \$x +2 << 32 | \$y2 } ) ) == 3 and \$new_cells{\$z} = undef; } } \$self->{Cells} = \%new_cells; } sub new { my \$class = shift; my %init_self = ( Cells => {} ); bless \%init_self, \$class; } 1;

Regards, Mario

Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1197314]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (2)
As of 2024-06-15 05:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
Voting Booth?

No recent polls found

Notices?
 • erzuuli ‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.