NAME
Game::Life::Faster - Plays John Horton Conway's Game of Life
SYNOPSIS
use Game::Life::Faster;
my $game = Game::Life::Faster->new( 20 );
$game->place_points( 10, 10, [
[ 1, 1, 1 ],
[ 1, 0, 0 ],
[ 0, 1, 0 ],
] );
for ( 1 .. 20 ) {
print scalar $game->get_text_grid(), "\n\n";
$game->process();
}
DESCRIPTION
This Perl package is yet another implementation of John Horton Conway's Game of Life. This "game" takes place on a rectangular grid, each of whose cells is considered "living" or "dead". The grid is seeded with an initial population, and then the rules are iterated. In each iteration cells change state based on their current state and how many of the 8 adjacent cells (orthogonally or diagonally) are "living".
In Conway's original formulation, the rules were that a "dead" cell becomes alive if it has exactly two living neighbors, and a "living" cell becomes "dead" unless it has two or three living neighbors.
This implementation was inspired by Game::Life, and is intended to be reasonably compatible with its API. But the internals have been tweaked in a number of ways in order to get better performance, particularly on large but mostly-empty grids.
METHODS
General note: In all methods that specify $x
-$y
coordinates, the $x
is the row number (zero-based) and the $y
is the column number (also zero-based).
This class supports the following public methods:
new
my $life = Game::Life::Faster->new( $size, $breed, $live )
This static method creates a new instance of the game. The arguments are:
- $size
-
This specifies the size of the grid. It must be either a positive integer (which creates a square grid) or a reference to an array containing two positive integers (which creates a rectangular grid of the given width and height). Note that this means we specify number of columns before number of rows, which is inconsistent with the
General note
above, but is consistent with Game::Life.The default is
100
. - $breed
-
This specifies the number of neighbors a "dead" cell needs to become "living". It must be a reference to an array of non-negative integers; the cell will become "living" if its number of neighbors appears in the array. Order is not important.
The default is
[ 3 ]
. - $live
-
This specifies the number of neighbors a "living" cell needs to remain "living". It must be a reference to an array of non-negative integers; the cell will remain "living" if its number of neighbors appears in the array. Order is not important.
clear
This method clears the grid, setting all cells to "dead." It returns its invocant.
This method is an extension to Game::Life.
get_breeding_rules
use Data::Dumper;
print Dumper( [ $self->get_breeding_rules() ] );
This method returns the breeding rule, as specified in the $breed
argument to new(), but as an array rather than an array reference.
Note that this method always returns the data in ascending order. The corresponding Game::Life method returns them in the originally-specified order.
get_grid
use Data::Dumper;
print Dumper( $life->get_grid() );
This method returns the state of the grid, as a reference to an array of array references. The contents of the inner arrays represent the states of the cells, with a true value representing a "living" cell and a false value representing a "dead" cell.
get_living_rules
use Data::Dumper;
print Dumper( [ $self->get_living_rules() ] );
This method returns the living rule, as specified in the $breed
argument to new(), but as an array rather than an array reference.
Note that this method always returns the data in ascending order. The corresponding Game::Life method returns them in the originally-specified order.
get_rule
use Data::Dumper;
print "'$rule' rule is ", Dump( [ $life->get_rule( $rule ) ] );
This method returns the rule specified by the $rule
argument, which must be either 'breed'
or 'live'
. Note that in contrast to set_rule(), this method returns an array rather than an array reference.
Note that this method always returns the data in ascending order. The corresponding Game::Life method returns them in the originally-specified order.
This method is an extension to Game::Life.
get_text_grid
print "$_\n" for $life->get_text_grid( $living, $dead );
This method returns an array of strings representing the state of the grid. The arguments are:
- $living
-
This is the character used to represent a "living" cell.
The default is
'X'
. - $dead
-
This is the character used to represent a "dead" cell.
The default is
'.'
.
As an incompatible change to the same-named method of Game::Life, if called in scalar context this method returns a single string representing the entire grid.
get_used_grid
use Data::Dumper;
print Dumper( $life->get_used_grid() );
This method is similar to get_grid(), but only returns cells that have actually been assigned a value, or acquired a value in the course of processing. Cells that have never had a value are represented by undef
. Trailing undef
s in a row are suppressed. Rows consisting only of unused cells are represented by undef
, not []
, and trailing undef
rows are also suppressed.
place_points
$life->place_points( $x, $y, $array );
This method populates a portion of the grid whose top left corner is specified by $x
and $y
with the state information found in $array
. This is a reference to an array of array references. Each value of the inner array represents the state of the corresponding cell, with a true value representing "living," and a false value representing "dead."
As an incompatible change to the same-named method of Game::Life, points whose value is undef
are ignored.
place_text_points
$life->place_text_points( $x, $y, $living, @array );
This method populates a portion of the grid whose top left corner is specified by $x
and $y
with the state information found in the text of @array
, one row per element. Characters in @array
that match the character in $living
cause the corresponding cells to be made "living." All other characters cause the cell to be made "dead." This method interprets the strings in @array
as new state
As an incompatible change to the same-named method of Game::Life, if @array
contains exactly one element and that element contains new line characters, it is split on new lines, allowing something like
$life->place_text_points( 0, 0, 'X', <<'EOD' );
.X.
..X
XXX
EOD
The heavy lifting is done by set_point_state().
process
$life->process( $iterations );
This method runs the game for the specified number of iterations, which defaults to 1
.
As an incompatible change to the same-named method of Game::Life, the number of points that actually changed state is returned. If $iterations
is greater than 1
, the return represents the last iteration. The corresponding Game::Life method does not have an explicit return
.
set_point
$life->set_point( $x, $y );
This method sets the state of the point at position $x
, $y
of the grid to "living." It returns a true value.
This method is a wrapper for set_point_state(). Because of this, it is fatal to attempt to set a point outside the grid.
set_point_state
$life->set_point_state( $x, $y, $state );
This method sets the state of the point at position $x
, $y
of the grid to $state
. An undef
value is ignored; a true value of $state
sets the cell "living;" a false value sets it "dead." It returns the state.
An exception will be raised if you attempt to set a point "live" which is outside the grid.
This method is an extension to Game::Life.
set_rule
$life->set_rule( $kind, $rule );
This method sets the breed
or live
rules, which govern the transition from "dead" to "living" and "living" to "dead" respectively. The arguments are:
- $kind
-
This argument specifies the kind of rule being set, and must be either
'breed'
or'live'
. - $rule
-
This argument specifies the actual rule. It must be either an array of non-negative integers specifying the number of neighbors that must exist to apply this rule, or a false value to specify the default.
The defaults depend on the value of
$kind
as follows:
This method is an extension to Game::Life.
set_rules
$life->set_rules( $breed, $live );
This method sets the breed
and live
rules from arguments $breed
and $live
respectively. It is implemented in terms of set_rule().
toggle_point
$life->toggle_point( $x, $y );
This method toggles the state of the point at position $x
, $y
of the grid. That is, if it was "dead" it becomes "living," and vice versa. It returns the a true value if the cell became "living," and a false one otherwise.
This method is a wrapper for set_point_state(). Because of this, it is fatal to attempt to toggle a point outside the grid.
unset_point
$life->unset_point( $x, $y );
This method sets the state of the point at position $x
, $y
of the grid to "dead." It returns a false value.
This method is a wrapper for set_point_state().
SERIALIZATION AND DESERIALIZATION
This package supports the Types::Serialiser object serialisation protocol. That is, it has FREEZE()
and THAW()
methods compatible with this specification.
Note that, to the best of my knowledge, only CBOR::XS|CBOR::XS
supports this out of the box. Sereal::Encoder requires at least version 2, with the freeze_callbacks
option set. Whether JSON
supports it or not depends on which JSON
module you are using (and which version of that module you have), and generally you have to turn on allow_tags()
(or something similar) to make it work, and you get non-standard JSON as a result.
SEE ALSO
SUPPORT
Support is by the author. Please file bug reports at http://rt.cpan.org, or in electronic mail to the author.
AUTHOR
Thomas R. Wyant, III wyant at cpan dot org
COPYRIGHT AND LICENSE
Copyright (C) 2019 by Thomas R. Wyant, III
This program is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For more details, see the full text of the licenses in the directory LICENSES.
This program is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.