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_active_grid_coord
my $coord = $life->get_active_text_grid();
This method returns the coordinates of the bounding rectangle for all active points in the grid -- that is, all whose value changed in the most-recent iteration (if any) or whose values were manually changed since the most-recent iteration. An exception is thrown if there are no active points.
The return is a reference to an array containing the minimum and maximum X coordinate followed by the minimum and maximum Y coordinate; that is:
[ $min_x, $max_x, $min_y, $max_y ]
Note that these intervals are closed on both ends. To iterate over the active rows you would specify $min_x .. $max_x
.
get_active_text_grid
print $life->get_active_text_grid( $living, $dead )
This convenience method returns the result of
$life->get_text_grid( $living, $dead,
$life->get_active_grid_coord() )
The arguments are the character to represent an occupied cell and the character to represent an empty cell.
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
my $grid = $life->get_grid( $coord )
This method returns the grid as a reference to an array of array references. The argument is a reference to the minimum and maximum X and Y coordinates:
[ $min_x, $max_x, $min_y, $max_y ]
If the argument is omitted you get the entire grid.
get_grid_coord
my $coord = $life->get_grid_coord();
This method returns the coordinates of the bounding rectangle for the entire grid.
The return is a reference to an array containing the minimum and maximum X coordinate followed by the minimum and maximum Y coordinate. Assuming the size specified when the object was created was
[ $size_x, $size_y ]
the return will be
[ 0, $size_x - 1, 0, $size_y - 1 ]
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_coord
my $coord = $life->get_used_grid_coord()
This method returns the coordinates of the bounding rectangle for all occupied points in the grid.
The return is a reference to an array containing the minimum and maximum X coordinate followed by the minimum and maximum Y coordinate; that is:
[ $min_x, $max_x, $min_y, $max_y ]
Note that these intervals are closed on both ends. To iterate over the active rows you would specify $min_x .. $max_x
.
get_used_text_grid
my ( $x, $y, $grid ) = $life->get_used_text_grid()
print "${grid}at row $x column $y\n"
This convenience method returns the living portion of the grid as text. Specifically, the returns are the number of the first row that contains a living cell, the number of the column that contains the first living cell, and the text grid with each line "\n"
-terminated.
If there are no living cells, nothing is returned.
If called in scalar context you get the living portion of the 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().
SEE ALSO
SUPPORT
Support is by the author. Please file bug reports at https://rt.cpan.org/Public/Dist/Display.html?Name=Game-Life-Faster, https://github.com/trwyant/perl-Game-Life-Faster/issues, or in electronic mail to the author.
AUTHOR
Thomas R. Wyant, III wyant at cpan dot org
COPYRIGHT AND LICENSE
Copyright (C) 2019-2021 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.