The Game of Life is a   cellular automaton   devised by the British mathematician   John Horton Conway   in 1970.   It is the best-known example of a cellular automaton.

Conway's game of life is described   here:

A cell   C   is represented by a   1   when alive,   or   0   when dead,   in an   m-by-m   (or m×m)   square array of cells.

We calculate   N   - the sum of live cells in C's   eight-location neighbourhood,   then cell   C   is alive or dead in the next generation based on the following table:

   C   N                 new C
   1   0,1             ->  0  # Lonely
   1   4,5,6,7,8       ->  0  # Overcrowded
   1   2,3             ->  1  # Lives
   0   3               ->  1  # It takes three to give birth!
   0   0,1,2,4,5,6,7,8 ->  0  # Barren

Assume cells beyond the boundary are always dead.

The "game" is actually a zero-player game, meaning that its evolution is determined by its initial state, needing no input from human players.   One interacts with the Game of Life by creating an initial configuration and observing how it evolves.



Task

Although you should test your implementation on more complex examples such as the   glider   in a larger universe,   show the action of the blinker   (three adjoining cells in a row all alive),   over three generations, in a 3 by 3 grid.



References

   Its creator John Conway, explains   the game of life.   Video from numberphile on youtube.
   John Conway   Inventing Game of Life   - Numberphile video.


Related task

   Langton's ant   - another well known cellular automaton.


 
// Life simulator (game). Console (CLI) version.
// It is a 'cellular automaton', and was invented by Cambridge mathematician John Conway.
 
// The Rules
 
// For a space that is 'populated':
//     Each cell with one or no neighbors dies, as if by solitude.
//     Each cell with four or more neighbors dies, as if by overpopulation.
//     Each cell with two or three neighbors survives.
// For a space that is 'empty' or 'unpopulated'
//     Each cell with three neighbors becomes populated.
// -----------------------------------------------------
#g
// Get the terminal-resolution:
terminallines   -- sto tlin
terminalcolumns    sto tcol
// .............................
// Verify the commandline parameters:
argc 3 < { #s ."Usage: " 0 argv print SPACE 1 argv print ." lifeshape-file.txt\n" end }
2 argv 'f !istrue { #s ."The given file ( " 2 argv print ." ) doesn't exist!\n" end }
startingshape 2 argv filetolist // read the file into the list
startingshape maxlinelength sto maxlinlen
neighbour    @tlin @tcol createlist   // Generate the stringarray for the neighbour-calculations
livingspace  @tlin @tcol createlist   // Generate the stringarray for the actual generations
cellscreen   @tlin @tcol createscreen // Generate the stringarray for the visible livingspace
// Calculate offset for the shape ( it must be put to the centre):
@tlin startingshape~ - 2 / sto originlin
@tcol @maxlinlen     - 2 / sto origincol
 
startingshape {{|
{{}} {{|}} {{-}} [[]] 32 > { 1 }{ 0 } sto emblem
livingspace @originlin {{|}} + @origincol {{-}} + @emblem [[^]]
|}}
 
cursoroff
// ==================================================================
{... // infinite loop starts
sbr §renderingsbr
topleft cellscreen !printlist
."Generation: " {...} print fflush // print the number of the generations.
neighbour 0 filluplist // fill up the neighbour list with zero value
// Calculate neighbourhoods
neighbour {{|
{{|}} {{-}} sbr §neighbors
{{}} {{|}} {{-}} @n [[^]] // store the neighbournumber
|}}
 
// Now, kill everybody if the neighbors are less than 2 or more than 3:
neighbour {{|
{{|}} {{-}} sbr §killsbr
|}}
 
// Generate the newborn cells:
neighbour {{|
{{}} {{|}} {{-}} [[]] 3 == { livingspace {{|}} {{-}} 1 [[^]] }
|}}
 
50000 usleep
//2 sleep
...} // infinite loop ends
// ==================================================================
end
killsbr:
sto innerindex sto outerindex
neighbour @outerindex @innerindex [[]] 2 < then §kill
neighbour @outerindex @innerindex [[]] 3 > then §kill
rts
kill: livingspace @outerindex @innerindex 0 [[^]] rts
// ==========================================================
neighbors: // This subroutine calculates the quantity of neighborhood
sto y sto x zero n
livingspace @x ? @tlin --                 @y ? @tcol --                  [[]] sum n // upleft    corner
livingspace @x ? @tlin --                 @y                             [[]] sum n // upmid     corner
livingspace @x ? @tlin --                 @y ++ dup  @tcol == { drop 0 } [[]] sum n // upright   corner
livingspace @x                            @y ? @tcol --                  [[]] sum n // midleft   corner
livingspace @x                            @y ++ dup  @tcol == { drop 0 } [[]] sum n // midright  corner
livingspace @x ++ dup @tlin == { drop 0 } @y ? @tcol --                  [[]] sum n // downleft  corner
livingspace @x ++ dup @tlin == { drop 0 } @y                             [[]] sum n // downmid   corner
livingspace @x ++ dup @tlin == { drop 0 } @y ++ dup  @tcol == { drop 0 } [[]] sum n // downright corner
rts
// ==========================================================
renderingsbr:
livingspace {{|
cellscreen   {{|}} {{-}}
{{}} {{|}} {{-}} [[]] { '* }{ 32 } [[^]]
|}}
rts
 
{ „startingshape” }
{ „livingspace” }
{ „cellscreen” }
{ „innerindex” }
{ „outerindex” }
{ „maxlinlen” }
{ „neighbour” }
{ „originlin” }
{ „origincol” }
{ „emblem” }
{ „tlin” }
{ „tcol” }
{ „x” } { „y” } { „n” }
 
 