Life in two dimensions

From Rosetta Code

Jump to: navigation, search

Programming Task
This is a programming task. It lays out a problem which Rosetta Code users are encouraged to solve, using languages they know.

Code examples should be formatted along the lines of one of the existing prototypes.

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 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.

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.

Contents

[edit] Ada

 
with Ada.Text_IO;  use Ada.Text_IO;
 
procedure Life is
   type Cell is (O, X); -- Two states of a cell
      -- Computation of neighborhood
   function "+" (L, R : Cell) return Integer is
   begin
      case L is
         when O =>
            case R is
               when O => return 0;
               when X => return 1;
            end case;
         when X =>
            case R is
               when O => return 1;
               when X => return 2;
            end case;
      end case;
   end "+";
   function "+" (L : Integer; R : Cell) return Integer is
   begin
      case R is
         when O => return L;
         when X => return L + 1;
      end case;
   end "+";
      -- A colony of cells. The borders are dire and unhabited
   type Petri_Dish is array (Positive range <>, Positive range <>) of Cell;
 
   procedure Step (Culture : in out Petri_Dish) is
      Above : array (Culture'Range (2)) of Cell := (others => O);
      Left  : Cell;
      This  : Cell;
   begin
      for I in Culture'First (1) + 1 .. Culture'Last (1) - 1 loop
         Left := O;
         for J in Culture'First (2) + 1 .. Culture'Last (2) - 1 loop
            case Above        (J-1) + Above        (J) + Above        (J+1) +
                 Left                                  + Culture (I,   J+1) +
                 Culture (I+1, J-1) + Culture (I+1, J) + Culture (I+1, J+1) is
               when 2 =>     -- Survives if alive
                  This := Culture (I, J);
               when 3 =>     -- Survives or else multiplies
                  This := X;
               when others => -- Dies
                  This := O;
            end case;
            Above (J-1) := Left;
            Left        := Culture (I, J);
            Culture (I, J) := This;
         end loop;
         Above (Above'Last - 1) := Left;
      end loop;
   end Step;
 
   procedure Put (Culture : Petri_Dish) is
   begin
      for I in Culture'Range loop
         for J in Culture'Range loop
            case Culture (I, J) is
               when O => Put (' ');
               when X => Put ('#');
            end case;
         end loop;
         New_Line;
      end loop;
   end Put;
 
   Blinker : Petri_Dish := (2..4 =>(O,O,X,O,O), 1|5 =>(O,O,O,O,O));
   Glider  : Petri_Dish :=
             (  (O,O,O,O,O,O,O,O,O,O,O),
                (O,O,X,O,O,O,O,O,O,O,O),
                (O,O,O,X,O,O,O,O,O,O,O),
                (O,X,X,X,O,O,O,O,O,O,O),
                (O,O,O,O,O,O,O,O,O,O,O),
                (O,O,O,O,O,O,O,O,O,O,O)
             );
begin
   for Generation in 1..3 loop
      Put_Line ("Blinker" & Integer'Image (Generation));
      Put (Blinker);
      Step (Blinker);
   end loop;
   for Generation in 1..5 loop
      Put_Line ("Glider" & Integer'Image (Generation));
      Put (Glider);
      Step (Glider);
   end loop;
end Life;
 

The solution uses one cell thick border around square Petri dish as uninhabited dire land. This simplifies computations of neighborhood. Sample output contains 3 generations of the blinker and 5 of the glider:

[edit] Sample output:

Blinker 1

  #
  #
  #

Blinker 2


 ###


Blinker 3

  #
  #
  #

Glider 1

  #
   #
 ###


Glider 2


 # #
  ##
  #

Glider 3


   #
 # #
  ##

Glider 4


  #
   ##
  ##

Glider 5


   #
    #
  ###

[edit] ALGOL 68

The first Life program was written for the PDP-7 by M. J. T. Guy and S. R. Bourne in 1970. It was written in ALGOL 68. c.f. Scientific American 223 (October 1970): 120-123

MODE UNIVERSE = [upb OF class universe, upb OF class universe]BOOL;
 
STRUCT(
  INT upb,
  BOOL lifeless, alive,
  PROC(REF UNIVERSE)VOID init,
  PROC(REF UNIVERSE)STRING repr,
  PROC(REF UNIVERSE, INT, INT)VOID insert glider,
  PROC(REF UNIVERSE)VOID next
) class universe = (
# upb = # 50,
# lifeless = # FALSE,
# alive = # TRUE,
 
# PROC init = # (REF UNIVERSE self)VOID:
    FOR row index FROM LWB self TO UPB self DO
      init row(self[row index, ])
    OD,
 
# PROC repr = # (REF UNIVERSE self)STRING:(
    FORMAT cell = $b("[]", "  ")$,
        horizon = $"+"n(UPB self)("--")"+"l$;
 
    FILE outf; STRING out; associate(outf, out);
    putf(outf, (horizon, $"|"n(UPB self)(f(cell))"|"l$, self, horizon));
    close(outf);
    out
  ),
 
# PROC insert glider = # (REF UNIVERSE self, INT row, col)VOID:(
    self[row-2, col+1] :=          TRUE;
    self[row-1, col+2] :=                TRUE;
    self[row, col:col+2] := (TRUE, TRUE, TRUE )
  ),
 
# PROC next = # (REF UNIVERSE self)VOID:(
    [0:2, LWB self-1:UPB self+1]BOOL window; # Create a 3 row window into the previous generation #
 
    # Set the universe horizon to be lifeless cells #
    init row(window[LWB window, ]);
    window[LWB   self, 2 LWB window] :=
      window[LWB   self, 2 UPB window] :=
        window[UPB window, 2 LWB window] :=
          window[UPB window, 2 UPB window] := lifeless OF class universe;
 
    # Initialise the first row #
    window[LWB self, LWB self:UPB self] := self[LWB self, ];
 
    FOR row FROM LWB self TO UPB self DO
      REF []BOOL next row = window[(row+1) MOD 3, ];
      IF row NE UPB self THEN
        next row[LWB self:UPB self] := self[row+1, ]
      ELSE
        init row(next row)
      FI;
      FOR col FROM LWB self TO UPB self DO
        INT live := 0;
        # Scan for life forms in 3x3 block #
        FOR row FROM row-1 TO row+1 DO
          REF[]BOOL window row = window[row MOD 3, ];
          FOR col FROM col-1 TO col+1 DO
            IF window row[col] THEN live +:= 1 FI
          OD
        OD;
        self[row, col] :=
            IF window[row MOD 3, col] THEN #
1. Any live cell with fewer than two live neighbours dies, as if by loneliness.
2. Any live cell with more than three live neighbours dies, as if by overcrowding.
3. Any live cell with two or three live neighbours lives, unchanged, to the next generation. #
              live -:= 1; # don't count life in current cell #
              live = 3 OR live = 2
            ELSE #
4. Any lifeless cell with exactly three live neighbours comes to life. #
              live = 3
            FI
      OD
    OD
  )
);
 
# Shared static procedure #
PROC init row = (REF [] BOOL xrow)VOID:
  FOR col FROM LWB xrow TO UPB xrow DO xrow[col] := lifeless OF class universe OD;
 
PROC insert gosper gun = (REF [, ] BOOL universe)VOID:(
  [, ]CHAR template = (
    ("________________________X___________"),
    ("______________________X X___________"),
    ("____________XX______XX____________XX"),
    ("___________X___X____XX____________XX"),
    ("XX________X_____X___XX______________"),
    ("XX________X___X_XX____X_X___________"),
    ("__________X_____X_______X___________"),
    ("___________X___X____________________"),
    ("____________XX______________________")
  );
  FOR row TO 1 UPB template DO
    FOR col TO 2 UPB template DO
      universe[row, col] := template[row, col]="X"
    OD
  OD
);
 
UNIVERSE conways universe; (init OF class universe)(conways universe);
 
# Insert a squadron of gliders #
FOR i FROM UPB conways universe OVER 2 BY 5 TO UPB conways universe DO
  (insert glider OF class universe)(conways universe, i, ENTIER (UPB conways universe*1.2 - i*0.9))
OD;
 
# Insert a gosper (repeating) gun #
insert gosper gun(conways universe[5:, :]);
 
STRING home = REPR 27 +"[H";
TO 564 DO
  print((home));
  print((repr OF class universe)(conways universe));
  (next OF class universe)(conways universe)
OD

Output after 564 iterations:

+----------------------------------------------------------------------------------------------------+
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                  [][]                                              |
|                                                []  []                                              |
|                    []                        [][][]        [][]  [][][]                            |
|                    [][][][]                [][][]        []    [][][][]                            |
|[][]                  [][][][]                [][][]        [][]                                    |
|[][]                  []    []                  []  []                                              |
|          []          [][][][]                    [][]                                              |
|          []        [][][][]                []                                                      |
|                    []                        []                                                    |
|                                          [][][]                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                            []                                      |
|                                                        []  []                                      |
|                                                          [][]                                      |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                              [][]                                                                  |
|                              []  []                                      []                        |
|                              []                                            []                      |
|                                                                        [][][]                      |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                                    |
|                                                                                    [][]            |
|                                                                                    [][]            |
|                                                    []                                              |
|                                                    []                                              |
|                                                    []                                              |
|                                                                                                    |
|                                            [][][]      [][][]                                      |
|                                                                                                    |
|                                                    []                                              |
|                                                    []                                              |
|                                                    []                                              |
|                                                                                      []            |
|                                                                                    []  []          |
|                                                                                    []    []        |
|                                                                                      [][]          |
+----------------------------------------------------------------------------------------------------+

[edit] Forth

gencell uses an optimization for the core Game of Life rules: new state = (old state | neighbors == 3).

\ The fast wrapping requires dimensions that are powers of 2.
1 6 lshift constant w \ 64
1 4 lshift constant h \ 16

: rows    w * 2* ;
1 rows constant row
h rows constant size

create world size allot
world   value old
old w + value new

variable gens
: clear  world size erase     0 gens ! ;
: age  new old to new to old  1 gens +! ;

: col+  1+ ;
: col-  1- dup w and + ; \ avoid borrow into row
: row+  row + ;
: row-  row - ;
: wrap ( i -- i ) [ size w - 1- ] literal and ;
: w@ ( i -- 0/1 ) wrap old + c@ ;
: w! ( 0/1 i -- ) wrap old + c! ;

: foreachrow ( xt -- )
  size 0 do  I over execute  row +loop drop ;

: showrow ( i -- ) cr
  old + w over + swap do I c@ if [char] * else bl then emit loop ;
: show  ['] showrow foreachrow  cr ." Generation " gens @ . ;

: sum-neighbors ( i -- i n )
  dup  col- row- w@
  over      row- w@ +
  over col+ row- w@ +
  over col-      w@ +
  over col+      w@ +
  over col- row+ w@ +
  over      row+ w@ +
  over col+ row+ w@ + ;
: gencell ( i -- )
  sum-neighbors  over old + c@
  or 3 = 1 and   swap new + c! ;
: genrow ( i -- )
  w over + swap do I gencell loop ;
: gen  ['] genrow foreachrow  age ;

: life  begin gen 0 0 at-xy show key? until ;
\ patterns
char | constant '|'
: pat ( i addr len -- )
  rot dup 2swap  over + swap do
    I c@ '|' = if drop row+ dup else
    I c@ bl  = 1+ over w!  col+ then
  loop 2drop ;

: blinker s" ***" pat ;
: toad s" ***| ***" pat ;
: pentomino s" **| **| *" pat ;
: pi s" **| **|**" pat ;
: glider s"  *|  *|***" pat ;
: pulsar s" *****|*   *" pat ;
: ship s"  ****|*   *|    *|   *" pat ;
: pentadecathalon s" **********" pat ;
: clock s"  *|  **|**|  *" pat ;
clear  0 glider show
 *
  *
***

Generation 0  ok
gen show

* *
 **
 *
Generation 1  ok

[edit] Fortran

Works with: Fortran version 90 and later

PROGRAM LIFE_2D
  IMPLICIT NONE

  INTEGER, PARAMETER :: gridsize = 10
  LOGICAL :: cells(0:gridsize+1,0:gridsize+1) = .FALSE.
  INTEGER :: i, j, generation=0
  REAL :: rnums(gridsize,gridsize)

!  Start patterns
!  **************
!  cells(2,1:3) = .TRUE.                                                  ! Blinker
!  cells(3,4:6) = .TRUE. ; cells(4,3:5) = .TRUE.                          ! Toad
!  cells(1,2) = .TRUE. ; cells(2,3) = .TRUE. ; cells(3,1:3) = .TRUE.      ! Glider
   cells(3:5,3:5) = .TRUE. ; cells(6:8,6:8) = .TRUE.                      ! Figure of Eight
!  CALL RANDOM_SEED
!  CALL RANDOM_NUMBER(rnums)
!  WHERE (rnums>0.6) cells(1:gridsize,1:gridsize) = .TRUE.                ! Random universe
  
  CALL Drawgen(cells(1:gridsize, 1:gridsize), generation)
  DO generation = 1, 8
     CALL Nextgen(cells)
     CALL Drawgen(cells(1:gridsize, 1:gridsize), generation)
  END DO

CONTAINS

  SUBROUTINE Drawgen(cells, gen)
    LOGICAL, INTENT(IN OUT) :: cells(:,:)
    INTEGER, INTENT(IN) :: gen

    WRITE(*, "(A,I0)") "Generation ", gen 
    DO i = 1, SIZE(cells,1)
       DO j = 1, SIZE(cells,2)
          IF (cells(i,j)) THEN
             WRITE(*, "(A)", ADVANCE = "NO") "#"
          ELSE
             WRITE(*, "(A)", ADVANCE = "NO") " "
          END IF
       END DO
       WRITE(*,*)
    END DO
    WRITE(*,*)
  END SUBROUTINE Drawgen

  SUBROUTINE Nextgen(cells)
    LOGICAL, INTENT(IN OUT) :: cells(0:,0:)
    LOGICAL :: buffer(0:SIZE(cells, 1)-1, 0:SIZE(cells, 2)-1)
    INTEGER :: neighbours, i, j

    buffer = cells   ! Store current status
    DO i = 1, SIZE(cells, 1)-2
       DO j = 1, SIZE(cells, 2)-2
          neighbours = Getneighbours(buffer(i-1:i+1, j-1:j+1))
            
          SELECT CASE(neighbours)
             CASE (0:1)
                cells(i,j) = .FALSE.
 
             CASE (2)
                ! No change
 
             CASE (3)
                cells(i,j) = .TRUE.
 
             CASE (4:8)
                cells(i,j) = .FALSE.
          END SELECT
       END DO
    END DO
 END SUBROUTINE Nextgen

 FUNCTION Getneighbours(neighbourhood)
   INTEGER :: Getneighbours
   LOGICAL, INTENT(IN) :: neighbourhood(:,:)
   INTEGER :: k
   
   Getneighbours = 0
   DO k = 1, 3
      IF (neighbourhood(1,k)) Getneighbours = Getneighbours + 1
   END DO
   DO k = 1, 3, 2
      IF (neighbourhood(2,k)) Getneighbours = Getneighbours + 1
   END DO
   DO k = 1, 3
      IF (neighbourhood(3,k)) Getneighbours = Getneighbours + 1
   END DO
 END FUNCTION Getneighbours

END PROGRAM LIFE_2D

[edit] Sample output:

Blinker
 Generation 0
    
  ### 
    
 
 Generation 1
  #  
  #  
  #  
 
 Generation 2
    
 ###
Figure of Eight (a period eight oscillator)
 Generation 0
           
           
   ###      
   ###      
   ###      
      ###   
      ###   
      ###   
           
           
 
 Generation 1
           
    #       
   # #      
  #   #     
   #   #    
    #   #   
     #   #  
      # #   
       #    
           
 
 Generation 2
           
    #       
   ###      
  ### #     
   #   #    
    #   #   
     # ###  
      ###   
       #    
           
 
 Generation 3
           
   ###      
  #         
  #   #     
  #  # #    
    # #  #  
     #   #  
         #  
      ###   
           
 
 Generation 4
    #       
   ##       
  # ##      
 ###  #     
   # # #    
    # # #   
     #  ### 
      ## #  
       ##   
       #    
 
 Generation 5
   ##       
           
 #   #      
 #    #     
   # # #    
    # # #   
     #    # 
      #   # 
           
       ##   
 
 Generation 6
           
    #       
           
  # ###     
    ## #    
    # ##    
     ### #  
           
       #    
           
 
 Generation 7
           
           
   ##       
   ## #     
       #    
    #       
     # ##   
       ##   
           
         
 
 Generation 8
           
           
   ###      
   ###      
   ###      
      ###   
      ###   
      ###

[edit] Java

public class GameOfLife{
	public static void main(String[] args){
		String[] dish= {
				"_#_",
				"_#_",
				"_#_",};
		int gens= 3;
		for(int i= 0;i < gens;i++){
			System.out.println("Generation " + i + ":");
			print(dish);
			dish= life(dish);
		}
	}
 
	public static String[] life(String[] dish){
		String[] newGen= new String[dish.length];
		for(int row= 0;row < dish.length;row++){//each row
			newGen[row]= "";
			for(int i= 0;i < dish[row].length();i++){//each char in the row
				String above= "";//neighbors above
				String same= "";//neighbors in the same row
				String below= "";//neighbors below
				if(i == 0){//all the way on the left
					//no one above if on the top row
					//otherwise grab the neighbors from above
					above= (row == 0) ? null : dish[row - 1].substring(i,
									i + 2);
					same= dish[row].substring(i + 1, i + 2);
					//no one below if on the bottom row
					//otherwise grab the neighbors from below
					below= (row == dish.length - 1) ? null : dish[row + 1]
									.substring(i, i + 2);
				}else if(i == dish[row].length() - 1){//right
					//no one above if on the top row
					//otherwise grab the neighbors from above
					above= (row == 0) ? null : dish[row - 1].substring(i - 1,
									i + 1);
					same= dish[row].substring(i - 1, i);
					//no one below if on the bottom row
					//otherwise grab the neighbors from below
					below= (row == dish.length - 1) ? null : dish[row + 1]
									.substring(i - 1, i + 1);
				}else{//anywhere else
					//no one above if on the top row
					//otherwise grab the neighbors from above
					above= (row == 0) ? null : dish[row - 1].substring(i - 1,
									i + 2);
					same= dish[row].substring(i - 1, i)
									+ dish[row].substring(i + 1, i + 2);
					//no one below if on the bottom row
					//otherwise grab the neighbors from below
					below= (row == dish.length - 1) ? null : dish[row + 1]
									.substring(i - 1, i + 2);
				}
				int neighbors= getNeighbors(above, same, below);
				if(neighbors < 2 || neighbors > 3){
					newGen[row]+= "_";//<2 or >3 neighbors -> die
				}else if(neighbors == 3){
					newGen[row]+= "#";//3 neighbors -> spawn/live
				}else{
					newGen[row]+= dish[row].charAt(i);//2 neighbors -> stay
				}
			}
		}
		return newGen;
	}
 
	public static int getNeighbors(String above, String same, String below){
		int ans= 0;
		if(above != null){//no one above
			for(char x: above.toCharArray()){//each neighbor from above
				if(x == '#') ans++;//count it if someone is here
			}
		}
		for(char x: same.toCharArray()){//two on either side
			if(x == '#') ans++;//count it if someone is here
		}
		if(below != null){//no one below
			for(char x: below.toCharArray()){//each neighbor below
				if(x == '#') ans++;//count it if someone is here
			}
		}
		return ans;
	}
 
	public static void print(String[] dish){
		for(String s: dish){
			System.out.println(s);
		}
	}
}

Output:

Generation 0:
_#_
_#_
_#_
Generation 1:
___
###
___
Generation 2:
_#_
_#_
_#_

[edit] OCaml

let get g x y =
  try g.(x).(y)
  with _ -> 0
 
let neighbourhood g x y =
  (get g (x-1) (y-1)) +
  (get g (x-1) (y  )) +
  (get g (x-1) (y+1)) +
  (get g (x  ) (y-1)) +
  (get g (x  ) (y+1)) +
  (get g (x+1) (y-1)) +
  (get g (x+1) (y  )) +
  (get g (x+1) (y+1)) 
 
let next_cell g x y =
  let n = neighbourhood g x y in
  match g.(x).(y), n with
  | 1, 0 | 1, 1                      -> 0  (* lonely *)
  | 1, 4 | 1, 5 | 1, 6 | 1, 7 | 1, 8 -> 0  (* overcrowded *)
  | 1, 2 | 1, 3                      -> 1  (* lives *)
  | 0, 3                             -> 1  (* get birth *)
  | _ (* 0, (0|1|2|4|5|6|7|8) *)     -> 0  (* barren *)
 
let copy g = Array.map Array.copy g
 
let next g =
  let width = Array.length g
  and height = Array.length g.(0)
  and new_g = copy g in
  for x = 0 to pred width do
    for y = 0 to pred height do
      new_g.(x).(y) <- (next_cell g x y)
    done
  done;
  (new_g)
 
let print g =
  let width = Array.length g
  and height = Array.length g.(0) in
  for x = 0 to pred width do
    for y = 0 to pred height do
      if g.(x).(y) = 0
      then print_char '.'
      else print_char 'o'
    done;
    print_newline()
  done
 

put the code above in a file named "life.ml", and then use it in the ocaml toplevel like this:

# #use "life.ml";;
val get : int array array -> int -> int -> int = <fun>
val neighbourhood : int array array -> int -> int -> int = <fun>
val next_cell : int array array -> int -> int -> int = <fun>
val copy : 'a array array -> 'a array array = <fun>
val next : int array array -> int array array = <fun>
val print : int array array -> unit = <fun>

# let g = [|
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 1; 1; 1; 0; 0; 0; |];
  [| 0; 0; 0; 1; 1; 1; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
  [| 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; |];
|] ;;
val g : int array array =
  [|[|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 1; 1; 1; 0; 0; 0|];
    [|0; 0; 0; 1; 1; 1; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|];
    [|0; 0; 0; 0; 0; 0; 0; 0; 0; 0|]|]
# print g;;
..........
..........
..........
..........
....ooo...
...ooo....
..........
..........
..........
..........
- : unit = ()
# print (next g) ;;
..........
..........
..........
.....o....
...o..o...
...o..o...
....o.....
..........
..........
..........
- : unit = ()

[edit] Python

This implementation uses defaultdict(int) to create dictionaries that return the result of calling int(), i.e. zero for any key not in the dictionary. This 'trick allows celltable to be initialized to just those keys with a value of 1.

Python allows many types other than strings and ints to be keys in a dictionary. The example uses a dictionary with keys that are a two entry tuple to represent the universe, which also returns a default value of zero. This simplifies the calculation N as out-of-bounds indexing of universe returns zero.

import random
from collections import defaultdict
 
printdead, printlive = '-#'
maxgenerations = 3
cellcount = 3,3
celltable = defaultdict(int, {
 (1, 2): 1,
 (1, 3): 1,
 (0, 3): 1,
 } ) # Only need to populate with the keys leading to life
 
##
## Start States
##
# blinker
u = universe = defaultdict(int)
u[(1,0)], u[(1,1)], u[(1,2)] = 1,1,1
 
## toad
#u = universe = defaultdict(int)
#u[(5,5)], u[(5,6)], u[(5,7)] = 1,1,1
#u[(6,6)], u[(6,7)], u[(6,8)] = 1,1,1
 
## glider
#u = universe = defaultdict(int)
#maxgenerations = 16
#u[(5,5)], u[(5,6)], u[(5,7)] = 1,1,1
#u[(6,5)] = 1
#u[(7,6)] = 1
 
## random start
#universe = defaultdict(int, 
#                       # array of random start values
#                       ( ((row, col), random.choice((0,1)))
#                         for col in range(cellcount[0])
#                         for row in range(cellcount[1])
#                       ) )  # returns 0 for out of bounds
 
for i in range(maxgenerations):
    print "\nGeneration %3i:" % ( i, )
    for row in range(cellcount[1]):
        print "  ", ''.join(str(universe[(row,col)])
                            for col in range(cellcount[0])).replace(
                                '0', printdead).replace('1', printlive)
    nextgeneration = defaultdict(int)
    for row in range(cellcount[1]):
        for col in range(cellcount[0]):
            nextgeneration[(row,col)] = celltable[
                ( universe[(row,col)],
                  -universe[(row,col)] + sum(universe[(r,c)]
                                             for r in range(row-1,row+2)
                                             for c in range(col-1, col+2) )
                ) ]
    universe = nextgeneration

[edit] Sample output:

Generation   0:
   ---
   ###
   ---

Generation   1:
   -#-
   -#-
   -#-

Generation   2:
   ---
   ###
   ---

[edit] Vedit macro language

This implementation uses an edit buffer for data storage and to show results. For purpose of this task, the macro writes the initial pattern in the buffer. However, easier way to enter patterns would be by editing them directly in the edit buffer before starting the macro (in which case the Ins_Text commands would be omitted).

The macro calculates one generation and then waits for a key press before calculating the next generation.

The algorithm used is kind of reverse to the one normally used in Life implementations. Instead of counting cells around each location, this implementation finds each living cell and then increments the values of the 8 surrounding cells. After going through all the living cells, each location of the grid contains an unique ascii value depending on the original value (dead or alive) and the number of living cells in surrounding positions. Two Replace commands are then used to change characters into '.' or 'O' to represent dead and living cells in the new generation.

IT("Generation 0    ") IN
IT(".O.") IN
IT(".O.") IN
IT(".O.")

#9  = 2		  // number of generations to calculate
#10 = Cur_Line
#11 = Cur_Col-1
for (#2 = 1; #2 <= #9; #2++) {
    Update()
    Get_Key("Next gen...", STATLINE)
    Call("calculate")
    itoa(#2, 20, LEFT)
    GL(1) GC(12) Reg_Ins(20, OVERWRITE)
}
EOF
Return

// Calculate one generation
:calculate:
Goto_Line(2)
While (At_EOF == 0) {
  Search("|A",ERRBREAK)		// find next living cell
  #3 = Cur_Line
  #4 = #7 = #8 = Cur_Col
  if (#4 > 1) {			// increment cell at left
      #7 = #4-1
      Goto_Col(#7)
      Ins_Char(Cur_Char+1,OVERWRITE)
  }
  if (#4 < #11) {		// increment cell at right
      #8 = #4+1
      Goto_Col(#8)
      Ins_Char(Cur_Char+1,OVERWRITE)
  }
  if (#3 > 2) {			// increment 3 cells above
      Goto_Line(#3-1)
      Call("inc_3")
  }
  if (#3 < #10) {		// increment 3 cells below
      Goto_Line(#3+1)
      Call("inc_3")
  }
  Goto_Line(#3)
  Goto_Col(#4+1)
}

Replace("[1QR]", "O", REGEXP+BEGIN+ALL)	    // these cells alive
Replace("[/-7P-X]", ".", REGEXP+BEGIN+ALL)  // these cells dead
Return

// increment values of 3 characters in a row
:inc_3:
for (#1 = #7; #1 <= #8; #1++) {
  Goto_Col(#1)
  Ins_Char(Cur_Char+1,OVERWRITE)
}
Return

Output:

Generation 0    
.O.
.O.
.O.

Generation 1    
...
OOO
...

Generation 2    
.O.
.O.
.O.
Personal tools