Conway's Game of Life: Difference between revisions

From Rosetta Code
Content added Content deleted
(→‎{{header|UNIX Shell}}: Add implementation)
Line 16,151: Line 16,151:
# display a matrix
# display a matrix
function disp {
function disp {
# remove sed for more compact display
printf '%s\n' "$@" #| sed 's/./ &/g'
printf '%s\n' "$@" | sed 's/./ &/g'
}
}


Line 16,255: Line 16,256:
.@.
.@.
.@.</pre>
.@.</pre>

=={{header|Ursala}}==
=={{header|Ursala}}==
Three functions are defined:
Three functions are defined:

Revision as of 17:32, 17 August 2022

Task
Conway's Game of Life
You are encouraged to solve this task according to the task description, using any language you may know.

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


Related task



11l

Translation of: Python

<lang 11l>V cellcountx = 6 V cellcounty = 5 V celltable = [(1, 2) = 1,

              (1, 3) = 1,
              (0, 3) = 1]

DefaultDict[(Int, Int), Int] universe universe[(1, 1)] = 1 universe[(2, 1)] = 1 universe[(3, 1)] = 1 universe[(1, 4)] = 1 universe[(2, 4)] = 1 universe[(3, 4)] = 1

L(i) 4

  print("\nGeneration "i‘:’)
  L(row) 0 .< cellcounty
     print(‘  ’(0 .< cellcountx).map(col -> [‘. ’, ‘O ’][:universe[(@row, col)]]).join(‘’))
  DefaultDict[(Int, Int), Int] nextgeneration
  L(row) 0 .< cellcounty
     L(col) 0 .< cellcountx
        nextgeneration[(row, col)] = celltable.get(
             (universe[(row, col)],
             -universe[(row, col)] + sum(multiloop(row-1..row+1,
                                                   col-1..col+1, (r, c) -> :universe[(r, c)]))
             ), 0)
  universe = nextgeneration</lang>

More optimal solution

<lang 11l>V cellcountx = 6 V cellcounty = 5 V universe = [[0B] * cellcountx] * cellcounty universe[1][1] = 1B universe[2][1] = 1B universe[3][1] = 1B universe[1][4] = 1B universe[2][4] = 1B universe[3][4] = 1B V nextgeneration = [[0B] * cellcountx] * cellcounty

L(i) 4

  print("\nGeneration "i‘:’)
  L(row) 0 .< cellcounty
     print(‘  ’, end' ‘’)
     L(col) 0 .< cellcountx
        print(I universe[row][col] {‘O ’} E ‘. ’, end' ‘’)
     print()
  L(row) 0 .< cellcounty
     L(col) 0 .< cellcountx
        V s = 0
        I row > 0
           s = universe[row-1][col]
           I col > 0
              s += universe[row-1][col-1]
           I col < cellcountx-1
              s += universe[row-1][col+1]
        I col > 0
           s += universe[row][col-1]
        I col < cellcountx-1
           s += universe[row][col+1]
        I row < cellcounty-1
           s += universe[row+1][col]
           I col > 0
              s += universe[row+1][col-1]
           I col < cellcountx-1
              s += universe[row+1][col+1]
        nextgeneration[row][col] = I universe[row][col] {s C 2..3} E s == 3
  universe = nextgeneration</lang>
Output:
Generation 0:
  . . . . . .
  . O . . O .
  . O . . O .
  . O . . O .
  . . . . . .

Generation 1:
  . . . . . .
  . . . . . .
  O O O O O O
  . . . . . .
  . . . . . .

Generation 2:
  . . . . . .
  . O O O O .
  . O O O O .
  . O O O O .
  . . . . . .

Generation 3:
  . . O O . .
  . O . . O .
  O . . . . O
  . O . . O .
  . . O O . .

6502 Assembly

Works with: [6502asm.com] version 1.2

<lang 6502asm>randfill: stx $01  ;$200 for indirect

           ldx #$02         ;addressing
           stx $02

randloop: lda $fe ;generate random

           and #$01         ;pixels on the
           sta ($01),Y      ;screen
           jsr inc0103
           cmp #$00
           bne randloop
           lda $02
           cmp #$06
           bne randloop


clearmem: lda #$df ;set $07df-$0a20

           sta $01          ;to $#00
           lda #$07
           sta $02

clearbyte: lda #$00

           sta ($01),Y
           jsr inc0103
           cmp #$20
           bne clearbyte
           lda $02
           cmp #$0a
           bne clearbyte


starttick: copyscreen: lda #$00 ;set up source

           sta $01          ;pointer at
           sta $03          ;$01/$02 and
           lda #$02         ;dest pointer
           sta $02          ;at $03/$04
           lda #$08
           sta $04
           ldy #$00

copybyte: lda ($01),Y ;copy pixel to

           sta ($03),Y      ;back buffer
           jsr inc0103      ;increment pointers
           cmp #$00         ;check to see
           bne copybyte     ;if we're at $600
           lda $02          ;if so, we've
           cmp #$06         ;copied the
           bne copybyte     ;entire screen


conway: lda #$df ;apply conway rules

           sta $01          ;reset the pointer
           sta $03          ;to $#01df/$#07df
           lda #$01         ;($200 - $21)
           sta $02          ;($800 - $21)
           lda #$07
           sta $04

onecell: lda #$00 ;process one cell

           ldy #$01         ;upper cell
           clc
           adc ($03),Y
           ldy #$41         ;lower cell
           clc
           adc ($03),Y

chkleft: tax ;check to see

           lda $01          ;if we're at the
           and #$1f         ;left edge
           tay
           txa
           cpy #$1f
           beq rightcells

leftcells: ldy #$00 ;upper-left cell

           clc
           adc ($03),Y
           ldy #$20         ;left cell
           clc
           adc ($03),Y
           ldy #$40         ;lower-left cell
           clc
           adc ($03),Y

chkright: tax ;check to see

           lda $01          ;if we're at the
           and #$1f         ;right edge
           tay
           txa
           cpy #$1e
           beq evaluate

rightcells: ldy #$02 ;upper-right cell

           clc
           adc ($03),Y
           ldy #$22         ;right cell
           clc
           adc ($03),Y
           ldy #$42         ;lower-right cell
           clc
           adc ($03),Y

evaluate: ldx #$01 ;evaluate total

           ldy #$21         ;for current cell
           cmp #$03         ;3 = alive
           beq storex
           ldx #$00
           cmp #$02         ;2 = alive if
           bne storex       ;c = alive
           lda ($03),Y
           and #$01
           tax

storex: txa ;store to screen

           sta ($01),Y
           jsr inc0103      ;move to next cell

conwayloop: cmp #$e0 ;if not last cell,

           bne onecell      ;process next cell
           lda $02
           cmp #$05
           bne onecell
           jmp starttick    ;run next tick


inc0103: lda $01 ;increment $01

           cmp #$ff         ;and $03 as 16-bit
           bne onlyinc01    ;pointers
           inc $02
           inc $04

onlyinc01: inc $01

           lda $01
           sta $03
           rts</lang>

68000 Assembly

I went a little further and created a 40x30 grid, but this implementation is accurate and does have a blinker in it. As always, thanks to Keith of Chibiakumas for the cartridge header and hardware routines. This is the source code for a Sega Genesis game that you can compile with VASM. (It was tested in the Fusion emulator but it should work anywhere.)

Explanation of the implementation:

  • I'm using the Genesis's foreground tilemap to create the graphics.
  • Grid boundaries are handled by using the classic trick of padding all sides with a value that's not used in the "real" grid, and always counts as a dead cell.
  • Every iteration of the main loop does the same thing: check neighbors of each cell in the grid, write the next generation to a buffer, copy that buffer over the original, and display the output. This way, updates don't impact the outcome of the rest of the cells down the line (which would go against the rules of the game, as all cell births/deaths happen simultaneously.)

Explanation of macros:

  • pushRegs = MOVEM.L ___,-(SP)
  • popRegs = MOVEM.L (SP)+,___
  • pushLong = MOVE.L ___,-(SP)
  • popLong = MOVE.L (SP)+,___

<lang 68000devpac>include "\SrcALL\68000_Macros.asm"

Ram Variables

Cursor_X equ $00FF0000 ;Ram for Cursor Xpos Cursor_Y equ $00FF0000+1 ;Ram for Cursor Ypos

conwayTilemapRam equ $00FF1000 conwayBackupTilemapRam equ $00FF2000

Video Ports

VDP_data EQU $C00000 ; VDP data, R/W word or longword access only VDP_ctrl EQU $C00004 ; VDP control, word or longword writes only

constants

ROWLENGTH equ 40

Traps

DC.L $FFFFFE00 ;SP register value DC.L ProgramStart ;Start of Program Code DS.L 7,IntReturn ; bus err,addr err,illegal inst,divzero,CHK,TRAPV,priv viol DC.L IntReturn ; TRACE DC.L IntReturn ; Line A (1010) emulator DC.L IntReturn ; Line F (1111) emulator DS.L 4,IntReturn ; Reserverd /Coprocessor/Format err/ Uninit Interrupt DS.L 8,IntReturn ; Reserved DC.L IntReturn ; spurious interrupt DC.L IntReturn ; IRQ level 1 DC.L IntReturn ; IRQ level 2 EXT DC.L IntReturn ; IRQ level 3 DC.L IntReturn ; IRQ level 4 Hsync DC.L IntReturn ; IRQ level 5 DC.L IntReturn ; IRQ level 6 Vsync DC.L IntReturn ; IRQ level 7 DS.L 16,IntReturn ; TRAPs DS.L 16,IntReturn ; Misc (FP/MMU)

Header

DC.B "SEGA GENESIS " ;System Name DC.B "(C)CHBI " ;Copyright

	DC.B	"2019.JAN"			;Date

DC.B "ChibiAkumas.com " ; Cart Name DC.B "ChibiAkumas.com " ; Cart Name (Alt) DC.B "GM CHIBI001-00" ;TT NNNNNNNN-RR T=Type (GM=Game) N=game Num R=Revision DC.W $0000 ;16-bit Checksum (Address $000200+) DC.B "J " ;Control Data (J=3button K=Keyboard 6=6button C=cdrom) DC.L $00000000 ;ROM Start DC.L $003FFFFF ;ROM Length DC.L $00FF0000,$00FFFFFF ;RAM start/end (fixed) DC.B " " ;External RAM Data DC.B " " ;Modem Data DC.B " " ;MEMO DC.B "JUE " ;Regions Allowed

Generic Interrupt Handler

IntReturn: rte

Program Start

ProgramStart: ;initialize TMSS (TradeMark Security System) move.b ($A10001),D0 ;A10001 test the hardware version and.b #$0F,D0 beq NoTmss ;branch if no TMSS chip move.l #'SEGA',($A14000);A14000 disable TMSS NoTmss:

Set Up Graphics

lea VDPSettings,A5 ;Initialize Screen Registers move.l #VDPSettingsEnd-VDPSettings,D1 ;length of Settings

move.w (VDP_ctrl),D0 ;C00004 read VDP status (interrupt acknowledge?) move.l #$00008000,d5 ;VDP Reg command (%8rvv)

NextInitByte: move.b (A5)+,D5 ;get next video control byte move.w D5,(VDP_ctrl) ;C00004 send write register command to VDP ; 8RVV - R=Reg V=Value add.w #$0100,D5 ;point to next VDP register dbra D1,NextInitByte ;loop for rest of block


Set up palette and graphics

move.l #$C0000000,d0 ;Color 0 move.l d0,VDP_Ctrl MOVE.W #$0A00,VDP_Data ;BLUE

move.l #$C01E0000,d0 ;Color 0 move.l d0,VDP_Ctrl MOVE.W #$00EE,VDP_Data ;YELLOW

lea Graphics,a0 ;background tiles move.w #(GraphicsEnd-Graphics)-1,d1 ;data size CLR.L D2 ;start loading at tile 0 of VRAM jsr DefineTiles

clr.b Cursor_X ;Clear Cursor XY clr.b Cursor_Y

;Turn on screen move.w #$8144,(VDP_Ctrl);C00004 reg 1 = 0x44 unblank display

TESTING AREA

;load the tilemaps LEA Conway_Tilemap,a3 LEA ConwayTilemapRam,A2 move.l #(Conway_Backup_Tilemap-Conway_Tilemap),d1 JSR LDIR

LEA Conway_Backup_Tilemap,a3 LEA conwayBackupTilemapRam,A2 move.l #(Conway_Backup_Tilemap-Conway_Tilemap),d1 JSR LDIR

CLR.B Cursor_X CLR.B Cursor_Y ;print the tilemap once LEA ConwayTilemapRam,A3 JSR Conway_Print

main:

;do the behavior jsr Conway_CheckTilemap

;copy the tilemap lea conwayBackupTilemapRam,A3 LEA ConwayTilemapRam,A2 move.l #(Conway_Backup_Tilemap-Conway_Tilemap),d1 jsr LDIR

CLR.B Cursor_X CLR.B Cursor_Y ;print the tilemap LEA ConwayTilemapRam,A3 JSR Conway_Print

;repeat JMP main

Conway_CheckTilemap:

;since we don't want the partial results of the checks to mess with later ones, we'll copy the changes to a buffer, and then ;have that buffer clobber the original. That way, all changes to the ecosystem are effectively atomic.

LEA ConwayTilemapRam,A0 LEA conwayBackupTilemapRam,A6 LEA (ROWLENGTH+3,A0),A0 ;actual data starts here LEA (ROWLENGTH+3,A6),A6 ;actual data starts here .loop: MOVE.B (A0),D2 CMP.B #255,D2 BEQ .done CMP.B #2,D2 BEQ .overhead JSR Conway_CheckNeighbors

pushLong D0 JSR popcnt_8 MOVE.B D0,D3 popLong D0

;now implement the table here. ;neighbor bits in D0 ;current state in D2 ;popcnt in D3 ;pointer to where we are in A0

;the only time the current state is relevant to the output, is when popcnt = 2. Otherwise, it's entirely determined by popcnt. CMP.B #4,D3 BCC .DeadCell CMP.B #1,D3 BLS .DeadCell CMP.B #3,D3 BEQ .LiveCell ;else, must be 2. MOVE.B D2,(A6) ;store current value into backup table. bra .overhead .LiveCell: MOVE.B #1,(A6) BRA .overhead .DeadCell: MOVE.B #0,(A6) ;store in backup table. .overhead: ADDA.L #1,A0 ADDA.L #1,A6 JMP .loop .done: RTS

popcnt_8: pushRegs D2-D5 MOVEQ #8-1,D5 MOVEQ #0,D3 .loop: ROR.B #1,D0 BCC .overhead ADDQ.B #1,D3 .overhead: dbra d5,.loop MOVE.B D3,D0 popRegs D2-D5 RTS

Conway_CheckNeighbors: ;A0 = pointer to where we are in the tilemap. ;returns: D0.B = uUrRdDlL ;u = top left ;U = top ;r = top Right ;R = Right ;d = bottom right ;D = bottom ;l = bottom Left ;L = Left pushRegs D2-D5/A0 MOVEQ #0,D0 MOVE.L A0,A1 MOVE.L A1,A2 SUBA.L #ROWLENGTH+2,A1 ;POINTS ABOVE ADDA.L #ROWLENGTH+2,A2 ;POINTS BELOW

MOVE.B (A1),D1 MOVE.B (A2),D2

CMP.B #1,D1 BNE .noUpper BSET #6,D0 bra .next .noUpper: BCLR #6,D0 .next: CheckLower: CMP.B #1,D2 BNE .noLower BSET #2,D0 bra .next .noLower: BCLR #2,D0 .next:

SUBA.L #1,A0 ;left SUBA.L #1,A1 ;upper-left SUBA.L #1,A2 ;lower-left

MOVE.B (A1),D1 MOVE.B (A2),D2 MOVE.B (A0),D3 CheckUpperLeft: CMP.B #1,D1 BNE .noUpperLeft BSET #7,D0 bra .next .noUpperLeft: BCLR #7,D0 .next:

CheckLowerLeft: CMP.B #1,D2 BNE .noLowerLeft BSET #1,D0 bra .next .noLowerLeft: BCLR #1,D0 .next:

CheckLeft: CMP.B #1,D3 BNE .noLeft BSET #0,D0 bra .next .noLeft: BCLR #0,D0 .next:


addA.L #2,A0 addA.L #2,A1 addA.L #2,A2

MOVE.B (A1),D1 MOVE.B (A2),D2 MOVE.B (A0),D3

CheckUpperRight: CMP.B #1,D1 BNE .noUpperRight BSET #5,D0 bra .next .noUpperRight: BCLR #5,D0 .next:

CheckLowerRight: CMP.B #1,D2 BNE .noLowerRight BSET #3,D0 bra .next .noLowerRight: BCLR #3,D0 .next:

CheckRight: CMP.B #1,D3 BNE .noRight BSET #4,D0 bra .next .noRight: BCLR #4,D0 .next: popRegs D2-D5/A0 rts

Conway_Print: ;input: A3 = base address of tilemap MOVE.B (A3)+,D0 CMP.B #255,D0 BEQ .done CMP.B #2,D0 BEQ .skip ;else, print JSR Conway_PrintChar .skip BRA Conway_Print .done rts

Conway_PrintChar: ;Show D0 to screen moveM.l d0-d7/a0-a7,-(sp) and.l #$FF,d0 ;Keep only 1 byte Move.L #$40000003,d5 ;top 4=write, bottom $3=Cxxx range MOVEQ #0,D4 ;Tilemap at $C000+

Move.B (Cursor_Y),D4 rol.L #8,D4 ;move $-FFF to $-FFF---- rol.L #8,D4 rol.L #7,D4 ;2 bytes per tile * 64 tiles per line add.L D4,D5 ;add $4------3

Move.B (Cursor_X),D4 rol.L #8,D4 ;move $-FFF to $-FFF---- rol.L #8,D4 rol.L #1,D4 ;2 bytes per tile add.L D4,D5 ;add $4------3

MOVE.L D5,(VDP_ctrl) ; C00004 write next character to VDP MOVE.W D0,(VDP_data) ; C00000 store next word of name data

addq.b #1,(Cursor_X) ;INC Xpos move.b (Cursor_X),d0 cmp.b #39,d0 bls .nextpixel_Xok jsr NewLine ;If we're at end of line, start newline .nextpixel_Xok: moveM.l (sp)+,d0-d7/a0-a7 rts

don't forget, these are in ROM so we can't write to them directly.
instead, they will be copied to ram and worked with from there.

Conway_Tilemap: ;(screenwidth + 2) by (screenheight+2) DC.B $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$01,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$01,$01,$00,$00,$00,$00,$00,$00,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$01,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$01,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 DC.B $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02 DC.B 255 EVEN Conway_Backup_Tilemap: ;(screenwidth + 2) by (screenheight+2) DC.B $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02 rept 30 DC.B $02,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$02 endr DC.B $02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02,$02 DC.B 255 EVEN

NewLine: addq.b #1,(Cursor_Y) ;INC Y clr.b (Cursor_X) ;Zero X rts


LDIR: ;COPY D1 BYTES FROM A3 TO A2 move.b (a3)+,(a2)+ DBRA D1,LDIR rts

DefineTiles: ;Copy D1 bytes of data from A0 to VDP memory D2 jsr prepareVram ;Calculate the memory location we want to write .again: ; the tile pattern definitions to move.l (a0)+,(VDP_data) dbra d1,.again rts

prepareVram: ;To select a memory location D2 we need to calculate ;the command byte... depending on the memory location pushall ;$7FFF0003 = Vram $FFFF.... $40000000=Vram $0000 move.l d2,d0 and.w #%1100000000000000,d0 ;Shift the top two bits to the far right rol.w #2,d0

and.l #%0011111111111111,d2  ; shift all the other bits left two bytes rol.l #8,d2 rol.l #8,d2

or.l d0,d2 or.l #$40000000,d2 ;Set the second bit from the top to 1 ;#%01000000 00000000 00000000 00000000 move.l d2,(VDP_ctrl) popallRTS: popall rts

Graphics: DC.L $0000000F,$0000000F,$0000000F,$0000000F,$0000000F,$0000000F,$0000000F,$FFFFFFFF DC.L $FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF,$FFFFFFFF GraphicsEnd:

VDPSettings: DC.B $04 ; 0 mode register 1 ---H-1M- DC.B $04 ; 1 mode register 2 -DVdP--- DC.B $30 ; 2 name table base for scroll A (A=top 3 bits) --AAA--- = $C000 DC.B $3C ; 3 name table base for window (A=top 4 bits / 5 in H40 Mode) --AAAAA- = $F000 DC.B $07 ; 4 name table base for scroll B (A=top 3 bits) -----AAA = $E000 DC.B $6C ; 5 sprite attribute table base (A=top 7 bits / 6 in H40) -AAAAAAA = $D800 DC.B $00 ; 6 unused register -------- DC.B $00 ; 7 background color (P=Palette C=Color) --PPCCCC DC.B $00 ; 8 unused register -------- DC.B $00 ; 9 unused register -------- DC.B $FF ;10 H interrupt register (L=Number of lines) LLLLLLLL DC.B $00 ;11 mode register 3 ----IVHL DC.B $81 ;12 mode register 4 (C bits both1 = H40 Cell) C---SIIC DC.B $37 ;13 H scroll table base (A=Top 6 bits) --AAAAAA = $FC00 DC.B $00 ;14 unused register -------- DC.B $02 ;15 auto increment (After each Read/Write) NNNNNNNN DC.B $01 ;16 scroll size (Horiz & Vert size of ScrollA & B) --VV--HH = 64x32 tiles DC.B $00 ;17 window H position (D=Direction C=Cells) D--CCCCC DC.B $00 ;18 window V position (D=Direction C=Cells) D--CCCCC DC.B $FF ;19 DMA length count low LLLLLLLL DC.B $FF ;20 DMA length count high HHHHHHHH DC.B $00 ;21 DMA source address low LLLLLLLL DC.B $00 ;22 DMA source address mid MMMMMMMM DC.B $80 ;23 DMA source address high (C=CMD) CCHHHHHH VDPSettingsEnd: even</lang>

Output:

Screenshot of emulator

ABAP

Works with: ABAP version 7.4 SP05 or Above only

For the proposed task use 10,9;10,10;10,11 on screen field P_POS. Can be left blank for random filling <lang ABAP>

  • &---------------------------------------------------------------------*
  • & Report ZCONWAYS_GAME_OF_LIFE
  • &---------------------------------------------------------------------*
  • & by Marcelo Bovo
  • &---------------------------------------------------------------------*

report zconways_game_of_life line-size 174 no standard page heading

                            line-count 40.

parameters: p_char type c default '#',

           p_pos  type string.

class lcl_game_of_life definition.

 public section.
   data: x_max      type i value 174,
         y_max      type i value 40,
         character  type c value abap_true,
         x          type i,
         y          type i,
         pos        type string,
         offlimits  type i value 9998,
         grid(9999) type c. " every X_MAX characters on grid equals one line on screen
   data: o_random_y type ref to cl_abap_random_int,
         o_random_x type ref to cl_abap_random_int.
   methods: constructor,
     play,
     initial_position,
     initial_grid,
     write,
     change_grid.

endclass.

class lcl_game_of_life implementation.

 method constructor.
   o_random_y = cl_abap_random_int=>create( seed = cl_abap_random=>create( conv i( sy-uzeit ) )->intinrange( low = 1 high = 999999 )
                                            min  = 1
                                            max = y_max ).
   o_random_x = cl_abap_random_int=>create( seed = cl_abap_random=>create( conv i( |{ sy-datum(4) }{ sy-uzeit }| ) )->intinrange( low = 1 high = 999999 )
                                            min  = 1
                                            max = x_max ).
 endmethod.
 method play.
   "fill initial data ramdonly if user hasnt typed any coordenates
   if pos is initial.
     initial_position( ).
   endif.
   initial_grid( ).
   write( ).
 endmethod.
 method initial_position.
   do cl_abap_random_int=>create( "seed = conv i( sy-uzeit )
                                  min  = 50
                                  max = 800 )->get_next( ) times.
     data(lv_index) = sy-index.
     x = o_random_x->get_next( ).
     y = o_random_y->get_next( ).
     p_pos = |{ p_pos }{ switch char1( lv_index when '1' then space else ';' ) }{ y },{ x }|.
   enddo.
 endmethod.
 method initial_grid.
   "Split coordenates
   split p_pos at ';' into table data(lt_pos_inicial) .
   "Sort By Line(Easy to read)
   sort lt_pos_inicial.
   loop at lt_pos_inicial assigning field-symbol(<pos_inicial>).
     split <pos_inicial> at ',' into data(y_char) data(x_char).
     x = x_char.
     y = y_char.
     "Ensure maximum coordenates are not surpassed
     x = cond #( when x <= x_max then x
                  else o_random_x->get_next( ) ).
     y = cond #( when y <= y_max then y
                  else o_random_y->get_next( ) ).
     "Write on string grid
     "Every x_max lines represent one line(Y) on the grid
     data(grid_xy) = ( x_max * y ) + x - x_max - 1.
     grid+grid_xy(1) = character.
   endloop.
 endmethod.
 method write.
   skip to line 1.
   "Write every line on screen
   do y_max times.
     data(lv_index) = sy-index - 1.
     "Write whole line(current line plus number of maximum X characters)
     data(grid_xy) = ( lv_index * x_max ).
     write / grid+grid_xy(x_max) no-gap.
     if grid+grid_xy(x_max) is initial.
       skip.
     endif.
   enddo.
   change_grid( ).
 endmethod.
 method change_grid.
   data(grid_aux) = grid.
   clear grid_aux.
   data(grid_size) = strlen( grid ).
   "Validate neighbours based on previous written grid
   "ABC
   "D.F
   "GHI
   do grid_size + x_max times.
     "Doens't write anything beyond borders
     check sy-index <= x_max * y_max.
     data(grid_xy) = sy-index - 1.
     data(neighbours) = 0.
     "Current Line neighbours
     data(d) = grid_xy - 1.
     data(f) = grid_xy + 1.
     "Line above neighbours
     data(b) = grid_xy - x_max.
     data(a) = b - 1.
     data(c) = b + 1.
     "Line Bellow neighbours
     data(h) = grid_xy + x_max.
     data(g) = h - 1.
     data(i) = h + 1.
     "Previous Neighbours
     neighbours += cond #( when a < 0 then 0 else cond #( when grid+a(1) is not initial then 1 else 0 )   ).
     neighbours += cond #( when b < 0 then 0 else cond #( when grid+b(1) is not initial then 1 else 0 )   ).
     neighbours += cond #( when c < 0 then 0 else cond #( when grid+c(1) is not initial then 1 else 0 )   ).
     neighbours += cond #( when d < 0 then 0 else cond #( when grid+d(1) is not initial then 1 else 0 )   ).
     "Next Neighbours
     neighbours += cond #( when f > grid_size then 0 else cond #( when grid+f(1) is not initial then 1 else 0 )   ).
     neighbours += cond #( when g > grid_size then 0 else cond #( when grid+g(1) is not initial then 1 else 0 )   ).
     neighbours += cond #( when h > grid_size then 0 else cond #( when grid+h(1) is not initial then 1 else 0 )   ).
     neighbours += cond #( when i > grid_size then 0 else cond #( when grid+i(1) is not initial then 1 else 0 )   ).
     grid_aux+grid_xy(1) = cond #( when  neighbours = 3 or (  neighbours = 2  and grid+grid_xy(1) = character )
                                    then character
                                   else space ).
   enddo.
   grid = grid_aux.
 endmethod.

endclass.

start-of-selection.

 set pf-status 'STANDARD_FULLSCREEN'. "Use &REFRESH button with F8 Shortcut to go to next generation
 data(lo_prog) = new lcl_game_of_life( ).
 lo_prog->character = p_char.
 lo_prog->pos = p_pos.
 lo_prog->play( ).

at user-command.

 case sy-ucomm.
   when 'REFR' or '&REFRESH'.
     sy-lsind = 1. "Prevents LIST_TOO_MANY_LEVELS DUMP
     lo_prog->write( ).
   when others.
     leave list-processing.
 endcase.

</lang>

ACL2

<lang Lisp>(defun print-row (row)

  (if (endp row)
      nil
      (prog2$ (if (first row)
                  (cw "[]")
                  (cw "  "))
              (print-row (rest row)))))

(defun print-grid-r (grid)

  (if (endp grid)
      nil
      (progn$ (cw "|")
              (print-row (first grid))
              (cw "|~%")
              (print-grid-r (rest grid)))))

(defun print-line (l)

  (if (zp l)
      nil
      (prog2$ (cw "-")
              (print-line (1- l)))))

(defun print-grid (grid)

  (progn$ (cw "+")
          (print-line (* 2 (len (first grid))))
          (cw "+~%")
          (print-grid-r grid)
          (cw "+")
          (print-line (* 2 (len (first grid))))
          (cw "+~%")))

(defun neighbors-row-r (row)

  (if (endp (rest (rest row)))
      (list (if (first row) 1 0))
      (cons (+ (if (first row) 1 0)
               (if (third row) 1 0))
            (neighbors-row-r (rest row)))))

(defun neighbors-row (row)

  (cons (if (second row) 1 0)
        (neighbors-row-r row)))

(defun zip+ (xs ys)

  (if (or (endp xs) (endp ys))
      (append xs ys)
      (cons (+ (first xs) (first ys))
            (zip+ (rest xs) (rest ys)))))

(defun counts-row (row)

  (if (endp row)
      nil
      (cons (if (first row) 1 0)
            (counts-row (rest row)))))

(defun neighbors-r (grid prev-counts curr-counts next-counts

                        prev-neighbors curr-neighbors
                        next-neighbors)
  (if (endp (rest grid))
      (list (zip+ (zip+ prev-counts
                        prev-neighbors)
                  (neighbors-row (first grid))))
      (cons (zip+ (zip+ (zip+ prev-counts next-counts)
                        (zip+ prev-neighbors next-neighbors))
                  curr-neighbors)
            (neighbors-r (rest grid)
                         curr-counts
                         next-counts
                         (counts-row (third grid))
                         curr-neighbors
                         next-neighbors
                         (neighbors-row (third grid))))))

(defun neighbors (grid)

  (neighbors-r grid
               nil
               (counts-row (first grid))
               (counts-row (second grid))
               nil
               (neighbors-row (first grid))
               (neighbors-row (second grid))))

(defun life-rules-row (life neighbors)

  (if (or (endp life) (endp neighbors))
      nil
      (cons (or (and (first life)
                     (or (= (first neighbors) 2)
                         (= (first neighbors) 3)))
                (and (not (first life))
                     (= (first neighbors) 3)))
            (life-rules-row (rest life) (rest neighbors)))))

(defun life-rules-r (grid neighbors)

  (if (or (endp grid) (endp neighbors))
      nil
      (cons (life-rules-row (first grid) (first neighbors))
            (life-rules-r (rest grid) (rest neighbors)))))

(defun conway-step (grid)

  (life-rules-r grid (neighbors grid)))

(defun conway (grid steps)

  (if (zp steps)
      nil
      (progn$ (print-grid grid)
              (conway (conway-step grid) (1- steps)))))</lang>
Output:
+------+
|  []  |
|  []  |
|  []  |
+------+
+------+
|      |
|[][][]|
|      |
+------+
+------+
|  []  |
|  []  |
|  []  |
+------+

Ada

<lang ada> WITH Ada.Text_IO; USE Ada.Text_IO;

PROCEDURE Life IS

  SUBTYPE Cell IS Natural RANGE 0 .. 1;
  TYPE Petri_Dish IS ARRAY (Positive RANGE <>, Positive RANGE <>) OF Cell;
  PROCEDURE Step (Gen : IN OUT Petri_Dish) IS
     Above       : ARRAY (Gen'Range (2)) OF Cell := (OTHERS => 0);
     Left, This  : Cell;
  BEGIN
     FOR I IN Gen'First (1) + 1 .. Gen'Last (1) - 1 LOOP
        Left := 0;
        FOR J IN Gen'First (2) + 1 .. Gen'Last (2) - 1 LOOP
           This := (CASE Above (J - 1) + Above (J) + Above (J + 1) +
                         Left			    + Gen (I, J + 1) +
                         Gen (I + 1, J - 1) + Gen (I + 1, J) 	+ Gen (I + 1, J + 1) IS
                       WHEN 2      => Gen (I, J),
                       WHEN 3      => 1,
                       WHEN OTHERS => 0);
           Above (J - 1):= Left;
           Left         := Gen (I, J);
           Gen (I, J) 	 := This;
        END LOOP;
        Above (Above'Last - 1) := Left;
     END LOOP;
  END Step;

  PROCEDURE Put (Gen : Petri_Dish) IS
  BEGIN
     FOR I IN Gen'Range (1) LOOP
        FOR J IN Gen'Range (2) LOOP
           Put ( if Gen (I, J) = 0 then " " else "#");
        END LOOP;
        New_Line;
     END LOOP;
  END Put;

  Blinker : Petri_Dish := (2 .. 4 => (0, 0, 1, 0, 0), 1 | 5 => (0, 0, 0, 0, 0));
  Glider  : Petri_Dish (1..6,1..11):= (2 => (3 => 1, others => 0),
                                       3 => (4 => 1, others => 0),
                                       4 => (2|3|4=>1, others => 0),
                                       others => (others => 0));
  PROCEDURE Put_And_Step_Generation (N : Positive; Name : String; P : IN OUT Petri_Dish) IS
  BEGIN
     FOR Generation IN 1 .. N LOOP
        Put_Line (Name & Generation'Img);
        Put (P);
        Step (P);
     END LOOP;
  END Put_And_Step_Generation;

BEGIN

  Put_And_Step_Generation (3, "Blinker", Blinker);
  Put_And_Step_Generation (5, "Glider", Glider);

END Life;</lang> 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:

Output:
Blinker 1

  #
  #
  #

Blinker 2


 ###


Blinker 3

  #
  #
  #

Glider 1

  #
   #
 ###


Glider 2


 # #
  ##
  #

Glider 3


   #
 # #
  ##

Glider 4


  #
   ##
  ##

Glider 5


   #
    #
  ###

ALGOL 68

See Conway's Game of Life/ALGOL 68

APL

APL2 (Dialog) Example in one line

APL \ 1130 example (very old APL dialect via simulator)
https://web.archive.org/web/20160313204013/http://www.farnik.com/wiki/uploads/lifeAPL1130.jpg

From: APL \ 1130 Samples

The following APL \ 1130 code will need APL385 font installed to display correctly.
See Download APL TT Font
<lang>

     ∇LIFE[⎕]∇

[0] NG←LIFE CG;W [1] W←CG+(¯1⊖CG)+(1⊖CG)+(¯1⌽CG)+(1⌽CG) [2] W←W+(1⊖1⌽CG)+(¯1⊖1⌽CG)+(1⊖¯1⌽CG)+(¯1⊖¯1⌽CG) [3] NG←(3=W)+(CG∧4=W)

     ∇
     RP←5 5⍴0 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 0 0
     RP

0 0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 1 0 0 0 0 0 0 0

     LIFE RP

0 0 0 0 0 0 1 1 1 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0

     LIFE LIFE RP

0 0 1 0 0 0 1 1 0 0 1 0 0 1 0 0 1 1 0 0 0 0 0 0 0

</lang>

AppleScript

This handler creates and returns a "universe" script object initialised with given "seed" text and dimensions. For convenience, the seed text's visible characters can be anything, the set-up code itself replacing them with "■" characters. The use of the returned universe is demo'd later.

<lang applescript>use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later use framework "Foundation" -- For the regex at the top of newUniverse() use scripting additions

-- The characters to represent the live and dead cells. property live : "■" -- character id 9632 (U+25A0). property dead : space -- Infinite universes are expensive to maintain, so only a local region of universe is represented here. -- Its invisible border is a wall of "dead" cells one cell deep, lined with a two-cell buffer layer into which -- objects nominally leaving the region can disappear without being seen to hit the wall or bouncing back. property borderThickness : 3

on newUniverse(seed, {w, h})

   -- Replace every visible character in the seed text with "■" and every horizontal space with a space.
   set seed to current application's class "NSMutableString"'s stringWithString:(seed)
   set regex to current application's NSRegularExpressionSearch
   tell seed to replaceOccurrencesOfString:("\\S") withString:(live) options:(regex) range:({0, its |length|()})
   tell seed to replaceOccurrencesOfString:("\\h") withString:(dead) options:(regex) range:({0, its |length|()})
   -- Ensure the universe dimensions are at least equal to the number of lines and the length of the longest.
   set seedLines to paragraphs of (seed as text)
   set lineCount to (count seedLines)
   if (lineCount > h) then set h to lineCount
   set seedWidth to 0
   repeat with thisLine in seedLines
       set lineLength to (count thisLine)
       if (lineLength > seedWidth) then set seedWidth to lineLength
   end repeat
   if (seedWidth > w) then set w to seedWidth
   
   -- Get a new universe.
   script universe
       -- State lists. These will contain or be lists of 0s and 1s and will include the border cells.
       property newState : {}
       property previousState : {}
       property currentRow : {}
       property rowAbove : {}
       property rowBelow : {}
       property replacementRow : {}
       -- Equivalent text lists. These will only cover what's in the bounded region.
       property lineList : {}
       property characterGrid : {}
       property currentLineCharacters : {}
       -- Precalculated border cell indices.
       property rightInnerBuffer : borderThickness + w + 1
       property rightOuterBuffer : rightInnerBuffer + borderThickness - 2
       property bottomInnerBuffer : borderThickness + h + 1
       property bottomOuterBuffer : bottomInnerBuffer + borderThickness - 2
       -- Generation counter.
       property counter : 0
       -- Temporary lists used in the set-up.
       property rowTemplate : {}
       property lineCharacterTemplate : {}
       
       -- Built-in handlers. Both return text representing a universe state and
       -- a boolean indicating whether or not the state's the same as the previous one.
       on nextState()
           set astid to AppleScript's text item delimiters
           set AppleScript's text item delimiters to ""
           copy newState to previousState
           set currentRow to beginning of my previousState
           set rowBelow to item 2 of my previousState
           -- Check each occupiable cell in each occupiable row of the 'previousState' grid, including the buffer cells.
           -- If warranted by the number of live neighbours, edit the equivalent cell in 'newState' and,
           -- if within the region's bounds, change the corresponding text character too.
           repeat with r from 2 to bottomOuterBuffer
               set rowAbove to currentRow
               set currentRow to rowBelow
               set rowBelow to item (r + 1) of my previousState
               set replacementRow to item r of my newState
               set rowCrossesRegion to ((r comes after borderThickness) and (r comes before bottomInnerBuffer))
               if (rowCrossesRegion) then set currentLineCharacters to item (r - borderThickness) of my characterGrid
               set lineChanged to false
               repeat with c from 2 to rightOuterBuffer
                   set liveNeighbours to ¬
                       (item (c - 1) of my rowAbove) + (item c of my rowAbove) + (item (c + 1) of my rowAbove) + ¬
                       (item (c - 1) of my currentRow) + (item (c + 1) of my currentRow) + ¬
                       (item (c - 1) of my rowBelow) + (item c of my rowBelow) + (item (c + 1) of my rowBelow)
                   if (item c of my currentRow is 1) then
                       if ((liveNeighbours < 2) or (liveNeighbours > 3)) then
                           set item c of my replacementRow to 0
                           if ((c comes after borderThickness) and (c comes before rightInnerBuffer) and (rowCrossesRegion)) then
                               set item (c - borderThickness) of my currentLineCharacters to dead
                               set lineChanged to true
                           else if ((c is 3) or (c is rightOuterBuffer) or (r is 3) or (r is bottomOuterBuffer)) then
                               -- This is a fudge to dissolve "bombers" entering the buffer zone.
                               set item (c - 1) of my replacementRow to -1
                               set item c of item (r - 1) of my newState to -1
                           end if
                       end if
                   else if (liveNeighbours is 3) then
                       set item c of my replacementRow to 1
                       if ((c comes after borderThickness) and (c comes before rightInnerBuffer) and (rowCrossesRegion)) then
                           set item (c - borderThickness) of my currentLineCharacters to live
                           set lineChanged to true
                       end if
                   end if
               end repeat
               if (lineChanged) then set item (r - borderThickness) of my lineList to currentLineCharacters as text
           end repeat
           set AppleScript's text item delimiters to astid
           set counter to counter + 1
           set last item of my lineList to "Generation " & counter
           
           return currentState()
       end nextState
       
       on currentState()
           set noChanges to (newState = previousState)
           if (noChanges) then ¬
               set last item of my lineList to (last item of my lineList) & " (all dead, still lifes, or left the universe)"
           set astid to AppleScript's text item delimiters
           set AppleScript's text item delimiters to return
           set stateText to lineList as text
           set AppleScript's text item delimiters to astid
           
           return {stateText, noChanges}
       end currentState
   end script
   
   -- Set the universe's start conditions.
   -- Build a row template list containing w + 2 * borderThickness zeros
   -- and a line character template list containing w 'dead' characters.
   repeat (borderThickness * 2) times
       set end of universe's rowTemplate to 0
   end repeat
   repeat w times
       set end of universe's rowTemplate to 0
       set end of universe's lineCharacterTemplate to dead
   end repeat
   set astid to AppleScript's text item delimiters
   set AppleScript's text item delimiters to ""
   set blankLine to universe's lineCharacterTemplate as text
   
   -- Use the templates to populate lists representing the universe's conditions.
   -- Firstly the top border rows ('newState' list only).
   repeat borderThickness times
       copy universe's rowTemplate to end of universe's newState
   end repeat
   -- Then enough rows and text lines to centre the input roughly halfway down the grid.
   set headroom to (h - lineCount) div 2
   repeat headroom times
       copy universe's rowTemplate to end of universe's newState
       copy universe's lineCharacterTemplate to end of universe's characterGrid
       set end of universe's lineList to blankLine
   end repeat
   -- Then the rows and lines representing the input itself, centring it roughly halfway across the grid.
   set textInset to (w - seedWidth) div 2
   set stateInset to textInset + borderThickness
   repeat with thisLine in seedLines
       copy universe's rowTemplate to universe's currentRow
       copy universe's lineCharacterTemplate to universe's currentLineCharacters
       repeat with c from 1 to (count thisLine)
           set thisCharacter to character c of thisLine
           set item (textInset + c) of universe's currentLineCharacters to thisCharacter
           set item (stateInset + c) of universe's currentRow to (thisCharacter is live) as integer
       end repeat
       set end of universe's newState to universe's currentRow
       set end of universe's characterGrid to universe's currentLineCharacters
       set end of universe's lineList to universe's currentLineCharacters as text
   end repeat
   set AppleScript's text item delimiters to astid
   -- Then the rows and lines beneath and the bottom border.
   repeat (h - (headroom + lineCount)) times
       copy universe's rowTemplate to end of universe's newState
       copy universe's lineCharacterTemplate to end of universe's characterGrid
       set end of universe's lineList to blankLine
   end repeat
   repeat borderThickness times
       copy universe's rowTemplate to end of universe's newState
   end repeat
   -- Add a generation counter display line to the end of the line list.
   set end of universe's lineList to "Generation 0"
   -- Lose the no-longer-needed template lists.
   set universe's rowTemplate to missing value
   set universe's lineCharacterTemplate to universe's rowTemplate
   
   return universe

end newUniverse</lang>

In conjunction with the above, this fulfills the task as set:

<lang applescript>on RCTask(seed, dimensions, maxGenerations)

   -- Create a universe and start a list with its initial state.
   set universe to newUniverse(seed, dimensions)
   set {stateText} to universe's currentState()
   set output to {stateText}
   -- Add successive states to the list.
   repeat maxGenerations times
       set {stateText, noChanges} to universe's nextState()
       set end of output to stateText
       if (noChanges) then exit repeat
   end repeat
   -- Coerce the states to a single text, each followed by a short line of dashes.
   set astid to AppleScript's text item delimiters
   set AppleScript's text item delimiters to linefeed & "-----" & linefeed & linefeed
   set output to (output as text) & linefeed & "-----"
   set AppleScript's text item delimiters to astid
   
   return output

end RCTask

-- Return text containing the original and three generations of a "blinker" in a 3 x 3 grid. return RCTask("***", {3, 3}, 3)</lang>

Output:

<lang applescript>" ■■■

Generation 0


■ 
■ 
■ 

Generation 1



■■■

Generation 2


■ 
■ 
■ 

Generation 3


"</lang>

This alternative to the task code runs an animation of a "Gosper glider gun" in TextEdit, the AppleScriptable text editor included with macOS. The animation's achieved by replacing the entire text of a document with successive universe states. It's faster than it sounds, but the universe size specified shouldn't be much greater than 150 x 150 with current machines.

<lang applescript>on runGame(seed, dimensions, maxGenerations)

   -- Create an RTF file set up for Menlo-Regular 12pt, half spacing, and a reasonable window size.
   set fontName to "Menlo-Regular"
   set fontSize to 12
   set viewScale to fontSize * 12.4 -- Seems to work well.
   set {w, h} to dimensions
   
   set RTFHeaders to "{\\rtf1\\ansi\\ansicpg1252\\cocoartf1671\\cocoasubrtf600

{\\fonttbl\\f0\\fnil\\fcharset0 " & fontName & ";} {\\colortbl;\\red255\\green255\\blue255;} {\\*\\expandedcolortbl;;} \\margl1440\\margr1440\\vieww" & (w * viewScale as integer) & "\\viewh" & ((h + 1) * viewScale as integer) & "\\viewkind0 \\pard\\sl120\\slmult1\\pardirnatural\\partightenfactor0 \\f0\\fs" & (fontSize * 2) & " \\cf0 }" -- Contains a space as body text for TextEdit to see as an 'attribute run'.

   set RTFFile to ((path to temporary items as text) & "Conway's Game of Life.rtf") as «class furl»
   set fRef to (open for access RTFFile with write permission)
   try
       set eof fRef to 0
       write RTFHeaders as «class utf8» to fRef
       close access fRef
   on error errMsg number errNum
       close access fRef
       error errMsg number errNum
   end try
   -- Open the file as a document in TextEdit.
   tell application "TextEdit"
       activate
       tell document "Conway's Game of Life.rtf" to if (it exists) then close saving no
       set CGoLDoc to (open RTFFile)
   end tell
   
   -- Create a universe and display its initial state in the document window.
   set universe to newUniverse(seed, dimensions)
   set {stateText} to universe's currentState()
   tell application "TextEdit" to set CGoLDoc's first attribute run to stateText
   -- Get and display successive states.
   repeat maxGenerations times
       set {stateText, noChanges} to universe's nextState()
       tell application "TextEdit" to set CGoLDoc's first attribute run to stateText
       if (noChanges) then exit repeat
   end repeat

end runGame

set GosperGliderGun to " *

                     * *
           **      **            ** 
          *   *    **            **
    • * * **
    • * * ** * *
         *     *       *
          *   *
           **"

-- Run for 500 generations in a 100 x 100 universe. runGame(GosperGliderGun, {100, 100}, 500)</lang>

ARM Assembly

Works with: TI-Nspire

<lang ARM Assembly> .string "PRG"

lcd_ptr .req r4 active_fb .req r5 inactive_fb .req r6 offset_r .req r7 backup_fb .req r8

@ start push {r4-r10, r12, lr}

ldr lcd_ptr, =0xC0000000 @ address of the LCD controller adr offset_r, offsets ldrh r0, [offset_r, #6] @ 0xffff is already in memory because -1 is in the offsets table str r0, [lcd_ptr, #0x200] @ set up paletted colors: 1 is black, 0 is white

ldr r2, [lcd_ptr, #0x18] @ load lcd configuration bic r2, #14 orr r2, #6 @ Set color mode to 8 bpp, paletted str r2, [lcd_ptr, #0x18]

ldr backup_fb, [lcd_ptr, #0x10] @ Save address of OS framebuffer

@ allocate a buffer for game state / framebuffer ldr r0, =153600 @ 320 * 240 * 2 add r0, #8 svc #5 @ malloc push {r0} orr inactive_fb, r0, #7 add inactive_fb, #1 add active_fb, inactive_fb, #76800

@ fill buffer with random ones and zeroes ldr r10, =76800 mov r9, #0 1: subs r10, r10, #1 strb r9, [active_fb, r10] @ zero other framebuffer svc #206 @ rand syscall and r0, r0, #1 strb r0, [inactive_fb, r10] bne 1b

@ set first and last rows to zero mov r2, #320 mov r1, #0 mov r0, inactive_fb push {r1,r2} svc #7 @ memset pop {r1,r2} ldr r3, =76480 add r0, r0, r3 svc #7

@ beginning of main loop, swap framebuffers 3: ldr r0, =76480 @ 320 * 239 str inactive_fb, [lcd_ptr, #0x10] mov inactive_fb, active_fb ldr active_fb, [lcd_ptr, #0x10]

@ per-pixel loop 2: mov r1, #16 @ 8 * 2 mov r2, #0 sub r0, #1

@ loop to count up neighboring living cells 1: subs r1, #2 ldrsh r3, [offset_r, r1] @ cant use lsl #1 add r3, r3, r0 ldrb r3, [active_fb, r3] add r2, r2, r3 bne 1b @ at end of loop, r1 and r3 can be discarded

@ decides whether the cell should live or die based on neighbors ldrb r1, [active_fb, r0] add r2, r2, r1 teq r2, #3 moveq r1, #1 teqne r2, #4 movne r1, #0 strb r1, [inactive_fb, r0] teq r0, #320 bne 2b

@ checks if the escape key is pressed ldr r0, =0x900E001C ldr r1, [r0] tst r1, #0x80 beq 3b

str backup_fb, [lcd_ptr, #0x10] @ restores OS framebuffer

pop {r0} svc #6 @ free buffer pop {r4-r10, r12, pc} offsets: .hword -321, -320, -319, -1, 1, 319, 320, 321 </lang> http://i.imgur.com/kV9RirP.gif

AutoHotkey

ahk discussion <lang autohotkey>rows := cols := 10  ; set grid dimensions i = -1,0,1, -1,1, -1,0,1  ; neighbors' x-offsets j = -1,-1,-1, 0,0, 1,1,1  ; neighbors' y-offsets StringSplit i, i, `,  ; make arrays StringSplit j, j, `,

Loop % rows {  ; setup grid of checkboxes

  r := A_Index, y := r*17-8                     ; looks good in VISTA
  Loop % cols {
     c := A_Index, x := c*17-5
     Gui Add, CheckBox, x%x% y%y% w17 h17 vv%c%_%r% gCheck
  }

} Gui Add, Button, % "x12 w" x+2, step  ; button to step to next generation Gui Show Return

Check:

  GuiControlGet %A_GuiControl%                  ; manual set of cells

Return

ButtonStep:  ; move to next generation

  Loop % rows {
     r := A_Index
     Loop % cols {
        c := A_Index, n := 0
        Loop 8                                  ; w[x,y] <- new states
           x := c+i%A_Index%, y := r+j%A_Index%, n += 1=v%x%_%y%
        GuiControl,,v%c%_%r%,% w%c%_%r% := v%c%_%r% ? n=2 || n=3 : n=3
     }
  }
  Loop % rows {                                 ; update v[x,y] = states
     r := A_Index
     Loop % cols
        v%A_Index%_%r% := w%A_Index%_%r%
  }

Return

GuiClose:  ; exit when GUI is closed ExitApp</lang>

AWK

50x20 grid (hardcoded) with empty border, filled with random cells, running for 220 generations, using ANSI escape-codes for output to terminal: <lang AWK> BEGIN {

c=220; d=619; i=10000; 
printf("\033[2J");      # Clear screen
while(i--) m[i]=0;
while(d--) m[int(rand()*1000)]=1;
while(c--){
 for(i=52; i<=949; i++){
  d=m[i-1]+m[i+1]+m[i-51]+m[i-50]+m[i-49]+m[i+49]+m[i+50]+m[i+51];
  n[i]=m[i];
  if(m[i]==0 && d==3) n[i]=1;
  else if(m[i]==1 && d<2) n[i]=0;
       else if(m[i]==1 && d>3) n[i]=0;
 }
 printf("\033[1;1H");   # Home cursor
 for(i=1;i<=1000;i++)   # gridsize 50x20
 {
  if(n[i]) printf("O"); else printf(".");
  m[i]=n[i];
  if(!(i%50)) printf("\n");
 }
 printf("%3d\n",c);     # Countdown
 x=30000; while(x--) ;  # Delay
}

} </lang>

Output:

Finally

..................................................
..........................................OO......
..........................................O.O.....
...........................................O......
......................................OOO.......OO
................................................OO
....................................O.....O.......
....................................O.....O.......
....................................O.....O.......
..................................................
......................................OOO.........
..................................................
..................................................
..................................................
..O...............................................
.O.O..............................................
O.O...........OO...........OO.....................
.O............OO.........O..O.....................
.........................OOO......................
..................................................
  0

Axe

This example is in need of improvement:

Improve performance and add a way to interactively seed the map.

This implementation uses the full screen buffer instead of a 3x3 grid. This naive, unoptimized version gets less than 1 FPS. <lang axe>Full

While getKey(0) End

ClrDraw .BLINKER Pxl-On(45,45) Pxl-On(46,45) Pxl-On(47,45)

.GLIDER Pxl-On(1,1) Pxl-On(2,2) Pxl-On(2,3) Pxl-On(3,1) Pxl-On(3,2)

Repeat getKey(0)

DispGraph
EVOLVE()
RecallPic
ClrDrawʳ

End Return

Lbl EVOLVE For(Y,0,63)

For(X,0,95)
 0→N
 For(B,Y-1,Y+1)
  For(A,X-1,X+1)
   pxl-Test(A,B)?N++
  End
 End
 pxl_Test(X,Y)?N--
 If N=3??(N=2?pxl-Test(X,Y))
  Pxl-On(X,Y)ʳ
 Else
  Pxl-Off(X,Y)ʳ
 End
End

End Return</lang>

BASIC

BASIC256

"Thunderbird" methuselah evolution in the Game of Life (created with BASIC-256)

Saving to PNG files function is omited. You can find it in the Galton box animation example.

<lang basic256># Conway's_Game_of_Life

X = 59 : Y = 35 : H = 4

fastgraphics graphsize X*H,Y*H

dim c(X,Y) : dim cn(X,Y) : dim cl(X,Y) </lang><lang basic256>

  1. Thunderbird methuselah

c[X/2-1,Y/3+1] = 1 : c[X/2,Y/3+1] = 1 : c[X/2+1,Y/3+1] = 1 c[X/2,Y/3+3] = 1 : c[X/2,Y/3+4] = 1 : c[X/2,Y/3+5] = 1

s = 0 do color black rect 0,0,graphwidth,graphheight alive = 0 : stable = 1 s = s + 1 for y = 0 to Y-1 for x = 0 to X-1 xm1 = (x-1+X)%X : xp1 = (x+1+X)%X ym1 = (y-1+Y)%Y : yp1 = (y+1+Y)%Y cn[x,y] = c[xm1,y] + c[xp1,y] cn[x,y] = c[xm1,ym1] + c[x,ym1] + c[xp1,ym1] + cn[x,y] cn[x,y] = c[xm1,yp1] + c[x,yp1] + c[xp1,yp1] + cn[x,y] if c[x,y] = 1 then if cn[x,y] < 2 or cn[x,y] > 3 then cn[x,y] = 0 else cn[x,y] = 1 alive = alive + 1 end if else if cn[x,y] = 3 then cn[x,y] = 1 alive = alive + 1 else cn[x,y] = 0 end if end if if c[x,y] then if cn[x,y] then if cl[x,y] then color purple # adult if not cl[x,y] then color green # newborn else if cl[x,y] then color red # old if not cl[x,y] then color yellow # shortlived end if rect x*H,y*H,H,H end if next x next y refresh pause 0.06 # Copy arrays for i = 0 to X-1 for j = 0 to Y-1 if cl[i,j]<>cn[i,j] then stable = 0 cl[i,j] = c[i,j] c[i,j] = cn[i,j] next j next i until not alive or stable

if not alive then print "Died in "+s+" iterations" color black rect 0,0,graphwidth,graphheight refresh else print "Stabilized in "+(s-2)+" iterations" end if</lang>

Output:
 Stabilized in 243 iterations

BBC BASIC

<lang bbcbasic> dx% = 64

     dy% = 64
     DIM old&(dx%+1,dy%+1), new&(dx%+1,dy%+1)
     VDU 23,22,dx%*4;dy%*4;16,16,16,0
     OFF
     
     REM Set blinker:
     old&(50,50) = 1 : old&(50,51) = 1 : old&(50,52) = 1
     REM Set glider:
     old&(5,7) = 1 : old&(6,7) = 1 : old&(7,7) = 1 : old&(7,6) = 1 : old&(6,5) = 1
     
     REM Draw initial grid:
     FOR X% = 1 TO dx%
       FOR Y% = 1 TO dy%
         IF old&(X%,Y%) GCOL 11 ELSE GCOL 4
         PLOT 69, X%*8-6, Y%*8-4
       NEXT
     NEXT X%
     
     REM Run:
     GCOL 4,0
     REPEAT
       FOR X% = 1 TO dx%
         FOR Y% = 1 TO dy%
           S% = old&(X%-1,Y%) + old&(X%,Y%-1) + old&(X%-1,Y%-1) + old&(X%+1,Y%-1) + \
           \    old&(X%+1,Y%) + old&(X%,Y%+1) + old&(X%-1,Y%+1) + old&(X%+1,Y%+1)
           O% = old&(X%,Y%)
           N% = -(S%=3 OR (O%=1 AND S%=2))
           new&(X%,Y%) = N%
           IF N%<>O% PLOT X%*8-6, Y%*8-4
         NEXT
       NEXT X%
       SWAP old&(), new&()
       WAIT 30
     UNTIL FALSE</lang>
Output:


CASIO BASIC

<lang casiobasic>Filename:JG VIDA Cls 20→D D+2→F 1→E {F,F}→Dim Mat A {F,F}→Dim Mat B {F,F}→Dim Mat C Fill(0,Mat A) Fill(0,Mat B) Fill(0,Mat C) "PONDERACION 1"?→G "PONDERACION 2"?→H For 1→I To D For 1→J To D RanInt#(1,G)→R If R≦H:Then 0→Mat A[I+1,J+1] Else 1→Mat A[I+1,J+1] IfEnd Next Next Goto 2 Lbl 1 Mat A→Mat C Mat B→Mat A Lbl 2 For 1→I To D For 1→J To D I+1→K J+1→L K→M L+20→N If Mat C[K,L]=0:Then If Mat A[K,L]=1:Then For 0→R To 2 For 0→S To 2 PxlOn 3I+R-2,3J+S-2 Next Next IfEnd IfEnd If Mat C[K,L]=1:Then If Mat A[K,L]=0:Then For 0→R To 2 For 0→S To 2 PxlOff 3I+R-2,3J+S-2 Next Next IfEnd IfEnd Next Next For 1→I To D For 1→J To D 0→C I+1→K J+1→L Mat A[I,J]=1⇨C+1→C Mat A[I+1,J]=1⇨C+1→C Mat A[I+2,J]=1⇨C+1→C Mat A[I+2,J+1]=1⇨C+1→C Mat A[I+2,J+2]=1⇨C+1→C Mat A[I+1,J+2]=1⇨C+1→C Mat A[I,J+2]=1⇨C+1→C Mat A[I,J+1]=1⇨C+1→C If Mat A[K,L]=1:Then C<2⇨0→Mat B[K,L] C>3⇨0→Mat B[K,L] IfEnd If Mat A[K,L]=0:Then C=3⇨1→Mat B[K,L] IfEnd Next Next Goto 1 </lang>

FreeBASIC

<lang freebasic>' FreeBASIC Conway's Game of Life ' May 2015 ' 07-10-2016 cleanup/little changes ' moved test inkey outside the ScreenLock - ScreenUnLock block ' compile: fbc -s gui

Const As UInteger grid = 300 '480 by 480 Const As UInteger gridy = grid Const As UInteger gridx = grid Const As UInteger pointsize = 5 'pixels Const As UInteger steps = 10 Dim As UInteger gen, n, neighbours, x, y, was

Dim As String press

Const As UByte red = 4 'red is color 6 Const As UByte white = 15 'color Const As UByte black = 0 'color

'color 0 normaly is black 'color 1 normaly is dark blue 'color 2 normaly is green Const As UInteger bot = 35 'this is 35 lines from the top of the page Dim As UByte old( grid + 10, grid +10), new_( grid +10, grid +10)

'Set blinker: ' old( 160, 160) =1: old( 160, 170) =1 : old( 160, 180) =1

'Set blinker: ' old( 160, 20) =1: old( 160, 30) =1 : old( 160, 40) =1

'Set blinker: ' old( 20, 20) =1: old( 20, 30) =1 : old( 20, 40) =1

'Set glider: ' old( 50, 70) =1: old( 60, 70) =1: old( 70, 70) =1 ' old( 70, 60) =1: old( 60, 50) =1

' http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life ' Thunderbird methuselah 'X = 59 : Y = 35 : H = 4 'c[X/2-1,Y/3+1] = 1 : c[X/2,Y/3+1] = 1 : c[X/2+1,Y/3+1] = 1 'c[X/2,Y/3+3] = 1 : c[X/2,Y/3+4] = 1 : c[X/2,Y/3+5] = 1

'xb = 59 : yb = 35 ' old( Xb/2-1,Yb/3+1) =1: old(Xb/2,Yb/3+1) =1: old(Xb/2+1,Yb/3+1) =1 ' old( Xb/2,Yb/3+3) =1: old(Xb/2,Yb/3+4) =1 :old(Xb/2,Yb/3+5) = 1 'r-pentomino ' old( 150,140) =1: old( 160,140) =1 ' old( 140,150) =1 :old( 150,150) =1 ' old( 150,160) =1

'Die Hard around 150 generations ' old( 150,140) =1: old(160,140) =1 : old(160,150) =1 ' old( 200,150) =1: old(210,150) =1 : old(210,130) = 1 : old(220,150) = 1

'Acorn around 450 generations ' it looks like this: ' 0X ' 000X ' XX00XXX old( 180,200) =1 old( 200,210) =1 old( 170,220) =1 : old( 180,220) =1 : old( 210,220) =1 : old( 220,220) =1 : old( 230,220) =1

Screen 20 'Resolution 800x600 with at least 256 colors

Color white Line (10, 10) - (gridx + 10, gridy + 10),,B 'box from top left to bottom right

Locate bot, 1 'Use a standard place on the bottom of the page Color white Print " Welcome to Conway's Game of Life" Print " Using a constrained playing field (300x300), the Acorn seed runs" Print " for about 450 generations before it becomes stable (or stale)." Print " Enter any key to start" Beep Sleep

Do ' flush the key input buffer

 press = Inkey

Loop Until press = "" 'Print " "

'Draw initial grid For x = 10 To gridX Step steps

 For y = 10 To gridY Step steps
   Color white 'old(x,y)
   If old(x,y) = 1 Then Circle (x + pointsize, y + pointsize), pointsize,,,,, F
 Next y

Next x ' Locate bot, 1 Color white Print " Welcome to Conway's Game of Life" Print " Using a constrained playing field, the Acorn seed runs for " Print " about 450 generations before it becomes stable (or stale). " Color red Print " Enter spacebar to continue or pause, ESC to stop" Sleep ' Do ' flush the key input buffer

 press = Inkey

Loop Until press = ""

Do

 gen = gen + 1
 Locate bot+5,1
 Color white
 Print " Gen = "; gen
 ScreenLock
 For x = 10 To gridX Step steps
   For y = 10 To gridY Step steps
     'find number of live neighbours
     neighbours = old( x - steps, y - steps) +old( x , y - steps)
     neighbours = neighbours + old( x + steps, y -steps)
     neighbours = neighbours + old( x - steps, y) + old( x + steps, y)
     neighbours = neighbours + old( x - steps, y + steps)
     neighbours = neighbours + old( x, y + steps) +old( x + steps, y + steps)
     was =old( x, y)
     If was =0 Then
       If neighbours =3 Then N =1 Else N =0
     Else
       If neighbours =3  Or neighbours =2 Then N =1 Else N =0
     End If
     new_( x, y) = N
     If n = 2 Then Color white
     If n = 1 Then Color red
     If n = 0 Then Color black
     Circle (x + pointsize, y + pointsize), pointsize,,,,, F
   Next y
 Next x
 Color white
 Line (10, 10) - (gridx + 10, gridy + 10),,B  'box from top left to bottom right
 ' Locate bot,1
 '
 't = timer
 'do
 'loop until timer > t + .2
 ScreenUnlock
 ' might not be slow enough
 Sleep 70, 1  ' ignore key press
 press = Inkey
 If press = " " Then
   Do      ' flush the key input buffer
     press = Inkey
   Loop Until press = ""
   Do      ' wait until a key is pressed
     press = Inkey
   Loop Until press <> ""
 End If
 If press = Chr(27) Then Exit Do
 ' mouse click on close window "X"
 If press = Chr(255)+"k" Then End ' stop and close window
 For x =10 To gridX Step steps
   For y =10 To gridY Step steps
     old( x, y) =new_( x, y)
   Next y
 Next x

Loop ' UNTIL press = CHR(27) 'return to do loop up top until "esc" key is pressed.

Color white Locate bot+3,1 Print Space(55) 'clear instructions Locate bot+6,1 Print " Press any key to exit " Sleep End</lang>

GFA Basic

<lang> ' ' Conway's Game of Life ' ' 30x30 world held in an array size 32x32 ' world is in indices 1->30, 0 and 31 are always false, for neighbourhoods ' DIM world!(32,32) DIM ns%(31,31) ! used to hold the neighbour counts clock%=1 ' ' run the world ' @setup_world @open_window DO

 @display_world
 t$=INKEY$
 EXIT IF t$="q" ! need to hold key down to exit
 @update_world
 DELAY 0.5 ! delay of 0.5s needed in compiled version

LOOP @close_window ' ' Setup the world, with a blinker in one corner and a glider in the other ' PROCEDURE setup_world

 ARRAYFILL world!(),FALSE
 ' blinker in lower-right
 world!(25,25)=TRUE
 world!(26,25)=TRUE
 world!(27,25)=TRUE
 ' glider in top-left
 world!(2,2)=TRUE
 world!(3,3)=TRUE
 world!(3,4)=TRUE
 world!(2,4)=TRUE
 world!(1,4)=TRUE

RETURN ' ' Count the number of neighbours of the point i,j ' (Assume i/j +/- 1 will not fall out of world) ' FUNCTION count_neighbours(i%,j%)

 LOCAL count%,l%
 count%=0
 FOR l%=-1 TO 1
   IF world!(i%+l%,j%-1)
     count%=count%+1
   ENDIF
   IF world!(i%+l%,j%+1)
     count%=count%+1
   ENDIF
 NEXT l%
 IF world!(i%-1,j%)
   count%=count%+1
 ENDIF
 IF world!(i%+1,j%)
   count%=count%+1
 ENDIF
 RETURN count%

ENDFUNC ' ' Update the world one step ' PROCEDURE update_world

 LOCAL i%,j%
 ' compute neighbour counts and store
 FOR i%=1 TO 30
   FOR j%=1 TO 30
     ns%(i%,j%)=@count_neighbours(i%,j%)
   NEXT j%
 NEXT i%
 ' update the world cells
 FOR i%=1 TO 30
   FOR j%=1 TO 30
     IF world!(i%,j%)
       SELECT ns%(i%,j%)
       CASE 0,1
         world!(i%,j%)=FALSE ! LONELY
       CASE 2,3
         world!(i%,j%)=TRUE ! LIVES
       CASE 4,5,6,7,8
         world!(i%,j%)=FALSE ! OVERCROWDED
       ENDSELECT
     ELSE
       IF ns%(i%,j%)=3
         world!(i%,j%)=TRUE ! BIRTH
       ELSE
         world!(i%,j%)=FALSE ! BARREN
       ENDIF
     ENDIF
   NEXT j%
 NEXT i%
 ' update the clock
 clock%=clock%+1

RETURN ' ' Display the world in window ' PROCEDURE display_world

 LOCAL offsetx%,offsety%,i%,j%,x%,y%,scale%
 @clear_window
 ' show clock
 VSETCOLOR 2,0,0,0
 DEFTEXT 2
 PRINT AT(5,1);"Clock: ";clock%
 ' offset from top-left of display
 offsetx%=10
 offsety%=10
 ' colour to display active cell
 VSETCOLOR 1,15,0,0
 DEFFILL 1
 ' scale of display
 scale%=9
 ' display each cell in world
 FOR i%=1 TO 30
   FOR j%=1 TO 30
     IF world!(i%,j%)
       ' display active cell
       x%=offsetx%+scale%*i%
       y%=offsety%+scale%*j%
       PBOX x%,y%,x%+scale%,y%+scale%
     ENDIF
   NEXT j%
 NEXT i%

RETURN ' ' Manage window for display ' PROCEDURE open_window

 OPENW 1
 CLEARW 1

RETURN ' PROCEDURE clear_window

 VSETCOLOR 0,15,15,15
 DEFFILL 0
 PBOX 0,0,300,300

RETURN ' PROCEDURE close_window

 CLOSEW 1

RETURN </lang>

GW-BASIC

Allows a blinker to be loaded. It also has a routine for randomising the grid; common objects like blocks, gliders, etc turn up semi-frequently so it won't take long to verify that these all work.

<lang gwbasic>10 REM Conway's Game of Life 20 REM 30x30 grid, padded with zeroes as the boundary 30 DIM WORLD(31, 31, 1) 40 RANDOMIZE TIMER 50 CUR = 0 : BUF = 1 60 CLS 70 SCREEN 2 80 LOCATE 5,10: PRINT "Press space to perform one iteration" 90 LOCATE 6,10: PRINT "B to load a blinker" 100 LOCATE 7,10: PRINT "R to randomise the world" 110 LOCATE 8,10: PRINT "Q to quit" 120 K$ = INKEY$ 130 IF K$=" " THEN GOSUB 250: GOSUB 180 140 IF K$="B" OR K$="b" THEN GOSUB 400: GOSUB 180 150 IF K$="R" OR K$="r" THEN GOSUB 480: GOSUB 180 160 IF K$="Q" OR K$="q" THEN SCREEN 0: END 170 GOTO 120 180 REM draw the world 190 FOR XX=1 TO 30 200 FOR YY=1 TO 30 210 PSET (XX, YY), 15*WORLD(XX, YY, CUR) 220 NEXT YY 230 NEXT XX 240 RETURN 250 REM perform one iteration 260 FOR XX=1 TO 30 270 FOR YY=1 TO 30 280 SM=0 290 SM = SM + WORLD(XX-1, YY-1, CUR) + WORLD(XX, YY-1, CUR) + WORLD(XX+1, YY-1, CUR) 300 SM = SM + WORLD(XX-1, YY, CUR) + WORLD(XX+1, YY, CUR) 310 SM = SM + WORLD(XX-1, YY+1, CUR) + WORLD(XX, YY+1, CUR) + WORLD(XX+1, YY+1, CUR) 320 IF SM<2 OR SM>3 THEN WORLD(XX, YY, BUF) = 0 330 IF SM=3 THEN WORLD(XX, YY, BUF) = 1 340 IF SM=2 THEN WORLD(XX,YY,BUF) = WORLD(XX,YY,CUR) 350 NEXT YY 360 NEXT XX 370 CUR = BUF : REM exchange identities of current and buffer 380 BUF = 1 - BUF 390 RETURN 400 REM produces a vertical blinker at the top left corner, and blanks the rest 410 FOR XX=1 TO 30 420 FOR YY=1 TO 30 430 WORLD(XX,YY,CUR) = 0 440 IF XX=2 AND YY<4 THEN WORLD(XX, YY, CUR) = 1 450 NEXT YY 460 NEXT XX 470 RETURN 480 REM randomizes the world with a density of 1/2 490 FOR XX = 1 TO 30 500 FOR YY = 1 TO 30 510 WORLD(XX, YY, CUR) = INT(RND*2) 520 NEXT YY 530 NEXT XX 540 RETURN</lang>

Liberty BASIC

It will run slow for grids above say 25! <lang lb>

     nomainwin
     gridX = 20
     gridY = gridX
     mult      =500 /gridX
     pointSize =360 /gridX
     dim old( gridX +1, gridY +1), new( gridX +1, gridY +1)

'Set blinker:

     old( 16, 16) =1: old( 16, 17) =1 : old( 16, 18) =1

'Set glider:

     old(  5,  7) =1: old(  6,  7) =1: old(  7,  7) =1
     old(  7,  6) =1: old(  6,  5) =1
     WindowWidth  =570
     WindowHeight =600
     open "Conway's 'Game of Life'." for graphics_nsb_nf as #w
     #w "trapclose [quit]"
     #w "down ; size "; pointSize
     #w "fill black"

'Draw initial grid

     for x = 1 to gridX
       for y = 1 to gridY
         '#w "color "; int( old( x, y) *256); " 0 255"
         if old( x, y) <>0 then #w "color red" else #w "color darkgray"
         #w "set "; x *mult +20; " "; y *mult +20
       next y
     next x

' ______________________________________________________________________________ 'Run

     do
       for x =1 to gridX
         for y =1 to gridY
           'find number of live Moore neighbours
           neighbours =old( x -1, y -1) +old( x, y -1) +old( x +1, y -1)+_
                       old( x -1, y)                   +old( x +1, y   )+_
                       old( x -1, y +1) +old( x, y +1) +old( x +1, y +1)
           was =old( x, y)
           if was =0 then
               if neighbours =3 then N =1 else N =0
           else
               if neighbours =3  or neighbours =2 then N =1 else N =0Tail Recursive
           end if
           new( x, y) = N
           '#w "color "; int( N /8 *256); " 0 255"
           if N <>0 then #w "color red" else #w "color darkgray"
           #w "set "; x *mult +20; " "; y *mult +20
         next y
       next x
       scan

'swap

       for x =1 to gridX
         for y =1 to gridY
           old( x, y) =new( x, y)
         next y
       next x

'Re-run until interrupted...

     loop until FALSE

'User shutdown received

   [quit]
   close #w
   end

</lang>

MSX Basic

<lang basic> 10 DEFINT A-Z 20 DIM L(16,16), N(16,16) 30 M = 16 40 CLS 50 PRINT "PRESS A KEY TO START..."; 60 W = RND(1) 70 IF INKEY$ = "" THEN 60 80 CLS 100 FOR I=1 TO M 110 FOR J=1 TO M 120 IF RND(1)>=.7 THEN N(I,J) = 1 ELSE N(I,J) = 0 130 NEXT J 140 NEXT I 1000 FOR I=0 TO M+1 1010 LOCATE I,0 : PRINT "+"; 1020 LOCATE I,M+1 : PRINT "+"; 1030 LOCATE 0,I : PRINT "+"; 1040 LOCATE M+1,I : PRINT "+"; 1050 NEXT I 1080 G=0 1090 LOCATE 1,M+3 : PRINT USING "#####";G 1100 FOR I=1 TO M 1110 FOR J=1 TO M 1115 W = N(I,J) : L(I,J) = W 1120 LOCATE I,J 1130 IF W=0 THEN PRINT " "; ELSE PRINT "*"; 1160 NEXT J 1170 NEXT I 1180 FOR I=1 TO M 1190 FOR J=1 TO M 1200 NC=0 1210 FOR K=I-1 TO I+1 1215 IF K=0 OR K>M THEN 1260 1220 FOR W=J-1 TO J+1 1230 IF W=0 OR W>M OR (K=I AND W=J) THEN 1250 1240 NC = NC + L(K,W) 1250 NEXT W 1260 NEXT K 1270 IF NC=2 THEN N(I,J)=L(I,J) : GOTO 1300 1280 IF NC=3 THEN N(I,J)=1 ELSE N(I,J)=0 1300 NEXT J 1310 NEXT I 1350 G=G+1 1360 GOTO 1090 </lang>

PureBasic

<lang PureBasic>EnableExplicit Define.i x, y ,Xmax ,Ymax ,N Xmax = 13 : Ymax = 20 Dim world.i(Xmax+1,Ymax+1) Dim Nextworld.i(Xmax+1,Ymax+1)

Glider test
------------------------------------------
world(1,1)=1 : world(1,2)=0 : world(1,3)=0
world(2,1)=0 : world(2,2)=1 : world(2,3)=1
world(3,1)=1 : world(3,2)=1 : world(3,3)=0
------------------------------------------

OpenConsole() EnableGraphicalConsole(1) ClearConsole() Print("Press any key to interrupt") Repeat

 ConsoleLocate(0,2)
 PrintN(LSet("", Xmax+2, "-"))
;---------- endless world ---------
 For y = 1 To Ymax
   world(0,y)=world(Xmax,y)
   world(Xmax+1,y)=world(1,y)  
 Next
 For x = 1 To Xmax
   world(x,0)=world(x,Ymax)
   world(x,Ymax+1)=world(x,1)
 Next
 world(0     ,0     )=world(Xmax,Ymax)
 world(Xmax+1,Ymax+1)=world(1   ,1   )
 world(Xmax+1,0     )=world(1   ,Ymax)
 world(     0,Ymax+1)=world(Xmax,1   )
;---------- endless world ---------
 For y = 1 To Ymax
   Print("|") 
   For x = 1 To Xmax
     Print(Chr(32+world(x,y)*3))
     N = world(x-1,y-1)+world(x-1,y)+world(x-1,y+1)+world(x,y-1)
     N + world(x,y+1)+world(x+1,y-1)+world(x+1,y)+world(x+1,y+1)
     If (world(x,y) And (N = 2 Or N = 3))Or (world(x,y)=0 And N = 3)
       Nextworld(x,y)=1      
     Else
       Nextworld(x,y)=0
     EndIf
   Next
   PrintN("|")
 Next
 PrintN(LSet("", Xmax+2, "-"))
 Delay(100) 
 ;Swap world() , Nextworld()    ;PB  <4.50
 CopyArray(Nextworld(), world());PB =>4.50
 Dim Nextworld.i(Xmax+1,Ymax+1) 

Until Inkey() <> ""

PrintN("Press any key to exit"): Repeat: Until Inkey() <> ""</lang> Sample output:


QBasic

El código es de Ben Wagner (bwgames.org)
The code is from Ben Wagner (bwgames.org)
Yo solo lo transcrito y comento al español.
I just transcribed it and comment it in Spanish. <lang qbasic>SCREEN 9, 0, 0, 1

RANDOMIZE TIMER

WINDOW (0, 0)-(80, 80)

'La matrizA es la actual, la matrizB es la siguiente iteración 'ArrayA is current, arrayB is next iteration DIM matrizA(-1 TO 81, -1 TO 81) DIM matrizB(-1 TO 81, -1 TO 81)

'Aleatorizar las celdas de matrizA, 'Randomize cells in arrayA, 'y establecer las de matrizB a 0 'and set those of matrixB to 0 y = 0 DO x = 0 DO x = x + 1 matrizA(x, y) = INT(RND + .5)

       matrizB(x, y) = 0
   LOOP UNTIL x > 80
   
   y = y + 1

LOOP UNTIL y > 80

--- Bucle Principal --- --- Main Loop --- DO

   CLS   
   'Dibuja la matriz 
   'Draw the matrix
   y = 0
   DO
       x = 0			 
       DO
           IF matrizA(x, y) = 1 THEN LINE (x, y)-(x + 1, y + 1), 1, BF
           x = x + 1
       LOOP UNTIL x > 80
       
       y = y + 1
   LOOP UNTIL y > 80
   
   'Cuenta el recuento de la celda circundante
   'Counts the count of the surrounding cell
    'Luego aplica la operación a la celda
    'Then apply the operation to the cell
   y = 0
   DO
       x = 0
       DO
           'Cuenta las células circundantes
           'Count the surrounding cells
           cuenta = 0
           
           IF matrizA(x - 1, y + 1) = 1 THEN cuenta = cuenta + 1
           IF matrizA(x, y + 1) = 1 THEN cuenta = cuenta + 1
           IF matrizA(x + 1, y + 1) = 1 THEN cuenta = cuenta + 1
           IF matrizA(x - 1, y) = 1 THEN cuenta = cuenta + 1
           IF matrizA(x + 1, y) = 1 THEN cuenta = cuenta + 1
           IF matrizA(x - 1, y - 1) = 1 THEN cuenta = cuenta + 1
           IF matrizA(x, y - 1) = 1 THEN cuenta = cuenta + 1
           IF matrizA(x + 1, y - 1) = 1 THEN cuenta = cuenta + 1
           
           'Aplica las operaciones
           'Apply the operations
           'Muerte
           'Death
           IF matrizA(x, y) = 1 THEN
               IF cuenta = 2 OR cuenta = 3 THEN matrizB(x, y) = 1 ELSE matrizB(x, y) = 0
           END IF
           
           'Nacimiento
           'Birth
           IF matrizA(x, y) = 0 THEN
               IF cuenta = 3 THEN matrizB(x, y) = 1 ELSE matrizB(x, y) = 0
           END IF
           x = x + 1
       LOOP UNTIL x > 80
       
       y = y + 1
   LOOP UNTIL y > 80
   
   'Actualiza la matriz con la nueva matriz que hemos calculado.
   'Update the matrix with the new matrix that we have calculated.
   y = 0
   DO
       x = 0
       DO
           x = x + 1
           matrizA(x, y) = matrizB(x, y)
       LOOP UNTIL x > 80
       y = y + 1
       
   LOOP UNTIL y > 80
   PCOPY 0, 1

LOOP WHILE INKEY$ = ""</lang>

Sinclair ZX81 BASIC

Requires at least 2k of RAM. Expects to find a square array of "0" and "1" characters, L$(), giving the initial configuration. You can build this up by issuing commands in immediate mode and then run the program by entering GOTO 1000, but it's probably easier—assuming you can spare some RAM—to write the setup into the program using line numbers below 1000.

The graphics character in lines 1030 to 1060 can be obtained by typing SHIFT9 then SHIFTH, and the one in line 1130 by typing SHIFT9 then SPACE. <lang basic>1000 LET M=LEN L$(1) 1010 DIM N$(M,M) 1020 FOR I=0 TO M+1 1030 PRINT AT I,0;"▩" 1040 PRINT AT I,M+1;"▩" 1050 PRINT AT 0,I;"▩" 1060 PRINT AT M+1,I;"▩" 1070 NEXT I 1080 LET G=0 1090 PRINT AT 1,M+3;G 1100 FOR I=1 TO M 1110 FOR J=1 TO M 1120 IF L$(I,J)="0" THEN GOTO 1150 1130 PRINT AT I,J;"■" 1140 GOTO 1160 1150 PRINT AT I,J;" " 1160 NEXT J 1170 NEXT I 1180 FOR I=1 TO M 1190 FOR J=1 TO M 1200 LET N=0 1210 FOR K=I-1 TO I+1 1220 FOR L=J-1 TO J+1 1230 IF K=0 OR K>M OR L=0 OR L>M OR (K=I AND L=J) THEN GOTO 1250 1240 LET N=N+VAL L$(K,L) 1250 NEXT L 1260 NEXT K 1270 LET N$(I,J)=L$(I,J) 1280 IF N<=1 OR N>=4 THEN LET N$(I,J)="0" 1290 IF N=3 THEN LET N$(I,J)="1" 1300 NEXT J 1310 NEXT I 1320 FOR I=1 TO M 1330 LET L$(I)=N$(I) 1340 NEXT I 1350 LET G=G+1 1360 GOTO 1090</lang> To run the blinker, add this code: <lang basic>10 DIM L$(3,3) 20 LET L$(1)="000" 30 LET L$(2)="111" 40 LET L$(3)="000"</lang> A screenshot of it running can be found here.

To try a random starting configuration on a 16x16 grid, use this: <lang basic>10 DIM L$(16,16) 20 FOR I=1 TO 16 30 FOR J=1 TO 16 40 LET L$(I,J)="0" 50 IF RND>=.7 THEN LET L$(I,J)="1" 60 NEXT J 70 NEXT I</lang> A screenshot is here.

TI-83 BASIC

This implementation is loosely based on the Processing Version. It uses the home screen and draws cells as "X"s. It is extremely slow, and limited to a bounding box of 16 by 8. In order for it to work, you need to initialize arrays [A] and [B] to be 18x10. <lang ti83b> PROGRAM:CONWAY

While 1
For(X,2,9,1)
For(Y,2,17,1)
If [A](Y,X)
Then
Output(X-1,Y-1,"X")
Else
Output(X-1,Y-1," ")
End
[A](Y-1,X-1)+[A](Y,X-1)+[A](Y+1,X-1)+[A](Y-1,X)+[A](Y+1,X)+[A](Y-1,X+1)+[A](Y,X+1)+[A](Y+1,X+1)→N
If ([A](Y,X) and (N=2 or N=3)) or (not([A](Y,X)) and N=3)
Then
1→[B](Y,X)
Else
0→[B](Y,X)
End
End
End
[B]→[A]
End

</lang> Here is an additional, very simple program to input the top corner of the GRAPH screen into the starting array. Make sure to draw on pixels in the rectangle (1,1) to (8,16). <lang ti83b>PROGRAM:PIC2LIFE

For(I,0,17,1)
For(J,0,9,1)
pxl-Test(J,I)→[A](I+1,J+1)
End
End

</lang>

TI-89 BASIC

This program draws its cells as 2x2 blocks on the graph screen. In order to avoid needing external storage for the previous generation, it uses the upper-left corner of each block to mark the next generation's state in all cells, then updates each cell to match its corner pixel.

A further improvement would be to have an option to start with the existing picture rather than clearing, and stop at a point where the picture has clean 2x2 blocks.

<lang ti89b>Define life(pattern) = Prgm

 Local x,y,nt,count,save,xl,yl,xh,yh
 Define nt(y,x) = when(pxlTest(y,x), 1, 0)
 
 {}→save
 setGraph("Axes", "Off")→save[1]
 setGraph("Grid", "Off")→save[2]
 setGraph("Labels", "Off")→save[3]
 FnOff
 PlotOff
 ClrDraw
 If pattern = "blinker" Then
   36→yl
   40→yh
   78→xl
   82→xh
   PxlOn  36,80
   PxlOn  38,80
   PxlOn  40,80
 ElseIf pattern = "glider" Then
   30→yl
   40→yh
   76→xl
   88→xh
   PxlOn  38,76
   PxlOn  36,78
   PxlOn  36,80
   PxlOn  38,80
   PxlOn  40,80
 ElseIf pattern = "r" Then
   38-5*2→yl
   38+5*2→yh
   80-5*2→xl
   80+5*2→xh
   PxlOn  38,78
   PxlOn  36,82
   PxlOn  36,80
   PxlOn  38,80
   PxlOn  40,80
 EndIf
 While getKey() = 0
   © Expand upper-left corner to whole cell
   For y,yl,yh,2
     For x,xl,xh,2
       If pxlTest(y,x) Then
         PxlOn y+1,x
         PxlOn y+1,x+1
         PxlOn y,  x+1
       Else
         PxlOff y+1,x
         PxlOff y+1,x+1
         PxlOff y,  x+1
       EndIf
     EndFor
   EndFor
   © Compute next generation
   For y,yl,yh,2
     For x,xl,xh,2
       nt(y-1,x-1) + nt(y-1,x) + nt(y-1,x+2) + nt(y,x-1) + nt(y+1,x+2) + nt(y+2,x-1) + nt(y+2,x+1) + nt(y+2,x+2) → count
       If count = 3 Then
         PxlOn y,x
       ElseIf count ≠ 2 Then
         PxlOff y,x
       EndIf
     EndFor
   EndFor
 EndWhile
 © Restore changed options
 setGraph("Axes", save[1])
 setGraph("Grid", save[2])
 setGraph("Labels", save[3])

EndPrgm</lang>

Batch File

This code takes three parameters: m chance iterations Where,
m - The length and width of the array of cells
chance - The percent chance of any cell within the set array initially being alive. Full numbers only.
iterations - The amount of iterations of evolution the array goes through to display.

If no parameters are parsed, it defaults to 5 iterations of the blinking example.

<lang dos> @echo off setlocal enabledelayedexpansion

if "%1"=="" (

 call:_blinkerArray

) else (

 call:_randomArray %*

)

for /l %%i in (1,1,%iterations%) do (

 call:_setStatus
 call:_display
 
 for /l %%m in (1,1,%m%) do (
   for /l %%n in (1,1,%m%) do (
     call:_evolution %%m %%n
   )
 )

)

_blinkerArray

for /l %%m in (0,1,4) do (

 for /l %%n in (0,1,4) do (
   set cell[%%m][%%n]=0
 )

) set cell[2][1]=1 set cell[2][2]=1 set cell[2][3]=1 set iterations=5 set m=3 set cellsaddone=4

exit /b

_randomArray

set cellsaddone=%1+1 for /l %%m in (0,1,%cellsaddone%) do for /l %%n in (0,1,%cellsaddone%) do set cell[%%m][%%n]=0 for /l %%m in (1,1,%1) do (

 for /l %%n in (1,1,%1) do (
   set /a cellrandom=!random! %% 101
   set cell[%%m][%%n]=0
   if !cellrandom! leq %2 set cell[%%m][%%n]=1
 )

) set iterations=%3 set m=%1

exit /b

_setStatus

for /l %%m in (0,1,%cellsaddone%) do (

 for /l %%n in (0,1,%cellsaddone%) do (
   if !cell[%%m][%%n]!==1 set cellstatus[%%m][%%n]=alive
   if !cell[%%m][%%n]!==0 set cellstatus[%%m][%%n]=dead
 )

) exit /b


_evolution

set /a lowerm=%1-1 set /a upperm=%1+1 set /a lowern=%2-1 set /a uppern=%2+1 set numm=%1 set numn=%2 set sum=0 for /l %%m in (%lowerm%,1,%upperm%) do (

 for /l %%n in (%lowern%,1,%uppern%) do (
   if %%m==%numm% (
     if %%n==%numn% (
       set /a sum=!sum!
     ) else (
       if !cellstatus[%%m][%%n]!==alive set /a sum+=1
     )
   ) else (
     if !cellstatus[%%m][%%n]!==alive set /a sum+=1
   )
 )

) goto:!cell[%numm%][%numn%]!

exit /b

0

set alive=3 set death=0 1 2 4 5 6 7 8 for %%i in (%alive%) do if %sum%==%%i set cell[%numm%][%numn%]=1 for %%i in (%death%) do if %sum%==%%i set cell[%numm%][%numn%]=0 exit /b

1

set alive=2 3 set death=0 1 4 5 6 7 8 for %%i in (%alive%) do if %sum%==%%i set cell[%1][%2]=1 for %%i in (%death%) do if %sum%==%%i set cell[%1][%2]=0 exit /b

_display

echo. for /l %%m in (1,1,%m%) do (

 set m%%m= 
 for /l %%n in (1,1,%m%) do set m%%m=!m%%m! !cell[%%m][%%n]!
 echo !m%%m!

)

exit /b </lang>

Output:

Blinking example:

0 0 0
1 1 1
0 0 0

0 1 0
0 1 0
0 1 0

0 0 0
1 1 1
0 0 0

0 1 0
0 1 0
0 1 0

0 0 0
1 1 1
0 0 0
Input:
10 35 5
Output:
1 1 0 0 0 0 1 1 0 0
1 1 0 0 1 1 0 1 1 0
1 0 1 1 0 0 0 1 0 0
0 1 0 1 0 1 0 1 0 1
1 0 0 0 1 0 0 1 0 1
0 0 0 1 0 0 0 0 0 0
0 0 0 0 0 0 1 1 0 0
0 0 1 0 0 0 0 0 0 0
1 0 1 0 0 0 0 0 1 1
1 1 0 0 1 0 0 1 1 0

1 1 0 0 0 1 1 1 1 0
0 0 0 1 1 1 0 0 1 0
1 0 0 1 0 1 0 1 0 0
1 1 0 1 0 0 0 1 0 0
0 0 1 1 1 0 1 0 0 0
0 0 0 0 0 0 1 1 1 0
0 0 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 1 1 0
1 0 1 1 0 0 0 1 1 1
1 1 0 0 0 0 0 1 1 1

0 0 0 0 0 1 1 1 1 0
1 1 1 1 0 0 0 0 1 0
1 1 0 1 0 1 0 1 1 0
1 1 0 0 0 1 0 1 0 0
0 1 1 1 1 1 1 0 1 0
0 0 0 1 0 1 1 1 0 0
0 0 0 0 0 0 1 0 0 0
0 1 1 0 0 0 0 1 0 1
1 0 1 0 0 0 1 0 0 0
1 1 1 0 0 0 0 1 0 1

0 1 1 0 0 0 1 1 1 0
1 0 0 1 0 1 0 0 0 1
0 0 0 1 0 0 0 1 1 0
0 0 0 0 0 0 0 0 0 0
1 1 0 1 0 0 0 0 1 0
0 0 0 1 0 0 0 0 0 0
0 0 1 0 0 1 0 0 1 0
0 1 1 0 0 0 1 1 0 0
1 0 0 1 0 0 1 1 0 0
1 0 1 0 0 0 0 0 0 0

0 1 1 0 0 0 1 1 1 0
0 1 0 1 1 0 0 0 0 1
0 0 0 0 1 0 0 0 1 0
0 0 1 0 0 0 0 1 1 0
0 0 1 0 0 0 0 0 0 0
0 1 0 1 1 0 0 0 0 0
0 1 1 1 0 0 1 1 0 0
0 1 1 1 0 1 0 0 1 0
1 0 0 1 0 0 1 1 0 0
0 1 0 0 0 0 0 0 0 0

Befunge

Takes as input the width and height of the universe, followed by the pattern (which is terminated by the end of file). If your interpreter can't easily redirect the input from a file, or doesn't handle end-of-file detection, you can also type in the pattern manually and mark the end of input with a ~ character.

The pattern format itself is fairly lenient in what it accepts. You can use either space or . for dead cells, and o, O, * or # for live cells. This should make it fairly easy to cut and paste a number of existing formats, including the Life 1.05 format and the Plaintext .cells format used on the LifeWiki website (comments aren't supported though, so make sure to copy just the pattern itself).

In Befunge-93, the maximum value for the width and height of the universe is 127, but there is an additional constraint of 4080 cells in total, so the largest universe would really be something like 120x34 or 68x60. Befunge-98 has no real limit on the size, although in practice a much larger universe will probably be unbearably slow.

<lang befunge>00p10p20p30p&>40p&>50p60p>$#v~>:55+-vv+`1:%3:+*g04p03< >3/"P"%\56v>p\56*8*/8+:v v5\`\"~"::-*3p06!:!-+67:_^#!<*<!g06!<>1+70g*\:3/"P"%v^ ^::+*g04%<*0v`1:%3\gp08< >6*`*#v_55+-#v_p10g1+10p>^pg08g07+gp08:+8/*8*65\p07:<^ >/10g-50g^87>+1+:01p/8/v >%#74#<-!!70p 00g::1+00p:20g\-:0`*+20p10g::30g\-:0`*+^ ^2+2+g03*<*:v+g06p09:%2< .v,:*93"[2J"0<>"H["39*,,,50g0v!:-1,+55$_:40g3*20g+2+2/\-40g%50g3^/%\ >:3-\3-90v O>"l52?[">:#,_^v/3+2:*g05g04$_>:10p40g0^!:-1,g+4\0%2/+1+`1:%3\g+8<^: $v10!*-g<< g+70g80gp:#v_$^>1-:::"P"%\"P"/8+:10v >/10g+1-50g+50g%40g*+::3/"P"^>!|>g*70g80g

p00%g04:-1<<$_^#!:pg01%"P"\*8%8gp<< ^3\%g04+g04-1+g00%3:%9+4:-1p06\<90p01/g04</lang>
Input:

Here's an example of what the input could look like for the Blinker pattern in a 5x5 universe:

5
5
OOO

And for a more complicated example, this is the Queen bee pattern in a 50x30 universe:

50
30
...*
..*.*
.*...*
..***
**...**
Output:

In order to produce an animated view of the universe evolving, we use a few basic ANSI escape sequences to reset the cursor position between frames. Without ANSI support, you'll just see the individual frames scrolling past with a bit of junk inbetween. The output shown below is just an extract of the first three generations of the Blinker in a 5x5 universe.

.....   .....   .....
.....   ..O..   .....
.OOO.   ..O..   .OOO.
.....   ..O..   .....
.....   .....   .....

Brainf***

A life-program written in Brainf***

With Example-Output.

Brat

<lang brat>width = 3 height = 3 rounds = 3

universe = [[0 1 0]

           [0 1 0]
           [0 1 0]]

next = height.of({width.of(0)})

cell = { x, y |

 true? x < width && { x >= 0 && { y >= 0 && { y < height }}}
 {
   universe[y][x]
 }
 { 0 }

}

neighbors = { x, y |

 cell(x - 1, y - 1) +
 cell(x, y - 1) +
 cell(x + 1, y - 1) +
 cell(x + 1, y) +
 cell(x + 1, y + 1) +
 cell(x, y + 1) +
 cell(x - 1, y + 1) +
 cell(x - 1, y)

}

set_next = { x, y, v |

 next[y][x] = v

}

step = {

 universe.each_with_index { row, y |
   row.each_with_index { c, x |
     n = neighbors(x, y)
     when { n < 2 } { set_next x,y, 0 }
          { n > 3 } { set_next x, y, 0 }
          { n == 3 } { set_next x, y, 1 }
          { true } { set_next x, y, c }
   }
 }
 u2 = universe
 universe = next
 next = u2

}

display = {

 p universe.map({ r |
   r.map({ n | true? n == 0, '-', "O" }).join
 }).join("\n")

}

rounds.times {

 display
 p
 step

}</lang>

Output:
-O-
-O-
-O-

---
OOO
---

-O-
-O-
-O-

BQN

<lang bqn>Life←{

  r←¯1(⌽⎉1)¯1⌽(2+≢𝕩)↑𝕩
  s←∨´ (1∾<r) ∧ 3‿4 = <+´⥊ ¯1‿0‿1 (⌽⎉1)⌜ ¯1‿0‿1 ⌽⌜ <r
  1(↓⎉1) ¯1(↓⎉1) 1↓ ¯1↓s

}

blinker←>⟨0‿0‿0,1‿1‿1,0‿0‿0⟩ (<".#") ⊏¨˜ Life⍟(↕3) blinker</lang>

Output:
┌─                         
· ┌─      ┌─      ┌─       
  ╵"...   ╵".#.   ╵"...    
    ###     .#.     ###    
    ..."    .#."    ..."   
        ┘       ┘       ┘  
                          ┘

C

Play game of life on your console: gcc -std=c99 -Wall game.c; ./a.out [width] [height] <lang C>#include <stdio.h>

  1. include <stdlib.h>
  2. include <unistd.h>
  1. define for_x for (int x = 0; x < w; x++)
  2. define for_y for (int y = 0; y < h; y++)
  3. define for_xy for_x for_y

void show(void *u, int w, int h) { int (*univ)[w] = u; printf("\033[H"); for_y { for_x printf(univ[y][x] ? "\033[07m \033[m" : " "); printf("\033[E"); } fflush(stdout); }

void evolve(void *u, int w, int h) { unsigned (*univ)[w] = u; unsigned new[h][w];

for_y for_x { int n = 0; for (int y1 = y - 1; y1 <= y + 1; y1++) for (int x1 = x - 1; x1 <= x + 1; x1++) if (univ[(y1 + h) % h][(x1 + w) % w]) n++;

if (univ[y][x]) n--; new[y][x] = (n == 3 || (n == 2 && univ[y][x])); } for_y for_x univ[y][x] = new[y][x]; }

void game(int w, int h) { unsigned univ[h][w]; for_xy univ[y][x] = rand() < RAND_MAX / 10 ? 1 : 0; while (1) { show(univ, w, h); evolve(univ, w, h); usleep(200000); } }

int main(int c, char **v) { int w = 0, h = 0; if (c > 1) w = atoi(v[1]); if (c > 2) h = atoi(v[2]); if (w <= 0) w = 30; if (h <= 0) h = 30; game(w, h); }</lang> Also see Conway's Game of Life/C

C for Arduino

Play game of life on your arduino (using FastLED) - based on the C example. <lang C>

  1. include <FastLED.h>
  1. define LED_PIN 3
  2. define LED_TYPE WS2812B
  3. define WIDTH 20
  4. define HEIGHT 15
  5. define NUM_LEDS (WIDTH*HEIGHT)
  6. define BRIGHTNESS 100
  7. define COLOR_ORDER GRB
  8. define SERPENTINE 1
  9. define FRAMERATE 1
  10. define SCALE 1

CRGB leds[NUM_LEDS];

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <unistd.h>
  1. define for_x for (int x = 0; x < w; x++)
  2. define for_y for (int y = 0; y < h; y++)
  3. define for_xy for_x for_y

const int w = WIDTH, h = HEIGHT; unsigned univ[h][w];

int getLEDpos(int x, int y){ // for a serpentine raster

   return (y%2 || !SERPENTINE) ? y*WIDTH + x : y*WIDTH + (WIDTH - 1 - x);

}

void show(void *u, int w, int h) {

   int (*univ)[w] = u;
   for_xy {
       leds[getLEDpos(x, y)] = univ[y][x] ? CRGB::White: CRGB::Black;
   }
   FastLED.show();

}

void evolve(void *u, int w, int h) {

   unsigned (*univ)[w] = u;
   unsigned newU[h][w];
   for_y for_x {
       int n = 0;
       for (int y1 = y - 1; y1 <= y + 1; y1++)
           for (int x1 = x - 1; x1 <= x + 1; x1++)
               if (univ[(y1 + h) % h][(x1 + w) % w])
                   n++;
       if (univ[y][x]) n--;
       newU[y][x] = (n == 3 || (n == 2 && univ[y][x]));
   }
   for_y for_x univ[y][x] = newU[y][x];

}

void setup(){

   //Initialize leds after safety period
   FastLED.delay(500);
   FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
   FastLED.setBrightness(  BRIGHTNESS );
   
   //Seed random with analog noise
   randomSeed(analogRead(0));
   for_xy univ[y][x] = random() %10 <= 1 ? 1 : 0;

}

void loop(){

   show(univ, w, h);
   evolve(univ, w, h);
   FastLED.delay(1000/FRAMERATE);

} </lang>

C for Arduino

Play game of life on your arduino (using two MAX7219 led 'screens') - based on the C example. <lang C>

  1. include <MaxMatrix.h>

int DIN = 11; // DIN pin of MAX7219 module int CS = 12; // CS pin of MAX7219 module int CLK = 13; // CLK pin of MAX7219 module int DIN2 = 8; // DIN pin of MAX7219 module int CS2 = 9; // CS pin of MAX7219 module int CLK2 = 10; // CLK pin of MAX7219 module int maxInUse = 1;

//setup two screens MaxMatrix m(DIN, CS, CLK, maxInUse); MaxMatrix m2(DIN2, CS2, CLK2, maxInUse);

void setup() {

 randomSeed(analogRead(0));
 m.init(); // MAX7219 initialization
 m.setIntensity(0); // initial led matrix intensity, 0-15
 m.clear(); // Clears the display
 m2.init(); // MAX7219 initialization
 m2.setIntensity(0); // initial led matrix intensity, 0-15
 m2.clear(); // Clears the display

}

void loop() {

 game(16,8);//w,h

}

void setDot(int x,int y,bool isOn){

 if(x<8){
   m.setDot(x,y,isOn); 
 }else{
   m2.setDot(x-8,y,isOn); 
 }

}

void show(void *u, int w, int h){

 int (*univ)[w] = u;
 for (int y = 0; y < h; y++){
   for (int x = 0; x < w; x++){
     bool sh=(univ[y][x]==1);
     setDot(x,y,sh); 
   }
 }    

}

void evolve(void *u, int w, int h){

 unsigned (*univ)[w] = u;
 unsigned newar[h][w];

 for (int y = 0; y < h; y++){
   for (int x = 0; x < w; x++){
     int n = 0;
     for (int y1 = y - 1; y1 <= y + 1; y1++)
       for (int x1 = x - 1; x1 <= x + 1; x1++)
         if (univ[(y1 + h) % h][(x1 + w) % w])
           n++;
  
     if (univ[y][x]) n--;
     newar[y][x] = (n == 3 || (n == 2 && univ[y][x]));
    
   }
 } 

 for (int y = 0; y < h; y++){
   for (int x = 0; x < w; x++){
     univ[y][x] = newar[y][x];
   }
 }

}

void game(int w, int h) {

 unsigned univ[h][w];
 for (int x = 0; x < w; x++){
   for (int y = 0; y < h; y++){
     univ[y][x] = random(0, 100)>65 ? 1 : 0;
   }
 }
 int sc=0;
 while (1) {
   show(univ, w, h);
   evolve(univ, w, h);
   delay(150);
   sc++;if(sc>150)break;
 }

} </lang>

C#

<lang csharp> using System; using System.Text; using System.Threading;

namespace ConwaysGameOfLife {

   // Plays Conway's Game of Life on the console with a random initial state.
   class Program
   {
       // The delay in milliseconds between board updates.
       private const int DELAY = 50;

       // The cell colors.
       private const ConsoleColor DEAD_COLOR = ConsoleColor.White;
       private const ConsoleColor LIVE_COLOR = ConsoleColor.Black;

       // The color of the cells that are off of the board.
       private const ConsoleColor EXTRA_COLOR = ConsoleColor.Gray;

       private const char EMPTY_BLOCK_CHAR = ' ';
       private const char FULL_BLOCK_CHAR = '\u2588';

       // Holds the current state of the board.
       private static bool[,] board;

       // The dimensions of the board in cells.
       private static int width = 32;
       private static int height = 32;

       // True if cell rules can loop around edges.
       private static bool loopEdges = true;


       static void Main(string[] args)
       {
           // Use initializeRandomBoard for a larger, random board.
           initializeDemoBoard();

           initializeConsole();

           // Run the game until the Escape key is pressed.
           while (!Console.KeyAvailable || Console.ReadKey(true).Key != ConsoleKey.Escape) {
               Program.drawBoard();
               Program.updateBoard();

               // Wait for a bit between updates.
               Thread.Sleep(DELAY);
           }
       }

       // Sets up the Console.
       private static void initializeConsole()
       {
           Console.BackgroundColor = EXTRA_COLOR;
           Console.Clear();

           Console.CursorVisible = false;

           // Each cell is two characters wide.
           // Using an extra row on the bottom to prevent scrolling when drawing the board.
           int width = Math.Max(Program.width, 8) * 2 + 1;
           int height = Math.Max(Program.height, 8) + 1;
           Console.SetWindowSize(width, height);
           Console.SetBufferSize(width, height);

           Console.BackgroundColor = DEAD_COLOR;
           Console.ForegroundColor = LIVE_COLOR;
       }

       // Creates the initial board with a random state.
       private static void initializeRandomBoard()
       {
           var random = new Random();

           Program.board = new bool[Program.width, Program.height];
           for (var y = 0; y < Program.height; y++) {
               for (var x = 0; x < Program.width; x++) {
                   // Equal probability of being true or false.
                   Program.board[x, y] = random.Next(2) == 0;
               }
           }
       }

       // Creates a 3x3 board with a blinker.
       private static void initializeDemoBoard()
       {
           Program.width = 3;
           Program.height = 3;

           Program.loopEdges = false;

           Program.board = new bool[3, 3];
           Program.board[1, 0] = true;
           Program.board[1, 1] = true;
           Program.board[1, 2] = true;
       }

       // Draws the board to the console.
       private static void drawBoard()
       {
           // One Console.Write call is much faster than writing each cell individually.
           var builder = new StringBuilder();

           for (var y = 0; y < Program.height; y++) {
               for (var x = 0; x < Program.width; x++) {
                   char c = Program.board[x, y] ? FULL_BLOCK_CHAR : EMPTY_BLOCK_CHAR;

                   // Each cell is two characters wide.
                   builder.Append(c);
                   builder.Append(c);
               }
               builder.Append('\n');
           }

           // Write the string to the console.
           Console.SetCursorPosition(0, 0);
           Console.Write (builder.ToString());
       }

       // Moves the board to the next state based on Conway's rules.
       private static void updateBoard()
       {
           // A temp variable to hold the next state while it's being calculated.
           bool[,] newBoard = new bool[Program.width, Program.height];

           for (var y = 0; y < Program.height; y++) {
               for (var x = 0; x < Program.width; x++) {
                   var n = countLiveNeighbors(x, y);
                   var c = Program.board[x, y];

                   // A live cell dies unless it has exactly 2 or 3 live neighbors.
                   // A dead cell remains dead unless it has exactly 3 live neighbors.
                   newBoard[x, y] = c && (n == 2 || n == 3) || !c && n == 3;
               }
           }

           // Set the board to its new state.
           Program.board = newBoard;
       }

       // Returns the number of live neighbors around the cell at position (x,y).
       private static int countLiveNeighbors(int x, int y)
       {
           // The number of live neighbors.
           int value = 0;

           // This nested loop enumerates the 9 cells in the specified cells neighborhood.
           for (var j = -1; j <= 1; j++) {
               // If loopEdges is set to false and y+j is off the board, continue.
               if (!Program.loopEdges && y + j < 0 || y + j >= Program.height) {
                   continue;
               }

               // Loop around the edges if y+j is off the board.
               int k = (y + j + Program.height) % Program.height;

               for (var i = -1; i <= 1; i++) {
                   // If loopEdges is set to false and x+i is off the board, continue.
                   if (!Program.loopEdges && x + i < 0 || x + i >= Program.width) {
                       continue;
                   }

                   // Loop around the edges if x+i is off the board.
                   int h = (x + i + Program.width) % Program.width;

                   // Count the neighbor cell at (h,k) if it is alive.
                   value += Program.board[h, k] ? 1 : 0;
               }
           }

           // Subtract 1 if (x,y) is alive since we counted it as a neighbor.
           return value - (Program.board[x, y] ? 1 : 0);
       }
   }

}

</lang>

Output: <lang> Frame 1: Frame 2: Frame 3:

             ██              

██████ ██ ██████

             ██                    

</lang>

C++

Considering that the simplest implementation in C++ would lack any use of the object-oriented paradigm, this code was specifically written to demonstrate the various object-oriented features of C++. Thus, while it is somewhat verbose, it fully simulates Conway's Game of Life and is relatively simple to expand to feature different starting shapes. <lang c>#include <iostream>

  1. define HEIGHT 4
  2. define WIDTH 4

struct Shape { public:

   char xCoord;
   char yCoord;
   char height;
   char width;
   char **figure;

};

struct Glider : public Shape {

   static const char GLIDER_SIZE = 3;
   Glider( char x , char y );
   ~Glider();

};

struct Blinker : public Shape {

   static const char BLINKER_HEIGHT = 3;
   static const char BLINKER_WIDTH = 1;
   Blinker( char x , char y );
   ~Blinker();

};

class GameOfLife { public:

   GameOfLife( Shape sh );
   void print();
   void update();
   char getState( char state , char xCoord , char yCoord , bool toggle);
   void iterate(unsigned int iterations);

private:

   char world[HEIGHT][WIDTH];
   char otherWorld[HEIGHT][WIDTH];
   bool toggle;
   Shape shape;

};

GameOfLife::GameOfLife( Shape sh ) :

   shape(sh) ,
   toggle(true) 

{

   for ( char i = 0; i < HEIGHT; i++ ) {
       for ( char j = 0; j < WIDTH; j++ ) {
           world[i][j] = '.';
       }
   }
   for ( char i = shape.yCoord; i - shape.yCoord < shape.height; i++ ) {
       for ( char j = shape.xCoord; j - shape.xCoord < shape.width; j++ ) {
           if ( i < HEIGHT && j < WIDTH ) {
               world[i][j] = 
                   shape.figure[ i - shape.yCoord ][j - shape.xCoord ];
           }
       }
   }

}

void GameOfLife::print() {

   if ( toggle ) {
       for ( char i = 0; i < HEIGHT; i++ ) {
           for ( char j = 0; j < WIDTH; j++ ) {
               std::cout << world[i][j];
           }
           std::cout << std::endl;
       }
   } else {
       for ( char i = 0; i < HEIGHT; i++ ) {
           for ( char j = 0; j < WIDTH; j++ ) {
               std::cout << otherWorld[i][j];
           }
           std::cout << std::endl;
       }
   }
   for ( char i = 0; i < WIDTH; i++ ) {
       std::cout << '=';
   }
   std::cout << std::endl;

}

void GameOfLife::update() {

   if (toggle) {
       for ( char i = 0; i < HEIGHT; i++ ) {
           for ( char j = 0; j < WIDTH; j++ ) {
               otherWorld[i][j] = 
                   GameOfLife::getState(world[i][j] , i , j , toggle);
           }
       }
       toggle = !toggle;
   } else {
       for ( char i = 0; i < HEIGHT; i++ ) {
           for ( char j = 0; j < WIDTH; j++ ) {
               world[i][j] = 
                   GameOfLife::getState(otherWorld[i][j] , i , j , toggle);
           }
       }
       toggle = !toggle;
   }

}

char GameOfLife::getState( char state, char yCoord, char xCoord, bool toggle ) {

   char neighbors = 0;
   if ( toggle ) {
       for ( char i = yCoord - 1; i <= yCoord + 1; i++ ) {
           for ( char j = xCoord - 1; j <= xCoord + 1; j++ ) {
               if ( i == yCoord && j == xCoord ) {
                   continue;
               }
               if ( i > -1 && i < HEIGHT && j > -1 && j < WIDTH ) {
                   if ( world[i][j] == 'X' ) {
                       neighbors++;
                   }
               }
           }
       }
   } else {
       for ( char i = yCoord - 1; i <= yCoord + 1; i++ ) {
           for ( char j = xCoord - 1; j <= xCoord + 1; j++ ) {
               if ( i == yCoord && j == xCoord ) {
                   continue;
               }
               if ( i > -1 && i < HEIGHT && j > -1 && j < WIDTH ) {
                   if ( otherWorld[i][j] == 'X' ) {
                       neighbors++;
                   }
               }
           }
       }
   }
   if (state == 'X') {
       return ( neighbors > 1 && neighbors < 4 ) ? 'X' : '.';
   }
   else {
       return ( neighbors == 3 ) ? 'X' : '.';
   }

}

void GameOfLife::iterate( unsigned int iterations ) {

   for ( int i = 0; i < iterations; i++ ) {
       print();
       update();
   }

}

Glider::Glider( char x , char y ) {

   xCoord = x;
   yCoord = y;
   height = GLIDER_SIZE;
   width = GLIDER_SIZE;
   figure = new char*[GLIDER_SIZE];
   for ( char i = 0; i < GLIDER_SIZE; i++ ) {
       figure[i] = new char[GLIDER_SIZE];
   }
   for ( char i = 0; i < GLIDER_SIZE; i++ ) {
       for ( char j = 0; j < GLIDER_SIZE; j++ ) {
           figure[i][j] = '.';
       }
   }
   figure[0][1] = 'X';
   figure[1][2] = 'X';
   figure[2][0] = 'X';
   figure[2][1] = 'X';
   figure[2][2] = 'X';

}

Glider::~Glider() {

   for ( char i = 0; i < GLIDER_SIZE; i++ ) {
       delete[] figure[i];
   }
   delete[] figure;

}

Blinker::Blinker( char x , char y ) {

   xCoord = x;
   yCoord = y;
   height = BLINKER_HEIGHT;
   width = BLINKER_WIDTH;
   figure = new char*[BLINKER_HEIGHT];
   for ( char i = 0; i < BLINKER_HEIGHT; i++ ) {
       figure[i] = new char[BLINKER_WIDTH];
   }
   for ( char i = 0; i < BLINKER_HEIGHT; i++ ) {
       for ( char j = 0; j < BLINKER_WIDTH; j++ ) {
           figure[i][j] = 'X';
       }
   }

}

Blinker::~Blinker() {

   for ( char i = 0; i < BLINKER_HEIGHT; i++ ) {
       delete[] figure[i];
   }
   delete[] figure;

}

int main() {

   Glider glider(0,0);
   GameOfLife gol(glider);
   gol.iterate(5);
   Blinker blinker(1,0);
   GameOfLife gol2(blinker);
   gol2.iterate(4);

} </lang>

Output:

first a glider, then a blinker, over a few iterations

(reformatted for convenience).

.X.. .... .... .... ....
..X. X.X. ..X. .X.. ..X.
XXX. .XX. X.X. ..XX ...X
.... .X.. .XX. .XX. .XXX
==== ==== ==== ==== ====

.X.. .... .X.. 
.X.. XXX. .X..
.X.. .... .X..
.... .... ....
==== ==== ====

Alternate version

Another aproach - a pretty simple one.
This version allows you to start the automata with different set of rules. Just for the fun of it. <lang cpp>

  1. include <algorithm>
  2. include <vector>
  3. include <iostream>
  4. include <string>

typedef unsigned char byte;

class world { public:

   world( int x, int y ) : _wid( x ), _hei( y ) {
       int s = _wid * _hei * sizeof( byte );
       _cells = new byte[s];
       memset( _cells, 0, s );
   }
   ~world() {
       delete [] _cells;
   }
   int wid() const {
       return _wid;
   }
   int hei() const {
       return _hei;
   }
   byte at( int x, int y ) const {
       return _cells[x + y * _wid];
   }
   void set( int x, int y, byte c ) {
       _cells[x + y * _wid] = c;
   }
   void swap( world* w ) {
       memcpy( _cells, w->_cells, _wid * _hei * sizeof( byte ) );
   }

private:

   int _wid, _hei;
   byte* _cells;

}; class rule { public:

   rule( world* w ) : wrd( w ) {
       wid = wrd->wid();
       hei = wrd->hei();
       wrdT = new world( wid, hei );
   }
   ~rule() {
       if( wrdT ) delete wrdT;
   }
   bool hasLivingCells() {
       for( int y = 0; y < hei; y++ )
           for( int x = 0; x < wid; x++ )
               if( wrd->at( x, y ) ) return true;
       std::cout << "*** All cells are dead!!! ***\n\n";
       return false;
   }
   void swapWrds() {
       wrd->swap( wrdT );
   }
   void setRuleB( std::vector<int>& birth ) {
       _birth = birth;
   }
   void setRuleS( std::vector<int>& stay ) {
       _stay = stay;
   }
   void applyRules() {
       int n;
       for( int y = 0; y < hei; y++ ) {
           for( int x = 0; x < wid; x++ ) {
               n = neighbours( x, y );
               if( wrd->at( x, y ) ) {
                   wrdT->set( x, y, inStay( n ) ? 1 : 0 );
               } else {
                   wrdT->set( x, y, inBirth( n ) ? 1 : 0 );
               }
           }
       }
   }

private:

   int neighbours( int xx, int yy ) {
       int n = 0, nx, ny;
       for( int y = -1; y < 2; y++ ) {
           for( int x = -1; x < 2; x++ ) {
               if( !x && !y ) continue;
               nx = ( wid + xx + x ) % wid;
               ny = ( hei + yy + y ) % hei;
               n += wrd->at( nx, ny ) > 0 ? 1 : 0;
           }
       }
       return n;
   }
   bool inStay( int n ) {
       return( _stay.end() != find( _stay.begin(), _stay.end(), n ) );
   }
   bool inBirth( int n ) {
       return( _birth.end() != find( _birth.begin(), _birth.end(), n ) );
   }
   int wid, hei;
   world *wrd, *wrdT;
   std::vector<int> _stay, _birth;

}; class cellular { public:

   cellular( int w, int h ) : rl( 0 ) {
       wrd = new world( w, h );
   }
   ~cellular() {
       if( rl ) delete rl;
       delete wrd;
   }
   void start( int r ) {
       rl = new rule( wrd );
       gen = 1;
       std::vector<int> t;
       switch( r ) {
           case 1: // conway
               t.push_back( 2 ); t.push_back( 3 ); rl->setRuleS( t );
               t.clear(); t.push_back( 3 ); rl->setRuleB( t );
               break;
           case 2: // amoeba
               t.push_back( 1 ); t.push_back( 3 ); t.push_back( 5 ); t.push_back( 8 ); rl->setRuleS( t );
               t.clear(); t.push_back( 3 ); t.push_back( 5 ); t.push_back( 7 ); rl->setRuleB( t );
               break;
           case 3: // life34
               t.push_back( 3 ); t.push_back( 4 ); rl->setRuleS( t );
               rl->setRuleB( t );
               break;
           case 4: // maze
               t.push_back( 1 ); t.push_back( 2 ); t.push_back( 3 ); t.push_back( 4 ); t.push_back( 5 ); rl->setRuleS( t );
               t.clear(); t.push_back( 3 ); rl->setRuleB( t );
               break;
       }
       /* just for test - shoud read from a file */
       /* GLIDER */
       wrd->set( 6, 1, 1 ); wrd->set( 7, 2, 1 );
       wrd->set( 5, 3, 1 ); wrd->set( 6, 3, 1 );
       wrd->set( 7, 3, 1 );
       /* BLINKER */
       wrd->set( 1, 3, 1 ); wrd->set( 2, 3, 1 );
       wrd->set( 3, 3, 1 );
       /******************************************/
       generation();
   }

private:

   void display() {
       system( "cls" );
       int wid = wrd->wid(),
           hei = wrd->hei();
       std::cout << "+" << std::string( wid, '-' ) << "+\n";
       for( int y = 0; y < hei; y++ ) {
           std::cout << "|";
           for( int x = 0; x < wid; x++ ) {
               if( wrd->at( x, y ) ) std::cout << "#";
               else std::cout << ".";
           }
           std::cout << "|\n";
       }
       std::cout << "+" << std::string( wid, '-' ) << "+\n";
       std::cout << "Generation: " << gen << "\n\nPress [RETURN] for the next generation...";
       std::cin.get();
   }
   void generation() {
       do {
           display();
           rl->applyRules();
           rl->swapWrds();
           gen++;
       }
       while ( rl->hasLivingCells() );
   }
   rule* rl;
   world* wrd;
   int gen; 

};

int main( int argc, char* argv[] ) {

   cellular c( 20, 12 );
   std::cout << "\n\t*** CELLULAR AUTOMATA ***" << "\n\n Which one you want to run?\n\n\n";
   std::cout << " [1]\tConway's Life\n [2]\tAmoeba\n [3]\tLife 34\n [4]\tMaze\n\n > ";
   int o; 
   do {
       std::cin >> o;
   } 
   while( o < 1 || o > 4 );
   std::cin.ignore();
   c.start( o );
   return system( "pause" );

} </lang>

Output:

+--------------------+ +--------------------+ +--------------------+ +--------------------+ |....................| |....................| |....................| |....................| |......#.............| |....................| |....................| |....................| |.......#............| |..#..#.#............| |.......#............| |..#...#.............| |.###.###............| |..#...##............| |.###.#.#............| |..#....##...........| |....................| |..#...#.............| |......##............| |..#...##............| |....................| |....................| |....................| |....................| |....................| |....................| |....................| |....................| |....................| |....................| |....................| |....................| +--------------------+ +--------------------+ +--------------------+ +--------------------+ Generation: 1 Generation: 2 Generation: 3 Generation: 4

Simple Without Classes

Shows a glider over 20 generations Board edges wrap around to simulate infinite board <lang cpp>

  1. include <iostream>
  2. include <vector>
  3. include <numeric>

// ----------------------------------------------------------------------------

using Row = std::vector<int>; using Cells = std::vector<Row>;

// ----------------------------------------------------------------------------

Cells board = {

   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
   {0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
   {0,0,0,1,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,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,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,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}, 

};

int numRows = 10; int numCols = 20;

// ----------------------------------------------------------------------------

int getNeighbor(int row, int col, Cells& board) {

   // use modulus to get wrapping effect at board edges
   return board.at((row + numRows) % numRows).at((col + numCols) % numCols);

}

int getCount(int row, int col, Cells& board) {

   int count = 0;
   std::vector<int> deltas {-1, 0, 1};
   for (int dc : deltas) {
       for (int dr : deltas) {
           if (dr || dc) {
               count += getNeighbor(row + dr, col + dc, board);
           }
       }
   }
   return count;

}

void showCell(int cell) {

   std::cout << (cell ? "*" : " ");

}

void showRow(const Row& row) {

   std::cout << "|";
   for (int cell : row) {showCell(cell);}
   std::cout << "|\n";

}

void showCells(Cells board) {

   for (const Row& row : board) { showRow(row); }

}

int tick(Cells& board, int row, int col) {

   int count = getCount(row, col, board);
   bool birth = !board.at(row).at(col) && count == 3;
   bool survive = board.at(row).at(col) && (count == 2 || count == 3);
   return birth || survive;

}

void updateCells(Cells& board) {

   Cells original = board;
   for (int row = 0; row < numRows; row++) {
       for (int col = 0; col < numCols; col++) {
           board.at(row).at(col) = tick(original, row, col);
       }
   }

}

int main () {

   for (int gen = 0; gen < 20; gen++) {
       std::cout << "\ngeneration " << gen << ":\n";
       showCells(board);
       updateCells(board);
   }

} </lang>

Output:

generation 0: | | | * | | * | | *** | | | | | | | | | | | | |

generation 1: | | | | | * * | | ** | | * | | | | | | | | | | |

generation 2: | | | | | * | | * * | | ** | | | | | | | | | | |

generation 3: | | | | | * | | ** | | ** | | | | | | | | | | | ...

Chapel

<lang chapel> config const gridHeight: int = 3; config const gridWidth: int = 3;

enum State { dead = 0, alive = 1 };

class ConwaysGameofLife {

 var gridDomain: domain(2);
 var computeDomain: subdomain( gridDomain );
 var grid: [gridDomain] int;
 
 proc ConwaysGameofLife( height: int, width: int ) {
   this.gridDomain = {0..#height+2, 0..#width+2};
   this.computeDomain = this.gridDomain.expand( -1 );
 }
 
 proc step(){
   
   var tempGrid: [this.computeDomain] State;
   forall (i,j) in this.computeDomain {
     var isAlive = this.grid[i,j] == State.alive;
     var numAlive = (+ reduce this.grid[ i-1..i+1, j-1..j+1 ]) - if isAlive then 1 else 0;      
     tempGrid[i,j] = if ( (2 == numAlive && isAlive) || numAlive == 3 ) then State.alive else State.dead ;
   }
   
   this.grid[this.computeDomain] = tempGrid;
   
 }
 
 proc this( i: int, j: int ) ref : State {
   return this.grid[i,j];
 }
 
 proc prettyPrint(): string {
   var str: string;
   for i in this.gridDomain.dim(1) {
     if i == 0 || i == gridDomain.dim(1).last {
       for j in this.gridDomain.dim(2) {
         str += "-";
       }
     } else {
       for j in this.gridDomain.dim(2) {
         if j == 0 || j == this.gridDomain.dim(2).last {
           str += "|";
         } else {
           str += if this.grid[i,j] == State.alive then "#" else " ";
         }
       }
     }
     str += "\n";
   }
   return str;
 }

}

proc main{

 var game = new ConwaysGameofLife( gridHeight, gridWidth );
 game[gridHeight/2 + 1, gridWidth/2     ] = State.alive;
 game[gridHeight/2 + 1, gridWidth/2 + 1 ] = State.alive;
 game[gridHeight/2 + 1, gridWidth/2 + 2 ] = State.alive;
 for i in 1..3 {
   writeln( game.prettyPrint() );
   game.step();
 }

} </lang> Output:

-----
|   |
|###|
|   |
-----

-----
| # |
| # |
| # |
-----

-----
|   |
|###|
|   |
-----

Clojure

Based on the implementation by Christophe Grand here: http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/ This implementation models the live cells as a set of coordinates. <lang lisp>(defn moore-neighborhood x y

 (for [dx [-1 0 1]
       dy [-1 0 1]
       :when (not (= [dx dy] [0 0]))]
   [(+ x dx) (+ y dy)]))

(defn step [set-of-cells]

 (set (for [[cell count] (frequencies (mapcat moore-neighborhood set-of-cells))
            :when (or (= 3 count)
                      (and (= 2 count) (contains? set-of-cells cell)))]
        cell)))

(defn print-world

 ([set-of-cells] (print-world set-of-cells 10))
 ([set-of-cells world-size]
    (let [r (range 0 (+ 1 world-size))]
      (pprint (for [y r] (apply str (for [x r] (if (set-of-cells [x y]) \# \.))))))))

(defn run-life [world-size num-steps set-of-cells]

 (loop [s num-steps 
        cells set-of-cells]
   (print-world cells world-size)
   (when (< 0 s) 
     (recur (- s 1) (step cells)))))

(def *blinker* #{[1 2] [2 2] [3 2]}) (def *glider* #{[1 0] [2 1] [0 2] [1 2] [2 2]}) </lang>

COBOL

<lang cobol>identification division. program-id. game-of-life-program. data division. working-storage section. 01 grid.

   05 cell-table.
       10 row occurs 5 times.
           15 cell pic x value space occurs 5 times.
   05 next-gen-cell-table.
       10 next-gen-row occurs 5 times.
           15 next-gen-cell pic x occurs 5 times.

01 counters.

   05 generation pic 9.
   05 current-row pic 9.
   05 current-cell pic 9.
   05 living-neighbours pic 9.
   05 neighbour-row pic 9.
   05 neighbour-cell pic 9.
   05 check-row pic s9.
   05 check-cell pic s9.

procedure division. control-paragraph.

   perform blinker-paragraph varying current-cell from 2 by 1
   until current-cell is greater than 4.
   perform show-grid-paragraph through life-paragraph
   varying generation from 0 by 1
   until generation is greater than 2.
   stop run.

blinker-paragraph.

   move '#' to cell(3,current-cell).

show-grid-paragraph.

   display 'GENERATION ' generation ':'.
   display '   +---+'.
   perform show-row-paragraph varying current-row from 2 by 1
   until current-row is greater than 4.
   display '   +---+'.
   display .

life-paragraph.

   perform update-row-paragraph varying current-row from 2 by 1
   until current-row is greater than 4.
   move next-gen-cell-table to cell-table.

show-row-paragraph.

   display '   |' with no advancing.
   perform show-cell-paragraph varying current-cell from 2 by 1
   until current-cell is greater than 4.
   display '|'.

show-cell-paragraph.

   display cell(current-row,current-cell) with no advancing.

update-row-paragraph.

   perform update-cell-paragraph varying current-cell from 2 by 1
   until current-cell is greater than 4.

update-cell-paragraph.

   move 0 to living-neighbours.
   perform check-row-paragraph varying check-row from -1 by 1
   until check-row is greater than 1.
   evaluate living-neighbours,
       when 2 move cell(current-row,current-cell) to next-gen-cell(current-row,current-cell),
       when 3 move '#' to next-gen-cell(current-row,current-cell),
       when other move space to next-gen-cell(current-row,current-cell),
   end-evaluate.

check-row-paragraph.

   add check-row to current-row giving neighbour-row.
   perform check-cell-paragraph varying check-cell from -1 by 1
   until check-cell is greater than 1.

check-cell-paragraph.

   add check-cell to current-cell giving neighbour-cell.
   if cell(neighbour-row,neighbour-cell) is equal to '#',
   and check-cell is not equal to zero or check-row is not equal to zero,
   then add 1 to living-neighbours.</lang>
Output:
GENERATION 0:
   +---+
   |   |
   |###|
   |   |
   +---+

GENERATION 1:
   +---+
   | # |
   | # |
   | # |
   +---+

GENERATION 2:
   +---+
   |   |
   |###|
   |   |
   +---+

Common Lisp

<lang lisp>(defun next-life (array &optional results)

 (let* ((dimensions (array-dimensions array))
        (results (or results (make-array dimensions :element-type 'bit))))
   (destructuring-bind (rows columns) dimensions
     (labels ((entry (row col)
                "Return array(row,col) for valid (row,col) else 0."
                (if (or (not (< -1 row rows))
                        (not (< -1 col columns)))
                  0
                  (aref array row col)))
              (neighbor-count (row col &aux (count 0))
                "Return the sum of the neighbors of (row,col)."
                (dolist (r (list (1- row) row (1+ row)) count)
                  (dolist (c (list (1- col) col (1+ col)))
                    (unless (and (eql r row) (eql c col))
                      (incf count (entry r c))))))
              (live-or-die? (current-state neighbor-count)
                (if (or (and (eql current-state 1)
                             (<=  2 neighbor-count 3))
                        (and (eql current-state 0)
                             (eql neighbor-count 3)))
                  1
                  0)))
       (dotimes (row rows results)
         (dotimes (column columns)
           (setf (aref results row column)
                 (live-or-die? (aref array row column)
                               (neighbor-count row column)))))))))

(defun print-grid (grid &optional (out *standard-output*))

 (destructuring-bind (rows columns) (array-dimensions grid)
   (dotimes (r rows grid)
     (dotimes (c columns (terpri out))
       (write-char (if (zerop (aref grid r c)) #\+ #\#) out)))))

(defun run-life (&optional world (iterations 10) (out *standard-output*))

 (let* ((world (or world (make-array '(10 10) :element-type 'bit)))
        (result (make-array (array-dimensions world) :element-type 'bit)))
   (do ((i 0 (1+ i))) ((eql i iterations) world)
     (terpri out) (print-grid world out)
     (psetq world (next-life world result)
            result world))))</lang>

<lang lisp>(run-life (make-array '(3 3)

                     :element-type 'bit
                     :initial-contents '((0 0 0) 
                                         (1 1 1)
                                         (0 0 0)))
         3)</lang>

produces

+++
###
+++

+#+
+#+
+#+

+++
###
+++

A version using a sparse list of living cells rather than an explicit board.

<lang lisp>(defun moore-neighborhood (cell)

 (let ((r '(-1 0 1)))
   (mapcan

(lambda (delta-x) (loop for delta-y in r unless (and (= delta-x 0) (= delta-y 0)) collect (cons (+ (car cell) delta-x) (+ (cdr cell) delta-y)))) r)))

(defun frequencies (cells)

 (let ((h (make-hash-table :test #'equal)))
   (loop for c in cells
      if (gethash c h)
        do (incf (gethash c h))
      else
      do (setf (gethash c h) 1))
   h))

(defun life-step (cells)

 (let ((f (frequencies (mapcan #'moore-neighborhood cells))))
   (loop for k being the hash-keys in f
      when (or 

(= (gethash k f) 3) (and (= (gethash k f) 2) (member k cells :test #'equal))) collect k)))

(defun print-world (live-cells &optional (world-size 10))

 (dotimes (y world-size)
   (dotimes (x world-size)
     (if (member (cons x y) live-cells :test #'equal)

(format t "X") (format t ".")))

   (format t "~%")))

(defun run-life (world-size steps cells)

 (print-world cells world-size)
 (format t "~%")
 (when (< 0 steps)
   (run-life world-size (- steps 1) (life-step cells))))

(defparameter *blinker* '((1 . 2) (2 . 2) (3 . 2))) (defparameter *glider* '((1 . 0) (2 . 1) (0 . 2) (1 . 2) (2 . 2)))</lang>

D

<lang d>import std.stdio, std.string, std.algorithm, std.array, std.conv;

struct GameOfLife {

 enum Cell : char { dead = ' ', alive = '#' }
 Cell[][] grid, newGrid;
 this(in int x, in int y) pure nothrow @safe {
   grid = new typeof(grid)(y + 2, x + 2);
   newGrid = new typeof(grid)(y + 2, x + 2);
 }
 void opIndexAssign(in string[] v, in size_t y, in size_t x)
 pure /*nothrow*/ @safe /*@nogc*/ {
   foreach (immutable nr, row; v)
     foreach (immutable nc, state; row)
       grid[y + nr][x + nc] = state.to!Cell;
 }
 void iteration() pure nothrow @safe @nogc {
   newGrid[0][] = Cell.dead;
   newGrid[$ - 1][] = Cell.dead;
   foreach (row; newGrid)
     row[0] = row[$ - 1] = Cell.dead;
   foreach (immutable r; 1 .. grid.length - 1)
     foreach (immutable c; 1 .. grid[0].length - 1) {
       uint count = 0;
       foreach (immutable i; -1 .. 2)
         foreach (immutable j; -1 .. 2)
           if (i != 0 || j != 0)
             count += grid[r + i][c + j] == Cell.alive;
       immutable a = count == 3 ||
                     (count == 2 && grid[r][c] == Cell.alive);
       newGrid[r][c] = a ? Cell.alive : Cell.dead;
     }
   grid.swap(newGrid);
 }
 string toString() const pure /*nothrow @safe*/ {
   auto ret = "-".replicate(grid[0].length - 1) ~ "\n";
   foreach (const row; grid[1 .. $ - 1])
     ret ~= "|%(%c%)|\n".format(row[1 .. $ - 1]);
   return ret ~ "-".replicate(grid[0].length - 1);
 }

}

void main() /*@safe*/ {

 immutable glider1 = ["  #", "# #", " ##"];
 immutable glider2 = ["#  ", "# #", "## "];
 auto uni = GameOfLife(60, 20);
 uni[3,  2] = glider1;
 uni[3, 15] = glider2;
 uni[3, 19] = glider1;
 uni[3, 32] = glider2;
 uni[5, 50] = [" #  #", "#  ", "#   #", "#### "];
 uni.writeln;
 foreach (immutable _; 0 .. 20) {
   uni.iteration;
   uni.writeln;
 }

}</lang>

Output, first iteration:
-------------------------------------------------------------
|                                                            |
|                                                            |
|   #          #     #          #                            |
| # #          # # # #          # #                          |
|  ##          ##   ##          ##                 #  #      |
|                                                 #          |
|                                                 #   #      |
|                                                 ####       |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
|                                                            |
-------------------------------------------------------------

Faster Version

Same output. <lang d>import std.stdio, std.string, std.algorithm, std.typetuple,

      std.array, std.conv;

struct GameOfLife {

 enum Cell : char { dead = ' ', alive = '#' }
 Cell[] grid, newGrid;
 immutable size_t nCols;
 this(in int nx, in int ny) pure nothrow @safe {
   nCols = nx + 2;
   grid = new typeof(grid)(nCols * (ny + 2));
   newGrid = new typeof(grid)(grid.length);
 }
 void opIndexAssign(in string[] v, in size_t y, in size_t x)
 pure /*nothrow*/ @safe /*@nogc*/ {
   foreach (immutable nr, const row; v)
     foreach (immutable nc, immutable state; row)
       grid[(y + nr) * nCols + x + nc] = state.to!Cell;
 }
 void iteration() pure nothrow @safe @nogc {
   newGrid[0 .. nCols] = Cell.dead;
   newGrid[$ - nCols .. $] = Cell.dead;
   foreach (immutable nr; 1 .. (newGrid.length / nCols) - 1) {
     newGrid[nr * nCols + 0] = Cell.dead;
     newGrid[nr * nCols + nCols - 1] = Cell.dead;
   }
   foreach (immutable nr; 1 .. (grid.length / nCols) - 1) {
     size_t nr_nCols = nr * nCols;
     foreach (immutable nc; 1 .. nCols - 1) {
       uint count = 0;
       /*static*/ foreach (immutable i; TypeTuple!(-1, 0, 1))
         /*static*/ foreach (immutable j; TypeTuple!(-1, 0, 1))
           static if (i != 0 || j != 0)
             count += (grid[nr_nCols + i * nCols + nc + j] == Cell.alive);
       immutable a = count == 3 ||
                     (count == 2 && grid[nr_nCols + nc] == Cell.alive);
       newGrid[nr_nCols + nc] = a ? Cell.alive : Cell.dead;
     }
   }
   swap(grid, newGrid);
 }
 string toString() const pure /*nothrow @safe*/ {
   string ret = "-".replicate(nCols - 1) ~ "\n";
   foreach (immutable nr; 1 .. (grid.length / nCols) - 1)
     ret ~= "|%(%c%)|\n".format(grid[nr * nCols + 1 .. nr * nCols + nCols - 1]);
   return ret ~ "-".replicate(nCols - 1);
 }

}

void main() {

 immutable glider1 = ["  #", "# #", " ##"];
 immutable glider2 = ["#  ", "# #", "## "];
 auto uni = GameOfLife(60, 20);
 uni[3,  2] = glider1;
 uni[3, 15] = glider2;
 uni[3, 19] = glider1;
 uni[3, 32] = glider2;
 uni[5, 50] = [" #  #", "#  ", "#   #", "#### "];
 uni.writeln;
 foreach (immutable _; 0 .. 20) {
   uni.iteration;
   uni.writeln;
 }

}</lang>

Dart

<lang dart>/**

  • States of a cell. A cell is either [ALIVE] or [DEAD].
  • The state contains its [symbol] for printing.
  • /

class State {

 const State(this.symbol);
 static final ALIVE = const State('#');
 static final DEAD = const State(' ');
 final String symbol;

}

/**

  • The "business rule" of the game. Depending on the count of neighbours,
  • the [cellState] changes.
  • /

class Rule {

 Rule(this.cellState);
 reactToNeighbours(int neighbours) {
   if (neighbours == 3) {
     cellState = State.ALIVE;
   } else if (neighbours != 2) {
     cellState = State.DEAD;
   }
 }
 var cellState;

}

/**

  • A coordinate on the [Grid].
  • /

class Point {

 const Point(this.x, this.y);
 operator +(other) => new Point(x + other.x, y + other.y);
 final int x;
 final int y;

}

/**

  • List of the relative indices of the 8 cells around a cell.
  • /

class Neighbourhood {

 List<Point> points() {
   return [
     new Point(LEFT, UP), new Point(MIDDLE, UP), new Point(RIGHT, UP),
     new Point(LEFT, SAME), new Point(RIGHT, SAME),
     new Point(LEFT, DOWN), new Point(MIDDLE, DOWN), new Point(RIGHT, DOWN)
   ];
 }
 static final LEFT = -1;
 static final MIDDLE = 0;
 static final RIGHT = 1;
 static final UP = -1;
 static final SAME = 0;
 static final DOWN = 1;

}

/**

  • The grid is an endless, two-dimensional [field] of cell [State]s.
  • /

class Grid {

 Grid(this.xCount, this.yCount) {
   _field = new Map();
   _neighbours = new Neighbourhood().points();
 }
 set(point, state) {
   _field[_pos(point)] = state;
 }
 State get(point) {
   var state = _field[_pos(point)];
   return state != null ? state : State.DEAD;
 }
 int countLiveNeighbours(point) =>
   _neighbours.filter((offset) => get(point + offset) == State.ALIVE).length;
 _pos(point) => '${(point.x + xCount) % xCount}:${(point.y + yCount) % yCount}';
 print() {
   var sb = new StringBuffer();
   iterate((point) { sb.add(get(point).symbol); }, (x) { sb.add("\n"); });
   return sb.toString();
 }
 iterate(eachCell, [finishedRow]) {
   for (var x = 0; x < xCount; x++) {
     for (var y = 0; y < yCount; y++) {
        eachCell(new Point(x, y));
     }
     if(finishedRow != null) {
       finishedRow(x);
     }
   }
 }
 final xCount, yCount;
 List<Point> _neighbours;
 Map<String, State> _field;

}

/**

  • The game updates the [grid] in each step using the [Rule].
  • /

class Game {

 Game(this.grid);
 tick() {
   var newGrid = createNewGrid();
   grid.iterate((point) {
     var rule = new Rule(grid.get(point));
     rule.reactToNeighbours(grid.countLiveNeighbours(point));
     newGrid.set(point, rule.cellState);
   });
   grid = newGrid;
 }
 createNewGrid() => new Grid(grid.xCount, grid.yCount);
 printGrid() => print(grid.print());
 Grid grid;

}

main() {

 // Run the GoL with a blinker.
 runBlinker();

}

runBlinker() {

 var game = new Game(createBlinkerGrid());
 for(int i = 0; i < 3; i++) {
   game.printGrid();
   game.tick();
 }
 game.printGrid();

}

createBlinkerGrid() {

 var grid = new Grid(4, 4);
 loadBlinker(grid);
 return grid;

}

loadBlinker(grid) => blinkerPoints().forEach((point) => grid.set(point, State.ALIVE));

blinkerPoints() => [new Point(0, 1), new Point(1, 1), new Point(2, 1)];</lang>

Test cases driving the design of this code: <lang dart>#import('<path to sdk>/lib/unittest/unittest.dart');

main() {

 group('rules', () {
   test('should let living but lonely cell die', () {
     var rule = new Rule(State.ALIVE);
     rule.reactToNeighbours(1);
     expect(rule.cellState, State.DEAD);
   });
   test('should let proper cell live on', () {
     var rule = new Rule(State.ALIVE);
     rule.reactToNeighbours(2);
     expect(rule.cellState, State.ALIVE);
   });
   test('should let dead cell with three neighbours be reborn', () {
     var rule = new Rule(State.DEAD);
     rule.reactToNeighbours(3);
     expect(rule.cellState, State.ALIVE);
   });
   test('should let living cell with too many neighbours die', () {
     var rule = new Rule(State.ALIVE);
     rule.reactToNeighbours(4);
     expect(rule.cellState, State.DEAD);
   });
 });
 group('grid', () {
   var origin = new Point(0, 0);
   test('should have state', () {
     var grid = new Grid(1, 1);
     expect(grid.get(origin), State.DEAD);
     grid.set(origin, State.ALIVE);
     expect(grid.get(origin), State.ALIVE);
   });
   test('should have dimension', () {
     var grid = new Grid(2, 3);
     expect(grid.get(origin), State.DEAD);
     grid.set(origin, State.ALIVE);
     expect(grid.get(origin), State.ALIVE);
     expect(grid.get(new Point(1, 2)), State.DEAD);
     grid.set(new Point(1, 2), State.ALIVE);
     expect(grid.get(new Point(1, 2)), State.ALIVE);
   });
   test('should be endless', () {
     var grid = new Grid(2, 4);
     grid.set(new Point(2, 4), State.ALIVE);
     expect(grid.get(origin), State.ALIVE);
     grid.set(new Point(-1, -1), State.ALIVE);
     expect(grid.get(new Point(1, 3)), State.ALIVE);
   });
   test('should print itself', () {
     var grid = new Grid(1, 2);
     grid.set(new Point(0, 1), State.ALIVE);
     expect(grid.print(), " #\n");
   });
 });
 group('game', () {
   test('should exists', () {
    var game = new Game(null);
    expect(game, isNotNull);
   });
   test('should create a new grid when ticked', () {
     var grid = new Grid(1, 1);
     var game = new Game(grid);
     game.tick();
     expect(game.grid !== grid);
   });
   test('should have a grid with the same dimension after tick', (){
     var game = new Game(new Grid(2, 3));
     game.tick();
     expect(game.grid.xCount, 2);
     expect(game.grid.yCount, 3);
   });
   test('should apply rules to middle cell', (){
     var grid = new Grid(3, 3);
     grid.set(new Point(1, 1), State.ALIVE);
     var game = new Game(grid);
     game.tick();
     expect(game.grid.get(new Point(1, 1)), State.DEAD);
     grid.set(new Point(0, 0), State.ALIVE);
     grid.set(new Point(1, 0), State.ALIVE);
     game = new Game(grid);
     game.tick();
     expect(game.grid.get(new Point(1, 1)), State.ALIVE);
   });
   test('should apply rules to all cells', (){
     var grid = new Grid(3, 3);
     grid.set(new Point(0, 1), State.ALIVE);
     grid.set(new Point(1, 0), State.ALIVE);
     grid.set(new Point(1, 1), State.ALIVE);
     var game = new Game(grid);
     game.tick();
     expect(game.grid.get(new Point(0, 0)), State.ALIVE);
   });
 });

}</lang>

Output:
 #
 #
 #



###



 #
 #
 #



###


Delphi

Translation of: Go

Thanks Rudy Velthuis for the Velthuis.Console library. <lang Delphi> program game_of_life;

{$APPTYPE CONSOLE}


uses

 System.SysUtils,
 Velthuis.Console; // CrlScr

type

 TBoolMatrix = TArray<TArray<Boolean>>;
 TField = record
   s: TBoolMatrix;
   w, h: Integer;
   procedure SetValue(x, y: Integer; b: boolean);
   function Next(x, y: Integer): boolean;
   function State(x, y: Integer): boolean;
   class function NewField(w1, h1: Integer): TField; static;
 end;
 TLife = record
   a, b: TField;
   w, h: Integer;
   class function NewLife(w1, h1: Integer): TLife; static;
   procedure Step;
   function ToString: string;
 end;

{ TField }

class function TField.NewField(w1, h1: Integer): TField; var

 s1: TBoolMatrix;

begin

 SetLength(s1, h1);
 for var i := 0 to High(s1) do
   SetLength(s1[i], w1);
 with Result do
 begin
   s := s1;
   w := w1;
   h := h1;
 end;

end;

function TField.Next(x, y: Integer): boolean; var

 _on: Integer;

begin

 _on := 0;
 for var i := -1 to 1 do
   for var j := -1 to 1 do
     if self.State(x + i, y + j) and not ((j = 0) and (i = 0)) then
       inc(_on);
 Result := (_on = 3) or (_on = 2) and self.State(x, y);

end;

procedure TField.SetValue(x, y: Integer; b: boolean); begin

 self.s[y, x] := b;

end;

function TField.State(x, y: Integer): boolean; begin

 while y < 0 do
   inc(y, self.h);
 while x < 0 do
   inc(x, self.w);
 result := self.s[y mod self.h, x mod self.w]

end;

{ TLife }

class function TLife.NewLife(w1, h1: Integer): TLife; var

 a1: TField;

begin

 a1 := TField.NewField(w1, h1);
 for var i := 0 to (w1 * h1 div 2) do
   a1.SetValue(Random(w1), Random(h1), True);
 with Result do
 begin
   a := a1;
   b := TField.NewField(w1, h1);
   w := w1;
   h := h1;
 end;

end;

procedure TLife.Step; var

 tmp: TField;

begin

 for var y := 0 to self.h - 1 do
   for var x := 0 to self.w - 1 do
     self.b.SetValue(x, y, self.a.Next(x, y));
 tmp := self.a;
 self.a := self.b;
 self.b := tmp;

end;

function TLife.ToString: string; begin

 result := ;
 for var y := 0 to self.h - 1 do
 begin
   for var x := 0 to self.w - 1 do
   begin
     var b: char := ' ';
     if self.a.State(x, y) then
       b := '*';
     result := result + b;
   end;
   result := result + #10;
 end;

end;

begin

 Randomize;
 var life := TLife.NewLife(80, 15);
 for var i := 1 to 300 do
 begin
   life.Step;
   ClrScr;
   writeln(life.ToString);
   sleep(30);
 end;
 readln;

end.</lang>

Output:
                *  ***   *        *                   *
                 *  **                                           **      *
                  ****     *                                   *  *      *
                       *** *                               *  ** *       *
                      *** **                              * *  *
                *        *                                   *
              ** **   ****                                ** *
              ******    **                                  * *
               *  *                                     * *** **     ***
                **                                          * *
                      *                                 *    **
                      *                                   * *
                  *  *            *                         *
                    * ***        * *                  *     **
                    * ***        * *                  *                    ***

E

Just does three generations of a blinker in a dead-boundary grid, as specified. (User:Kevin Reid has graphical and wrapping versions.)

<lang e>def gridWidth := 3 def gridHeight := 3 def X := 0..!gridWidth def Y := 0..!gridHeight

def makeFlexList := <elib:tables.makeFlexList> def makeGrid() {

 def storage := makeFlexList.fromType(<type:java.lang.Boolean>, gridWidth * gridHeight)
 storage.setSize(gridWidth * gridHeight)
 def grid {
   to __printOn(out) {
     for y in Y {
       out.print("[")
       for x in X {
         out.print(grid[x, y].pick("#", " "))
       }
       out.println("]")
     }
   }
   to get(xb :int, yb :int) {
     return if (xb =~ x :X && yb =~ y :Y) {
       storage[y * gridWidth + x]
     } else {
       false
     }
   }
   to put(x :X, y :Y, c :boolean) { 
     storage[y * gridWidth + x] := c
   }
 }
 return grid

}

def mooreNeighborhood := [[-1,-1],[0,-1],[1,-1],[-1,0],[1,0],[-1,1],[0,1],[1,1]] def computeNextLife(prevGrid, nextGrid) {

 for y in Y {
   for x in X {
     var neighbors := 0
     for [nx, ny] ? (prevGrid[x+nx, y+ny]) in mooreNeighborhood {
       neighbors += 1
     }
     def self := prevGrid[x, y]
     nextGrid[x, y] := (self && neighbors == 2 || neighbors == 3)
   }
 }

}

var currentFrame := makeGrid() var nextFrame := makeGrid() currentFrame[1, 0] := true currentFrame[1, 1] := true currentFrame[1, 2] := true

for _ in 1..3 {

 def frame := nextFrame
 computeNextLife(currentFrame, frame)
 nextFrame := currentFrame
 currentFrame := frame
 println(currentFrame)

}</lang>

EasyLang

Run it

<lang>n = 70 n += 1 subr init

 for r = 1 to n - 1
   for c = 1 to n - 1
     i = r * n + c
     if randomf < 0.3
       f[i] = 1
     .
   .
 .

. f = 100 / (n - 1) subr show

 clear
 for r = 1 to n - 1
   for c = 1 to n - 1
     if f[r * n + c] = 1
       move (c - 1) * f (r - 1) * f
       rect f * 0.9 f * 0.9
     .
   .
 .

. subr update

 swap f[] p[]
 for r = 1 to n - 1
   sm = 0
   i = r * n
   sr = p[i - n + 1] + p[i + 1] + p[i + n + 1]
   for c = 1 to n - 1
     i += 1
     sl = sm
     sm = sr
     sr = p[i - n + 1] + p[i + 1] + p[i + n + 1]
     s = sl + sm + sr
     if s = 3 or s = 4 and p[i] = 1
       f[i] = 1
     else
       f[i] = 0
     .
   .
 .

. on timer

 call update
 call show
 timer 0.2

. on mouse_down

 c = mouse_x div f
 r = mouse_y div f
 i = r * n + c + n + 1
 f[i] = 1 - f[i]
 call show
 timer 3

. len f[] n * n + n + 1 len p[] n * n + n + 1 call init timer 0</lang>

eC

Library: Ecere

<lang eC> import "ecere"

define seed = 12345; define popInit = 1000; define width = 100; define height = 100; define cellWidth = 4; define cellHeight = 4;

Array<byte> grid { size = width * height }; Array<byte> newState { size = width * height };

class GameOfLife : Window {

  caption = $"Conway's Game of Life";
  background = lightBlue;
  borderStyle = sizable;
  hasMaximize = true;
  hasMinimize = true;
  hasClose = true;
  clientSize = { width * cellWidth, height * cellHeight };
  Timer tickTimer
  {
     delay = 0.05, started = true, userData = this;
     bool DelayExpired()
     {
        int y, x, ix = 0;
        for(y = 0; y < height; y++)
        {
           for(x = 0; x < width; x++, ix++)
           {
              int nCount = 0;
              byte alive;
              if(x > 0       && y > 0        && grid[ix - width - 1]) nCount++;
              if(               y > 0        && grid[ix - width    ]) nCount++;
              if(x < width-1 && y > 0        && grid[ix - width + 1]) nCount++;
              if(x > 0                       && grid[ix         - 1]) nCount++;
              if(x < width - 1               && grid[ix         + 1]) nCount++;
              if(x > 0       && y < height-1 && grid[ix + width - 1]) nCount++;
              if(               y < height-1 && grid[ix + width    ]) nCount++;
              if(x < width-1 && y < height-1 && grid[ix + width + 1]) nCount++;
              if(grid[ix])
                 alive = nCount >= 2 && nCount <= 3; // Death
              else
                 alive = nCount == 3; // Birth
              newState[ix] = alive;
           }
        }
        memcpy(grid.array, newState.array, width * height);
        Update(null);
        return true;
     }
  };
  void OnRedraw(Surface surface)
  {
     int x, y;
     int ix = 0;
     surface.background = navy;
     for(y = 0; y < height; y++)
     {
        for(x = 0; x < width; x++, ix++)
        {
           if(grid[ix])
           {
              int sy = y * cellHeight;
              int sx = x * cellWidth;
              surface.Area(sx, sy, sx + cellWidth-1, sy + cellHeight-1);
           }
        }
     }
  }
  bool OnCreate()
  {
     int i;
     RandomSeed(seed);
     for(i = 0; i < popInit; i++)
     {
        int x = GetRandom(0, width-1);
        int y = GetRandom(0, height-1);
        grid[y * width + x] = 1;
     }
     return true;
  }

}

GameOfLife life {}; </lang>

Egel

<lang Egel>import "prelude.eg" import "io.ego"

using System using List using IO

def boardsize = 5

def empty = [ X Y -> 0 ]

def insert =

   [ X Y BOARD -> 
       [ X0 Y0 -> if and (X0 == X) (Y0 == Y) then 1
                   else BOARD X0 Y0 ] ]

def coords =

   let R = fromto 0 (boardsize - 1) in
       [ XX YY -> map (\X -> map (\Y -> X Y) YY) XX ] R R

def printcell =

   [ 0 -> print ". "
   | _ -> print "* " ]

def printboard =

   [ BOARD ->
       let M  = map [XX -> let _ = map [(X Y) -> printcell (BOARD X Y)] XX in print "\n" ] coords in
           nop ]

def count =

   [ BOARD, X, Y ->
       (BOARD (X - 1) (Y - 1)) + (BOARD (X) (Y - 1)) + (BOARD (X+1) (Y - 1)) +
       (BOARD (X - 1) Y) + (BOARD (X+1) Y) +
       (BOARD (X - 1) (Y+1)) + (BOARD (X) (Y+1)) + (BOARD (X+1) (Y+1)) ]

def next =

   [ 0 N -> if N == 3 then 1 else 0
   | _ N -> if or (N == 2) (N == 3) then 1 else 0 ]

def updateboard =

   [ BOARD ->
       let XX = map (\(X Y) -> X Y (BOARD X Y) (count BOARD X Y)) (flatten coords) in
       let YY = map (\(X Y C N) -> X Y (next C N)) XX in
           foldr [(X Y 0) BOARD -> BOARD | (X Y _) BOARD -> insert X Y BOARD ] empty YY ]

def blinker =

   (insert 1 2) @ (insert 2 2) @ (insert 3 2)

def main =

   let GEN0 = blinker empty in
   let GEN1 = updateboard GEN0 in
   let GEN2 = updateboard GEN1 in
   let _ = map [ G -> let _ = print "generation:\n" in printboard G ] {GEN0, GEN1, GEN2} in
       nop

</lang>

Elena

ELENA 5.0, using cellular library <lang elena>import extensions; import system'threading; import cellular;

const int maxX = 48; const int maxY = 28;

const int DELAY = 50;

sealed class Model {

   Space   theSpace;
   RuleSet theRuleSet;
   bool    started;
   event Func<Space, object> OnUpdate;
   
   constructor newRandomset(RuleSet transformSet)
   {
       theSpace := new IntMatrixSpace.allocate(maxY, maxX, randomSet);
       theRuleSet := transformSet;
       
       started := false
   }
   
   constructor newLoaded(RuleSet initSet, RuleSet transformSet)
   {
       theSpace := IntMatrixSpace.allocate(maxY, maxX, initSet);
                       
       theRuleSet := transformSet;
       
       started := false
   }
   
   private onUpdate()
   {
       OnUpdate.?(theSpace)
   }
   
   run()
   {
       if (started)
       { 
           theSpace.update(theRuleSet) 
       }
       else
       {
           started := true
       };
       
       self.onUpdate()
   }

}

singleton gameOfLifeRuleSet : RuleSet {

   proceed(Space s, int x, int y, ref int retVal)
   {
       int cell := s.at(x, y);
       int number := s.LiveCell(x, y, 1); // NOTE : number of living cells around the self includes the cell itself
       
       if (cell == 0 && number == 3)
       {
           retVal := 1 
       }
       else if (cell == 1 && (number == 4 || number == 3))
       {
           retVal := 1 
       }
       else
       {
           retVal := 0
       }
   }

}

public extension presenterOp : Space {

   print()
   {
       console.setCursorPosition(0, 0);
       
       int columns := self.Columns;
       int rows := self.Rows;
       
       for(int i := 0, i < rows, i += 1)
       {
           for(int j := 0, j < columns, j += 1)
           {
               int cell := self.at(i, j);
               
               console.write((cell == 0).iif(" ","o"));
           };
           
           console.writeLine()
       }
   }

}

public program() {

   auto model := Model.newRandomset(gameOfLifeRuleSet);
   console.clear();
   
   model.OnUpdate := (Space sp){ sp.print() };
   until (console.KeyAvailable)
   {
       model.run();
       
       threadControl.sleep:DELAY
   };
   console.readChar()

}</lang>

Elixir

Works with: Elixir version 1.2
Translation of: Ruby

<lang elixir>defmodule Conway do

 def game_of_life(name, size, generations, initial_life\\nil) do
   board = seed(size, initial_life)
   print_board(board, name, size, 0)
   reason = generate(name, size, generations, board, 1)
   case reason do
     :all_dead -> "no more life."
     :static   -> "no movement"
     _         -> "specified lifetime ended"
   end
   |> IO.puts
   IO.puts ""
 end
 
 defp new_board(n) do
   for x <- 1..n, y <- 1..n, into: %{}, do: {{x,y}, 0}
 end
 defp seed(n, points) do
   if points do
     points
   else # randomly seed board
     (for x <- 1..n, y <- 1..n, do: {x,y}) |> Enum.take_random(10)
   end
   |> Enum.reduce(new_board(n), fn pos,acc -> %{acc | pos => 1} end)
 end
 
 defp generate(_, _, generations, _, gen) when generations < gen, do: :ok
 defp generate(name, size, generations, board, gen) do
   new = evolve(board, size)
   print_board(new, name, size, gen)
   cond do
     barren?(new) -> :all_dead
     board == new -> :static
     true         -> generate(name, size, generations, new, gen+1)
   end
 end
 
 defp evolve(board, n) do
   for x <- 1..n, y <- 1..n, into: %{}, do: {{x,y}, fate(board, x, y, n)}
 end
 
 defp fate(board, x, y, n) do
   irange = max(1, x-1) .. min(x+1, n)
   jrange = max(1, y-1) .. min(y+1, n)
   sum = ((for i <- irange, j <- jrange, do: board[{i,j}]) |> Enum.sum) - board[{x,y}]
   cond do
     sum == 3                       -> 1
     sum == 2 and board[{x,y}] == 1 -> 1
     true                           -> 0
   end
 end
 
 defp barren?(board) do
   Enum.all?(board, fn {_,v} -> v == 0 end)
 end
 defp print_board(board, name, n, generation) do
   IO.puts "#{name}: generation #{generation}"
   Enum.each(1..n, fn y ->
     Enum.map(1..n, fn x -> if board[{x,y}]==1, do: "#", else: "." end)
     |> IO.puts
   end)
 end

end

Conway.game_of_life("blinker", 3, 2, [{2,1},{2,2},{2,3}]) Conway.game_of_life("glider", 4, 4, [{2,1},{3,2},{1,3},{2,3},{3,3}]) Conway.game_of_life("random", 5, 10)</lang>

Output:
blinker: generation 0
.#.
.#.
.#.
blinker: generation 1
...
###
...
blinker: generation 2
.#.
.#.
.#.
specified lifetime ended

glider: generation 0
.#..
..#.
###.
....
glider: generation 1
....
#.#.
.##.
.#..
glider: generation 2
....
..#.
#.#.
.##.
glider: generation 3
....
.#..
..##
.##.
glider: generation 4
....
..#.
...#
.###
specified lifetime ended

random: generation 0
.#...
#.#..
#...#
###.#
..#..
random: generation 1
.#...
#....
#.#..
#.#..
..##.
random: generation 2
.....
#....
#....
..#..
.###.
random: generation 3
.....
.....
.#...
..##.
.###.
random: generation 4
.....
.....
..#..
...#.
.#.#.
random: generation 5
.....
.....
.....
...#.
..#..
random: generation 6
.....
.....
.....
.....
.....
no more life.

Emacs Lisp

<lang lisp>#!/usr/bin/env emacs -script

-*- lexical-binding
t -*-
run
./conways-life conways-life.config

(require 'cl-lib)

(defconst blinker '("***")) (defconst toad '(".***" "***.")) (defconst pentomino-p '(".**" ".**" ".*.")) (defconst pi-heptomino '("***" "*.*" "*.*")) (defconst glider '(".*." "..*" "***")) (defconst pre-pulsar '("***...***" "*.*...*.*" "***...***")) (defconst ship '("**." "*.*" ".**")) (defconst pentadecathalon '("**********")) (defconst clock '("..*." "*.*." ".*.*" ".*.."))

(defmacro swap (a b)

 `(setq ,b (prog1 ,a (setq ,a ,b))))

(cl-defstruct world rows cols data)

(defun new-world (rows cols)

 (make-world :rows rows :cols cols :data (make-vector (* rows cols) nil)))

(defmacro world-pt (w r c)

 `(+ (* (mod ,r (world-rows ,w)) (world-cols ,w))
     (mod ,c (world-cols ,w))))

(defmacro world-ref (w r c)

 `(aref (world-data ,w) (world-pt ,w ,r ,c)))

(defun print-world (world)

 (dotimes (r (world-rows world))
   (dotimes (c (world-cols world))
     (princ (format "%c" (if (world-ref world r c) ?* ?.))))
   (terpri)))

(defun insert-pattern (world row col shape)

 (let ((r row)
       (c col))
   (unless (listp shape)
     (setq shape (symbol-value shape)))
   (dolist (row-data shape)
     (dolist (col-data (mapcar 'identity row-data))
       (setf (world-ref world r c) (not (or (eq col-data ?.))))
       (setq c (1+ c)))
     (setq r (1+ r))
     (setq c col))))

(defun neighbors (world row col)

 (let ((n 0))
   (dolist (offset '((1 . 1) (1 . 0) (1 . -1) (0 . 1) (0 . -1) (-1 . 1) (-1 . 0) (-1 . -1)))
     (when (world-ref world (+ row (car offset)) (+ col (cdr offset)))
       (setq n (1+ n))))
   n))

(defun advance-generation (old new)

 (dotimes (r (world-rows old))
   (dotimes (c (world-cols old))
     (let ((n (neighbors old r c)))
       (setf (world-ref new r c)
             (if (world-ref old r c)
                 (or (= n 2) (= n 3))
               (= n 3)))))))

(defun read-config (file-name)

 (with-temp-buffer
   (insert-file-contents-literally file-name)
   (read (current-buffer))))

(defun get-config (key config)

 (let ((val (assoc key config)))
   (if (null val)
       (error (format "missing value for %s" key))
     (cdr val))))

(defun insert-patterns (world patterns)

 (dolist (p patterns)
   (apply 'insert-pattern (cons world p))))

(defun simulate-life (file-name)

 (let* ((config (read-config file-name))
        (rows (get-config 'rows config))
        (cols (get-config 'cols config))
        (generations (get-config 'generations config))
        (a (new-world rows cols))
        (b (new-world rows cols)))
   (insert-patterns a (get-config 'patterns config))
   (dotimes (g generations)
     (princ (format "generation %d\n" g))
     (print-world a)
     (advance-generation a b)
     (swap a b))))

(simulate-life (elt command-line-args-left 0))</lang>

Configuration file, which defines the size starting patterns and how long the simulation will run. <lang lisp>((rows . 8)

(cols . 10)
(generations . 3)
(patterns
 ;; Blinker is defined in the script.
 (1 1 blinker)
 ;; This is a custom pattern.
 (4 4 (".***"
       "***."))))</lang>
Output:
generation 0
..........
.***......
..........
..........
.....***..
....***...
..........
..........
generation 1
..*.......
..*.......
..*.......
......*...
....*..*..
....*..*..
.....*....
..........
generation 2
..........
.***......
..........
..........
.....***..
....***...
..........
..........

Erlang

<lang Erlang>

-module(life).

-export([bang/1]).


-define(CHAR_DEAD, 32).  % " " -define(CHAR_ALIVE, 111).  % "o" -define(CHAR_BAR, 45).  % "-"

-define(GEN_INTERVAL, 100).


-record(state, {x  :: non_neg_integer()

              ,y            :: non_neg_integer()
              ,n            :: pos_integer()
              ,bar          :: nonempty_string()
              ,board        :: array()
              ,gen_count    :: pos_integer()
              ,gen_duration :: non_neg_integer()
              ,print_time   :: non_neg_integer()
              }).


%% ============================================================================ %% API %% ============================================================================

bang(Args) ->

   [X, Y] = [atom_to_integer(A) || A <- Args],
   {Time, Board} = timer:tc(fun() -> init_board(X, Y) end),
   State = #state{x            = X
                 ,y            = Y
                 ,n            = X * Y
                 ,bar          = [?CHAR_BAR || _ <- lists:seq(1, X)]
                 ,board        = Board
                 ,gen_count    = 1  % Consider inital state to be generation 1
                 ,gen_duration = Time
                 ,print_time   = 0  % There was no print time yet
   },
   life_loop(State).


%% ============================================================================ %% Internal %% ============================================================================

life_loop(

   #state{x            = X
         ,y            = Y
         ,n            = N
         ,bar          = Bar
         ,board        = Board
         ,gen_count    = GenCount
         ,gen_duration = Time
         ,print_time   = LastPrintTime
   }=State) ->
   {PrintTime, ok} = timer:tc(
       fun() ->
           do_print_screen(Board, Bar, X, Y, N, GenCount, Time, LastPrintTime)
       end
   ),
   {NewTime, NewBoard} = timer:tc(
       fun() ->
           next_generation(X, Y, Board)
       end
   ),
   NewState = State#state{board        = NewBoard
                         ,gen_count    = GenCount + 1
                         ,gen_duration = NewTime
                         ,print_time   = PrintTime
   },
   NewTimeMil = NewTime / 1000,
   NextGenDelay = at_least_zero(round(?GEN_INTERVAL - NewTimeMil)),
   timer:sleep(NextGenDelay),
   life_loop(NewState).


at_least_zero(Integer) when Integer >= 0 -> Integer; at_least_zero(_) -> 0.


do_print_screen(Board, Bar, X, Y, N, GenCount, Time, PrintTime) ->

   ok = do_print_status(Bar, X, Y, N, GenCount, Time, PrintTime),
   ok = do_print_board(Board).


do_print_status(Bar, X, Y, N, GenCount, TimeMic, PrintTimeMic) ->

   TimeSec = TimeMic / 1000000,
   PrintTimeSec = PrintTimeMic / 1000000,
   ok = io:format("~s~n", [Bar]),
   ok = io:format(
       "X: ~b Y: ~b CELLS: ~b GENERATION: ~b DURATION: ~f PRINT TIME: ~f~n",
       [X, Y, N, GenCount, TimeSec, PrintTimeSec]
   ),
   ok = io:format("~s~n", [Bar]).


do_print_board(Board) ->

   % It seems that just doing a fold should be faster than map + to_list
   % combo, but, after measuring several times, map + to_list has been
   % consistently (nearly twice) faster than either foldl or foldr.
   RowStrings = array:to_list(
       array:map(
           fun(_, Row) ->
               array:to_list(
                   array:map(
                       fun(_, State) ->
                           state_to_char(State)
                       end,
                       Row
                   )
               )
           end,
           Board
       )
   ),
   ok = lists:foreach(
       fun(RowString) ->
           ok = io:format("~s~n", [RowString])
       end,
       RowStrings
   ).


state_to_char(0) -> ?CHAR_DEAD; state_to_char(1) -> ?CHAR_ALIVE.


next_generation(W, H, Board) ->

   array:map(
       fun(Y, Row) ->
           array:map(
               fun(X, State) ->
                   Neighbors = filter_offsides(H, W, neighbors(X, Y)),
                   States = neighbor_states(Board, Neighbors),
                   LiveNeighbors = lists:sum(States),
                   new_state(State, LiveNeighbors)
               end,
               Row
           )
       end,
       Board
   ).


new_state(1, LiveNeighbors) when LiveNeighbors < 2 -> 0; new_state(1, LiveNeighbors) when LiveNeighbors < 4 -> 1; new_state(1, LiveNeighbors) when LiveNeighbors > 3 -> 0; new_state(0, LiveNeighbors) when LiveNeighbors =:= 3 -> 1; new_state(State, _LiveNeighbors) -> State.


neighbor_states(Board, Neighbors) ->

   [array:get(X, array:get(Y, Board)) || {X, Y} <- Neighbors].


filter_offsides(H, W, Coordinates) ->

   [{X, Y} || {X, Y} <- Coordinates, is_onside(X, Y, H, W)].


is_onside(X, Y, H, W) when (X >= 0) and (Y >= 0) and (X < W) and (Y < H) -> true; is_onside(_, _, _, _) -> false.


neighbors(X, Y) ->

   [{X + OffX, Y + OffY} || {OffX, OffY} <- offsets()].


offsets() ->

   [offset(D) || D <- directions()].


offset('N') -> { 0, -1}; offset('NE') -> { 1, -1}; offset('E') -> { 1, 0}; offset('SE') -> { 1, 1}; offset('S') -> { 0, 1}; offset('SW') -> {-1, 1}; offset('W') -> {-1, 0}; offset('NW') -> {-1, -1}.


directions() ->

   ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'].


init_board(X, Y) ->

   array:map(fun(_, _) -> init_row(X) end, array:new(Y)).


init_row(X) ->

   array:map(fun(_, _) -> init_cell_state() end, array:new(X)).


init_cell_state() ->

   crypto:rand_uniform(0, 2).


atom_to_integer(Atom) ->

   list_to_integer(atom_to_list(Atom)).

</lang>

ERRE

This is a simple implementation of Conway's game of Life with an endless world. Test pattern configuration is 'glider'. <lang ERRE> PROGRAM LIFE

!$INTEGER

!$KEY !for C-64 compatibility

CONST Xmax=38,Ymax=20

DIM x,y,N DIM WORLD[39,21],NextWORLD[39,21]

BEGIN

! Glider test !------------------------------------------ WORLD[1,1]=1 WORLD[1,2]=0 WORLD[1,3]=0 WORLD[2,1]=0 WORLD[2,2]=1 WORLD[2,3]=1 WORLD[3,1]=1 WORLD[3,2]=1 WORLD[3,3]=0 !------------------------------------------

PRINT(CHR$(12);"Press any key to interrupt") LOOP

 PRINT(CHR$(11);) PRINT
 PRINT(STRING$(Xmax+2,"-"))
 !---------- endless world ---------
 FOR y=1 TO Ymax DO
   WORLD[0,y]=WORLD[Xmax,y]
   WORLD[Xmax+1,y]=WORLD[1,y]
 END FOR
 FOR x=1 TO Xmax DO
   WORLD[x,0]=WORLD[x,Ymax]
   WORLD[x,Ymax+1]=WORLD[x,1]
 END FOR
 WORLD[0,0]=WORLD[Xmax,Ymax]
 WORLD[Xmax+1,Ymax+1]=WORLD[1,1]
 WORLD[Xmax+1,0]=WORLD[1,Ymax]
 WORLD[0,Ymax+1]=WORLD[Xmax,1]
 !---------- endless world ---------
 FOR y=1 TO Ymax DO
   PRINT("|";)
   FOR x=1 TO Xmax DO
     PRINT(CHR$(32+WORLD[x,y]*3);)
     N=WORLD[x-1,y-1]+WORLD[x-1,y]+WORLD[x-1,y+1]+WORLD[x,y-1]
     N=N+WORLD[x,y+1]+WORLD[x+1,y-1]+WORLD[x+1,y]+WORLD[x+1,y+1]
     IF (WORLD[x,y]<>0 AND (N=2 OR N=3)) OR (WORLD[x,y]=0 AND N=3) THEN
       NextWORLD[x,y]=1
     ELSE
       NextWORLD[x,y]=0
     END IF
   END FOR
   PRINT("|")
 END FOR
 PRINT(STRING$(Xmax+2,"-"))
 PAUSE(0.1)
 FOR x=0 TO Xmax+1 DO
   FOR y=0 TO Ymax+1 DO
     WORLD[x,y]=NextWORLD[x,y]
     NextWORLD[x,y]=0
   END FOR
 END FOR
 REPEAT
     GET(A$)
 UNTIL A$<>""
 EXIT IF A$=CHR$(27)

END LOOP

PRINT("Press any key to exit") REPEAT UNTIL GETKEY$<>"" END PROGRAM

</lang>

F#

The following F# implementation uses

for visualization and is easily compiled into a standalone executable:

<lang fsharp>let count (a: _ [,]) x y =

 let m, n = a.GetLength 0, a.GetLength 1
 let mutable c = 0
 for x in x-1..x+1 do
   for y in y-1..y+1 do
     if x>=0 && x<m && y>=0 && y<n && a.[x, y] then
       c <- c + 1
 if a.[x, y] then c-1 else c

let rule (a: _ [,]) x y =

 match a.[x, y], count a x y with
 | true, (2 | 3) | false, 3 -> true
 | _ -> false

open System.Windows open System.Windows.Media.Imaging

[<System.STAThread>] do

 let rand = System.Random()
 let n = 256
 let game = Array2D.init n n (fun _ _ -> rand.Next 2 = 0) |> ref
 let image = Controls.Image(Stretch=Media.Stretch.Uniform)
 let format = Media.PixelFormats.Gray8
 let pixel = Array.create (n*n) 0uy
 let update _ =
   game := rule !game |> Array2D.init n n
   for x in 0..n-1 do
     for y in 0..n-1 do
       pixel.[x+y*n] <- if (!game).[x, y] then 255uy else 0uy
   image.Source <-
     BitmapSource.Create(n, n, 1.0, 1.0, format, null, pixel, n)
 Media.CompositionTarget.Rendering.Add update
 Window(Content=image, Title="Game of Life")
 |> (Application()).Run |> ignore</lang>

Fermat

<lang fermat>;{Conway's Game of Life in Fermat}

{square grid with wrap-around boundaries}

size:=50; {how big a grid do you want? This fits my screen OK, change this for your own screen}

Array w1[size,size], w2[size,size]; {set up an active world and a 'scratchpad' world} act:=1; buf:=2; %[1]:=[w1]; {Fermat doesn't have 3D arrays in the normal sense--} %[2]:=[w2]; {we need to use the somewhat odd "array of arrays" functionality}

Func Cls = for i = 1 to size do !!; od.; {"clear screen" by printing a bunch of newlines}

Func Draw = {draw the active screen}

   for i = 1 to size do
       for j = 1 to size do
           if %[act][i, j] = 1 then !('# ') else !('. ') fi;
       od;
       !;
   od;

.;

Func Rnd = {randomize the grid with a density of 40% live cells}

   for i = 1 to size do
       for j = 1 to size do
           if Rand|5<2 then %[act][i, j] := 1 else %[act][i, j] := 0 fi;
       od;
   od;
   Cls;
   Draw;

.;

Func Blinker = {clears the screen except for a blinker in the top left corner}

   for i = 1 to size do
       for j = 1 to size do
           %[act][i, j] := 0;
       od;
   od;
   %[act][1,2] := 1;
   %[act][2,2] := 1;
   %[act][3,2] := 1;
   Cls;
   Draw;

.;

Func Iter = {do one iteration}

   for i = 1 to size do
       if i = 1 then im := size else im := i - 1 fi;        {handle wrap around}
       if i = size then ip := 1 else ip := i + 1 fi;
       for j = 1 to size do
           if j = 1 then jm := size else jm := j - 1 fi;
           if j = size then jp := 1 else jp := j + 1 fi;
           neigh :=  %[act][im, jm];                        {count neigbours}
           neigh :+ (%[act][im, j ]);
           neigh :+ (%[act][im, jp]);
           neigh :+ (%[act][i , jm]);
           neigh :+ (%[act][i , jp]);
           neigh :+ (%[act][ip, jm]);
           neigh :+ (%[act][ip, j ]);
           neigh :+ (%[act][ip, jp]);
           if neigh < 2 or neigh > 3 then %[buf][i, j] := 0 fi;      {alive and dead rules}
           if neigh = 2 then %[buf][i, j] := %[act][i, j] fi;
           if neigh = 3 then %[buf][i, j] := 1 fi;                              
       od;
   od;
   Swap(act, buf);     {rather than copying the scratch over into the active, just exchange their identities}
   Cls;
   Draw;

.;

choice := 9; while choice <> 0 do {really rough menu, not the point of this exercise}

   ?choice;
   if choice=4 then Cls fi;
   if choice=3 then Blinker fi;
   if choice=2 then Rnd fi;
   if choice=1 then Iter fi;

od;

!!'John Horton Conway (26 December 1937 – 11 April 2020)'; </lang>

Output:

One iteration starting from random soup, showing a few well-known objects (blinker, block, glider, beehive, loaf)

# . . . . . . . . . # . . # . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . # # . . . 
. . . . . . . # . . # . . . # . . . . # # . # # . . # # # . . . . . . . . . . . . . . . # # . # . # 
. . . . . . # . # # . . . # . . . . . # # . # . . . # . . # . . . . . . . . . . . . . . # # . . # . 
. . . . . . # . # . # . . # . . . . . # . # # . . # . . . # . . . . # # . . . . . . . . . . . . . . 
. . . . . . . # . # # . . # . . . # # # # . . . . # . . # . . . . # . . # . . . . . . . . . . . . . 
. . . . . . . . . . . . # . . . . # . . . . . . . . . . . . . . . . # . . # . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . # # # . . . . . . # # . . . . . . # . . # . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . . . # . # . . . . . . . . . . . . . 
. . . . # # # . . . . . . . . . . . # . . . . # # . . . . . . . . . . # . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . # # # # . . # . # . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . # # . . # . . # . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . . # # # . . . . . . . # # . . . . . # . . . . . . . . . . # . . . . . . . . . . . . . . . 
. . . . . . # # # . . . . . . . . . . . # # . . . . . . . . . . . # . # . . . . . . . . . . . . . . 
. . . . . # . . # . # # . . . . . . # # . # . . . . . . . . . . . # . . # . . . . . . . . . . . . . 
. . . . . . # # . # # . . . . . . . . # # . . . . . . . . . . . . . # # . . . . . . . . . . . . . . 
. . . . . . # # # # # . . . . . . . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . . . # . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . . . . . . . . 
. . . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . . . . . . . 
. . . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . # # . . . . . . # # # 
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . . . . . . # . . . 
# . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . # 
. . . . . . # . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . # . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . . . . 
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # 
# # . . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . # # 
. # # . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . . # 
. # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . # . # # . . . . . . . # # . . . 
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . # . # . . . . . . . . . # # . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . . # . # # . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . . # # # # . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . # # . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . # # # . . . . . . . . . . . . . . . . . . . . . . . . # . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . . . . . . . . # . . . . . . . . 
. . . . . . . . . . . . # . . . . . . . . . . . . . . # . # . # # . # . . . . . . # . . . . . . . . 
. . . . . . . . . . . . # . . . . . . . . . . . . . # . . . . . . . . # . . . . . . . . . . . . . . 
. . . . . . . . . . . . # . . . . . . . . . . . . # . . # # # # . . . # . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . # # # . . . . . . # . . . . . . . . . . . . . . . 
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . # # . 
. . . . . . . . . . . . . . . . . # # . . . . . . . . . . . . . . . . . . . . . . . . . . . # . # . 
. . . . . . . . . . . . # # . . # . . . . . . . . . . . . . . . . . . . . . . . . . . . . # . . # . 
. . . . . . . . . . . . # . # . . # . . . . . . . . . . . . . . # . . . . . . . . . . . . # . . . . 
. . . . . . . . . . . . # . . . . . . # . . . . . . . . . . . # . . # . . . . . . . . . # # . # . . 
. . . . . . . . . . . . . . . . . . # . . . . . . . . . . . . . # # . . . . . . . . . . . . . . # # 
. . . . . . . . . . . # . # . . . . # . . # . . . . . . . . . . . . . . . . . . . . . . . # # # . # 

Forth

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

<lang forth> \ 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</lang>

Fortran

Works with: Fortran version 90 and later

<lang fortran> 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 NextgenV2(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 j = 1, SIZE(cells, 2)-2
       DO i = 1, SIZE(cells, 1)-2
         if(buffer(i, j)) then
           neighbours = sum(count(buffer(i-1:i+1, j-1:j+1), 1)) - 1
         else
           neighbours = sum(count(buffer(i-1:i+1, j-1:j+1), 1))
         end if
 
         SELECT CASE(neighbours)
           CASE (0:1, 4:8)
              cells(i,j) = .FALSE.
 
           CASE (2)
              ! No change
 
           CASE (3)
              cells(i,j) = .TRUE.
         END SELECT
         
       END DO
    END DO
 END SUBROUTINE Nextgen

!########################################################################### ! In this version instead of cycling through all points an integer array ! is used the sum the live neighbors of all points. The sum is done with ! the entire array cycling through the eight positions of the neighbors. ! Executing a grid size of 10000 in 500 generations this version gave a ! speedup of almost 4 times. !###########################################################################

 PURE SUBROUTINE NextgenV2(cells)
    LOGICAL, INTENT(IN OUT) :: cells(:,:)
    INTEGER(KIND=1) :: buffer(1:SIZE(cells, 1)-2,1:SIZE(cells, 2)-2)
    INTEGER :: gridsize, i, j
    
    gridsize=SIZE(cells, 1)
    buffer=0
    
    DO j=-1, 1
       DO i=-1,1
          IF(i==0 .AND. j==0) CYCLE
          WHERE(cells(i+2:gridsize-i-1,j+2:gridsize-j-1)) buffer=buffer+1
       END DO
    END DO
    WHERE(buffer<2 .or. buffer>3) cells(2:gridsize-1,2:gridsize-1) = .FALSE.
    WHERE(buffer==3) cells(2:gridsize-1,2:gridsize-1) = .TRUE.
 END SUBROUTINE NextgenV2

!###########################################################################

END PROGRAM LIFE_2D</lang>
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
           
           
   ###      
   ###      
   ###      
      ###   
      ###   
      ###

Frink

Simple solution using two dictionaries (a display and a toggle) to store grid and track changes. The program outputs an animation of the game. <lang frink> start = now[] // Generate a random 10x10 grid with "1" being on and "0" being off instructions = ["1000100110","0001100010","1000111101","1001111110","0000110011","1111000001","0100001110","1011101001","1001011000","1101110111"]

// Create dictionary of starting positions. rowCounter = 0 display = new dict for instructionStr = instructions {

  rowCounter = rowCounter + 1
  columnCounter = 0
  instructionArr = charList[instructionStr]
  for instruction = instructionArr
  {
     columnCounter = columnCounter + 1
     arr = [rowCounter,columnCounter]
     if instruction == "1"
        display@arr = 1
     else
        display@arr = 0
  }

}

// Create toggle dictionary to track changes. It starts off with everything off. toggle = new dict multifor[x,y] = [new range[1,10],new range[1,10]] {

  arr = [x,y]
  toggle@arr = 0

}

// Animate the game of life a = new Animation[3/s] win = undef

// Loop through 10 changes to the grid. The starting points will tick down to two stable unchanging shapes in 10 steps. for i = 1 to 12 // 12 steps so animation will pause on final state. {

  // Graphics item for this frame of the animation.
  g = new graphics
  g.backgroundColor[1,1,1]
  // Add in a transparent shape to prevent the image from jiggle to automatic scaling.
  g.color[0,0,0,0] // Transparent black
  g.fillRectSides[-1, -1, 12, 12] // Set minimum size
  g.clipRectSides[-1, -1, 12, 12] // Set maximum size
  g.color[0,0,0] // Color back to default black
  multifor[x1,y1] = [new range[1,10],new range[1,10]]
  {
     tval = [x1,y1]
     // This is programmed with a hard edge. Points beyond the border aren't considered.
     xmax = min[x1+1,10]
     xmin = max[x1-1,1]
     ymax = min[y1+1,10]
     ymin = max[y1-1,1]
     // Range will be 8 surrounding cells or cells up to border.
     pointx = new range[xmin,xmax]
     pointy = new range[ymin,ymax]
     pointsum = 0
     status = 0
     // Process each surrounded point
     multifor[x2,y2] = [pointx,pointy]
     {
        // Assign the array to a variable so it can be used as a dictionary reference.
        point = [x2,y2]
        if x2 == x1 && y2 == y1
        {
           status = display@point
        } else // Calculate the total of surrounding points
        {
           pointsum = pointsum + display@point
        }
     }
     // Animate if the point is on.
     if status == 1
     {
        g.color[0,0,0]
        g.fillEllipseCenter[x1,y1,1,1]
     }
     toggle@tval = status // This will be overwritten if needed by neighbor check conditions below.

// Check if off point has 3 on point neighbors

     if status == 0 && pointsum == 3
     {
        toggle@tval = 1
     }

// Check if on point has between 2 and 3 on point neighbors

     if status == 1 && (pointsum < 2 || pointsum > 3)
     {
        toggle@tval = 0
     }
  }
  // Add the current frame to the animation
  a.add[g]
  // Replace the current display with the toggle values.
  for toggleKeys = keys[toggle]
  {
     val = toggle@toggleKeys
     display@toggleKeys = val
  }

}

// Write the animation file a.write["FrinkAnimationGoL.gif",400,400]

end = now[] println["Program run time: " + ((end - start)*1.0 -> "seconds")] </lang>

FunL

<lang funl>import lists.zipWithIndex import util.Regex

data Rule( birth, survival )

val Mirek = Regex( '([0-8]+)/([0-8]+)' ) val Golly = Regex( 'B([0-8]+)/S([0-8]+)' )

def decode( rule ) =

 def makerule( b, s ) = Rule( [int(d) | d <- b], [int(d) | d <- s] )
 case rule
   Mirek( s, b ) -> makerule( b, s )
   Golly( b, s ) -> makerule( b, s )
   _ -> error( "unrecognized rule: $rule" )

def fate( state, crowding, rule ) = crowding in rule( int(state) )

def crowd( buffer, x, y ) =

 res = 0
 def neighbour( x, y ) =
   if x >= 0 and x < N and y >= 0 and y < N
     res += int( buffer(x, y) )
 for i <- x-1..x+1
   neighbour( i, y - 1 )
   neighbour( i, y + 1 )
 neighbour( x - 1, y )
 neighbour( x + 1, y )
 res

def display( buffer ) =

 for j <- 0:N
   for i <- 0:N
     print( if buffer(i, j) then '*' else '\u00b7' )
   println()

def generation( b1, b2, rule ) =

 for i <- 0:N, j <- 0:N
   b2(i, j) = fate( b1(i, j), crowd(b1, i, j), rule )

def pattern( p, b, x, y ) =

 for (r, j) <- zipWithIndex( list(WrappedString(p).stripMargin().split('\n')).drop(1).dropRight(1) )
   for i <- 0:r.length()
     b(x + i, y + j) = r(i) == '*'

var current = 0 val LIFE = decode( '23/3' ) val N = 4 val buffers = (array( N, N, (_, _) -> false ), array( N, N ))

def reset =

 for i <- 0:N, j <- 0:N
   buffers(0)(i, j) = false
 current = 0

def iteration =

 display( buffers(current) )
 generation( buffers(current), buffers(current = (current + 1)%2), LIFE )
 println( 5'-' )

// two patterns to be tested blinker =

 |
 |***
 

glider =

 | *
 |  *
 |***
 

// load "blinker" pattern and run for three generations pattern( blinker, buffers(0), 0, 0 )

repeat 3

 iteration()

// clear grid, load "glider" pattern and run for five generations reset() pattern( glider, buffers(0), 0, 0 )

repeat 5

 iteration()</lang>
Output:
····
***·
····
····
-----
·*··
·*··
·*··
····
-----
····
***·
····
····
-----
·*··
··*·
***·
····
-----
····
*·*·
·**·
·*··
-----
····
··*·
*·*·
·**·
-----
····
·*··
··**
·**·
-----
····
··*·
···*
·***
-----

Furor

<lang Furor> // 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. // -----------------------------------------------------

  1. 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 {{| {{}} {{|}} Template:- [[]] 32 > { 1 }{ 0 } sto emblem livingspace @originlin {{|}} + @origincol Template:- + @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 {{| {{|}} Template:- sbr §neighbors {{}} {{|}} Template:- @n ^ // store the neighbournumber |}}

// Now, kill everybody if the neighbors are less than 2 or more than 3: neighbour {{| {{|}} Template:- sbr §killsbr |}}

// Generate the newborn cells: neighbour {{| {{}} {{|}} Template:- [[]] 3 == { livingspace {{|}} Template:- 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 {{|}} Template:- {{}} {{|}} Template:- [[]] { '* }{ 32 } ^ |}} rts

{ „startingshape” } { „livingspace” } { „cellscreen” } { „innerindex” } { „outerindex” } { „maxlinlen” } { „neighbour” } { „originlin” } { „origincol” } { „emblem” } { „tlin” } { „tcol” } { „x” } { „y” } { „n” }

</lang>

Futhark

This example is incorrect. Please fix the code and remove this message.

Details: Futhark's syntax has changed, so this example will not compile

<lang Futhark> fun bint(b: bool): int = if b then 1 else 0 fun intb(x: int): bool = if x == 0 then False else True

fun to_bool_board(board: [][]int): [][]bool =

 map (fn (r: []int): []bool  => map intb r) board

fun to_int_board(board: [][]bool): [][]int =

 map (fn (r: []bool): []int  => map bint r) board

fun cell_neighbors(i: int, j: int, board: [n][m]bool): int =

 unsafe
 let above = (i - 1) % n
 let below = (i + 1) % n
 let right = (j + 1) % m
 let left = (j - 1) % m in
 bint board[above,left] + bint board[above,j]  + bint board[above,right] +
 bint board[i,left] + bint board[i,right] +
 bint board[below,left] + bint board[below,j] + bint board[below,right]

fun all_neighbours(board: [n][m]bool): [n][m]int =

 map (fn (i: int): []int  =>
       map (fn (j: int): int  => cell_neighbors(i,j,board)) (iota m))
     (iota n)

fun iteration(board: [n][m]bool): [n][m]bool =

 let lives = all_neighbours(board) in
 zipWith (fn (lives_r: []int) (board_r: []bool): []bool  =>
           zipWith (fn (neighbors: int) (alive: bool): bool  =>
                     if neighbors < 2
                     then False
                     else if neighbors == 3 then True
                     else if alive && neighbors < 4 then True
                     else False)
                   lives_r board_r)
          lives board

fun main(int_board: [][]int, iterations: int): [][]int =

 -- We accept the board as integers for convenience, and then we
 -- convert to booleans here.
 let board = to_bool_board int_board in
 loop (board) = for i < iterations do
   iteration board in
 to_int_board board

</lang>

Go

<lang go>package main

import ( "bytes" "fmt" "math/rand" "time" )

type Field struct { s [][]bool w, h int }

func NewField(w, h int) Field { s := make([][]bool, h) for i := range s { s[i] = make([]bool, w) } return Field{s: s, w: w, h: h} }

func (f Field) Set(x, y int, b bool) { f.s[y][x] = b }

func (f Field) Next(x, y int) bool { on := 0 for i := -1; i <= 1; i++ { for j := -1; j <= 1; j++ { if f.State(x+i, y+j) && !(j == 0 && i == 0) { on++ } } } return on == 3 || on == 2 && f.State(x, y) }

func (f Field) State(x, y int) bool { for y < 0 { y += f.h } for x < 0 { x += f.w } return f.s[y%f.h][x%f.w] }

type Life struct { w, h int a, b Field }

func NewLife(w, h int) *Life { a := NewField(w, h) for i := 0; i < (w * h / 2); i++ { a.Set(rand.Intn(w), rand.Intn(h), true) } return &Life{ a: a, b: NewField(w, h), w: w, h: h, } }

func (l *Life) Step() { for y := 0; y < l.h; y++ { for x := 0; x < l.w; x++ { l.b.Set(x, y, l.a.Next(x, y)) } } l.a, l.b = l.b, l.a }

func (l *Life) String() string { var buf bytes.Buffer for y := 0; y < l.h; y++ { for x := 0; x < l.w; x++ { b := byte(' ') if l.a.State(x, y) { b = '*' } buf.WriteByte(b) } buf.WriteByte('\n') } return buf.String() }

func main() { l := NewLife(80, 15) for i := 0; i < 300; i++ { l.Step() fmt.Print("\x0c") fmt.Println(l) time.Sleep(time.Second / 30) } }</lang> Running this program will compute and draw the first 300 "frames". The final frame looks like this:

        ** ****        *                                                        
         * **                                                                   
          *                                         **                          
*                                                  *  *                         
 *                   **        ****                 **                         *
  *                  **       *  **                                             
  *                      **        *                                            
                         **      *                                              
  ****              *        *                                     **         * 
 ***   **           *         ** ****                             *  *        **
* **     *  **      *              **                              **           
  *    *** ***                                                                  
            * **                                                                
         **   **       **                                                       
         ** *  *      * *                                                       

Groovy

<lang Groovy> class GameOfLife {

int generations int dimensions def board

GameOfLife(generations = 5, dimensions = 5) { this.generations = generations this.dimensions = dimensions this.board = createBlinkerBoard() }

static def createBlinkerBoard() { [ [].withDefault{0}, [0,0,1].withDefault{0}, [0,0,1].withDefault{0}, [0,0,1].withDefault{0} ].withDefault{[]} }

static def createGliderBoard() { [ [].withDefault{0}, [0,0,1].withDefault{0}, [0,0,0,1].withDefault{0}, [0,1,1,1].withDefault{0} ].withDefault{[]} }

static def getValue(board, point) { def x,y (x,y) = point if(x < 0 || y < 0) { return 0 } board[x][y] ? 1 : 0 }

static def countNeighbors(board, point) { def x,y (x,y) = point def neighbors = 0 neighbors += getValue(board, [x-1,y-1]) neighbors += getValue(board, [x-1,y]) neighbors += getValue(board, [x-1,y+1]) neighbors += getValue(board, [x,y-1]) neighbors += getValue(board, [x,y+1]) neighbors += getValue(board, [x+1,y-1]) neighbors += getValue(board, [x+1,y]) neighbors += getValue(board, [x+1,y+1]) neighbors }

static def conwaysRule(currentValue, neighbors) { def newValue = 0 if(neighbors == 3 || (currentValue && neighbors == 2)) { newValue = 1 } newValue }

static def createNextGeneration(currentBoard, dimensions) { def newBoard = [].withDefault{[].withDefault{0}} (0..(dimensions-1)).each { row -> (0..(dimensions-1)).each { column -> def point = [row, column] def currentValue = getValue(currentBoard, point) def neighbors = countNeighbors(currentBoard, point) newBoard[row][column] = conwaysRule(currentValue, neighbors) } } newBoard }

static def printBoard(generationCount, board, dimensions) { println "Generation ${generationCount}" println '*' * 80 (0..(dimensions-1)).each { row -> (0..(dimensions-1)).each { column -> print board[row][column] ? 'X' : '.' } print System.getProperty('line.separator') } println }

def start() { (1..generations).each { generation -> printBoard(generation, this.board, this.dimensions) this.board = createNextGeneration(this.board, this.dimensions) } }

}

// Blinker def game = new GameOfLife() game.start()

// Glider game = new GameOfLife(10, 10) game.board = game.createGliderBoard() game.start() </lang>

The output of this program:

Generation 1
********************************************************************************
.....
..X..
..X..
..X..
.....

Generation 2
********************************************************************************
.....
.....
.XXX.
.....
.....

Generation 3
********************************************************************************
.....
..X..
..X..
..X..
.....

Generation 4
********************************************************************************
.....
.....
.XXX.
.....
.....

Generation 5
********************************************************************************
.....
..X..
..X..
..X..
.....

Generation 1
********************************************************************************
..........
..X.......
...X......
.XXX......
..........
..........
..........
..........
..........
..........

Generation 2
********************************************************************************
..........
..........
.X.X......
..XX......
..X.......
..........
..........
..........
..........
..........

Generation 3
********************************************************************************
..........
..........
...X......
.X.X......
..XX......
..........
..........
..........
..........
..........

Generation 4
********************************************************************************
..........
..........
..X.......
...XX.....
..XX......
..........
..........
..........
..........
..........

Generation 5
********************************************************************************
..........
..........
...X......
....X.....
..XXX.....
..........
..........
..........
..........
..........

Generation 6
********************************************************************************
..........
..........
..........
..X.X.....
...XX.....
...X......
..........
..........
..........
..........

Generation 7
********************************************************************************
..........
..........
..........
....X.....
..X.X.....
...XX.....
..........
..........
..........
..........

Generation 8
********************************************************************************
..........
..........
..........
...X......
....XX....
...XX.....
..........
..........
..........
..........

Generation 9
********************************************************************************
..........
..........
..........
....X.....
.....X....
...XXX....
..........
..........
..........
..........

Generation 10
********************************************************************************
..........
..........
..........
..........
...X.X....
....XX....
....X.....
..........
..........
..........

Haskell

<lang haskell>import Data.Array.Unboxed

type Grid = UArray (Int,Int) Bool

-- The grid is indexed by (y, x).

life :: Int -> Int -> Grid -> Grid {- Returns the given Grid advanced by one generation. -} life w h old =

   listArray b (map f (range b))
 where b@((y1,x1),(y2,x2)) = bounds old
       f (y, x) = ( c && (n == 2 || n == 3) ) || ( not c && n == 3 )
         where c = get x y
               n = count [get (x + x') (y + y') |
                   x' <- [-1, 0, 1], y' <- [-1, 0, 1],
                   not (x' == 0 && y' == 0)]
       get x y | x < x1 || x > x2 = False
               | y < y1 || y > y2 = False
               | otherwise       = old ! (y, x)

count :: [Bool] -> Int count = length . filter id</lang>

Example of use:

<lang haskell>import Data.List (unfoldr)

grid :: [String] -> (Int, Int, Grid) grid l = (width, height, a)

 where (width, height) = (length $ head l, length l)
       a = listArray ((1, 1), (height, width)) $ concatMap f l
       f = map g
       g '.' = False
       g _   = True

printGrid :: Int -> Grid -> IO () printGrid width = mapM_ f . split width . elems

 where f = putStrLn . map g
       g False = '.'
       g _     = '#'

split :: Int -> [a] -> a split n = takeWhile (not . null) . unfoldr (Just . splitAt n)

blinker = grid

  [".#.",
   ".#.",
   ".#."]

glider = grid

  ["............",
   "............",
   "............",
   ".......###..",
   ".......#....",
   "........#...",
   "............"]

printLife :: Int -> (Int, Int, Grid) -> IO () printLife n (w, h, g) = mapM_ f $ take n $ iterate (life w h) g

 where f g = do
           putStrLn "------------------------------"
           printGrid w g

main = printLife 10 glider</lang>

Here's the gridless version. It could probably be improved with some light use of Data.Set, but I leave that as an exercise for the reader. Note that the function lifeStep is the solution in its entirety. The rest of this code deals with printing and test data for the particular model of the world we're using.

<lang haskell>module Main where import Data.List

lifeStep :: [(Int, Int)] -> [(Int, Int)] lifeStep cells = [head g | g <- grouped cells, viable g]

 where grouped = group . sort . concatMap neighbors
       neighbors (x, y) = [(x+dx, y+dy) | dx <- [-1..1], dy <- [-1..1], (dx,dy) /= (0,0)]
       viable [_,_,_] = True
       viable [c,_] = c `elem` cells
       viable _ = False


showWorld :: [(Int, Int)] -> IO () showWorld cells = mapM_ putStrLn $ worldToGrid cells

 where worldToGrid cells =  x <- [least..greatest | y <- [least..greatest]]
       cellChar cell = if cell `elem` cells then '#' else '.'
       (least, greatest) = worldBounds cells

worldBounds cells = (least, greatest)

 where least = min x y
       greatest = max x' y'
       (x, y) = head cells
       (x', y') = last cells

runLife :: Int -> [(Int, Int)] -> IO () runLife steps cells = rec (steps - 1) cells

 where rec 0 cells = showWorld cells
       rec s cells = do showWorld cells
                        putStrLn ""
                        rec (s - 1) $ lifeStep cells

glider = [(1, 0), (2, 1), (0, 2), (1, 2), (2, 2)] blinker = [(1, 0), (1, 1), (1, 2)]

main :: IO () main = do

 putStrLn "Glider >> 10"
 putStrLn "------------"
 runLife 10 glider
 putStrLn ""
 putStrLn "Blinker >> 3"
 putStrLn "------------"
 runLife 3 blinker</lang>

HolyC

Conway's Game of Life in HolyC for TempleOS ported from Conway's_Game_of_Life#C.

Also see the TempleOS implementation of Conway's Game of Life which makes use of the graphics engine.

Icon and Unicon

<lang icon>global limit

procedure main(args)

   n := args[1] | 50        # default is a 50x50 grid
   limit := args[2] | &null #  optional limit to number of generations
   write("Enter the starting pattern, end with EOF")
   grid := getInitialGrid(n)
   play(grid)

end

  1. This procedure reads in the initial pattern, inserting it
  2. into an nXn grid of cells. The nXn grid also gets a
  3. new border of empty cells, which just makes the test simpler
  4. for determining what do with a cell on each generation.
  5. It would be better to let the user move the cursor and click
  6. on cells to create/delete living cells, but this version
  7. assumes a simple ASCII terminal.

procedure getInitialGrid(n)

   static notBlank, allStars
   initial {
       notBlank := ~' '            
       allStars := repl("*",*notBlank)
       }
   g := []                # store as an array of strings
   put(g,repl(" ",n))
   while r := read() do {                        # read in rows of grid
       r := left(r,n)                            #   force each to length n
       put(g," "||map(r,notBlank,allStars)||" ") #   and making any life a '*'
       }
   while *g ~= (n+2) do
       put(g,repl(" ",n))
  
   return g

end

  1. Simple-minded procedure to 'play' Life from a starting grid.

procedure play(grid)

   while not allDone(grid) do {
       display(grid)
       grid := onePlay(grid)
       }

end

  1. Display the grid

procedure display(g)

   write(repl("-",*g[1]))
   every write(!g)
   write(repl("-",*g[1]))

end

  1. Compute one generation of Life from the current one.

procedure onePlay(g)

   ng := []
   every put(ng, !g)        # new generation starts as copy of old
   every ng[r := 2 to *g-1][c := 2 to *g-1] := case sum(g,r,c) of {
                           3:       "*"     # cell lives (or is born)
                           2:       g[r][c] # cell unchanged
                           default: " "     # cell dead
                           }
   return ng

end

  1. Return the number of living cells surrounding the current cell.

procedure sum(g,r,c)

   cnt := 0
   every (i := -1 to 1, j := -1 to 1) do
       if ((i ~= 0) | (j ~= 0)) & (g[r+i][c+j] == "*") then cnt +:= 1
   return cnt

end

  1. Check to see if all the cells have died or we've exceeded the
  2. number of allowed generations.

procedure allDone(g)

  static count
  initial count := 0
  return ((count +:= 1) > \limit) | (trim(!g) == " ")

end</lang>

A sample run:

->life 3 3
Enter the starting pattern, end with EOF

***
---
   
     
 *** 
   
   
---
---
   
  *  
  *  
  *
   
---
---
   
     
 *** 
   
   
---
->

INTERCAL

Works with: [the Pit] version 1

J

Solution: <lang j>pad=: 0,0,~0,.0,.~] life=: (3 3 (+/ e. 3+0,4&{)@,;._3 ])@pad NB. the above could also be a one-line solution: life=: (3 3 (+/ e. 3+0,4&{)@,;._3 ])@(0,0,~0,.0,.~]) </lang>

In other words, given a life instance, the next generation can be found by:

  1. . adding extra empty cells, surrounding the life instance,
  2. . tessellating the result, finding every overlapping 3 by 3 subinstance,
  3. . totaling the number of live cells in each subinstance,
  4. . treating a subinstance as a live cell iff that total is a member of the sequence 3,x where x is 3 if the center cell was previously dead, and 4 if the center cell was previously alive (that said, note that 4 is also the index of the center cell, with the sub instance arranged as a flat list).

Example (showing generations 0, 1 and 2 of a blinker): <lang j> life^:0 1 2 #:0 7 0 0 0 0 1 1 1 0 0 0

0 1 0 0 1 0 0 1 0

0 0 0 1 1 1 0 0 0</lang>

Example (showing start and six following generations of a glider)

<lang j> blocks=: (2 2$2) ((7 u:' ▗▖▄▝▐▞▟▘▚▌▙▀▜▛█') {~ #.@,);._3 >.&.-:@$ {. ]</lang>

   blocks"2 life^:(i.7) 4 5{.#:1 5 3
▖▌ 
▝▘ 

▝▄ 
▝▘ 

 ▚   
▝▀ 

▗▗ 
 ▛   

 ▗   
▝▟ 

 ▖   
 ▟▘

 ▗   
 ▄▌

JAMES II/Rule-based Cellular Automata

Library: JAMES II

<lang j2carules>@caversion 1;

dimensions 2;

//using Moore neighborhood neighborhood moore;

//available states state DEAD, ALIVE;

/*

if current state is ALIVE and the 
neighborhood does not contain 2 or 
3 ALIVE states the cell changes to 
DEAD
  • /

rule{ALIVE}:!ALIVE{2,3}->DEAD;

/*

if current state is DEAD and there 
are exactly 3 ALIVE cells in the 
neighborhood the cell changes to 
ALIVE
  • /

rule{DEAD}:ALIVE{3}->ALIVE;</lang> Animated output for the blinker example:

Java

<lang 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); } } }</lang>

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

Stretch

This fills in a random 10% of the grid, then activates the Game on it. Uncomment the call to the setCustomConfig function to use your own input. Just mind the grid limits. Use the input file given below to create a cool screensaver on your terminal. <lang java> //package conway;

import java.util.*; import java.io.*;

public class GameOfLife { //Set grid size int l=20,b=60; public static void main(String[] args) {

GameOfLife now=new GameOfLife(); now.setGame(); } void setGame() { char[][] config=new char[l][b]; startGame(config,l,b); } void startGame(char[][] mat,int l, int b) { Scanner s=new Scanner(System.in); String ch=""; float per=0; while(!ch.equals("y")) { per=setConfig(mat); //setCustomConfig(mat,"GOLglidergun.txt"); display2D(mat); System.out.println((per*100)+"% of grid filled."); System.out.println("Begin? y/n"); ch=s.nextLine(); } while(!ch.equals("x")) { mat=transform(mat,l,b); display2D(mat);

System.out.println("Ctrl+Z to stop.");

try { Thread.sleep(100); } catch(Exception e) { System.out.println("Something went horribly wrong."); }

//ch=s.nextLine(); } s.close(); System.out.println("Game Over"); }

char[][] transform(char[][] mat,int l, int b) {

char[][] newmat=new char[l][b]; for(int i=0;i<l;i++) for(int j=0;j<b;j++) newmat[i][j]=flip(mat,i,j); return newmat; } char flip(char[][] mat,int i, int j) { int count=around(mat,i,j); if(mat[i][j]=='*') { if(count<2||count>3) return '_'; return '*'; } else { if(count==3) return '*'; return '_'; } } int around(char[][] mat, int i, int j) { int count=0; for(int x=i-1;x<=i+1;x++) for(int y=j-1;y<=j+1;y++) { if(x==i&&y==j) continue; count+=eval(mat,x,y); } return count; } int eval(char[][] mat, int i, int j) { if(i<0||j<0||i==l||j==b) return 0; if(mat[i][j]=='*') return 1; return 0; }

float setCustomConfig(char[][] arr,String infile) { try { BufferedReader br=new BufferedReader(new FileReader(infile)); String line; for(int i=0;i<arr.length;i++) { line=br.readLine(); for(int j=0;j<arr[0].length;j++) arr[i][j]=line.charAt(j); } br.close(); } catch(Exception e) { System.out.println(e.getMessage()); } return 0; }

float setConfig(char[][] arr) { //Enter percentage of grid to be filled. float per=0.10f;//(float)Math.random(); for(int i=0;i<arr.length;i++) setConfig1D(arr[i],per); return per; } void setConfig1D(char[] arr,float per) { for(int i=0;i<arr.length;i++) { if(Math.random()<per) arr[i]='*'; else arr[i]='_'; } } void display2D(char[][] arr) { for(int i=0;i<arr.length;i++) display1D(arr[i]); System.out.println(); } void display1D(char[] arr) { for(int i=0;i<arr.length;i++) System.out.print(arr[i]); System.out.println(); } } </lang>

Glider Gun design. Save it in GOLglidergun.txt and uncomment the setCustomConfig function.

____________________________________________________________
_________________________*__________________________________
_______________________*_*__________________________________
_____________**______**____________**_______________________
____________*___*____**____________**_______________________
_**________*_____*___**_____________________________________
_**________*___*_**____*_*__________________________________
___________*_____*_______*__________________________________
____________*___*___________________________________________
_____________**_____________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________
____________________________________________________________

Swing

See Conway's Game of Life/Java/Swing

Java 10

<lang java> import static java.util.List.of;

class GameOfLife {

  boolean[][] board = new boolean[3][3];
  GameOfLife() {}
  GameOfLife(String[] board) {
     set((i, j, s) -> board[i].charAt(j * 2) == '■');
  }
  void set(Setter setter) {
     for (int i = 0; i < board.length; i++) {
        for (int j = 0; j < board[i].length; j++) {
           board[i][j] = setter.set(i, j, board[i][j]);
        }
     }
  }
  void get(Getter getter) {
     set((i, j, s) -> {
        getter.get(i, j, s);
        return s;
     });
  }
  int countNeighbors(int i, int j) {
     var counter = new Getter() {
        int count;
        @Override
        public void get(int li, int lj, boolean state) {
           if (distance(i, j, li, lj) == 1 && board[li][lj])
              count++;
        }
     };
     get(counter);
     return counter.count;
  }
  int distance(int i, int j, int li, int lj) {
     return Math.max(
          Math.abs(i - li),
          Math.abs(j - lj));
  }
  GameOfLife makeNextGeneration() {
     var n = new GameOfLife();
     n.set((i, j, s) -> {
        var alive = board[i][j];
        int c = countNeighbors(i, j);
        if (alive) {
           return c == 2 || c == 3;
        } else {
           return c == 3;
        }
     });
     return n;
  }
  void print() {
     get((i, j, s) -> {
        if (j == 0)
           System.out.println();
        System.out.print(s ? "■ " : "□ ");
     });
  }
  interface Setter {
     boolean set(int i, int j, boolean state);
  }
  interface Getter {
     void get(int i, int j, boolean state);
  }
  public static void main(String[] args) {
     String[] board = {
          "□ ■ □ ",
          "□ ■ □ ",
          "□ ■ □ ",
     };
     var gol = new GameOfLife(board);
     for (var generation : of(0, 1, 2)) {
        gol.print();
        System.out.println("\n");
        gol = gol.makeNextGeneration();
     }
  }

} </lang> Outputs:

□ ■ □ 
□ ■ □ 
□ ■ □ 


□ □ □ 
■ ■ ■ 
□ □ □ 


□ ■ □ 
□ ■ □ 
□ ■ □ 

JavaScript

Works with: SpiderMonkey
Works with: V8

<lang javascript>function GameOfLife () {

this.init = function (turns,width,height) { this.board = new Array(height); for (var x = 0; x < height; x++) { this.board[x] = new Array(width); for (var y = 0; y < width; y++) { this.board[x][y] = Math.round(Math.random()); } } this.turns = turns; }

this.nextGen = function() { this.boardNext = new Array(this.board.length); for (var i = 0; i < this.board.length; i++) { this.boardNext[i] = new Array(this.board[i].length); } for (var x = 0; x < this.board.length; x++) { for (var y = 0; y < this.board[x].length; y++) { var n = 0; for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { if ( dx == 0 && dy == 0){} else if (typeof this.board[x+dx] !== 'undefined' && typeof this.board[x+dx][y+dy] !== 'undefined' && this.board[x+dx][y+dy]) { n++; } } } var c = this.board[x][y]; switch (n) { case 0: case 1: c = 0; break; case 2: break; case 3: c = 1; break; default: c = 0; } this.boardNext[x][y] = c; } } this.board = this.boardNext.slice(); }

this.print = function() { for (var x = 0; x < this.board.length; x++) { var l = ""; for (var y = 0; y < this.board[x].length; y++) { if (this.board[x][y]) l += "X"; else l += " "; } print(l); } }

this.start = function() { for (var t = 0; t < this.turns; t++) { print("---\nTurn "+(t+1)); this.print(); this.nextGen() } }

}


var game = new GameOfLife();

print("---\n3x3 Blinker over three turns."); game.init(3); game.board = [ [0,0,0], [1,1,1], [0,0,0]]; game.start();

print("---\n10x6 Glider over five turns."); game.init(5); game.board = [ [0,0,0,0,0,0,0,0,0,0], [0,0,1,0,0,0,0,0,0,0], [0,0,0,1,0,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]]; game.start();

print("---\nRandom 5x10"); game.init(5,5,10); game.start();</lang>

Output:
---
3x3 Blinker over three turns.
---
Turn 1
   
XXX
   
---
Turn 2
 X 
 X 
 X 
---
Turn 3
   
XXX
   
---
10x6 Glider over five turns.
---
Turn 1
          
  X       
   X      
 XXX      
          
          
---
Turn 2
          
          
 X X      
  XX      
  X       
          
---
Turn 3
          
          
   X      
 X X      
  XX      
          
---
Turn 4
          
          
  X       
   XX     
  XX      
          
---
Turn 5
          
          
   X      
    X     
  XXX     
          
---
Random 5x10
---
Turn 1
XXXX 
   XX
X    
 XX X
  XX 
X   X
X    
X   X
 X   
X  XX
---
Turn 2
 XXXX
X  XX
 XX X
 XX  
  X X
 X X 
XX   
XX   
XX XX
     
---
Turn 3
 XX X
X    
X   X
     
     
XX X 
     
     
XXX  
     
---
Turn 4
 X   
X  X 
     
     
     
     
     
 X   
 X   
 X   
---
Turn 5
     
     
     
     
     
     
     
     
XXX  
     
Library: HTML5

Essentially the same as the above straight JavaScript but displayed in an HTML5 Canvas. <lang javascript> <html> <head> <title></title> <script type="text/javascript">

function GameOfLife () {

this.init = function (turns,width,height) { this.board = new Array(height); for (var x = 0; x < height; x++) { this.board[x] = new Array(width); for (var y = 0; y < width; y++) { this.board[x][y] = Math.round(Math.random()); } } this.turns = turns; }

this.nextGen = function() { this.boardNext = new Array(this.board.length); for (var i = 0; i < this.board.length; i++) { this.boardNext[i] = new Array(this.board[i].length); } for (var x = 0; x < this.board.length; x++) { for (var y = 0; y < this.board[x].length; y++) { var n = 0; for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { if ( dx == 0 && dy == 0){} else if (typeof this.board[x+dx] !== 'undefined' && typeof this.board[x+dx][y+dy] !== 'undefined' && this.board[x+dx][y+dy]) { n++; } } } var c = this.board[x][y]; switch (n) { case 0: case 1: c = 0; break; case 2: break; case 3: c = 1; break; default: c = 0; } this.boardNext[x][y] = c; } } this.board = this.boardNext.slice(); }

this.print = function(ctx,w,h) { if (!w) w = 8; if (!h) h = 8; for (var x = 0; x < this.board.length; x++) { var l = ""; for (var y = 0; y < this.board[x].length; y++) { if (this.board[x][y]) // x and y reversed to draw matrix like it looks in source // rather than the "actual" positions ctx.fillStyle = "orange"; else ctx.fillStyle = "black"; ctx.fillRect(y*h,x*w,h,w); } } }

this.start = function(ctx,w,h) { for (var t = 0; t < this.turns; t++) { this.print(ctx,w,h); this.nextGen() } }

}

function init() { // Change document title and text under canvas document.title = "Conway's Game of Life";

// Setup game boards for Conway's Game of Life var blinker = new GameOfLife(); blinker.board = [ [0,1,0], [0,1,0], [0,1,0]];

var glider = new GameOfLife(); glider.board = [ [0,0,0,0,0,0], [0,0,1,0,0,0], [0,0,0,1,0,0], [0,1,1,1,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0]];

var random = new GameOfLife(); random.init(null,8,8);

// Get canvas contexts or return 1 blinker.canvas = document.getElementById('blinker'); glider.canvas = document.getElementById('glider'); random.canvas = document.getElementById('random'); if (blinker.canvas.getContext && glider.canvas.getContext && random.canvas.getContext) { blinker.ctx = blinker.canvas.getContext('2d'); glider.ctx = glider.canvas.getContext('2d'); random.ctx = random.canvas.getContext('2d'); } else { return 1; }


// Run main() at set interval setInterval(function(){run(glider,glider.ctx,25,25)},250); setInterval(function(){run(blinker,blinker.ctx,25,25)},250); setInterval(function(){run(random,random.ctx,25,25)},250); return 0; }

function run(game,ctx,w,h) { game.print(ctx,w,h); game.nextGen()

return 0; }

</script> </head> <body onLoad="init();"> 3x3 Blinker
<canvas id="blinker" width="75" height="75"> No canvas support found! </canvas>

6x6 Glider
<canvas id="glider" width="150" height="150"> No canvas support found! </canvas>

8x8 Random
<canvas id="random" width="200" height="200"> No canvas support found! </canvas>
</body> </html></lang>

Output:

for 3x3 Blinker


More functional style: <lang javascript> const _ = require('lodash');

/////////////////// // LODASH IMPORT // ///////////////////

// import all lodash functions to the main namespace, but isNaN not to cause conflicts _.each(_.keys(_), k => global[k === 'isNaN' ? '_isNaN' : k] = _[k]);

/////////////// // FUNCTIONS // /////////////// const WORLD_WIDTH = 3,

     WORLD_HEIGHT = 3,
     displayWorld = (world) => console.log(map(world, x => x.join(' ')).join('\n') + '\n'),
     aliveNeighbours = (world, x, y) => chain(range(-1, 2))
                                         .reduce((acc, i) => acc.concat(map(range(-1, 2), ii => [i, ii])), [])
                                         .reject(partial(isEqual, [0, 0]))
                                         .map(i => {
                                           try {
                                             return world[x + i[0]][y + i[1]];
                                           } catch (err) {
                                             return null;
                                           }
                                         })
                                         .compact()
                                         .value()
                                         .length,
     isAlive = (cell, numAliveNeighbours) => (cell === 1 && inRange(numAliveNeighbours, 2, 4)) || (cell === 0 && numAliveNeighbours === 3) ? 1 : 0,
     updateWorld = (world) => map(world, (row, rowidx) => map(row, (cell, colidx) => isAlive(cell, aliveNeighbours(world, rowidx, colidx))));


// let world = map(range(WORLD_WIDTH), partial(ary(map, 2), range(WORLD_HEIGHT), partial(random, 0, 1, false))); let world = [[0, 0, 0], [1, 1, 1], [0, 0, 0]];

setInterval(() => {

 world = updateWorld(world)
 displayWorld(world);

}, 1000); </lang>

ES6 + : <lang javascript> const alive = 1; const dead = 0;

const conwaysGameOfLife = (game) => {

 const newGame = []
 for (let y = 0; y < game.length; y += 1) {
   const newRow = []
   for (let x = 0; x < game[y].length; x += 1) {
     const cell = game[y][x];
     const prevX = x > 0 ? x - 1 : x;
     const nextX = x < game[y].length - 1 ? x + 2 : x + 1;
     const counter =
       (game[y - 1] ? game[y - 1].slice(prevX, nextX).reduce((acc, v) => acc + v) : 0) +
       (game[y][x - 1] || 0) + (game[y][x + 1] || 0) +
       (game[y + 1] ? game[y + 1].slice(prevX, nextX).reduce((acc, v) => acc + v) : 0)
     cell === alive
       ? counter > 1 && counter <= 3
         ? newRow.push(alive)
         : newRow.push(dead)
       : counter === 3
         ? newRow.push(alive)
         : newRow.push(dead)
   }
   newGame.push(newRow)
 }
 return newGame

}

const generateGame = (height, width) => {

 return Array.from({ length: height }, (v, k) => (
   Array.from({ length: width}, (v, k) => {
     return (Math.random() * 100 | 0) < 50 ? dead : alive
   })
 ))

}

const output = (game) =>{

 process.stdout.write('\033c');
 let screen = ;
 for (let i = 0; i < game.length; i += 1) {
   screen += game[i].join()
   screen += '\n'
 }
 console.log(screen)

}

const setup = ((game) => {

 return () => {
   setInterval(() => {
   output(game)
   const newGame = conwaysGameOfLife(game)
   game = newGame
   }, 1000)
 }

})

// for random game // const game = generateGame(10, 10)

// glider test const game = [

 [0,0,0,0,0,0,0,0,0,0],
 [0,0,1,0,0,0,0,0,0,0],
 [0,0,0,1,0,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]

]; const run = setup(game); run()

</lang>

jq

Works with: jq version 1.4

In this implementation, a "world" is simply a suitably constructed string as illustrated by world3 and world11 below. The "game" can be played either by creating separate frames (using frames(n)) or by calling animation(n; sleep) with sleep approximately equal to the number of milliseconds between refreshes. <lang jq># Notes on the implementation:

  1. 1. For efficiency, the implementation requires that the world
  2. has boundaries, as illustrated in the examples.
  3. 2. For speed, the simulation uses the exploded string.
  4. 3. The ASCII values of the "alive" and "empty" symbols are
  5. hardcoded: "." => 46; " " => 32
  6. 4. To adjust the refresh rate, adjust the input to "spin".

def lines: split("\n")|length;

def cols: split("\n")[0]|length + 1; # allow for the newline

  1. Is there a "." (46) at [x,y] relative to position i,
  2. assuming the width is w?
  3. Input is an array; result is 0 or 1 so we can easily count the total.

def isAlive(x; y; i; w): if .[i+ w*y + x] == 46 then 1 else 0 end;

def neighborhood(i;w):

 isAlive(-1; -1; i; w) + isAlive(0; -1; i; w) + isAlive(1; -1; i; w) +
 isAlive(-1;  0; i; w)                        + isAlive(1;  0; i; w) +
 isAlive(-1;  1; i; w) + isAlive(0;  1; i; w) + isAlive(1;  1; i; w) ;
  1. The basic rules:

def evolve(cell; sum) :

 if   cell == 46 then if sum == 2 or sum == 3 then 46 else 32 end
 elif cell == 32 then if sum == 3 then 46 else 32 end
 else cell
 end ;
  1. [world, lines, cols] | next(w) => [world, lines, cols]

def next:

 .[0] as $world | .[1] as $lines | .[2] as $w
 | reduce range(0; $world|length) as $i
   ($world;
     .[$i] as $c
     | if $c == 32 or $c == 46 then
          # updates are "simultaneous" i.e. relative to $world, not "."
          ($world | neighborhood($i; $w)) as $sum
          | evolve($c; $sum) as $next
          | if $c == $next then . else .[$i] = $next end
       else .
       end )
 | [., $lines, $w] ;

</lang> Animation: <lang jq># "clear screen": def cls: "\u001b[2J";

  1. Input: an integer; 1000 ~ 1 sec

def spin:

 reduce range(1; 500 * .) as $i
   (0; . + ($i|cos)*($i|cos) + ($i|sin)*($i|sin) )
 |  "" ;

  1. Animate n steps;
  2. if "sleep" is non-negative then cls and
  3. sleep about "sleep" ms between frames.

def animate(n; sleep):

 if n == 0 then empty
 else (if sleep >= 0 then cls else "" end),
      (.[0]|implode), n, "\n",
      (sleep|spin),
      ( next|animate(n-1; sleep) )
 end ;

  1. Input: a string representing the initial state

def animation(n; sleep):

 [ explode, lines, cols] | animate(n; sleep) ;

  1. Input: a string representing the initial state

def frames(n): animation(n; -1); </lang> Examples: <lang jq>def world3: "+---+\n" + "| |\n" + "|...|\n" + "| |\n" + "+---+\n" ;

def world11: "+-----------+\n" + "| |\n" + "| .. |\n" + "| ... |\n" + "| .. |\n" + "| |\n" + "+-----------+\n" ;</lang>

Task: <lang jq>world3 | frames(3)</lang>

Output:

<lang sh>$ jq -n -r -f Game_of_life.jq

+---+ | | |...| | | +---+

3



+---+ | . | | . | | . | +---+

2



+---+ | | |...| | | +---+

1</lang>

Animation example <lang jq># Animation of 100 frames with approximately 1 second between each update: world11 | animation(100; 1000)</lang>

Jsish

From Javascript, SpiderMonkey entry.

<lang javascript>/* Conway's game of life, in Jsish */ function GameOfLife () {

   this.title = "Conway's Game of Life";
   this.cls = "\u001B[H\u001B[2J";
   this.init = function (turns, width, height) {
       this.board = new Array(height);
       for (var x = 0; x < height; x++) {
           this.board[x] = new Array(width);
           for (var y = 0; y < width; y++) {
               this.board[x][y] = Math.round(Math.random());
           }
       }
       this.turns = turns;
   };
   this.nextGen = function() {
       this.boardNext = new Array(this.board.length);
       for (var i = 0; i < this.board.length; i++) {
           this.boardNext[i] = new Array(this.board[i].length);
       }
       for (var x = 0; x < this.board.length; x++) {
           for (var y = 0; y < this.board[x].length; y++) {
               var n = 0;
               for (var dx = -1; dx <= 1; dx++) {
                   for (var dy = -1; dy <= 1; dy++) {
                       if ( dx == 0 && dy == 0){}
                       else if (typeof this.board[x+dx] !== 'undefined'
                               && typeof this.board[x+dx][y+dy] !== 'undefined'
                               && this.board[x+dx][y+dy]) {
                           n++;
                       }
                   }
               }
               var c = this.board[x][y];
               switch (n) {
                   case 0:
                   case 1:
                       c = 0;
                       break;
                   case 2:
                       break;
                   case 3:
                       c = 1;
                       break;
                   default:
                       c = 0;
               }
               this.boardNext[x][y] = c;
           }
       }
       this.board = this.boardNext.slice(0);
   };
   this.print = function() {
       for (var x = 0; x < this.board.length; x++) {
           var l = "";
           for (var y = 0; y < this.board[x].length; y++) {
               if (this.board[x][y])
                   l += "X";
               else
                   l += " ";
           }
           puts(l);
       }
   };
   this.start = function() {
       for (var t = 0; t < this.turns; t++) {
           sleep(500);
           printf(this.cls);
           puts(this.title + "\n---\nTurn "+(t+1));
           this.print();
           this.nextGen();
       }
   };

}

var game = new GameOfLife(); if (Interp.conf('unitTest')) {

   game.init(3,3,3);
   game.title="---\n3x3 Blinker over three turns.";
   game.board = [
       [0,0,0],
       [1,1,1],
       [0,0,0]];
   game.cls="";
   game.start();

} else {

   game.init(3,3,3);
   game.title="---\n3x3 Blinker over three turns.";
   game.board = [
       [0,0,0],
       [1,1,1],
       [0,0,0]];
   game.start();
   game.init(5,10,6);
   game.title="---\n10x6 Glider over five turns.";
   game.board = [
       [0,0,0,0,0,0,0,0,0,0],
       [0,0,1,0,0,0,0,0,0,0],
       [0,0,0,1,0,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]];
   game.start();
   var steps = (console.args[0]) ? parseInt(console.args[0]) || 1  : 50;
   game.init(steps, 32,16);
   game.title="---\nRandom 32x16, " + steps + " step" + ((steps === 1) ? "" : "s");
   game.start();

}

/*

!EXPECTSTART!

--- 3x3 Blinker over three turns. --- Turn 1

XXX

--- 3x3 Blinker over three turns. --- Turn 2

X
X
X

--- 3x3 Blinker over three turns. --- Turn 3

XXX

!EXPECTEND!

  • /</lang>
Output:
prompt$ jsish -u conwaysGame.jsi
[PASS] conwaysGame.jsi

Julia

Works with: julia version 0.3.5

Using the CellularAutomata package: https://github.com/natj/CellularAutomata.jl

<lang cpp>julia> Pkg.add("CellularAutomata") INFO: Installing CellularAutomata v0.1.2 INFO: Package database updated

julia> using CellularAutomata

julia> gameOfLife{T<:Int}(n::T, m::T, gen::T) = CA2d([3], [2,3], int(randbool(n, m)), gen) gameOfLife (generic function with 1 method)

julia> gameOfLife(15, 30, 5) 30x15x5 Cellular Automaton</lang>

       # ##   #   ######  ###  ### ##
       #    ####    #  #  # ##  #####
         ## #   # ## ###   ## # # ## 
       #  # ##### # # # ## #     #  #
         ##  ## # #  ##     ###      
       #   #### ## ## ### # # # # # #
       # ## ##### #  ##### # ## ### #
        ### #   ##        ####  ## # 
        #### #   ## ##   ### ###  ###
         ## ####   #######  #    ## #
           # ## ##### ## #### # #####
        ##  ## ##### # # # #  #   # #
        #   # ## ##   ## ##   ##### #
        ##   # #   #  # #############
       #      ## #    # ###  ##  ##  


                # ###          #     
       #    # ## #      # #   #      
        ###     # #      #     ##    
        #   #   # # #   # ##  ## ####
        ###       #       # # ## # # 
       #           ##     #     # # #
                  ####        #      
                   ##  #             
               # ##    #      ##    #
        #      #                     
        #  #                #  ##   #
        ## #         #      # #     #
            #       ##              #
        ##   #   #   ##     #       #
          #  # ##                    


             #    ##                 
        ##     #         #    # #    
        ## # #  # ##    #  #    #####
           #      #       ## #   # ##
        ##       ## #     #  ##      
       ###           #     # ## #####
                  #  #               
                 #   ##       ##     
                # ##                 
                #             # #    
        # #                  # #     
        #####       ##       # #   ##
          # #       #        #     ##
       # #  ### #   ###              
         #    ### ####               


        ##      ###                  
       #### # #  #             ## ## 
        ##  #    ###     # ##  ##   #
            #            ### ## ##  #
         ##      ###      #    ##    
       # #       #####      #### ####
       ##           ##       #  #####
                 # ####              
                # #           #      
                 #            ##     
       ## #                  # ##    
        #   #       ##      ##     ##
                   #  #       #    # 
        ##### # ##    #             #
        #   #   # #   #


          ## # ## #
          ## #     #           ### ##
          # #    ##      # ###    # #
       ## ##             #   ##  #
       ####      #       ##
         ##      #   #      ##
        #        #          ## ##
       #         ###  #          ####
                # ####        ##
                 #           #  #
       ###                  ## ##   #
        ##          ##      ## #   ##
        # # ##      # #      #     #
       ####### ####  ###
            ##    #

GPU calculation based version

Requires a CUDA compatible graphics card and uses the ArrayFire library. <lang julia>using ArrayFire using Images using LinearAlgebra

const blinker = [0 0 0; 1 1 1; 0 0 0] const glider = [0 0 1; 1 0 1; 0 1 1] const lwss = [0 1 1 1 1; 1 0 0 0 1; 0 0 0 0 1; 1 0 0 1 0] const glidergun = [

 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 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 0 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 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0;
 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0;
 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
 0 1 1 0 0 0 0 0 0 0 0 1 0 0 0 1 0 1 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0;
 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 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 1 0 0 0 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 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]

function lifegame(fname, initializer, mapsize=30, imgsteps=50, upscaleratio=20)

   kernel = convert(Array{Float32}, [1 1 1; 1 0 1; 1 1 1]) |> AFArray
   initialstate = zeros(Bool, mapsize, mapsize)
   mid = div(mapsize, 2)
   (xlen, ylen), (halfx, halfy) = size(initializer), div.(size(initializer), 2)
   x1, x2 = mid - halfx, isodd(xlen) ? mid + halfx : mid + halfx - 1
   y1, y2 = mid - halfy, isodd(ylen) ? mid + halfy : mid + halfy - 1
   initialstate[x1:x2, y1:y2] .= initializer
   state = initialstate .+ Float32(.0) |> AFArray
   img = zeros(Float32, mapsize * upscaleratio, mapsize * upscaleratio, imgsteps)
   for i in 1:imgsteps
       nb = convolve2(state, kernel, UInt32(0), UInt32(0))
       a = (nb == 2)
       b = (nb == 3)
       state = ((state .* a .+ b) > 0) + Float32(0)
       frame = imresize(state, ratio=upscaleratio)
       img[:, :, i] .= frame
   end
   save(fname, img)

end

lifegame("blinker.gif", blinker) lifegame("glider.gif", glider) lifegame("lwss.gif", lwss) lifegame("glidergun.gif", glidergun, 90, 200) </lang>

Kotlin

This is based on the Go entry but has been altered in several respects.

In particular, it now allows for the blinker and glider patterns as well as an initially random pattern.

Also any cells beyond the boundary are now treated as dead as per the current task description.

The particular random pattern used now needs only 99 generations to reach stability.

<lang scala>// version 1.2.0

import java.util.Random

val rand = Random(0) // using a seed to produce same output on each run

enum class Pattern { BLINKER, GLIDER, RANDOM }

class Field(val w: Int, val h: Int) {

   val s = List(h) { BooleanArray(w) }
   operator fun set(x: Int, y: Int, b: Boolean) {
       s[y][x] = b
   }
   fun next(x: Int, y: Int): Boolean {
       var on = 0
       for (i in -1..1) {
           for (j in -1..1) {
               if (state(x + i, y + j) && !(j == 0 && i == 0)) on++
           }
       }
       return on == 3 || (on == 2 && state(x, y))
   }
   fun state(x: Int, y: Int): Boolean {
       if ((x !in 0 until w) || (y !in 0 until h)) return false
       return s[y][x]
   }

}

class Life(val pattern: Pattern) {

   val w: Int
   val h: Int
   var a: Field
   var b: Field
   init {
       when (pattern) {
           Pattern.BLINKER -> {
               w = 3
               h = 3
               a = Field(w, h)
               b = Field(w, h)
               a[0, 1] = true
               a[1, 1] = true
               a[2, 1] = true
           }
           Pattern.GLIDER -> {
               w = 4
               h = 4
               a = Field(w, h)
               b = Field(w, h)
               a[1, 0] = true
               a[2, 1] = true
               for (i in 0..2) a[i, 2] = true
           }
           Pattern.RANDOM -> {
               w = 80
               h = 15
               a = Field(w, h)
               b = Field(w, h)
               for (i in 0 until w * h / 2) {
                   a[rand.nextInt(w), rand.nextInt(h)] = true
               }
           }
       }
   }
   fun step() {
       for (y in 0 until h) {
           for (x in 0 until w) {
               b[x, y] = a.next(x, y)
           }
       }
       val t = a
       a = b
       b = t
   }
   override fun toString(): String {
       val sb = StringBuilder()
       for (y in 0 until h) {
           for (x in 0 until w) {
               val c = if (a.state(x, y)) '#' else '.'
               sb.append(c)
           }
           sb.append('\n')
       }
       return sb.toString()
   }

}

fun main(args: Array<String>) {

   val lives = listOf(
       Triple(Life(Pattern.BLINKER), 3, "BLINKER"),
       Triple(Life(Pattern.GLIDER), 4, "GLIDER"),
       Triple(Life(Pattern.RANDOM), 100, "RANDOM")
   )
   for ((game, gens, title) in lives) {
       println("$title:\n")
       repeat(gens + 1) {
           println("Generation: $it\n$game")
           Thread.sleep(30)
           game.step()
       }
       println()
   }

}</lang>

Output:

In the interests of brevity, only generations 0 and 100 are shown for the 'random' pattern:

BLINKER:

Generation: 0
...
###
...

Generation: 1
.#.
.#.
.#.

Generation: 2
...
###
...

Generation: 3
.#.
.#.
.#.


GLIDER:

Generation: 0
.#..
..#.
###.
....

Generation: 1
....
#.#.
.##.
.#..

Generation: 2
....
..#.
#.#.
.##.

Generation: 3
....
.#..
..##
.##.

Generation: 4
....
..#.
...#
.###


RANDOM:

Generation: 0
....###....#.#....###...#.#..#.###...#..#......#.#..#####......######...##.#.##.
####..###.#....#.#####.##.....####.##..####.####.........#.#.###...#.##.#.#.....
..##.##.#.##...#..#.#..#.#.#.#..####.#...#..##....#..##.........#.#..#....#...#.
..##..#..##.#.#.....#.##.##...#####...##.##.....##...#.....##......###..##.#..##
......##..........#.#.#.......#..#.##.#.##....#.#...#.#.#.#.....#..#.......#.#.#
.#.#.....#####..#..##............#.#.#...###..#...##.....#..##...#.#.##.#..##...
.##.#.#.##.#..#####.....##..#.####..#.#..#...#.#..#...#.#.#.#....#.#..#.#.#..##.
.#..#..#.....#...###..###.....####..........##.##.####.....#..##..####..#...##..
..##.#...#.#..#.#....#..#...##.#..##.......#.#..##..##..##.#.....##.#......#.#.#
#.######..#.#.#.###.#....###.....#.....#..#......####.#.#..#....#...#.......#.#.
#...#..###.##....#.#..##..#..#.#.#...#..#....#....##...#..#..#.#....#...##....#.
#....##.......#.####.##..#....#.#....#....#######.#..####.#..#.#.##....#.#####..
...#.......##..##.##......##....#..#.####.......#..#.#..##.###.#.#.#.#..##.....#
#.##..####....#..#..##..#.#..#..#....#.###.##.....#.....##....#.#..#.##.....##..
...#.#..#.#.....###...#..##.#.....#......#...........###...#.#....#..#.#..##.#.#

Generation: 100
................................................................................
................................................................................
.........................................#......................................
......................#.................#.#.....................................
.##..................#.#................#.#.....................................
.##..................#.#.................#...#..................................
......................#.....................#.#.................................
...........................................#..#.................................
............................................##..................................
.............##.................................................................
............#..#................................................................
.##..........#.#.......................................##..........#............
.##...........#........................................##.........#.#...........
..........##.......................................................##...........
..........##....................................................................

Lua

A slight modernization of my original "life.lua" for Lua 3.x circa 2000 -- heck, we didn't even have for loops back then! :D (a copy can be found in the 4.0 source distro if interested in comparing syntax) <lang lua>local function T2D(w,h) local t={} for y=1,h do t[y]={} for x=1,w do t[y][x]=0 end end return t end

local Life = {

 new = function(self,w,h)
   return setmetatable({ w=w, h=h, gen=1, curr=T2D(w,h), next=T2D(w,h)}, {__index=self})
 end,
 set = function(self, coords)
   for i = 1, #coords, 2 do
     self.curr[coords[i+1]][coords[i]] = 1
   end
 end,
 evolve = function(self)
   local curr, next = self.curr, self.next
   local ym1, y, yp1 = self.h-1, self.h, 1
   for i = 1, self.h do
     local xm1, x, xp1 = self.w-1, self.w, 1
     for j = 1, self.w do
       local sum = curr[ym1][xm1] + curr[ym1][x] + curr[ym1][xp1] +
                   curr[y][xm1] + curr[y][xp1] +
                   curr[yp1][xm1] + curr[yp1][x] + curr[yp1][xp1]
       next[y][x] = ((sum==2) and curr[y][x]) or ((sum==3) and 1) or 0
       xm1, x, xp1 = x, xp1, xp1+1
     end
     ym1, y, yp1 = y, yp1, yp1+1
   end
   self.curr, self.next, self.gen = self.next, self.curr, self.gen+1
 end,
 render = function(self)
   print("Generation "..self.gen..":")
   for y = 1, self.h do
     for x = 1, self.w do
       io.write(self.curr[y][x]==0 and "□ " or "■ ")
     end
     print()
   end
 end

}</lang> Example usage. Coordinates wrap to simulate an infinite universe, so here a glider/lwss are evolved through one complete period, then advanced forward until returning to starting conditions. <lang lua>print("GLIDER:") local life = Life:new(5,5) life:set({ 2,1, 3,2, 1,3, 2,3, 3,3 }) for i = 1, 5 do

 life:render()
 life:evolve()

end for i = 6,20 do life:evolve() end life:render()

print()

print("LWSS:") life = Life:new(10,7) life:set({ 2,2, 5,2, 6,3, 2,4, 6,4, 3,5, 4,5, 5,5, 6,5 }) for i = 1, 5 do

 life:render()
 life:evolve()

end for i = 6,20 do life:evolve() end life:render()</lang>

Output:
GLIDER:
Generation 1:
□ ■ □ □ □
□ □ ■ □ □
■ ■ ■ □ □
□ □ □ □ □
□ □ □ □ □
Generation 2:
□ □ □ □ □
■ □ ■ □ □
□ ■ ■ □ □
□ ■ □ □ □
□ □ □ □ □
Generation 3:
□ □ □ □ □
□ □ ■ □ □
■ □ ■ □ □
□ ■ ■ □ □
□ □ □ □ □
Generation 4:
□ □ □ □ □
□ ■ □ □ □
□ □ ■ ■ □
□ ■ ■ □ □
□ □ □ □ □
Generation 5:
□ □ □ □ □
□ □ ■ □ □
□ □ □ ■ □
□ ■ ■ ■ □
□ □ □ □ □
Generation 21:
□ ■ □ □ □
□ □ ■ □ □
■ ■ ■ □ □
□ □ □ □ □
□ □ □ □ □

LWSS:
Generation 1:
□ □ □ □ □ □ □ □ □ □
□ ■ □ □ ■ □ □ □ □ □
□ □ □ □ □ ■ □ □ □ □
□ ■ □ □ □ ■ □ □ □ □
□ □ ■ ■ ■ ■ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
Generation 2:
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ ■ ■ □ □ □ □
□ □ ■ ■ □ ■ ■ □ □ □
□ □ ■ ■ ■ ■ □ □ □ □
□ □ □ ■ ■ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
Generation 3:
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ ■ ■ ■ ■ □ □ □
□ □ ■ □ □ □ ■ □ □ □
□ □ □ □ □ □ ■ □ □ □
□ □ ■ □ □ ■ □ □ □ □
□ □ □ □ □ □ □ □ □ □
Generation 4:
□ □ □ □ □ □ □ □ □ □
□ □ □ □ ■ ■ □ □ □ □
□ □ □ ■ ■ ■ ■ □ □ □
□ □ □ ■ ■ □ ■ ■ □ □
□ □ □ □ □ ■ ■ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
Generation 5:
□ □ □ □ □ □ □ □ □ □
□ □ □ ■ □ □ ■ □ □ □
□ □ □ □ □ □ □ ■ □ □
□ □ □ ■ □ □ □ ■ □ □
□ □ □ □ ■ ■ ■ ■ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □
Generation 21:
□ □ □ □ □ □ □ □ □ □
□ ■ □ □ ■ □ □ □ □ □
□ □ □ □ □ ■ □ □ □ □
□ ■ □ □ □ ■ □ □ □ □
□ □ ■ ■ ■ ■ □ □ □ □
□ □ □ □ □ □ □ □ □ □
□ □ □ □ □ □ □ □ □ □

ksh

<lang ksh>

  1. !/bin/ksh
  2. # Version AJM 93u+ 2012-08-01
  1. Conway's Game of Life
  1. # Variables:

integer RAND_MAX=32767 LIFE="�[07m �[m" NULL=" " typeset -a char=( "$NULL" "$LIFE" )

  1. # Input x y or default to 30x30, positive integers only

integer h=${1:-30} ; h=$(( h<=0 ? 30 : h )) # Height (y) integer w=${2:-30} ; w=$(( w<=0 ? 30 : w )) # Width (x)

  1. # Functions:
  1. # Function _display(map, h, w)

function _display { typeset _dmap ; nameref _dmap="$1" typeset _h _w ; integer _h=$2 _w=$3

typeset _x _y ; integer _x _y

printf %s "�[H" for (( _y=0; _y<_h; _y++ )); do for (( _x=0; _x<_w; _x++ )); do printf %s "${char[_dmap[_y][_x]]}" done printf "%s\n" done }

  1. # Function _evolve(h, w)

_evolve() { typeset _h _w ; integer _h=$1 _w=$2

typeset _x _y _n _y1 _x1 ; integer _x _y _n _y1 _x1 typeset _new _newdef ; typeset -a _new

for (( _y=0; _y<_h; _y++ )); do for (( _x=0; _x<_w; _x++ )); do _n=0 for (( _y1=_y-1; _y1<=_y+1; _y1++ )); do for (( _x1=_x-1; _x1<=_x+1; _x1++ )); do (( _map[$(( (_y1 + _h) % _h ))][$(( (_x1 + _w) % _w ))] )) && (( _n++ )) done done (( _map[_y][_x] )) && (( _n-- )) _new[_y][_x]=$(( (_n==3) || (_n==2 && _map[_y][_x]) )) done done

for (( _y=0; _y<_h; _y++ )); do for (( _x=0; _x<_w; _x++ )); do _map[_y][_x]=${_new[_y][_x]} done done }

  1. # Function _game(h, w)

function _game { typeset _h ; integer _h=$1 typeset _w ; integer _w=$2

typeset _x _y ; integer _x _y typeset -a _map

for (( _y=0 ; _y<_h ; _y++ )); do for (( _x=0 ; _x<_h ; _x++ )); do _map[_x][_y]=$(( RANDOM < RAND_MAX / 10 ? 1 : 0 )) # seed map done done

while : ; do _display _map ${_h} ${_w} _evolve ${_h} ${_w} sleep 0.2 done }

######
  1. main #
######
_game ${h} ${w}

</lang>


M2000 Interpreter

<lang M2000 Interpreter> Module Life { Font "courier new" Form 40, 18 Cls 3,0 Double Report 2, "Game of Life" Normal Cls 5, 2 Const Mx=20, My=10 Dim A(0 to Mx+1, 0 to My+1)=0 Flush REM Data (2,2),(2,3),(3,3),(4,3),(5,4),(,3,4),(5,3),(6,2),(8,5),(5,8) Data (5,3) Data (5,4) Data (5,5) generation=1 While not empty (A, B)=Array A(A,B)=1 End While Display() Do k$=Key$ If k$=chr$(13) Then exit A()=@GetNext() refresh 500 Display() Until A()#Sum()=0 K$=Key$ Cls, 0 End Function GetNext() Local B() B()=A() ' copy array Local B=B() ' get a pointer B*=0 ' make all element zero Local i, j, tot For j=1 to My For i=1 to Mx tot=-A(i,j) For k=j-1 to j+1 For m=i-1 to i+1 tot+=A(m, k) Next Next If A(i,j)=1 Then If tot=2 or tot=3 Then B(i,j)=1 Else.if tot=3 Then B(i,j)=1 End If Next Next =B() End Function Sub Display() Cursor 0,2 move ! ' move graphic to character cursor Fill scale.x, scale.y-pos.Y, 1, 5 Print "Generation:";Generation Generation++ Local i, j For j=1 to My Print @(width div 2-Mx div 2); For i=1 to Mx Print If$(A(I,J)=1->"■", "□"); Next Print Next Print Report 2, "Press enter to exit or any other key for Next generation" End Sub

} Life </lang>

MANOOL

Straightforward implementation useful for benchmarking: <lang MANOOL> { {extern "manool.org.18/std/0.3/all"} in

let { N = 40; M = 80 } in
let { G = 99 } in
let
 { Display =
   { proc { B } as
   : for { I = Range[N]$ } do
   : do Out.WriteLine[] after
   : for { J = Range[M]$ } do
     Out.Write[{if B[I; J] <> 0 then "*" else " "}]
   }
 }
 in
var { B = {array N of: array M of 0} } in
 -- initialization
 B[19; 41] = 1
 B[20; 40] = 1
 B[21; 40] = 1
 B[22; 40] = 1
 B[22; 41] = 1
 B[22; 42] = 1
 B[22; 43] = 1
 B[19; 44] = 1
 -- end of initialization
 Out.WriteLine["Before:"]; Display[B]
 { var { NextB = B } in
 : repeat G do
 : do {assign B = NextB; NextB = B} after
 : for { I = Range[N]$ } do
 : var { Up = (I - 1).Mod[N]; Down = (I + 1).Mod[N] } in
 : for { J = Range[M]$ } do
 : var { Left = (J - 1).Mod[M]; Right = (J + 1).Mod[M] } in
 : var
   { Count =
     B[Up  ; Left ] +
     B[Up  ; J    ] +
     B[Up  ; Right] +
     B[I   ; Right] +
     B[Down; Right] +
     B[Down; J    ] +
     B[Down; Left ] +
     B[I   ; Left ]
   }
   in
   NextB[I; J] =
   { if Count == 2 then B[I; J] else
   : if Count == 3 then 1 else
     0
   }
 }
 Out.WriteLine["After " G " generations:"]; Display[B]

} </lang> Using comprehension notation: <lang MANOOL> { {extern "manool.org.18/std/0.3/all"} in

let { N = 40; M = 80 } in
let { G = 99 } in
let
 { Display =
   { proc { B } as
   : for { I = Range[N]$ } do
   : do Out.WriteLine[] after
   : for { J = Range[M]$ } do
     Out.Write[{if B[I; J] <> 0 then "*" else " "}]
   }
 }
 in
var { B = {array N of: array M of 0} } in
 -- initialization
 B[19; 41] = 1
 B[20; 40] = 1
 B[21; 40] = 1
 B[22; 40] = 1
 B[22; 41] = 1
 B[22; 42] = 1
 B[22; 43] = 1
 B[19; 44] = 1
 -- end of initialization
 Out.WriteLine["Before:"]; Display[B]
 { repeat G do
   B =
   { array for { I = Range[N]$ } of
   : var { Up = (I - 1).Mod[N]; Down = (I + 1).Mod[N] } in
   : array for { J = Range[M]$ } of
   : var { Left = (J - 1).Mod[M]; Right = (J + 1).Mod[M] } in
   : var
     { Count =
       B[Up  ; Left ] +
       B[Up  ; J    ] +
       B[Up  ; Right] +
       B[I   ; Right] +
       B[Down; Right] +
       B[Down; J    ] +
       B[Down; Left ] +
       B[I   ; Left ]
     }
     in
   : if Count == 2 then B[I; J] else
   : if Count == 3 then 1 else
     0
   }
 }
 Out.WriteLine["After " G " generations:"]; Display[B]

} </lang>

Mathematica / Wolfram Language

Mathematica has cellular automaton functionality built in, so implementing Conway's Game of Life is a one-liner: <lang Mathematica>CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},{2,2,2}}},{1,1}}, startconfiguration, steps];</lang> Example of a glyder progressing 8 steps and showing the 9 frames afterwards as grids of hashes and dots: <lang Mathematica>results=CellularAutomaton[{224,{2,{{2,2,2},{2,1,2},{2,2,2}}},{1,1}},{{{0,1,0},{0,0,1},{1,1,1}},0},8];

Do[Print[i-1];Print[Grid[resultsi/.{1->"#",0->"."}]];,{i,1,Length[results]}]</lang>

gives back:

0
.#...
..#..
###..
.....
.....

1
.....
#.#..
.##..
.#...
.....

2
.....
..#..
#.#..
.##..
.....

3
.....
.#...
..##.
.##..
.....

4
.....
..#..
...#.
.###.
.....

5
.....
.....
.#.#.
..##.
..#..

6
.....
.....
...#.
.#.#.
..##.

7
.....
.....
..#..
...##
..##.

8
.....
.....
...#.
....#
..###

MATLAB

MATLAB has a builtin Game of Life GUI. Type <lang matlab>life</lang> to run it. To view the code, type

<lang matlab>open(fullfile(matlabroot, 'toolbox', 'matlab', 'demos', 'life.m'))</lang>

Here is an example code, more simple (runs the game of life for N generations in a square of side S) :

<lang matlab>function GoL(S, N) %

   colormap copper; whitebg('black');
   G= round(rand(S));
   A = [S 1:S-1]; B = [2:S 1];
   for k=1:N
       Sum = G(A,:)+G(B,:)+G(:,B)+G(:,A)+G(A,B)+G(A,A)+G(B,B)+G(B,A);
       G = double((G & (Sum == 2)) | (Sum == 3));
       surf(G); view([0 90]); pause(0.001)
   end

end</lang>

Maxima

<lang maxima>life(A) := block(

  [p, q, B: zerofor(A), s],
  [p, q]: matrix_size(A),
  for i thru p do (
     for j thru q do (
        s: 0,
        if j > 1 then s: s + A[i, j - 1],
        if j < q then s: s + A[i, j + 1],
        if i > 1 then (
           s: s + A[i - 1, j],
           if j > 1 then s: s + A[i - 1, j - 1],
           if j < q then s: s + A[i - 1, j + 1]
        ),
        if i < p then (
           s: s + A[i + 1, j],
           if j > 1 then s: s + A[i + 1, j - 1],
           if j < q then s: s + A[i + 1, j + 1]
        ),
        B[i, j]: charfun(s = 3 or (s = 2 and A[i, j] = 1))
     )
  ),
  B

)$


/* a glider */

L: matrix([0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],

         [0, 0, 0, 1, 0, 0, 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, 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, 0, 0, 0, 0, 0, 0, 0])$

gen(A, n) := block(thru n do A: life(A), A)$

gen(L, 4); matrix([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],

      [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 1, 0, 0, 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, 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])</lang>

MiniScript

This GUI implementation is for use with Mini Micro. <lang MiniScript>// Conway's Game of Life clear rows = 64; rowRange = range(0, rows-1) cols = 96; colRange = range(0, cols-1) // prepare two tile displays, in display layers 4 and 5 img = Image.create(2, 1); img.setPixel 1, 0, color.white grids = [] for dispIdx in [4,5] display(dispIdx).mode = displayMode.tile td = display(dispIdx) td.cellSize = 10 // size of cells on screen td.extent = [cols, rows] td.overlap = -1 // adds a small gap between cells td.tileSet = img; td.tileSetTileSize = 1 td.clear 0 grids.push td end for

// initialize to a random state for x in colRange for y in rowRange td.setCell x, y, rnd > 0.5 end for end for

curIdx = 5 // main loop while true yield td = grids[curIdx-4] newIdx = 4 + (curIdx == 4) newTd = grids[newIdx-4] for x in colRange for y in rowRange // get sum of neighboring states sum = 0 for i in [x-1, x, x+1] if i < 0 or i >= cols then continue for j in [y-1, y, y+1] if j < 0 or j >= rows then continue if i==x and j==y then continue sum = sum + td.cell(i,j) end for end for // Now, update the cell based on current state // and neighboring sum. if td.cell(x,y) then newTd.setCell x, y, (sum == 2 or sum == 3) else newTd.setCell x, y, sum == 3 end if end for end for display(newIdx).mode = displayMode.tile display(curIdx).mode = displayMode.off curIdx = newIdx end while</lang>

Nim

Translation of: C

<lang nim>import os, strutils, random

randomize() var w, h: int if paramCount() >= 2:

 w = parseInt(paramStr(1))
 h = parseInt(paramStr(2))

if w <= 0: w = 30 if h <= 0: h = 30

  1. Initialize

var univ, utmp = newSeq[seq[bool]](h) for y in 0..<h:

 univ[y].newSeq w
 utmp[y].newSeq w
 for x in 0 ..< w:
   if rand(9) < 1:
     univ[y][x] = true

while true:

 # Show
 stdout.write "\e[H"
 for y in 0..<h:
   for x in 0..<w:
     stdout.write if univ[y][x]: "\e[07m  \e[m" else: "  "
   stdout.write "\e[E"
 stdout.flushFile
 # Evolve
 for y in 0..<h:
   for x in 0..<w:
     var n = 0
     for y1 in y-1..y+1:
       for x1 in x-1..x+1:
         if univ[(y1+h) mod h][(x1 + w) mod w]:
           inc n
     if univ[y][x]: dec n
     utmp[y][x] = n == 3 or (n == 2 and univ[y][x])
 swap(univ,utmp)
 sleep 200</lang>

OCaml

<lang 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</lang>

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 = ()

A graphical version

This implementation has 6 starting patterns (most get quite large) and a random option, and you can set the grid size. <lang OCaml>let alive = 0 let dead = 0xFFFFFF

let iteration ib ob m n =

  let rule = function 3,_ | 2,true -> alive | _ -> dead in
  let f x y =
     if x >= 0 && x < m && y >= 0 && y < n && ib.(x).(y) = alive
     then 1 else 0 in
  let count b q =
     let a, c, p, r = b-1, b+1, q-1, q+1 in
     f a p + f a q + f a r + f b p + f b r + f c p + f c q + f c r in
  for i = 0 to m-1 do
     for j = 0 to n-1 do
        ob.(i).(j) <- rule (count i j, ib.(i).(j) = alive)
     done
  done

let make_random w h bd =

  Random.self_init ();
  for i = 0 to w-1 do
     for j = 0 to h-1 do
        bd.(i).(j) <- if Random.bool () then alive else dead
     done
  done

let set_cells a b cells w h bd =

  let w', h' = w/2 - a, h/2 - b in
  List.iter (fun (i,j) -> bd.(i+w').(j+h') <- alive) cells

let make_blinker = set_cells 1 1 [(1,0); (1,1); (1,2)]

let make_acorn =

  set_cells 1 3 [(0,1); (1,3); (2,0); (2,1); (2,4); (2,5); (2,6)]

let make_growth =

  set_cells 2 3
  [(0,6); (1,4); (1,6); (1,7); (2,4); (2,6); (3,4); (4,2); (5,0); (5,2)]

let make_rabbits =

  set_cells 1 3
  [(0,0); (0,4); (0,5); (0,6); (1,0); (1,1); (1,2); (1,5); (2,1)]

let make_engine =

  set_cells (-100) (-100)
  [(0,1); (0,3); (1,0); (2,1); (2,4); (3,3); (3,4); (3,5); (4,26); (4,27); (5,26); (5,27)]

let make_line w h bd =

  let w', h', l = w/2, h/2, w/3 in
  for i = -l to l do bd.(i+w').(h') <- alive done

let () =

  let argc = Array.length Sys.argv in
  let init =
     let default () = (print_endline "Using random start"; make_random) in
     if argc < 2 then default () else
     match Sys.argv.(1) with
        | "acorn" -> make_acorn
        | "blinker" -> make_blinker
        | "growth" -> make_growth
        | "engine" -> make_engine
        | "line" -> make_line
        | "rabbits" -> make_rabbits
        | "random" -> make_random
        | "-h" -> Printf.printf
           "Usage: %s [acorn|growth|blinker|engine|line|rabbits|random] width height\n" Sys.argv.(0);
           exit 0
        | _ -> default () in
  let width = if argc > 2 then int_of_string Sys.argv.(2) else 300 in
  let height = if argc > 3 then int_of_string Sys.argv.(3) else 300 in
  let bd1 = Array.make_matrix width height dead in
  let bd2 = Array.make_matrix width height dead in
  let border = 5 in
  let disp m = Graphics.draw_image (Graphics.make_image m) border border in
  init width height bd1;
  Graphics.open_graph (Printf.sprintf " %dx%d" (height+2*border) (width+2*border));
  while true do
     disp bd1;
     iteration bd1 bd2 width height;
     disp bd2;
     iteration bd2 bd1 width height
  done</lang>

Compile with:

opam install graphics && ocamlopt -o life -I $(ocamlfind query graphics) graphics.cmxa life.ml

and run with

./life acorn 250 250

If you run the blinker it will probably blink too fast to see unless you choose a large grid size.

OCTAVE

1st order two variable recurrence relation m-file, will also run under MATLAB.

<lang matlab> clear all x=55;  % Size of the Lattice (same as LAWE)

z(1:1:x^2)=0;  % Initialise the binary lattice z_prime=z;  % prepare the z prime

idx=7*x+2;  % Origin z(idx+4)=1;  % Populate the binary lattice with the Gosper Glider z(idx+x+4)=1; z(idx+1+4)=1; z(idx+x+1+4)=1;

z(idx+14)=1; z(idx+14+x)=1; z(idx+14+x+x)=1; z(idx+15+x+x+x)=1; z(idx+15-x)=1; z(idx+16-x-x)=1; z(idx+16+x+x+x+x)=1; z(idx+17-x-x)=1; z(idx+17+x+x+x+x)=1;

z(idx+18+x)=1; z(idx+19-x)=1; z(idx+19+x+x+x)=1; z(idx+20)=1; z(idx+20+x)=1; z(idx+20+x+x)=1; z(idx+21+x)=1;

z(idx+24)=1; z(idx+25)=1; z(idx+24-x)=1; z(idx+25-x)=1; z(idx+24-x-x)=1; z(idx+25-x-x)=1; z(idx+26-x-x-x)=1; z(idx+26+x)=1; z(idx+28-x-x-x)=1; z(idx+28+x)=1; z(idx+28-x-x-x-x)=1; z(idx+28+x+x)=1;

z(idx+38)=1; z(idx+38-x)=1; z(idx+39)=1; z(idx-x+39)=1;



for k=1:1:80;  % Number of frames for n=x+2:1:x^2-x-1;  % one time pass

theta=0;  % Sum the surrounding area (top equation) for c=n-1:1:n+1; for m=-1:1:1; theta=theta+z(m*x+c); endfor endfor

z_prime(n)= round(1/5*(z(n)*acos(sin(pi/4*(theta-z(n)-9/2))) + (1-z(n)) * acos(sin(pi/4*(theta-z(n) + 3)))));  % bottom equation

endfor

figure(2) title('GOL','FontWeight','bold'); xlabel("X"); ylabel("Y"); imagesc(reshape(z,x,x)') z=z_prime; pause  % each press advances the algorithm one step endfor </lang>


Ol

Library: OpenGL

<lang scheme>

  1. !/usr/bin/ol

(import (otus random!))

(define MAX 65536)  ; should be power of two

size of game board (should be less than MAX)

(define WIDTH 170) (define HEIGHT 96)

helper function

(define (hash x y)

  (let ((x (mod (+ x WIDTH) WIDTH))
        (y (mod (+ y HEIGHT) HEIGHT)))
  (+ (* y MAX) x)))
helper function

(define neighbors '(

  (-1 . -1) ( 0 . -1) ( 1 . -1)
  (-1 .  0)           ( 1 .  0)
  (-1 .  1) ( 0 .  1) ( 1 .  1)

))

dead-or-alive cell test

(define (alive gen x y)

  (case (fold (lambda (f xy)
                    (+ f (get gen (hash (+ x (car xy)) (+ y (cdr xy))) 0)))
              0 neighbors)
     (2
        (get gen (hash x y) #false))
     (3
        #true)))
---------------

(import (lib gl2)) (gl:set-window-title "Convey's The game of Life")

(glShadeModel GL_SMOOTH) (glClearColor 0.11 0.11 0.11 1) (glOrtho 0 WIDTH 0 HEIGHT 0 1)

(glPointSize (/ 854 WIDTH))

generate random field

(gl:set-userdata

  (list->ff (map (lambda (i) (let ((x (rand! WIDTH)) (y (rand! HEIGHT)))
                                (cons (hash x y) 1))) (iota 2000))))
main game loop

(gl:set-renderer (lambda (mouse) (let ((generation (gl:get-userdata)))

  (glClear GL_COLOR_BUFFER_BIT)
  ; draw the cells
  (glColor3f 0.2 0.5 0.2)
  (glBegin GL_POINTS)
     (ff-fold (lambda (st key value)
        (glVertex2f (mod key MAX)
                    (div key MAX))
     ) #f generation)
  (glEnd)
  (gl:set-userdata
     ; next cells generation
     (ff-fold (lambda (st key value)
        (let ((x (mod key MAX))
              (y (div key MAX)))
           (fold (lambda (st key)
                    (let ((x (+ x (car key)))
                          (y (+ y (cdr key))))
                       (if (alive generation x y) (put st (hash x y) 1) st)))
              (if (alive generation x y) (put st (hash x y) 1) st) ; the cell
              neighbors)))
        #empty generation)))))

</lang>

ooRexx

<lang oorexx>/* REXX ---------------------------------------------------------------

  • 07.08.2014 Walter Pachl Conway's Game of life graphical
  • Input is a file containing the initial pattern.
  • The compute area is extended when needed
  • (i.e., when cells are born outside the current compute area)
  • When computing the pattern sequence is complete, the graphical
  • output starts and continues until Cancel is pressed.
  • 10.08.2014 WP fixed the output of what.txt
  • --------------------------------------------------------------------*/
Parse Arg what speed
If what='?' Then Do
  Say 'Create a file containing the pattern to be processed'
  Say 'named somename.in (octagon.in such as this for the octagon):'
  Say '   **   '
  Say '  *  *  '
  Say ' *    * '
  Say '*      *'
  Say '*      *'
  Say ' *    * '
  Say '  *  *  '
  Say '   **   '
  Say 'Run the program by entering "rexx conlife somename [pause]"',
                                                'on the command line.'
  Say '(pause is the amount of milliseconds between 2 pictures.',
                                                    'default is 1000)'
  Say 'A file somename.lst will be created.'
  Say 'Hereafter you will see the patterns development',
                                                    'in a new window.'
  Say 'Press the Cancel button to end the presentation.'
  Exit
  End
Parse Version interpreter '_' level '('
If interpreter<>'REXX-ooRexx' Then Do
  Say interpreter  level
  Say 'This program must be run with object Rexx.'
  Exit
  End
If what= Then what='octagon'
If right(what,3)='.in' then
  what=left(what,length(what)-3)
infile=what'.in'
If lines(infile)=0 Then Do
  Say 'Input file' infile 'not found.'
  Say 'Enter conlife ? for help.'
  Exit
  End
If speed= Then
  speed=1000
.local~myspeed=speed
Call tl what
--'type' what'.lst'
.local~title=what
array=.local~myarrayData
d = .drawDlg~new
if d~initCode <> 0 then do
   say 'The Draw dialog was not created correctly.  Aborting.'
   return d~initCode
end
d~execute("SHOWTOP")
return 0
requires "ooDialog.cls"
class 'drawDlg' subclass UserDialog
attribute interrupted unguarded
method init
  expose walterFont
  forward class (super) continue
  -- colornames:
  --  1 dark red      7 light grey   13 red
  --  2 dark green    8 pale green   14 light green
  --  3 dark yellow   9 light blue   15 yellow
  --  4 dark blue    10 white        16 blue
  --  5 purple       11 grey         17 pink
  --  6 blue grey    12 dark grey    18 turquoise
  self~interrupted = .true
  -- Create a font to write the nice big letters and digits
  opts = .directory~new
  opts~weight = 700
  walterFont = self~createFontEx("Arial",14,opts)
  walterFont = self~createFontEx("Courier",18,opts)
  if \self~createcenter(200, 235,"Walter's Clock", , ,"System",14) then
     self~initCode = 1
method defineDialog
  self~createPushButton(/*IDC_PB_DRAW*/100,  0,  0,240,200,"DISABLED NOTAB")  -- The drawing surface.
  self~createPushButton(IDCANCEL,160,220, 35, 12,,"&Cancel")
method initDialog unguarded
  expose x y dc myPen change al. fid nn what array
  change = 0
  x = self~factorx
  y = self~factory
  dc = self~getButtonDC(100)
  myPen   = self~createPen(1,'solid',0)
  t    = .TimeSpan~fromMicroSeconds(500000) -- .5 seconds
  msg  = .Message~new(self,'life')
  alrm = .Alarm~new(t, msg)
  array=.local~myArrayData
  Do s=1 to array~items
    al.s=array[s]
    Parse Var al.s ' == ' al.s
    End
  nn=s-2
  --say 'nn'nn
  Call lineout fid
method interrupt unguarded
  self~interrupted = .true
method cancel unguarded -- Stop the drawing program and quit.
  expose x y
  self~hide
  self~interrupted = .true
  return self~cancel:super
method leaving unguarded -- Best place to clean up resources
  expose dc myPen walterFont
  self~deleteObject(myPen)
  self~freeButtonDC(/*IDC_PB_DRAW*/100,dc)
  self~deleteFont(walterFont)
method life unguarded /* draw individual pixels */
  expose x y dc myPen change walterFont al. nn what
  mx = trunc(20*x); my = trunc(20*y); size = 400
  curPen = self~objectToDC(dc, myPen)
  -- Select the nice big letters and digits into the device context to use to
  -- to write with:
  curFont = self~fontToDC(dc, walterFont)
  -- Create a white brush and select it into the device to paint with.
  whiteBrush = self~createBrush(10)
  curBrush   = self~objectToDC(dc, whiteBrush)
  -- Paint the drawing area surface with the white brush
  self~rectangle(dc, 1, 1, 500, 600, 'FILL')
  self~writeDirect(dc,  10, 20,'Conways Game of Life')
  self~writeDirect(dc,  10, 40,.local~title)
  self~writeDirect(dc,  10,460,'Walter Pachl, 8 Aug 2014')
  dx=.local~dxval
  dy=.local~dyval
  do s=1 By 1 until self~interrupted
    self~transparentText(dc)
    self~interrupted = .false
    sm=s//nn+1
    If s>1 Then Do
      ali=al.sb
      Do While ali<>
        Parse Var ali x ',' y ali
        zxa=(x+dx)*10
        zya=(y+dy)*10
        self~draw_square(dc,zxa,zya,3,10)
        End
      End
    self~draw_square(dc, 380, 10,100,10)
    self~writeDirect(dc, 340, 20,time())
    self~writeDirect(dc, 340, 40,right(sm,2) 'of' right(nn,2))
    ali=al.sm
    Do While ali<>
      Parse Var ali x ',' y ali
      zxa=(x+dx)*10
      zya=(y+dy)*10
      self~draw_square(dc,zxa,zya,3,5)
      End
--    self~interrupted = .true
    sb=sm
    self~objectToDC(dc, curPen)
    self~objectToDC(dc, curBrush)
    call msSleep .local~myspeed
  --self~pause
    End
method pause
  j = msSleep(10)
method draw_square
 Use Arg dc, x, y, d, c
 Do zx=x-d to x+d
   Do zy=y-d to y+d
     self~drawPixel(dc, zx, zy, c)
     End
   End
method quot
 Parse Arg x,y
 If y=0 Then Return '???'
 Else Return x/y
routine tl

/* REXX ---------------------------------------------------------------

  • 02.08.2014 Walter Pachl
  • Input is a file containing the initial pattern
  • The compute area is extended when needed
  • (cells are born outside the current compute area)
  • The program stops when the picture shown is the same as the first
  • or equal to the previous one
  • --------------------------------------------------------------------*/

Parse Arg f If f= Then f='bipole' fid=f'.in' oid=f'.txt'; 'erase' oid oil=f'.lst'; 'erase' oil debug=0 If debug Then Do

 dbg=f'.xxx'; 'erase' dbg
 End

ml=0 l.= ol.= Parse Value '10 10' With xb yb xc=copies(' ',xb) Do ri=yb+1 By 1 While lines(fid)>0

 l.ri=xc||linein(fid)
 ml=max(ml,length(strip(l.ri,'T')))
 End

ri=ri-1 ml=ml+xb ri=ri+yb yy=ri a.=' ' b.=' ' m.= x.= list.= Parse Value 1 ml 1 yy With xmi xma ymi yma Parse Value '-10 30 -10 30' With xmi xma ymi yma Parse Value '999 -999 999 -999 999 -999 999 -999',

      With xmin xmax ymin ymax xlo xhi  ylo yhi

Do y=1 To yy

 z=yy-y+1
 l=l.z
 Do x=1 By 1 While l<>
   Parse Var l c +1 l
   If c='*' Then
     a.x.z='*'
   End
 End

Call show Do step=1 To 60

 Call store
 If step>1 & is_equal(step,1) Then Leave
 If step>1 & is_equal(step,step-1) Then Leave
 Call show_neighbors
 Do y=yma To ymi By -1
   ol=format(x,3)' '
   Do x=xmi To xma
     neighbors=neighbors(x,y)
     If a.x.y=' ' Then Do             /* dead cell                  */
       If neighbors=3 Then Do
         b.x.y='*'                    /*  gets life                 */
         mmo=xmi xma ymi yma
         xmi=min(xmi,x-1)
         xma=max(xma,x+1)
         ymi=min(ymi,y-1)
         yma=max(yma,y+1)
         mm=xmi xma ymi yma
         If mm<>mmo Then
           Call debug mmo '1->' mm
         End
       Else                           /* life cell                  */
         b.x.y=' '                    /*  remains dead              */
       End
     Else Do                          /* life cell                  */
       If neighbors=2 |,
          neighbors=3 Then Do
         b.x.y='*'  /*  remains life              */
         mmo=xmi xma ymi yma
         xmi=min(xmi,x-1)
         xma=max(xma,x+1)
         ymi=min(ymi,y-1)
         yma=max(yma,y+1)
         mm=xmi xma ymi yma
         If mm<>mmo Then
           Call debug mmo '2->' mm
         End
       Else
         b.x.y=' '  /*  dies                      */
       End
     End
   End
 /* b. is the new state and is now copied to a.                     */
 Do y=yma To ymi By -1
   Do x=xmi To xma
     a.x.y=b.x.y
     End
   End
 End

/* Output name and all states */ Call lineout oid,' 'f st=' +' /* top and bottom border */ sb=' +' /* top and bottom border */ Do s=1 To step

 st=st||'-'right(s,2,'-')||copies('-',xmax-xmin-2)'+'
 sb=sb||copies('-',xmax-xmin+1)'+'
 End

array=.array~new Do y=ymin To ymax

 Do s=1 To step
   Do x=xmin To xmax
     If substr(m.s.y,x,1)='*' Then Do
       xlo=min(xlo,x)
       xhi=max(xhi,x)
       ylo=min(ylo,y)
       yhi=max(yhi,y)
       End
     End
   End
 End

Do y=ymin To ymax

 ol=
 Do s=1 To step
   Do x=xmin To xmax
     If substr(m.s.y,x,1)='*' Then Do
       list.s=list.s (x-xlo+1)','||(y-ylo+1)
       End
     End
   array[s]=s '-' words(list.s) '==' list.s
   End
 --Call lineout oid,ol '|'
 .local~myArrayData=array
 End

height=yhi-ylo+1 width=xhi-xlo+1 .local~dxval=(48-width)%2 .local~dyval=(48-height)%2 Call o st /* top border */ xl.='|' Do y=ymax To ymin By -1

 Do s=1 To step
   xl.y=xl.y||substr(ol.s.y,xmin,xmax-xmin+1)'|'
   End
 End

Do y=ymax To ymin By -1

 Call o ' 'xl.y
 End

Call o sb /* bottom border */ Call lineout oid Say 'frames are shown in' oid If debug Then Do

 Say 'original area' 1 ml '/' 1 yy
 Say 'compute area ' xmi xma '/' ymi yma
 Say 'used area    ' xlo xhi '/' ylo yhi
 End

Do s=1 To step

 call lineout oil,s '==>' words(list.s) '=='  list.s
 End

Return

o: Parse Arg lili

  Call lineout oid,lili
  Return

set: Parse Arg x,y

    a.x.y='*'
    Return

neighbors: Procedure Expose a. debug

 Parse Arg x,y
 neighbors=0
 do xa=x-1 to x+1
   do ya=y-1 to y+1
     If xa<>x | ya<>y then
       If a.xa.ya='*' Then
         neighbors=neighbors+1
     End
   End
 Return neighbors

store: /* store current state (a.) in lines m.step.* */ Do y=yma To ymi By -1

 ol=
 Do x=xmi To xma
   z=a.x.y
   ol=ol||z
   End
 x.step.y=ol
 If ol<> then Do
   ymin=min(ymin,y)
   ymax=max(ymax,y)
   p=pos('*',ol)
   q=length(strip(ol,'T'))
   If p>0 Then
     xmin=min(xmin,p)
   xmax=max(xmax,q)
   End
 m.step.y=ol
 ol.step.y=ol
 --If pos('*',ol)>0 Then Do
 --  Say '====>' right(step,2) right(y,3) '>'ol'<'  xmin xmax
 --  Say '              'copies('1234567890',3)
 --  End
 End

Return

is_equal: /* test ist state a.b is equal to state a.a */

 Parse Arg a,b
 Do y=yy To 1 By -1
   If x.b.y<>x.a.y Then
     Return 0
   End
 Return 1

show: Procedure Expose dbg a. yy ml debug Do y=-5 To 13

 ol='>'
 Do x=-5 To 13
   ol=ol||a.x.y
   End
 Call debug ol
 End

Return

show_neighbors: Procedure Expose a. xmi xma ymi yma dbg debug

 Do y=yma To ymi By -1
   ol=format(y,3)' '
   Do x=xmi To xma
     ol=ol||neighbors(x,y)
     End
   Call debug ol
   End
 Return

debug:

 If debug Then
   Return lineout(dbg,arg(1))
 Else
   Return

</lang>

Output:
blinker.txt
 blinker
 +--1+--2+--3+
 |   | * |   |
 |***| * |***|
 |   | * |   |
 +---+---+---+  
blinker.lst
1 ==> 3 ==  1,2 2,2 3,2
2 ==> 3 ==  2,1 2,2 2,3
3 ==> 3 ==  1,2 2,2 3,2    

Oz

<lang oz>declare

 Rules = [rule(c:1 n:[0 1]             new:0)  %% Lonely
          rule(c:1 n:[4 5 6 7 8]       new:0)  %% Overcrowded
          rule(c:1 n:[2 3]             new:1)  %% Lives
          rule(c:0 n:[3]               new:1)  %% It takes three to give birth!
          rule(c:0 n:[0 1 2 4 5 6 7 8] new:0)  %% Barren
         ]
 Blinker = ["..."
            "###"
            "..."]
 Toad = ["...."
         ".###"
         "###."
         "...."]
 Glider = [".#.........."
           "..#........."
           "###........."
           "............"
           "............"
           "............"
           "............"
           "............"
           "............"
           "............"
           "............"]
 Init = Blinker
 MaxGen = 2
 %% G(i) -> G(i+1)
 fun {Evolve Gi}
    fun {Get X#Y}
       Row = {CondSelect Gi Y unit}
    in
       {CondSelect Row X 0} %% cells beyond boundaries are dead (0)
    end
    fun {GetNeighbors X Y}
       {Map [X-1#Y-1  X#Y-1  X+1#Y-1
             X-1#Y           X+1#Y
             X-1#Y+1  X#Y+1  X+1#Y+1]
        Get}
    end
 in
    {Record.mapInd Gi
     fun {$ Y Row}
        {Record.mapInd Row
         fun {$ X C}
            N = {Sum {GetNeighbors X Y}}
         in
            for Rule in Rules return:Return do
               if C == Rule.c andthen {Member N Rule.n} then
                  {Return Rule.new}
               end
            end
         end}
     end}
 end
 %% For example: [".#"
 %%                "#."] -> grid(1:row(1:0 2:1) 2:row(1:1 2:0))
 fun {ReadG LinesList}
    {List.toTuple grid
     {Map LinesList
      fun {$ Line}
         {List.toTuple row
          {Map Line
           fun {$ C}
              if C == &. then 0
              elseif C == &# then 1
              end
           end}}
      end}}
 end
 %% Inverse to ReadG
 fun {ShowG G}
    {Map {Record.toList G}
     fun {$ Row}
        {Map {Record.toList Row}
         fun {$ C}
            if C == 0 then &.
            elseif C == 1 then &#
            end
         end}
     end}
 end
 %% Helpers
 fun {Sum Xs} {FoldL Xs Number.'+' 0} end
 fun lazy {Iterate F V} V|{Iterate F {F V}} end
 G0 = {ReadG Init}
 Gn = {Iterate Evolve G0}

in

 for
    Gi in Gn
    I in 0..MaxGen
 do
    {System.showInfo "\nGen. "#I}
    {ForAll {ShowG Gi} System.showInfo}
 end</lang>

PARI/GP

Basic implementation; prints a matrix representing the state of the game directly. Supports large games but this example uses only the required 3 X 3 blinker. <lang parigp>step(M)={

 my(N=M,W=matsize(M)[1],L=#M,t);
 for(l=1,W,for(w=1,L,
   t=sum(i=l-1,l+1,sum(j=w-1,w+1,if(i<1||j<1||i>W||j>L,0,M[i,j])));
   N[l,w]=(t==3||(M[l,w]&&t==4))
 ));
 N

}; M=[0,1,0;0,1,0;0,1,0]; for(i=1,3,print(M);M=step(M))</lang>

Pascal

Uses crt for console output. Can make use of a "torus"-world. Optimized for speed on a Haswell CPU (without PrintGen ~ 8.5 Cpu-cyles/coordinate ) <lang pascal>program Gol; // Game of life {$IFDEF FPC}

  //save as gol.pp/gol.pas
 {$Mode delphi}

{$ELSE}

 //for Delphi save as gol.dpr
 {$Apptype Console}

{$ENDIF} uses

 crt;

const

 colMax = 76;
 rowMax = 22;
 dr = colMax+2; // element count of one row
 cDelay = 20;  // delay in ms

(* expand field by one row/column before and after for easier access no special treatment of torus

  • )

type

 tFldElem  = byte;//0..1
 tpFldElem = ^tFldElem;
 tRow = array[0..colMax+1] of tFldElem;
 tpRow = ^tRow;
 tBoard = array[0..rowMax+1] of tRow;
 tpBoard = ^tBoard;
 tpBoards = array[0..1] of tpBoard;

type

 tIntArr = array[0..2*dr+2] of tFldElem;
 tpIntArr = ^tIntArr;

var

 aBoard,bBoard : tBoard;
 pBoards :tpBoards;
 gblActBoard : byte;
 gblUseTorus :boolean;
 gblGenCnt   : integer;

procedure PrintGen; const

 cChar: array[0..1] of char = (' ','#');

var

 p0 : tpIntArr;
 col,row: integer;
 s : string[colMax];

begin

 setlength(s,colmax);
 gotoxy(1,1);
 writeln(gblGenCnt:10);
 For row := 1 to rowMax do
 begin
   p0 := @pBoards[gblActBoard]^[row,0];;
   For col := 1 to colMax do
     s[col] := cChar[p0[col]];
   writeln(s);
 end;
 delay(cDelay);

end;

procedure Init0(useTorus:boolean); begin

 gblUseTorus := useTorus;
 gblGenCnt := 0;
 fillchar(aBoard,SizeOf(aBoard),#0);
 pBoards[0] := @aBoard;
 pBoards[1] := @bBoard;
 gblActBoard := 0;
 clrscr;

end;

procedure InitRandom(useTorus:boolean); var

 col,row : integer;

begin

 Init0(useTorus);
 For row := 1 to rowMax do
   For col := 1 to colMax do
     aBoard[row,col]:= tFldElem(random>0.9);

end;

procedure InitBlinker(useTorus:boolean); var

 col,row : integer;

begin

 Init0(useTorus);
 For col := 1 to colMax do
 begin
   IF (col+2) mod 4 = 0 then
     begin
     For row := 1 to rowmax do
       IF row mod 4 <> 0 then
         aBoard[row,col]:= 1;
     end;
 end;

end;

procedure Torus; var

 p0 : tpIntArr;
 row: integer;

begin

 //copy column 1-> colMax+1 and colMax-> 0
 p0 := @pBoards[gblActBoard]^[1,0];
 For row := 1 to rowMax do
   begin
   p0^[0] := p0^[colMax];
   p0^[colmax+1] := p0^[1];
   //next row
   p0 := Pointer(PtrUint(p0)+SizeOf(tRow));
   end;
 //copy row  1-> rowMax+1
 move(pBoards[gblActBoard]^[1,0],pBoards[gblActBoard]^[rowMax+1,0],sizeof(trow));
 //copy row  rowMax-> 0
 move(pBoards[gblActBoard]^[rowMax,0],pBoards[gblActBoard]^[0,0],sizeof(trow));

end;

function Survive(p: tpIntArr):tFldElem; //p points to actual_board [row-1,col-1] //calculates the sum of alive around [row,col] aka p^[dr+1] //really fast using fpc 2.6.4 no element on stack const

 cSurvives : array[boolean,0..8] of byte =
             //0,1,2,3,4,5,6,7,8     sum of alive neighbours
             ((0,0,0,1,0,0,0,0,0),   {alive =false 1->born}
              (0,0,1,1,0,0,0,0,0));  {alive =true  0->die }

var

 sum : integer;

begin

 // row above
 // sum := byte(aBoard[row-1,col-1])+byte(aBoard[row-1,col])+byte(aBoard[row-1,col+1]);
 sum :=     integer(p^[     0])+integer(p^[     1])+integer(p^[     2]);
 sum := sum+integer(p^[  dr+0])                    +integer(p^[  dr+2]);
 sum := sum+integer(p^[2*dr+0])+integer(p^[2*dr+1])+integer(p^[2*dr+2]);
 survive := cSurvives[boolean(p^[dr+1]),sum];

end;

procedure NextGen; var

 p0,p1 : tpFldElem;
 row: NativeInt;
 col :NativeInt;

begin

 if gblUseTorus then
   Torus;
 p1 := @pBoards[1-gblActBoard]^[1,1];
 //One row above and one column before because of survive
 p0 := @pBoards[  gblActBoard]^[0,0];
 For row := rowMax-1 downto 0 do
 begin
   For col := colMax-1 downto 0 do
   begin
     p1^ := survive(tpIntArr(p0));
     inc(p0);
     inc(p1);
   end;
   // jump over the borders
   inc(p1,2);
   inc(p0,2);
 end;
 //aBoard := bBoard;
 gblActBoard :=1-gblActBoard;
 inc(gblGenCnt);

end;

begin

 InitBlinker(false);
 repeat
   PrintGen;
   NextGen;
 until keypressed;
 PrintGen;

end. </lang>

Perl

This a perl example the simulates Conway's life starting with a random grid of the given size for the given number of steps. Example:

life.pl numrows numcols numiterations 
life.pl 5 10 15 

would do 15 iterations over 5 rows and 10 columns.

<lang perl>my ($width, $height, $generations) = @ARGV;

my $printed;

sub generate {

  (map
      {[ (map { rand () < 0.5 } 1 .. $width), 0 ]}
      1 .. $height),
  [(0) x ($width + 1)];

}

sub nexgen {

  my @prev = map {[@$_]} @_;
  my @new = map {[ (0) x ($width + 1) ]} 0 .. $height;
  foreach my $row ( 0 .. $height - 1 ) {
      foreach my $col ( 0 .. $width - 1 ) {
          my $val =
            $prev[ $row - 1 ][ $col - 1 ] +
            $prev[ $row - 1 ][ $col     ] +
            $prev[ $row - 1 ][ $col + 1 ] +
            $prev[ $row     ][ $col - 1 ] +
            $prev[ $row     ][ $col + 1 ] +
            $prev[ $row + 1 ][ $col - 1 ] +
            $prev[ $row + 1 ][ $col     ] +
            $prev[ $row + 1 ][ $col + 1 ];
          $new[$row][$col] =
              ( $prev[$row][$col] && $val == 2 || $val == 3 );
      }
  }
  return @new;

}

sub printlife {

  my @life = @_;
  if ($printed) {

# Move the cursor up to print over prior generation. print "\e[1A" x $height;

  }
  $printed = 1;
  foreach my $row ( 0 .. $height - 1 ) {
      foreach my $col ( 0 .. $width - 1 ) {
          print($life[$row][$col]
            ? "\e[33;45;1m \e[0m"
            : "\e[1;34;1m \e[0m");
      }
      print "\n";
  }

}

my @life = generate; print "Start\n"; printlife @life; foreach my $stage ( 1 .. $generations ) {

  sleep 1;
  print "Generation $stage\n\e[1A";
  @life = nexgen @life;
  printlife @life;

} print "\n";</lang>

Another version, takes up the whole area of your terminal. Using warping edges.<lang Perl>my $w = `tput cols` - 1; my $h = `tput lines` - 1; my $r = "\033[H";

my @universe = map([ map(rand(1) < .1, 1 .. $w) ], 1 .. $h); sub iterate { my @new = map([ map(0, 1 .. $w) ], 1 .. $h); for my $i (0 .. $h - 1) { for my $j (0 .. $w - 1) { my $neighbor = 0; for ( [-1, -1], [-1, 0], [-1, 1], [ 0, -1], [ 0, 1], [ 1, -1], [ 1, 0], [ 1, 1] ) { my $y = $_->[0] + $i; my $x = $_->[1] + $j; $neighbor += $universe[$y % $h][$x % $w]; last if $neighbor > 3; }

$new[$i][$j] = $universe[$i][$j] ? ($neighbor == 2 or $neighbor == 3) : $neighbor == 3; }} @universe = @new; }

while(1) { print $r; print map((map($_ ? "#" : " ", @$_), "\n"), @universe); iterate; }</lang>

Next Generation in a Single Substitution Operator

<lang perl>#!/usr/bin/perl

print $_ = << =~ tr/./ /r; # test case, dots only for layout ..... ..... .###. ..... .....

my $gap = /..\n/ ? qr/.{$-[0]}/s : die "too small"; my $neighborhood = qr/(?<=(...) $gap (.)) . (?=(.) $gap (...))/x;

for my $generation ( 2 .. 4 )

 {
 s/$neighborhood/ substr "  $&#     ", "$1$2$3$4" =~ tr|#||, 1 /ge;
 print;
 }</lang>
Output:


### 
    
    
    
 #  
 #  
 #  
    
    
    
### 
    
    
    
 #  
 #  
 #

Phix

Translation of: basic256
Library: Phix/pGUI
Library: Phix/online

You can run this online here.

--
-- demo\rosetta\Conways_Game_of_Life.exw
-- =====================================
--
with javascript_semantics
include pGUI.e

constant title = "Conway's Game of Life"
Ihandle dlg, canvas
Ihandln hTimer = NULL
cdCanvas cddbuffer

sequence c = {},    -- cells
         cn,        -- new cells
         cl         -- last cells

procedure draw(integer what)
    integer x = floor(length(c)/2)+1,
            y = floor(length(c[1])/2)
    switch what do
        case ' ': c = sq_mul(c,0)                                   -- Clear
        case '+': c[x][y-1..y+1] = repeat(1,3)                      -- Blinker
        case 'G': {                    c[x+1,y+4],
                   c[x+2,y+2],         c[x+2,y+4],
                           c[x+3,y+3], c[x+3,y+4]} = repeat(1,5)    -- Glider
        case 'T': {c[x-1,y+1],c[x,y+1],c[x+1,y+1],
                   c[x  ,y+3],c[x,y+4],c[x  ,y+5]} = repeat(1,6)    -- Thunderbird
        case 'X': for i=0 to min(x,y)-1 do
                    {c[x-i,y+i],c[x+i,y+i],
                     c[x-i,y-i],c[x+i,y-i]} = repeat(1,4)           -- Cross
                  end for
    end switch
end procedure

atom t1 = time()+1
integer fps = 0

function redraw_cb(Ihandle /*ih*/)
    integer {width, height} = IupGetIntInt(canvas, "DRAWSIZE"),
            -- limit to 10K cells (performance target of 10fps)
            -- n here is the cell size in pixels (min of 1x1)
            n = ceil(sqrt(width*height/10000)),
            w = floor(width/n)+2, -- (see cx below)
            h = floor(height/n)+2,
            alive = 0
    -- keep w, h odd for symmetry (plus I suspect the 
    --  "Cross" code above may now crash without this)
    w -= even(w)
    h -= even(h)
    if length(c)!=w
    or length(c[1])!=h then
        c = repeat(repeat(0,h),w)
        cn = deep_copy(c)
        cl = deep_copy(c)
        draw('X')
        if hTimer!=NULL then
            IupStoreAttribute(hTimer, "RUN", "YES")
        end if
    end if
    cdCanvasActivate(cddbuffer)
    --
    -- There is a "dead border" of 1 cell all around the edge of c (etc) which
    -- we never display or update. If we have got this right/an exact fit, then 
    -- w*n should be exactly 2n too wide, whereas in the worst case there is an
    -- (2n-1) pixel border, which we split between left and right, ditto cy.
    --
    integer cx = n+floor((width-w*n)/2)
    for x=2 to w-1 do
        integer cy = n+floor((height-h*n)/2)
        for y=2 to h-1 do
            integer cxy = c[x,y],
                    clxy = cl[x,y],
                    cnxy = -cxy
            for i=x-1 to x+1 do
                for j=y-1 to y+1 do
                    cnxy += c[i,j]
                end for
            end for
            integer live = iff(cxy?cnxy>=2 and cnxy<=3:cnxy==3),
            colour = iff(live?iff(cxy?iff(clxy?CD_PURPLE    -- adult
                                              :CD_GREEN)    -- newborn
                                     :iff(clxy?CD_RED       -- old
                                              :CD_YELLOW))  -- shortlived
                             :CD_BLACK)
            cn[x,y] = live
            alive += live
            cdCanvasSetForeground(cddbuffer,colour)
            cdCanvasBox(cddbuffer, cx, cx+n-1, cy, cy+n-1)
            cy += n
        end for
        cx += n
    end for
    cdCanvasFlush(cddbuffer)
    if not alive then
        IupStoreAttribute(hTimer, "RUN", "NO")
        IupStoreAttribute(dlg, "TITLE", "died")
    elsif c=cn then
        IupStoreAttribute(hTimer, "RUN", "NO")
        IupStoreAttribute(dlg, "TITLE", "stable")
    else
        cl = c
        c = deep_copy(cn)
        fps += 1
        if time()>=t1 then
            IupSetStrAttribute(dlg,"TITLE","%s (%d FPS)",{title,fps})
            t1 = time()+1
            fps = 0
        end if
    end if
    return IUP_DEFAULT
end function

function map_cb(Ihandle ih)
    cdCanvas cdcanvas = cdCreateCanvas(CD_IUP, ih)
    cddbuffer = cdCreateCanvas(CD_DBUFFER, cdcanvas)
    cdCanvasSetBackground(cddbuffer, CD_WHITE)
    cdCanvasSetForeground(cddbuffer, CD_RED)
    return IUP_DEFAULT
end function

function key_cb(Ihandle /*ih*/, atom c)
    if c=K_ESC then return IUP_CLOSE end if -- (standard practice for me)
    if c=K_F5 then return IUP_DEFAULT end if -- (let browser reload work)
    if    find(c," ")   then draw(' ')  -- Clear
    elsif find(c,"+bB") then draw('+')  -- Blinker
    elsif find(c,"gG")  then draw('G')  -- Glider
    elsif find(c,"tT")  then draw('T')  -- Thunderbird
    elsif find(c,"xX")  then draw('X')  -- Cross
    end if
    IupStoreAttribute(hTimer, "RUN", "YES")
    return IUP_CONTINUE
end function

function timer_cb(Ihandle /*ih*/)
    IupUpdate(canvas)
    return IUP_IGNORE
end function

procedure main()
    IupOpen()
    canvas = IupCanvas("RASTERSIZE=390x390")
    IupSetCallbacks(canvas, {"MAP_CB", Icallback("map_cb"),
                             "ACTION", Icallback("redraw_cb")})
    dlg = IupDialog(canvas,`TITLE="%s", MINSIZE=350x55`, {title})
      -- (above MINSIZE prevents the title from getting squished)
    IupSetCallback(dlg, "KEY_CB", Icallback("key_cb"))
    IupShow(dlg)
    IupSetAttribute(canvas,"RASTERSIZE",NULL)
--  hTimer = IupTimer(Icallback("timer_cb"),40) -- 25fps (maybe)
    hTimer = IupTimer(Icallback("timer_cb"),100) -- 10fps
    if platform()!=JS then
        IupMainLoop()
        IupClose()
    end if
end procedure

main()

Picat

Blinker

<lang Picat>go =>

  Rows = 3,
  Cols = 3,
  println(blinker),
  pattern(blinker, Pattern,I,J),
  life(fill(Rows,Cols,Pattern,I,J)),
  nl.

fill(Rows, Cols, Obj) = fill(Rows, Cols, Obj,1,1). fill(Rows, Cols, Obj,OffsetI,OffsetJ) = Grid =>

  Grid = new_array(Rows,Cols), bind_vars(Grid,0),
  foreach(I in 1..Obj.length, J in 1..Obj[1].length) 
    Grid[I+OffsetI-1,J+OffsetJ-1] := Obj[I,J]
  end.

% We stop whenever a fixpoint/cycle is detected life(S) =>

   Rows = S.length,
   Cols = S[1].length,
   println([rows=Rows, cols=Cols]),
   print_grid(S),
   Seen = new_map(), % detect fixpoint and cycle
   Count = 0,
   while (not Seen.has_key(S))
      Seen.put(S,1),
      T = new_array(Rows,Cols),
      foreach(I in 1..Rows, J in 1..Cols) 
          Sum = sum([S[I+A,J+B] : A in -1..1,B in -1..1, 
                                  I+A > 0, J+B > 0, 
                                  I+A =< Rows, J+B =< Cols]) - S[I,J],
          C = rules(S[I,J], Sum),
          T[I,J] := C
      end,
      print_grid(T),
      S := T,
      Count := Count + 1
   end,
   printf("%d generations\n", Count).

print_grid(G) =>

 foreach(I in 1..G.length) 
    foreach(J in 1..G[1].length) 
       if G[I,J] == 1 then print("#") else print(".") end
    end,
    nl
 end,
 nl.

% The Rules of Life rules(This,Sum) = 1, (This == 1, member(Sum,[2,3]); This == 0, Sum == 3) => true. rules(_This, _Sum) = 0 => true.

% % The patterns % pattern(Name, Pattern, OffsetI, OffsetJ) % where Offset* is the recommended offsets in a grid. %

% For the task pattern(blinker, Pattern,I,J) ?=>

  Pattern = [[0,0,0],
             [1,1,1],
             [0,0,0]],
  I=1,J=1.</lang>
Output:
blinker
[rows = 3,cols = 3]
...
###
...

.#.
.#.
.#.

...
###
...

2 generations

Testing some more forms

<lang Picat>go2 =>

  Rows = 20,
  Cols = 20,
  Names = [blinker2, p4, p5, glider, figure_eight], 
  foreach(Name in Names )
    pattern(Name, Pattern,I,J),
    println(Name),     
    life(fill(Rows,Cols,Pattern,I,J)),
    nl
  end,
  nl.

% Increase the recommended offset pattern(blinker2, Pattern,I,J) ?=>

  Pattern = [[0,0,0],
             [1,1,1],
             [0,0,0]],
  I=5,J=5.

pattern(p4, Pattern,I,J) ?=>

  Pattern = [[0,0,0,0],
             [1,1,1,1],
             [1,1,1,1],
             [0,0,0,0]],
  I=10,J=10.

pattern(p5, Pattern,I,J) ?=>

  Pattern = [[0,0,0,0,0],
             [1,1,1,1,1],
             [1,1,1,1,1],
             [1,1,1,1,1],
             [0,0,0,0,0]],
  I=10,J=10.

pattern(glider, Pattern,I,J) ?=>

  Pattern = [[0,0,1],
             [1,0,1],
             [0,1,1]],
  I=5,J=5.

pattern(figure_eight, Pattern,I,J) =>

  Pattern = [[1,1,1,0,0,0],
             [1,1,1,0,0,0],
             [1,1,1,0,0,0],
             [0,0,0,1,1,1],
             [0,0,0,1,1,1],
             [0,0,0,1,1,1]],
  I=10,J=10.</lang>

PicoLisp

This example uses 'grid' and 'disp' from "lib/simul.l". These functions maintain an array of multiply linked objects, and are also used in the chess program and other games in the distribution. <lang PicoLisp>(load "@lib/simul.l")

(de life (DX DY . Init)

  (let Grid (grid DX DY)
     (for This Init
        (=: life T) )
     (loop
        (disp Grid NIL
           '((This) (if (: life) "X " "  ")) )
        (wait 1000)
        (for Col Grid
           (for This Col
              (let N  # Count neighbors
                 (cnt
                    '((Dir) (get (Dir This) 'life))
                    (quote
                       west east south north
                       ((X) (south (west X)))
                       ((X) (north (west X)))
                       ((X) (south (east X)))
                       ((X) (north (east X))) ) )
                 (=: next  # Next generation
                    (if (: life)
                       (>= 3 N 2)
                       (= N 3) ) ) ) ) )
        (for Col Grid  # Update
           (for This Col
              (=: life (: next)) ) ) ) ) )

(life 5 5 b3 c3 d3)</lang> Output:

 5
 4
 3   X X X
 2
 1
   a b c d e
 5
 4     X
 3     X
 2     X
 1
   a b c d e
 5
 4
 3   X X X
 2
 1
   a b c d e

PL/I

<lang PL/I>(subscriptrange): Conway: procedure options (main); /* 20 November 2013 */

  /* A grid of (1:100, 1:100) is desired; the array GRID is defined as (0:101, 0:101), */
  /* to satisfy the requirement that elements off-grid are zero.                       */
  declare n fixed binary; /* grid size) */
  put ('What grid size do you want?');
  get (n);
  put skip list ('Generating a grid of size ' || trim(n) );

begin;

  declare grid (0:n+1,0:n+1) bit(1) initial ((*) '0'b);
  declare new  (0:n+1,0:n+1) bit(1);
  declare cell(3,3) defined grid(1sub-2+i, 2sub-2+j) bit (1);
  declare (i, j, k) fixed binary;
  /* Initialize some cells. */
  grid(2,2) = '1'b; grid(2,3) = '1'b; grid(2,4) = '1'b;
  /* Print the initial state. */
  put list ('Initial pattern:');
  do i = 1 to n;
     put skip;
     do j = 1 to n;
        put edit (grid(i,j)) (b(1));
     end;
  end;
  do k = 1 to 4;
     /* Do one generation of life */
     new = '0'b;
     /* For each C, the center of a 3 x 3 cell matrix. */
     do i = 1 to n;
        do j = 1 to n;
           if grid(i,j) then
              select (sum(cell)-1);
                 when (0,1)       new(i,j) = '0'b;
                 when (4,5,6,7,8) new(i,j) = '0'b;
                 when (2,3)       new(i,j) = '1'b;
              end;
           else
              select (sum(cell));
                 when (3)         new(i,j) = '1'b;
                 otherwise        new(i,j) = '0'b;
              end;
        end;
     end;
     grid = new; /* Update GRID with the new generation. */
     /* Print the generation. */
     put skip(2) list ('Generation ' || trim(k));
     do i = 1 to n;
        put skip;
        do j = 1 to n;
           put edit (grid(i,j)) (b(1));
        end;
     end;
  end;

end; end Conway;</lang> Results:

What grid size do you want? 

Generating a grid of size 5 

Initial conditions: 
00000
01110
00000
00000
00000

Generation 1 
00100
00100
00100
00000
00000

Generation 2 
00000
01110
00000
00000
00000

Generation 3 
00100
00100
00100
00000
00000

Generation 4 
00000
01110
00000
00000
00000

Pointless

<lang pointless>----------------------------------------------------------- -- Print 100 simulated states of conway's game of life -- for a glider starting pattern on a wrapping grid -- Print generation number along with cells

output =

 initCells
 |> iterate(updateCells)
 |> take(130)
 |> enumerate
 |> map(showPair)
 |> printFrames

initCells =

[[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 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 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 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 0 0 0 0 1 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 1 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 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 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]

width = length(initCells[0]) height = length(initCells)

positions =

 for y in range(0, height - 1)
 for x in range(0, width - 1)
 yield (x, y)

-- Update each cell in the grid according to its position, -- and convert the resulting list back to a 2D array

updateCells(cells) =

 positions
 |> map(tick(cells))
 |> toNDArray((height, width))

-- Get the new value for a cell at a give position -- based on the current cell values in the grid

tick(cells, pos) = toInt(survive or birth) where {

 survive = cells[y][x] == 1 and count in {2, 3}
 birth   = cells[y][x] == 0 and count == 3
 count   = getCount(x, y, cells)
 (x, y)  = pos

}


-- Get the number of live neighbors of a given position

getCount(x, y, cells) = sum(

 for dx in [-1, 0, 1] 
 for dy in [-1, 0, 1] 
 when (dx != 0 or dy != 0)
 yield getNeighbor(x + dx, y + dy, cells) 

)

getNeighbor(x, y, cells) = cells[y % height][x % width]


-- Print the board and generation number given pairs -- of (gen, cells) from the enumerate function

showPair(pair) =

 format("{}\ngeneration: {}", [showCells(cells), gen])
 where (gen, cells) = pair

showCells(cells) =

 toList(cells)
 |> map(showRow)
 |> join("\n")

showRow(row) =

 format("|{}|", [map(showCell, toList(row)) |> join("")])

showCell(cell) =

 if cell == 1 then "*" else " "</lang>

PostScript

<lang PostScript>%!PS-Adobe-3.0 %%BoundingBox: 0 0 400 400

/size 400 def

realtime srand /rand1 { rand 2147483647 div } def

/m { moveto } bind def /l { rlineto} bind def /drawboard {

       0 1 n 1 sub { /y exch def
       0 1 n 1 sub { /x exch def
               board x get y get 1 eq {
                       x c mul y c mul m
                       c 0 l 0 c l c neg 0 l
                       closepath fill
               } if
       } for } for

} def

/r1n { dup 0 lt { n add } if dup n ge { n sub } if } def /neighbors { /y exch def /x exch def 0

       y 1 sub 1 y 1 add { r1n /y1 exch def
       x 1 sub 1 x 1 add { r1n /x1 exch def
               board x1 get y1 get add
       } for } for
       board x get y get sub

} def

/iter {

       /board
       [0 1 n 1 sub { /x exch def
       [0 1 n 1 sub { /y exch def
               x y neighbors
               board x get y get
               0 eq    { 3 eq {1}{0} ifelse }
                       { dup 2 eq exch 3 eq or {1}{0} ifelse } ifelse
       } for ]
       } for ] def

} def

/n 200 def /initprob .15 def /c size n div def /board [ n {[ n { rand1 initprob le {1}{0} ifelse } repeat]} repeat ] def

1000 { drawboard showpage iter } repeat %%EOF</lang>

Prolog

<lang Prolog> %----------------------------------------------------------------------% % GAME OF LIFE  % %  % % Adapt the prediacte grid_size according to the grid size of the  % % start pic.  % % Modify the number of generations.  % % Run PROLOG and type '[gol].' to compile the source file.  % % Create a subfolder <subfolder> where your gol.pl resides and place  % % your initial PBM '<filename>0.0000.pbm' inside <subfolder>.  % % You need to adjust the number of zeros after <filename>. The  % % sequence of zeros after '0.' must be as long as the number of  % % generations. This is important to obtain a propper animation.  % % (Maybe someone knows a better solution for this)  % % Start PROLOG and run  % %  % % cellular('./<subloder>/<filename>').  % %  % % Inside <subfolder> run the following shell command  % %  % % convert -delay 25 -loop 0 <filename>* <filename>.gif  % %  % %----------------------------------------------------------------------%

%----------------------------------------------------------------------% % Special thanks to René Thiemann improving the runtime performance.  % %----------------------------------------------------------------------%

% Size of the 2D grid grid_size(300). % Number of generations generations(1000).

%----------------------------------------------------------------------% % Main procedure: generate n generations of life and store each file.  % % cellular( +File path )  % %----------------------------------------------------------------------% cellular(I) :- grid_size(GS), string_concat(I,'0.0000.pbm',I1), read_pbm(I1,GS,M), cellular_(I,M,GS,1), !.

cellular_(I,M,GS,N) :- N1 is N+1, format(atom(N0),'~4d',N), string_concat(I,N0,I1), string_concat(I1,'.pbm',I2), step(M,M1), write_pbm(M1,GS,I2), !, cellular_(I,M1,GS,N1). cellular_(_,_,_,GE) :- generations(GE),!.

%----------------------------------------------------------------------% % Apply the Game Of Life rule set to every cell.  % % step( +OldMatrix, +NewMatrix )  % %  % % ss | s | ... | s ss ... step_ss  % % ----+---+-----+--- s ... step_s  % % ii | i | ... | i ii ... step_ii  % % ----+---+-----+--- i ... step_i  % %  : | : |  : | : ee ... step_ee  % % ----+---+-----+--- e ... step_e  % % ii | i | ... | i  % % ----+---+-----+---  % % ee | e | ... | e  % %  % %----------------------------------------------------------------------% step([R1,R2|M],[H|T]) :- step_ss(R1,R2,H), !, step_([R1,R2|M],T).

step_([R1,R2,R3|M],[H|T]) :- step_ii(R1,R2,R3,H), step_([R2,R3|M],T), !. step_([R1,R2],[H]) :- step_ee(R1,R2,H).

% Start case step_ss([A1,A2|R1],[B1,B2|R2],[H|T]) :- rule([0,0,0],[0,A1,A2],[0,B1,B2],H), step_s([A1,A2|R1],[B1,B2|R2],T). step_s([A1,A2,A3|R1],[B1,B2,B3|R2],[H|T]) :- rule([0,0,0],[A1,A2,A3],[B1,B2,B3],H), step_s([A2,A3|R1],[B2,B3|R2],T). step_s([A1,A2],[B1,B2],[H]) :- rule([0,0,0],[A1,A2,0],[B1,B2,0],H).

% Immediate case step_ii([A1,A2|R1],[B1,B2|R2],[C1,C2|R3],[H|T]) :- rule([0,A1,A2],[0,B1,B2],[0,C1,C2],H), step_i([A1,A2|R1],[B1,B2|R2],[C1,C2|R3],T). step_i([A1,A2,A3|R1],[B1,B2,B3|R2],[C1,C2,C3|R3],[H|T]) :- rule([A1,A2,A3],[B1,B2,B3],[C1,C2,C3],H), step_i([A2,A3|R1],[B2,B3|R2],[C2,C3|R3],T). step_i([A1,A2],[B1,B2],[C1,C2],[H]) :- rule([A1,A2,0],[B1,B2,0],[C1,C2,0],H).

% End case step_ee([A1,A2|R1],[B1,B2|R2],[H|T]) :- rule([0,A1,A2],[0,B1,B2],[0,0,0],H), step_e([A1,A2|R1],[B1,B2|R2],T). step_e([A1,A2,A3|R1],[B1,B2,B3|R2],[H|T]) :- rule([A1,A2,A3],[B1,B2,B3],[0,0,0],H), step_e([A2,A3|R1],[B2,B3|R2],T). step_e([A1,A2],[B1,B2],[H]) :- rule([A1,A2,0],[B1,B2,0],[0,0,0],H).

%----------------------------------------------------------------------% % o Any dead cell with exactly three live neighbours becomes a live  % % cell, as if by reproduction.  % % o Any other dead cell remains dead.  % % o Any live cell with fewer than two live neighbours dies, as if  % % caused by under-population.  % % o Any live cell with two or three live neighbours lives on to the  % % next generation.  % % o Any live cell with more than three live neighbours dies, as if by  % % overcrowding.  % %  % % [Source: Wikipedia]  % %----------------------------------------------------------------------% rule([A,B,C],[D,0,F],[G,H,I],1) :- A+B+C+D+F+G+H+I =:= 3. rule([_,_,_],[_,0,_],[_,_,_],0). rule([A,B,C],[D,1,F],[G,H,I],0) :- A+B+C+D+F+G+H+I < 2. rule([A,B,C],[D,1,F],[G,H,I],1) :- A+B+C+D+F+G+H+I =:= 2. rule([A,B,C],[D,1,F],[G,H,I],1) :- A+B+C+D+F+G+H+I =:= 3. rule([A,B,C],[D,1,F],[G,H,I],0) :- A+B+C+D+F+G+H+I > 3.

%----------------------------------------------------------------------% % Read a 2bit Protable Bitmap into a GS x GS 2-dimensional list.  % % read_pbm( +File path, +Grid size, -List 2D )  % %----------------------------------------------------------------------% read_pbm(F,GS,M) :- open(F,read,S), skip(S,10), skip(S,10), get(S,C), read_file(S,C,L), nest(L,GS,M), close(S).

read_file(S,C,[CHR|T]) :- CHR is C-48, get(S,NC), read_file(S,NC,T). read_file(_,-1,[]) :- !.

%----------------------------------------------------------------------% % Morph simple list into a 2-dimensional one with size GS x GS  % % nest( ?List simple, ?Grid size, ?2D list )  % %----------------------------------------------------------------------% nest(L,GS,[H|T]) :- length(H,GS), append(H,S,L), nest(S,GS,T). nest(L,GS,[L]) :- length(L,S), S =< GS, !.

%----------------------------------------------------------------------% % Write a GS x GS 2-dimensional list into a 2bit Protable Bitmap.  % % write_pbm( +List 2D, +Grid size, +File path )  % %----------------------------------------------------------------------% write_pbm(L,GS,F) :- open(F,write,S), write(S,'P1'), nl(S), write(S,GS), put(S,' '), write(S,GS), nl(S), write_file(S,L), close(S).

write_file(S,[H|T]) :- write_line(S,H), nl(S), write_file(S,T). write_file(_,[]) :- !.

write_line(S,[H|T]) :- write(S,H), put(S,' '), write_line(S,T). write_line(_,[]) :- !. </lang>

Sample output:


Processing

Inspired by Daniel Shiffman's book The Nature of Code (http://natureofcode.com)

<lang java>boolean play = true; int cellSize = 10; int cols, rows; int lastCell = 0; int sample = 10; // Game of life board int[][] grid;

void setup() {

 size(800, 500);
 noStroke();
 // Calculate cols, rows and init array
 cols = width/cellSize;
 rows = height/cellSize;
 grid = new int[cols][rows];
 init(-1); // randomized start
 println("Press 'space' to start/stop");
 println("'e' to clear all cells");
 println("'b' demonstrate 'blinker'");
 println("'g' demonstrate glider");
 println("'r' to randomize grid");
 println("'+'  and '-' to change speed");

}

void draw() {

 background(0);
 for ( int i = 0; i < cols; i++) {
   for ( int j = 0; j < rows; j++) {
     if ((grid[i][j] == 1)) fill(255);
     else fill(0); 
     rect(i*cellSize, j*cellSize, cellSize, cellSize);
   }
 }
 if (play && frameCount%sample==0 && !mousePressed) {
   generate();
 }

}

void generate() {

 int[][] nextGrid = new int[cols][rows];
 for (int x = 0; x < cols; x++) {
   for (int y = 0; y < rows; y++) {
     int ngbs = countNgbs(x, y);
     // the classic Conway rules
     if      ((grid[x][y] == 1) && (ngbs <  2)) nextGrid[x][y] = 0; // solitude
     else if ((grid[x][y] == 1) && (ngbs >  3)) nextGrid[x][y] = 0; // crowded 
     else if ((grid[x][y] == 0) && (ngbs == 3)) nextGrid[x][y] = 1; // cell born
     else                              nextGrid[x][y] = grid[x][y]; // keep
   }
 }
 grid = nextGrid;

}

int countNgbs(int x, int y) {

 int ngbCount = 0;
 for (int i = -1; i <= 1; i++) {
   for (int j = -1; j <= 1; j++) {
     // 'united' borders
     ngbCount += grid[(x+i+cols)%cols][(y+j+rows)%rows];
   }
 }
 // cell taken out of count
 ngbCount -= grid[x][y];
 return ngbCount;

}

void init(int option) {

 int state;
 for (int x = 0; x < cols; x++) {
   for (int y = 0; y < rows; y++) {
     if (option == -1) {
       state = int(random(2));
     } else {
       state = option;
     }
     grid[x][y] = state;
   }
 }

}

void keyReleased() {

 if (key == 'r') {
   init(-1); // randomize grid
 }
 if (key == 'e') {
   init(0); // empty grid
 }
 if (key == 'g') {
   int glider[][] = {
     {0, 1, 0}, 
     {0, 0, 1}, 
     {1, 1, 1}};
   setNine(10, 10, glider);
 }
 if (key == 'b') {
   int blinker[][] = {
     {0, 1, 0}, 
     {0, 1, 0}, 
     {0, 1, 0}};
   setNine(10, 10, blinker);
 }
 if (key == ' ') {
   play = !play;
 }
 if (key == '+' || key == '=') {
   sample=max(sample-1, 1);
 }
 if (key == '-') {
   sample++;
 }

}

void setNine(int x, int y, int nine[][]) {

 for (int i = 0; i <= 2; i++) {
   for (int j = 0; j <= 2; j++) {
     grid[(x+i+cols)%cols][(y+j+rows)%rows] = nine[i][j];
   }
 }

}

void mousePressed() {

 paint();

} void mouseDragged() {

 paint();

}

void paint() {

 int x = mouseX/cellSize;
 int y = mouseY/cellSize;
 int p = y*cols + x;
 if (p!=lastCell) {
   lastCell=p;
   int states[] = {1, 0};
   grid[x][y] = states[grid[x][y]]; // invert
 }

}</lang>

Processing Python mode

<lang python>cell_size = 10 sample = 10 play = False # simulation is running last_cell = 0

def setup():

   global grid, next_grid, rows, cols
   size(800, 500)
   rows = height / cell_size
   cols = width / cell_size
   grid = empty_grid()
   next_grid = empty_grid()
   randomize_grid()
   println("Press 'space' to start/stop")
   println("'e' to clear all cells")
   println("'b' demonstrate 'blinker'")
   println("'g' demonstrate glider")
   println("'r' to randomize grid")
   println("'+' and '-' to change speed")

def draw():

   background(0)
   for i in range(cols):
       x = i * cell_size
       for j in range(rows):
           y = j * cell_size
           current_state = grid[i][j]
           fill(255)
           noStroke()
           if current_state:
               rect(x, y, cell_size, cell_size)
           if play:
               ngbs_alive = calc_ngbs_alive(i, j)
               result = rule(current_state, ngbs_alive)
               next_grid[i][j] = result
               
   if play and frameCount % sample == 0 and not mousePressed:
       step()

def rule(current, ngbs):

   """ classic Conway's Game of Life rule """
   if ngbs < 2 or ngbs > 3:
       return 0  # dies / dead
   elif ngbs == 3:
       return 1  # born / alive
   else:
       return current  # stays the same (ngbs == 2)

def calc_ngbs_alive(i, j):

   NEIGHBOURS = ((-1, 00), (01, 00),  # a tuple describing the neighbourhood of a cell
                 (-1, -1), (00, -1),
                 (01, -1), (-1, 01),
                 (00, 01), (01, 01))
   alive = 0
   for iv, jv in NEIGHBOURS:
       alive += grid[(i + iv) % cols][(j + jv) % rows]
   return alive

def empty_grid():

   grid = []
   for _ in range(cols):
       grid.append([0] * rows)
   return grid

def randomize_grid():

   from random import choice
   for i in range(cols):
       for j in range(rows):
           grid[i][j] = choice((0, 1))

def step():

   global grid, next_grid
   grid = next_grid
   next_grid = empty_grid()

def keyReleased():

   global grid, play, sample
   if key == "e":
       grid = empty_grid()
   if key == "r":
       randomize_grid()
   if key == "g":
        grid[10][10:13] = [0, 1, 0]       
        grid[11][10:13] = [0, 0, 1]       
        grid[12][10:13] = [1, 1, 1]       
   if key == "b":
        grid[10][10:13] = [0, 1, 0]       
        grid[11][10:13] = [0, 1, 0]       
        grid[12][10:13] = [0, 1, 0]               
   if key == " ":
       play = not play 
   if  str(key) in '+=':
       sample = max(sample - 1, 1);
   if key == '-':
       sample += 1

def mousePressed():

   paint()
   

def mouseDragged():

   paint()

def paint():

   global last_cell
   i, j = mouseX // cell_size, mouseY // cell_size
   p = j * cols + i
   if p != last_cell:
       last_cell = p
       grid[i][j] = (1, 0)[grid[i][j]]</lang>

Python

Using defaultdict

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.

<lang python>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
    1. Start States
  1. blinker

u = universe = defaultdict(int) u[(1,0)], u[(1,1)], u[(1,2)] = 1,1,1

    1. toad
  1. u = universe = defaultdict(int)
  2. u[(5,5)], u[(5,6)], u[(5,7)] = 1,1,1
  3. u[(6,6)], u[(6,7)], u[(6,8)] = 1,1,1
    1. glider
  1. u = universe = defaultdict(int)
  2. maxgenerations = 16
  3. u[(5,5)], u[(5,6)], u[(5,7)] = 1,1,1
  4. u[(6,5)] = 1
  5. u[(7,6)] = 1
    1. random start
  1. universe = defaultdict(int,
  2. # array of random start values
  3. ( ((row, col), random.choice((0,1)))
  4. for col in range(cellcount[0])
  5. for row in range(cellcount[1])
  6. ) ) # 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</lang>
Output:

(sample)

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

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

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

Boardless approach

A version using the boardless approach. A world is represented as a set of (x, y) coordinates of all the alive cells.

<lang python>from collections import Counter

def life(world, N):

   "Play Conway's game of life for N generations from initial world."
   for g in range(N+1):
       display(world, g)
       counts = Counter(n for c in world for n in offset(neighboring_cells, c))
       world = {c for c in counts 
               if counts[c] == 3 or (counts[c] == 2 and c in world)}

neighboring_cells = [(-1, -1), (-1, 0), (-1, 1),

                    ( 0, -1),          ( 0, 1), 
                    ( 1, -1), ( 1, 0), ( 1, 1)]

def offset(cells, delta):

   "Slide/offset all the cells by delta, a (dx, dy) vector."
   (dx, dy) = delta
   return {(x+dx, y+dy) for (x, y) in cells}

def display(world, g):

   "Display the world as a grid of characters."
   print('          GENERATION {}:'.format(g))
   Xs, Ys = zip(*world)
   Xrange = range(min(Xs), max(Xs)+1)
   for y in range(min(Ys), max(Ys)+1):
       print(.join('#' if (x, y) in world else '.'
                     for x in Xrange))

blinker = {(1, 0), (1, 1), (1, 2)} block = {(0, 0), (1, 1), (0, 1), (1, 0)} toad = {(1, 2), (0, 1), (0, 0), (0, 2), (1, 3), (1, 1)} glider = {(0, 1), (1, 0), (0, 0), (0, 2), (2, 1)} world = (block | offset(blinker, (5, 2)) | offset(glider, (15, 5)) | offset(toad, (25, 5))

          | {(18, 2), (19, 2), (20, 2), (21, 2)} | offset(block, (35, 7)))


life(world, 5)</lang>

Output:
          GENERATION 0:
##...................................
##...................................
......#...........####...............
......#..............................
......#..............................
...............##........#...........
...............#.#.......##..........
...............#.........##........##
..........................#........##
          GENERATION 1:
##...................................
##.................##................
...................##................
.....###...........##................
.....................................
...............##........##..........
..............##........#............
................#..........#.......##
.........................##........##
          GENERATION 2:
##...................................
##.................##................
......#...........#..#...............
......#............##................
......#..............................
..............###........#...........
..............#..........##..........
...............#.........##........##
..........................#........##
          GENERATION 3:
##...................................
##.................##................
..................#..#...............
.....###...........##................
...............#.....................
..............##.........##..........
..............#.#.......#............
...........................#.......##
.........................##........##
          GENERATION 4:
##...................................
##.................##................
......#...........#..#...............
......#............##................
......#.......##.....................
..............#.#........#...........
..............#..........##..........
.........................##........##
..........................#........##
          GENERATION 5:
##...................................
##.................##................
..................#..#...............
.....###...........##................
..............##.....................
.............##..........##..........
...............#........#............
...........................#.......##
.........................##........##

Using an array to define the world

<lang python>import numpy as np from pandas import DataFrame import matplotlib.pyplot as plt

  1. import time

def conway_life(len=10, wid=10, gen=5):

   curr_gen = DataFrame(np.random.randint(0, 2, (len+2, wid+2)),
                        index = range(len+2), 
                        columns = range(wid+2))
   curr_gen[0] = 0
   curr_gen[wid+1] = 0
   curr_gen[0: 1] = 0
   curr_gen[len+1: len+2] = 0    
   
   for i in range(gen):
       
       fig, ax = plt.subplots()
       draw = curr_gen[1:len+1].drop([0, wid+1], axis=1)
       # 画图
       
       image = draw
       ax.imshow(image, cmap=plt.cm.cool, interpolation='nearest')
       ax.set_title("Conway's game of life.")
       
       # Move left and bottom spines outward by 10 points
       ax.spines['left'].set_position(('outward', 10))
       ax.spines['bottom'].set_position(('outward', 10))
       # Hide the right and top spines
       ax.spines['right'].set_visible(False)
       ax.spines['top'].set_visible(False)
       # Only show ticks on the left and bottom spines
       ax.yaxis.set_ticks_position('left')
       ax.xaxis.set_ticks_position('bottom')
       plt.show()
       # time.sleep(1)         
       
       
       # 初始化空表
       next_gen = DataFrame(np.random.randint(0, 1, (len+2, wid+2)),
                            index = range(len+2), 
                            columns = range(wid+2))
       
       
       # 生成下一代
       for x in range(1, wid+1):
           for y in range(1, len+1):
               env = (curr_gen[x-1][y-1] + curr_gen[x][y-1] + 
                      curr_gen[x+1][y-1]+ curr_gen[x-1][y] + 
                      curr_gen[x+1][y] + curr_gen[x-1][y+1] + 
                      curr_gen[x][y+1] + curr_gen[x+1][y+1])
           
               if (not curr_gen[x][y] and env == 3):
                   next_gen[x][y] = 1
               if (curr_gen[x][y] and env in (2, 3)):
                   next_gen[x][y] = 1
               
       curr_gen = next_gen 
        

conway_life()</lang>

R

<lang r># Generates a new board - either a random one, sample blinker or gliders, or user specified. gen.board <- function(type="random", nrow=3, ncol=3, seeds=NULL) {

   if(type=="random")
   {
      return(matrix(runif(nrow*ncol) > 0.5, nrow=nrow, ncol=ncol))
   } else if(type=="blinker")
   {
      seeds <- list(c(2,1),c(2,2),c(2,3))
   } else if(type=="glider")
   {
      seeds <- list(c(1,2),c(2,3),c(3,1), c(3,2), c(3,3))
   }
   board <- matrix(FALSE, nrow=nrow, ncol=ncol) 
   for(k in seq_along(seeds))
   {
     board[seedsk[1],seedsk[2]] <- TRUE
   }
   board

}

  1. Returns the number of living neighbours to a location

count.neighbours <- function(x,i,j) {

  sum(x[max(1,i-1):min(nrow(x),i+1),max(1,j-1):min(ncol(x),j+1)]) - x[i,j]

}

  1. Implements the rulebase

determine.new.state <- function(board, i, j) {

  N <- count.neighbours(board,i,j)
  (N == 3 || (N ==2 && board[i,j]))

}

  1. Generates the next interation of the board from the existing one

evolve <- function(board) {

  newboard <- board
  for(i in seq_len(nrow(board)))
  {
     for(j in seq_len(ncol(board)))
     {
        newboard[i,j] <- determine.new.state(board,i,j)         
     }   
  }
  newboard

}

  1. Plays the game. By default, the board is shown in a plot window, though output to the console if possible.

game.of.life <- function(board, nsteps=50, timebetweensteps=0.25, graphicaloutput=TRUE) {

  if(!require(lattice)) stop("lattice package could not be loaded")   
  nr <- nrow(board)
  
  for(i in seq_len(nsteps))
  {
     if(graphicaloutput) 
     {
        print(levelplot(t(board[nr:1,]), colorkey=FALSE)) 
     } else print(board)  
      
     Sys.sleep(timebetweensteps)
     
     newboard <- evolve(board)
     
     if(all(newboard==board))
     {
        message("board is static")
        break
     } else if(sum(newboard) < 1)
     {
        message("everything is dead")
        break
     } else board <- newboard
  }   
  invisible(board)

}

  1. Example usage

game.of.life(gen.board("blinker")) game.of.life(gen.board("glider", 18, 20)) game.of.life(gen.board(, 50, 50))</lang>

Racket

<lang racket>

  1. lang racket

(require 2htdp/image 2htdp/universe)

Grid object

(define (make-empty-grid m n)

 (build-vector m (lambda (y) (make-vector n 0))))

(define rows vector-length)

(define (cols grid)

 (vector-length (vector-ref grid 0)))

(define (make-grid m n living-cells)

 (let loop ([grid (make-empty-grid m n)]
            [cells living-cells])
   (if (empty? cells)
       grid
       (loop (2d-set! grid (caar cells) (cadar cells) 1) (cdr cells)))))

(define (2d-ref grid i j)

 (cond [(< i 0) 0]
       [(< j 0) 0]
       [(>= i (rows grid)) 0]
       [(>= j (cols grid)) 0]
       [else (vector-ref (vector-ref grid i) j)]))

(define (2d-refs grid indices)

 (map (lambda (ind) (2d-ref grid (car ind) (cadr ind))) indices))

(define (2d-set! grid i j val)

 (vector-set! (vector-ref grid i) j val)
 grid)
cartesian product of 2 lists

(define (cart l1 l2)

 (if (empty? l1)
     '()
     (append (let loop ([n (car l1)] [l l2])
               (if (empty? l) '() (cons (list n (car l)) (loop n (cdr l)))))
             (cart (cdr l1) l2))))
Count living cells in the neighbourhood

(define (n-count grid i j)

 (- (apply + (2d-refs grid (cart (list (- i 1) i (+ i 1))
                                 (list (- j 1) j (+ j 1)))))
    (2d-ref grid i j)))
Rules and updates of the grid
rules are stored in a 2d array
r_i,j = new state of a cell
in state i with j neighboors

(define conway-rules

 (list->vector (list (list->vector '(0 0 0 1 0 0 0 0 0))
                     (list->vector '(0 0 1 1 0 0 0 0 0)))))

(define (next-state rules grid i j)

 (let ([current (2d-ref grid i j)]
       [N (n-count grid i j)])
   (2d-ref rules current N)))

(define (next-grid rules grid)

 (let ([new-grid (make-empty-grid (rows grid) (cols grid))])
   (let loop ([i 0] [j 0])
     (if (>= i (rows grid))
         new-grid
         (if (>= j (cols grid))
             (loop (+ i 1) 0)
             (begin (2d-set! new-grid i j (next-state rules grid i j))
                    (loop i (+ j 1))))))))

(define (next-grid! rules grid)

 (let ([new-grid (next-grid rules grid)])
   (let loop ((i 0))
     (if (< i (rows grid))
       (begin (vector-set! grid i (vector-ref new-grid i))
              (loop (+ i 1)))
       grid))))
Image / Animation

(define (grid->image grid)

 (let ([m (rows grid)] [n (cols grid)] [size 5])
   (let loop ([img (rectangle (* m size) (* n size) "solid" "white")]
              [i 0] [j 0])
     (if (>= i (rows grid))
         img
         (if (>= j (cols grid))
             (loop img (+ i 1) 0)
             (if (= (2d-ref grid i j) 1)
                 (loop (underlay/xy img (* i (+ 1 size)) (* j (+ 1 size))
                                    (square (- size 2) "solid" "black"))
                       i (+ j 1))
                 (loop img i (+ j 1))))))))


(define (game-of-life grid refresh_time)

 (animate (lambda (n)
            (if (= (modulo n refresh_time) 0)
                (grid->image (next-grid! conway-rules grid))
                (grid->image grid)))))
Examples

(define (blinker)

 (make-grid 3 3 '((0 1) (1 1) (2 1))))

(define (thunder)

 (make-grid 70 50 '((30 19) (30 20) (30 21) (29 17) (30 17) (31 17))))

(define (cross)

 (let loop ([i 0] [l '()])
   (if (>= i 80)
       (make-grid 80 80 l)
       (loop (+ i 1) (cons (list i i) (cons (list (- 79 i) i) l))))))
To run examples
(game-of-life (blinker) 30)
(game-of-life (thunder) 2)
(game-of-life (cross) 2)

</lang>

Output for an 80x80 cross:

Raku

(formerly Perl 6)

<lang perl6>class Automaton {

   subset World of Str where {
       .lines>>.chars.unique == 1 and m/^^<[.#\n]>+$$/
   }
   has Int ($.width, $.height);
   has @.a;
   multi method new (World $s) {
       self.new:
           :width(.pick.chars), :height(.elems),
           :a( .map: { [ .comb ] } )
               given $s.lines.cache;
   }
   method gist { join "\n", map { .join }, @!a }
   method C (Int $r, Int $c --> Bool) {
       @!a[$r % $!height][$c % $!width] eq '#';
   }
   method N (Int $r, Int $c --> Int) {
       +grep ?*, map { self.C: |@$_ },
           [ $r - 1, $c - 1], [ $r - 1, $c ], [ $r - 1, $c + 1],
           [ $r    , $c - 1],                 [ $r    , $c + 1],
           [ $r + 1, $c - 1], [ $r + 1, $c ], [ $r + 1, $c + 1];
   }
   method succ {
       self.new: :$!width, :$!height,
           :a(
               gather for ^$.height -> $r {
                   take [
                       gather for ^$.width -> $c {
                           take
                           (self.C($r, $c) == 1 && self.N($r, $c) == 2|3)
                               || (self.C($r, $c) == 0 && self.N($r, $c) == 3)
                           ?? '#' !! '.'
                       }
                   ]
               }
           )
   }

}

my Automaton $glider .= new: q:to/EOF/;

   ............
   ............
   ............
   .......###..
   .###...#....
   ........#...
   ............
   EOF


for ^10 {

   say $glider++;
   say '--';

}</lang>

Red

<lang Rebol>Red [

   Purpose: "Conway's Game of Life"
   Author: "Joe Smith"

]

neigh: [[0 1] [0 -1] [1 0] [-1 0] [1 1] [1 -1] [-1 1] [-1 -1]] conway: function [petri] [ new-petri: copy/deep petri repeat row length? petri [ repeat col length? petri [ live-neigh: 0 foreach cell neigh [ try [ if petri/(:row + cell/1)/(:col + cell/2) = 1 [live-neigh: live-neigh + 1] ] ] switch petri/:row/:col [ 1 [if any [live-neigh < 2 live-neigh > 3] [new-petri/:row/:col: 0] ] 0 [if live-neigh = 3 [new-petri/:row/:col: 1]] ]]] clear insert petri new-petri ]

  • 3-3: [

[0 1 0] [0 1 0] [0 1 0] ]

  • 8-8: [

[0 0 1 0 0 0 0 0] [0 0 0 1 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] ]

display: function [table] [ foreach row table [ print replace/all (replace/all to-string row "0" "_") "1" "#" ] print "" ]

loop 5 [ display *3-3 conway *3-3 ] loop 23 [ display *8-8 conway *8-8 ] </lang>

Output:
 
_#_
_#_
_#_

___
###
___

_#_
_#_
_#_

___
###
___

_#_
_#_
_#_

__#_____
___#____
_###____
________
________
________
________
________

________
_#_#____
__##____
__#_____
________
________
________
________

________
___#____
_#_#____
__##____
________
________
________
________

________
__#_____
___##___
__##____
________
________
________
________

________
___#____
____#___
__###___
________
________
________
________

________
________
__#_#___
___##___
___#____
________
________
________

________
________
____#___
__#_#___
___##___
________
________
________

________
________
___#____
____##__
___##___
________
________
________

________
________
____#___
_____#__
___###__
________
________
________

________
________
________
___#_#__
____##__
____#___
________
________

________
________
________
_____#__
___#_#__
____##__
________
________

________
________
________
____#___
_____##_
____##__
________
________

________
________
________
_____#__
______#_
____###_
________
________

________
________
________
________
____#_#_
_____##_
_____#__
________

________
________
________
________
______#_
____#_#_
_____##_
________

________
________
________
________
_____#__
______##
_____##_
________

________
________
________
________
______#_
_______#
_____###
________

________
________
________
________
________
_____#_#
______##
______#_

________
________
________
________
________
_______#
_____#_#
______##

________
________
________
________
________
______#_
_______#
______##

________
________
________
________
________
________
_______#
______##

________
________
________
________
________
________
______##
______##

________
________
________
________
________
________
______##
______##

Retro

<lang Retro>:w/l [ $. eq? [ #0 ] [ #1 ] choose , ] s:for-each ;

'World d:create

 '.................... w/l
 '.................... w/l
 '.................... w/l
 '..ooo............... w/l
 '....o............... w/l
 '...o................ w/l
 '.................... w/l
 '.................... w/l
 '.................... w/l
 '.................... w/l
 '.................... w/l
 '....ooo............. w/l
 '.................... w/l
 '.................... w/l
 '.................... w/l
 '........ooo......... w/l
 '.......ooo.......... w/l
 '.................... w/l
 '.................... w/l
 '.................... w/l

'Next d:create

 #20 #20 * allot

{{

 'Surrounding var
 :get (rc-v)
   dup-pair [ #0 #19 n:between? 

] bi@ and

   [ &World + [ #20 * ] dip + fetch ] [ drop-pair #0 ] choose ;
 :neighbor?  (rc-) get &Surrounding v:inc-by ;
 :NW (rc-rc) dup-pair [ n:dec ] bi@       neighbor? ;
 :NN (rc-rc) dup-pair [ n:dec ] dip       neighbor? ;
 :NE (rc-rc) dup-pair [ n:dec ] dip n:inc neighbor? ;  
 :WW (rc-rc) dup-pair   n:dec             neighbor? ;
 :EE (rc-rc) dup-pair   n:inc             neighbor? ;
 :SW (rc-rc) dup-pair [ n:inc ] dip n:dec neighbor? ;
 :SS (rc-rc) dup-pair [ n:inc ] dip       neighbor? ;
 :SE (rc-rc) dup-pair [ n:inc ] bi@       neighbor? ;
 :count (rc-rcn)
   #0 !Surrounding NW NN NE
                   WW    EE
                   SW SS SE @Surrounding ;
 :alive (rc-n)
   count #2 #3 n:between? [ #1 ] if; #0 ;
 :dead (rc-n)
   count #3 eq? [ #1 ] if; #0 ;
 :new-state (rc-n)
   dup-pair get #1 eq? &alive &dead choose ;
 :set   (nrc-)  &Next + [ #20 * ] dip + store ;
 :cols (r-)
   #20 [ I over swap new-state rot rot set ] times<with-index> drop ;
 :output (n-) n:-zero? [ $o ] [ $. ] choose c:put sp ;

---reveal---

 :display (-)
   nl &World #20 [ #20 [ fetch-next output ] times nl ] times drop ;
 :gen (-)
   #20 [ I cols ] times<with-index> &Next &World #20 #20 * copy ;

}}

Divide

  1. 12 gens</lang>

REXX

version 1

This version has been trimmed down from the original REXX program, otherwise the size of the program (with all its options and optional formatting)
would probably be on the large side for general viewing,   and maybe a wee bit complex to demonstrate how to program for this task. <lang rexx>/*REXX program runs and displays the Conway's game of life, it stops after N repeats. */ signal on halt /*handle a cell growth interruptus. */ parse arg peeps '(' rows cols empty life! clearScreen repeats generations .

      rows =        p(rows               3)     /*the maximum number of cell  rows.    */
      cols =        p(cols               3)     /* "     "       "    "   "  columns.  */
       emp = pickChar(empty        'blank')     /*an empty cell character  (glyph).    */
  clearScr =        p(clearScreen        0)     /* "1"   indicates to clear the screen.*/
     life! = pickChar(life!            '☼')     /*the gylph kinda looks like an amoeba.*/
      reps =        p(repeats            2)     /*stop pgm  if there are  two  repeats.*/

generations = p(generations 100) /*the number of generations allowed. */ sw= max(linesize() - 1, cols) /*usable screen width for the display. */

  1. reps= 0; $.= emp /*the universe is new, ··· and barren.*/

gens=abs(generations) /*used for a programming convenience.*/ x= space(peeps); upper x /*elide superfluous spaces; uppercase. */ if x== then x= "BLINKER" /*if nothing specified, use BLINKER. */ if x=='BLINKER' then x= "2,1 2,2 2,3" if x=='OCTAGON' then x= "1,5 1,6 2,4 2,7 3,3 3,8 4,2 4,9 5,2 5,9 6,3 6,8 7,4 7,7 8,5 8,6" call assign. /*assign the initial state of all cells*/ call showCells /*show the initial state of the cells.*/

    do life=1  for gens;      call assign@      /*construct  next  generation of cells.*/
    if generations>0 | life==gens  then call showCells    /*should cells be displayed? */
    end   /*life*/                              /* [↑]  cell colony grows, lives, dies.*/

exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ showCells: if clearScr then 'CLS' /* ◄─── change 'command' for your OS.*/

          call showRows                         /*show the rows in the proper order.   */
          say right(copies('▒', sw)  life, sw)  /*show a fence between the generations.*/
          if _==  then exit                   /*if there's no life, then stop the run*/
          if !._    then #reps= #reps + 1       /*we detected a repeated cell pattern. */
          !._= 1                                /*existence  state and compare  later. */
          if reps\==0 & #reps<=reps then return /*so far, so good,   regarding repeats.*/
          say
          say center('"Life" repeated itself' reps "times, simulation has ended.",sw,'▒')
          exit                                  /*stick a fork in it,  we're all done. */

/*───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────*/ $: parse arg _row,_col; return $._row._col==life! assign$: do r=1 for rows; do c=1 for cols; $.r.c= @.r.c; end; end; return assign.: do while x\==; parse var x r "," c x; $.r.c=life!; rows=max(rows,r); cols=max(cols,c); end; life=0; !.=0; return assign?:  ?=$.r.c; n=neighbors(); if ?==emp then do;if n==3 then ?=life!; end; else if n<2 | n>3 then ?=emp; @.r.c=?; return assign@: @.=emp; do r=1 for rows; do c=1 for cols; call assign?; end; end; call assign$; return halt: say; say "REXX program (Conway's Life) halted."; say; exit 0 neighbors: return $(r-1,c-1) + $(r-1,c) + $(r-1,c+1) + $(r,c-1) + $(r,c+1) + $(r+1,c-1) + $(r+1,c) + $(r+1,c+1) p: return word(arg(1), 1) pickChar: _=p(arg(1)); arg u .; if u=='BLANK' then _=" "; L=length(_); if L==3 then _=d2c(_); if L==2 then _=x2c(_); return _ showRows: _=; do r=rows by -1 for rows; z=; do c=1 for cols; z=z||$.r.c; end; z=strip(z,'T',emp); say z; _=_||z; end; return</lang> This REXX program makes use of   linesize   REXX program (or BIF)   which is used to determine the screen width (or linesize) of the terminal (console);   not all REXXes have this BIF.

The   LINESIZE.REX   REXX program is included here   ──►   LINESIZE.REX.

output   when using the default inputs:
☼☼☼

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 0
 ☼
 ☼
 ☼
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 1

☼☼☼

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 2
 ☼
 ☼
 ☼
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 3

☼☼☼

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ 4

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒ "Life" repeated itself 2 times, simulation has ended. ▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

version 2

<lang rexx>/* REXX ---------------------------------------------------------------

  • 02.08.2014 Walter Pachl
  • Input is a file containing the initial pattern
  • The compute area is extended when needed
  • (cells are born outside the current compute area)
  • The program stops when the picture shown is the same as the first
  • or equal to the previous one
  • --------------------------------------------------------------------*/

Parse Arg f If f= Then f='bipole' fid=f'.in' oid=f'.txt'; 'erase' oid debug=0 If debug Then Do

 dbg=f'.xxx'; 'erase' dbg
 End

ml=0 l.= Do ri=3 By 1 While lines(fid)>0

 l.ri='  'linein(fid)
 ml=max(ml,length(strip(l.ri,'T')))
 End

ml=ml+2 ri=ri+1 yy=ri If debug Then

 say 'ml='ml 'yy='yy

yb=1 a.=' ' b.=' ' m.= x.= Parse Value 1 ml 1 yy With xmi xma ymi yma Parse Value '999 0' With xmin xmax Parse Value '999 0' With ymin ymax

Do y=1 To yy

 z=yy-y-1
 l=l.z
 Do x=1 By 1 While l<>
   Parse Var l c +1 l
   If c='*' Then Do
     a.x.z='*'
     End
   End
 End

Call show Do step=1 To 60

 Call store
 If step>1 & is_equal(step,1) Then Leave
 If step>1 & is_equal(step,step-1) Then Leave
   Call show_neighbors
 Do y=yma To ymi By -1
   ol=format(x,2)' '
   Do x=xmi To xma
     neighbors=neighbors(x,y)
     If a.x.y=' ' Then Do             /* dead cell                  */
       If neighbors=3 Then Do
         b.x.y='*'                    /*  gets life                 */
         mmo=xmi xma ymi yma
         xmi=min(xmi,x-1)
         xma=max(xma,x+1)
         ymi=min(ymi,y-1)
         yma=max(yma,y+1)
         mm=xmi xma ymi yma
         If mm<>mmo Then
           Call debug mmo '->' mm
         End
       Else                           /* life cell                  */
         b.x.y=' '                    /*  remains dead              */
       End
     Else Do                          /* life cell                  */
       If neighbors=2 |,
          neighbors=3 Then b.x.y='*'  /*  remains life              */
                      Else b.x.y=' '  /*  dies                      */
       End
     End
   End
 /* b. is the new state and is now copied to a.                     */
 Do y=yma To ymi By -1
   Do x=xmi To xma
     a.x.y=b.x.y
     End
   End
 End

/* Output name and all states */ Call lineout oid,' 'f st=' +' /* top and bottom border */ sb=' +' /* top and bottom border */ Do s=1 To step

 st=st||'-'right(s,2,'-')||copies('-',xmax-xmin)'+'
 sb=sb||copies('-',xmax-xmin+3)'+'
 End

Call lineout oid,st /* top border */ Do y=ymin To ymax

 ol=
 Do s=1 To step
   ol=ol '|' substr(m.s.y,xmin,xmax-xmin+1)
   End
 Call lineout oid,ol '|'
 End

Call lineout oid,sb /* bottom border */ Call lineout oid 'type' oid If debug Then Do

 Say 'original area' 1 ml '/' 1 yy
 Say 'compute area ' xmi xma '/' ymi yma
 End

Exit

set: Parse Arg x,y

    a.x.y='*'
    Return

neighbors: Procedure Expose a. debug

 Parse Arg x,y
 neighbors=0
 do xa=x-1 to x+1
   do ya=y-1 to y+1
     If xa<>x | ya<>y then
       If a.xa.ya='*' Then
         neighbors=neighbors+1
     End
   End
 Return neighbors

store: /* store current state (a.) in lines m.step.* */ Do y=yy To 1 By -1

 ol=
 Do x=1 To ml
   z=a.x.y
   ol=ol||z
   End
 x.step.y=ol
 If ol<> then Do
   ymin=min(ymin,y)
   ymax=max(ymax,y)
   p=pos('*',ol)
   q=length(strip(ol,'T'))
   If p>0 Then
     xmin=min(xmin,p)
   xmax=max(xmax,q)
   End
 m.step.y=ol
 Call debug '====>' right(step,2) y ol  xmin xmax
 End

Return

is_equal: /* test ist state a.b is equal to state a.a */

 Parse Arg a,b
 Do y=yy To 1 By -1
   If x.b.y<>x.a.y Then
     Return 0
   End
 Return 1

show: Procedure Expose dbg a. yy ml debug Do y=1 To yy

 ol='>'
 Do x=1 To ml
   ol=ol||a.x.y
   End
 Call debug ol
 End

Return

show_neighbors: Procedure Expose a. xmi xma ymi yma dbg debug

 Do y=yma To ymi By -1
   ol=format(y,2)' '
   Do x=xmi To xma
     ol=ol||neighbors(x,y)
     End
   Call debug ol
   End
 Return

debug:

 If debug Then
   Return lineout(dbg,arg(1))
 Else
   Return</lang>
Output:
 blinker
+--1--+--2--+--3--+
|     |  *  |     |
| *** |  *  | *** |
|     |  *  |     |
+-----+-----+-----+ 
oktagon
*--1-------*--2-------*--3-------*--4-------*--5-------*--6-------*
|    **    |    **    |   *  *   |          |          |    **    |
|   *  *   |   ****   |   *  *   |   *  *   |   ****   |   *  *   |
|  *    *  |  *    *  | ** ** ** |  * ** *  |  * ** *  |  *    *  |
| *      * | **    ** |   *  *   |   *  *   |  **  **  | *      * |
| *      * | **    ** |   *  *   |   *  *   |  **  **  | *      * |
|  *    *  |  *    *  | ** ** ** |  * ** *  |  * ** *  |  *    *  |
|   *  *   |   ****   |   *  *   |   *  *   |   ****   |   *  *   |
|    **    |    **    |   *  *   |          |          |    **    |
*----------*----------*----------*----------*----------*----------*

Ruby

<lang ruby>def game_of_life(name, size, generations, initial_life=nil)

 board = new_board size
 seed board, size, initial_life
 print_board board, name, 0
 reason = generations.times do |gen|
   new = evolve board, size
   print_board new, name, gen+1
   break :all_dead if barren? new, size
   break :static   if board == new
   board = new
 end
 if    reason == :all_dead then puts "no more life."
 elsif reason == :static   then puts "no movement"
 else                           puts "specified lifetime ended"
 end
 puts

end

def new_board(n)

 Array.new(n) {Array.new(n, 0)}

end

def seed(board, n, points=nil)

 if points.nil?
   # randomly seed board
   indices = []
   n.times {|x| n.times {|y| indices << [x,y] }}
   indices.shuffle[0,10].each {|x,y| board[y][x] = 1}
 else
   points.each {|x, y| board[y][x] = 1}
 end

end

def evolve(board, n)

 new = new_board n
 n.times {|i| n.times {|j| new[i][j] = fate board, i, j, n}}
 new

end

def fate(board, i, j, n)

 i1 = [0, i-1].max; i2 = [i+1, n-1].min
 j1 = [0, j-1].max; j2 = [j+1, n-1].min
 sum = 0
 for ii in (i1..i2)
   for jj in (j1..j2)
     sum += board[ii][jj] if not (ii == i and jj == j)
   end
 end
 (sum == 3 or (sum == 2 and board[i][j] == 1)) ? 1 : 0

end

def barren?(board, n)

 n.times {|i| n.times {|j| return false if board[i][j] == 1}}
 true

end

def print_board(m, name, generation)

 puts "#{name}: generation #{generation}"
 m.each {|row| row.each {|val| print "#{val == 1 ? '#' : '.'} "}; puts}

end

game_of_life "blinker", 3, 2, [[1,0],[1,1],[1,2]] game_of_life "glider", 4, 4, [[1,0],[2,1],[0,2],[1,2],[2,2]] game_of_life "random", 5, 10</lang>

Output:
blinker: generation 0
. # . 
. # . 
. # . 
blinker: generation 1
. . . 
# # # 
. . . 
blinker: generation 2
. # . 
. # . 
. # . 
specified lifetime ended

glider: generation 0
. # . . 
. . # . 
# # # . 
. . . . 
glider: generation 1
. . . . 
# . # . 
. # # . 
. # . . 
glider: generation 2
. . . . 
. . # . 
# . # . 
. # # . 
glider: generation 3
. . . . 
. # . . 
. . # # 
. # # . 
glider: generation 4
. . . . 
. . # . 
. . . # 
. # # # 
specified lifetime ended

random: generation 0
. . . # # 
. . . # . 
. . . # . 
# . . . # 
# . # # # 
random: generation 1
. . . # # 
. . # # . 
. . . # # 
. # # . # 
. # . # # 
random: generation 2
. . # # # 
. . # . . 
. # . . # 
. # . . . 
. # . # # 
random: generation 3
. . # # . 
. # # . # 
. # # . . 
# # . # # 
. . # . . 
random: generation 4
. # # # . 
. . . . . 
. . . . # 
# . . # . 
. # # # . 
random: generation 5
. . # . . 
. . # # . 
. . . . . 
. # . # # 
. # # # . 
random: generation 6
. . # # . 
. . # # . 
. . . . # 
. # . # # 
. # . # # 
random: generation 7
. . # # . 
. . # . # 
. . . . # 
. . . . . 
. . . # # 
random: generation 8
. . # # . 
. . # . # 
. . . # . 
. . . # # 
. . . . . 
random: generation 9
. . # # . 
. . # . # 
. . # . . 
. . . # # 
. . . . . 
random: generation 10
. . # # . 
. # # . . 
. . # . # 
. . . # . 
. . . . . 
specified lifetime ended

Class version

The above implementation uses only methods. Below is one that is object-oriented and feels perhaps a bit more Ruby-ish.

<lang ruby>class Game

 def initialize(name, size, generations, initial_life=nil)
   @size = size
   @board = GameBoard.new size, initial_life
   @board.display name, 0
   
   reason = generations.times do |gen|
     new_board = evolve
     new_board.display name, gen+1
     break :all_dead if new_board.barren?
     break :static   if @board == new_board
     @board = new_board
   end
   
   case reason
   when :all_dead  then puts "No more life."
   when :static    then puts "No movement."
   else                 puts "Specified lifetime ended."
   end
   puts
 end
 
 def evolve
   life = @board.each_index.select {|i,j| cell_fate(i,j)}
   GameBoard.new @size, life
 end
 
 def cell_fate(i, j)
   left_right = [0, i-1].max .. [i+1, @size-1].min
   top_bottom = [0, j-1].max .. [j+1, @size-1].min
   sum = 0
   for x in left_right
     for y in top_bottom
       sum += @board[x,y].value if x != i or y != j
     end
   end
   sum == 3 or (sum == 2 and @board[i,j].alive?)
 end

end

class GameBoard

 include Enumerable
 
 def initialize(size, initial_life=nil)
   @size = size
   @board = Array.new(size) {Array.new(size) {Cell.new false}}
   seed_board initial_life
 end
 
 def seed_board(life)
   if life.nil?
     # randomly seed board
     each_index.to_a.sample(10).each {|x,y| @board[y][x].live}
   else
     life.each {|x,y| @board[y][x].live}
   end
 end
 
 def each
   @size.times {|x| @size.times {|y| yield @board[y][x] }}
 end
 
 def each_index
   return to_enum(__method__) unless block_given?
   @size.times {|x| @size.times {|y| yield x,y }}
 end
 
 def [](x, y)
   @board[y][x]
 end
 
 def ==(board)
   self.life == board.life
 end
 
 def barren?
   none? {|cell| cell.alive?}
 end
 
 def life
   each_index.select {|x,y| @board[y][x].alive?}
 end
 
 def display(name, generation)
   puts "#{name}: generation #{generation}"
   puts @board.map {|row| row.map {|cell| cell.alive? ? '#' : '.'}.join(' ')}
 end
 
 def apocalypse
   # utility function to entirely clear the game board
   each {|cell| cell.die}
 end

end

class Cell

 def initialize(alive) @alive = alive  end
 def alive?;           @alive          end
 def value;            @alive ? 1 : 0  end
 def live;             @alive = true   end
 def die;              @alive = false  end

end

Game.new "blinker", 3, 2, [[1,0],[1,1],[1,2]] Game.new "glider", 4, 4, [[1,0],[2,1],[0,2],[1,2],[2,2]] Game.new "random", 5, 10</lang>

Rust

<lang rust> use std::collections::HashMap; use std::collections::HashSet;

type Cell = (i32, i32); type Colony = HashSet<Cell>;

fn print_colony(col: &Colony, width: i32, height: i32) {

   for y in 0..height {
       for x in 0..width {
           print!("{} ",
               if col.contains(&(x, y)) {"O"}
               else {"."}
           );
       }
       println!();
   }

}

fn neighbours(&(x,y): &Cell) -> Vec<Cell> {

   vec![
       (x-1,y-1), (x,y-1), (x+1,y-1),
       (x-1,y),            (x+1,y),
       (x-1,y+1), (x,y+1), (x+1,y+1),
   ]

}

fn neighbour_counts(col: &Colony) -> HashMap<Cell, i32> {

   let mut ncnts = HashMap::new();
   for cell in col.iter().flat_map(neighbours) {
       *ncnts.entry(cell).or_insert(0) += 1;
   }
   ncnts

}

fn generation(col: Colony) -> Colony {

   neighbour_counts(&col)
       .into_iter()
       .filter_map(|(cell, cnt)|
           match (cnt, col.contains(&cell)) {
               (2, true) |
               (3, ..) => Some(cell),
               _ => None
       })
       .collect()

}

fn life(init: Vec<Cell>, iters: i32, width: i32, height: i32) {

   let mut col: Colony = init.into_iter().collect(); 
   for i in 0..iters+1
   {
       println!("({})", &i);
       if i != 0 {
           col = generation(col);
       }
       print_colony(&col, width, height);
   }

}

fn main() {

   let blinker = vec![
       (1,0),
       (1,1),
       (1,2)];
   life(blinker, 3, 3, 3);
   let glider = vec![
               (1,0),
                       (2,1),
       (0,2),  (1,2),  (2,2)];
   life(glider, 20, 8, 8);

} </lang>

Scala

See Conway's Game of Life/Scala, Scala/Spark distributed

Scheme

Works with: Scheme version implementing R6RS (tested with PLT Scheme, Petite Chez Scheme)

<lang Scheme>

An R6RS Scheme implementation of Conway's Game of Life --- assumes
all cells outside the defined grid are dead
if n is outside bounds of list, return 0 else value at n

(define (nth n lst)

 (cond ((> n (length lst)) 0)
       ((< n 1) 0)
       ((= n 1) (car lst))
       (else (nth (- n 1) (cdr lst)))))
return the next state of the supplied universe

(define (next-universe universe)

 ;value at (x, y)
 (define (cell x y)
   (if (list? (nth y universe))
       (nth x (nth y universe))
       0))
 ;sum of the values of the cells surrounding (x, y)
 (define (neighbor-sum x y)
   (+ (cell (- x 1) (- y 1))
      (cell (- x 1) y)
      (cell (- x 1) (+ y 1))
      (cell x (- y 1))
      (cell x (+ y 1))
      (cell (+ x 1) (- y 1))
      (cell (+ x 1) y)
      (cell (+ x 1) (+ y 1))))
 ;next state of the cell at (x, y)
 (define (next-cell x y)
   (let ((cur (cell x y))
         (ns (neighbor-sum x y)))
     (cond ((and (= cur 1)
                 (or (< ns 2) (> ns 3)))
            0)
           ((and (= cur 0) (= ns 3))
            1)
           (else cur))))
 ;next state of row n
 (define (row n out)
   (let ((w (length (car universe))))
     (if (= (length out) w)
         out
         (row n
              (cons (next-cell (- w (length out)) n)
                    out)))))
 ;a range of ints from bot to top
 (define (int-range bot top)
   (if (> bot top) '()
       (cons bot (int-range (+ bot 1) top))))
 (map (lambda (n)
        (row n '()))
      (int-range 1 (length universe))))
represent the universe as a string

(define (universe->string universe)

 (define (prettify row)
   (apply string-append
          (map (lambda (b)
                 (if (= b 1) "#" "-"))
               row)))
 (if (null? universe)
     ""
     (string-append (prettify (car universe))
                    "\n"
                    (universe->string (cdr universe)))))
starting with seed, show reps states of the universe

(define (conway seed reps)

 (when (> reps 0)
   (display (universe->string seed))
   (newline)
   (conway (next-universe seed) (- reps 1))))
--- Example Universes --- ;;
blinker in a 3x3 universe

(conway '((0 1 0)

         (0 1 0)
         (0 1 0)) 5)
glider in an 8x8 universe

(conway '((0 0 1 0 0 0 0 0)

         (0 0 0 1 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)) 30)</lang>
Output:
-#-
-#-
-#-

---
###
---

-#-
-#-
-#-

---
###
---

-#-
-#-
-#-

--#-----
---#----
-###----
--------
--------
--------
--------
--------

--------
-#-#----
--##----
--#-----
--------
--------
--------
--------

--------
---#----
-#-#----
--##----
--------
--------
--------
--------

--------
--#-----
---##---
--##----
--------
--------
--------
--------

--------
---#----
----#---
--###---
--------
--------
--------
--------

--------
--------
--#-#---
---##---
---#----
--------
--------
--------

--------
--------
----#---
--#-#---
---##---
--------
--------
--------

--------
--------
---#----
----##--
---##---
--------
--------
--------

--------
--------
----#---
-----#--
---###--
--------
--------
--------

--------
--------
--------
---#-#--
----##--
----#---
--------
--------

--------
--------
--------
-----#--
---#-#--
----##--
--------
--------

--------
--------
--------
----#---
-----##-
----##--
--------
--------

--------
--------
--------
-----#--
------#-
----###-
--------
--------

--------
--------
--------
--------
----#-#-
-----##-
-----#--
--------

--------
--------
--------
--------
------#-
----#-#-
-----##-
--------

--------
--------
--------
--------
-----#--
------##
-----##-
--------

--------
--------
--------
--------
------#-
-------#
-----###
--------

--------
--------
--------
--------
--------
-----#-#
------##
------#-

--------
--------
--------
--------
--------
-------#
-----#-#
------##

--------
--------
--------
--------
--------
------#-
-------#
------##

--------
--------
--------
--------
--------
--------
-------#
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

Scilab

The game's initial state can be input manually by setting the values of Init_state, or using a bitmap image (or other supported formats). The output can be either printed on Scilab's console, or on a graphic window. For both image input and graphic output, either SIVP or IPCV modules are required, and console_output should be set to false.

<lang>Init_state=[0 0 0;...

           1 1 1;...
           0 0 0];

console_output=%T;

if (atomsIsLoaded('IPCV') | atomsIsLoaded('SIVP')) & ~console_output then

   Input=imread('initial_state.bmp');  //Comment this three lines in case
   Init_state=~im2bw(Input,0.1);       //there is no input image but
   Init_state=1.0.*Init_state;         //you still want the graphic window
   scf(0); clf();
   imshow(~Init_state);
   set(gca(),"isoview","on");

end

Curr_state=1.0.*Init_state; Grid_size=size(Init_state); Gens=4;

function varargout=neighbourhood(A,i,j)

   R_top=i-1;
   if i==1 then
       R_top=1;
   end
   
   R_bottom=i+1;
   if i==Grid_size(1) then
       R_bottom=Grid_size(1);
   end
   
   R_left=j-1;
   if j==1 then
       R_left=1;
   end
   
   C_right=j+1;
   if j==Grid_size(2) then
       C_right=Grid_size(2);
   end
   
   varargout=list(A(R_top:R_bottom,R_left:C_right));

endfunction

function []=console_print(Grid)

   String_grid=string(Grid);
   for i=1:size(Grid,'r')
       for j=1:size(Grid,'c')
           if Grid(i,j) then
               String_grid(i,j)="#";
           else
               String_grid(i,j)=" ";
           end
       end
   end
   disp(String_grid);

endfunction

neighbours=[]; Next_state=[];

for gen=1:Gens

   Next_state=zeros(Init_state);
   
   for i=1:Grid_size(1)
       for j=1:Grid_size(2)
           neighbours=zeros(3,3);
           neighbours=neighbourhood(Curr_state,i,j);
           
           Sum_neighbours=sum(neighbours)-1*Curr_state(i,j);
           
           Alive=Curr_state(i,j);
           if Alive then
               if Sum_neighbours<2 then
                   Next_state(i,j)=0;
               elseif Sum_neighbours==2 | Sum_neighbours==3 then
                   Next_state(i,j)=1;
               elseif Sum_neighbours>3 then
                   Next_state(i,j)=0;
               end
           else
               if Sum_neighbours==3 then
                   Next_state(i,j)=1;
               end
           end
       end
   end
   
   if (atomsIsLoaded('IPCV') | atomsIsLoaded('SIVP')) & ~console_output then
       imshow(~Next_state);
       sleep(50);
   else
       sleep(50);
       disp("Generation "+string(gen)+":")
       console_print(Next_state);
   end
   
   if sum(Next_state)==0 | Curr_state==Next_state then
       disp('ALL CELLS HAVE DIED OR BECAME INERT');
       disp('No. of Generations: '+string(gen))
       break
   end
   
   Curr_state=Next_state;

end</lang>

Output:

Output when console_output=%T.

 Generation 1:

!   #     !
!         !
!   #     !
!         !
!   #     !

 Generation 2:

!         !
!         !
!#  #  #  !
!         !
!         !

 Generation 3:

!   #     !
!         !
!   #     !
!         !
!   #     !

 Generation 4:

!         !
!         !
!#  #  #  !
!         !
!         !

SenseTalk

<lang sensetalk>set starting_condition to ((0, 0), (1, 0), (2, 0), (-1, -1), (0, -1), (1, -1))

RunGameOfLife starting_condition

to printColony colonies

   set xCoords to the first item of each item of colonies
   set yCoords to the second item of each item of colonies
   set min_x to the min of xCoords
   set max_x to the max of xCoords
   set min_y to the min of yCoords
   set max_y to the max of yCoords
   repeat for y in min_y..max_y
       set row to ()
       repeat for x in min_x..max_x
           if (x, y) is in colonies
               push "#" into row
           else
               push "-" into row
           end if
       end repeat
       join row using ""
       put row
   end repeat

end printColony

to neighboursOf coordinate

   return ( \
           coordinate + (-1, 1), \
           coordinate + (0, 1), \
           coordinate + (1, 1), \
           coordinate + (-1, 0), \
           coordinate + (1, 0), \
           coordinate + (-1, -1), \
           coordinate + (0, -1), \
           coordinate + (1, -1), \
           )

end neighboursOf

to WillNextGenHaveCell colony, coordinate

   set neighbour_count to the number of items in (each item of neighboursOf(coordinate) where each is in colony)
   if coordinate is in colony
       return neighbour_count is in (2, 3)
   else
       return neighbour_count equals 3
   end if

end WillNextGenHaveCell

to RunGameOfLife colony

   printColony colony
   set the listInsertionMode to "nested"
   repeat 10 times
       set new_colony to ()
       set xCoords to the first item of each item of colony
       set yCoords to the second item of each item of colony
       set min_x to (the min of xCoords) - 1
       set max_x to (the max of xCoords) + 1
       set min_y to (the min of yCoords) - 1
       set max_y to (the max of yCoords) + 1
       repeat for y in min_y..max_y
           repeat for x in min_x..max_x
               if WillNextGenHaveCell(colony, (x, y))
                   insert (x, y) into new_colony
               end if
           end repeat
       end repeat
       set colony to new_colony
       printColony colony
       wait 1 second
   end repeat

end RunGameOfLife</lang>

SequenceL

Library: CImg

SequenceL Code: <lang sequencel>life(Cells(2))[I, J] := let numNeighbors := Cells[I-1,J-1] + Cells[I-1,J] + Cells[I-1,J+1] + Cells[I,J-1] +/*current cell*/Cells[I,J+1] + Cells[I+1,J-1] + Cells[I+1,J] + Cells[I+1,J+1]; in 0 when I=1 or J=1 or I=size(Cells) or J=size(Cells[I]) //On Border else 0 when numNeighbors < 2 or numNeighbors > 3 //Cell Dies else 1 when Cells[I,J] = 1 and numNeighbors = 2 or numNeighbors = 3 //Cell lives on or is born. else Cells[I,J]; //No Change


stressTestInput(n(0))[y,x] := 0 when not y = n / 2 else 1 foreach y within 1 ... n, x within 1 ... n;</lang>

C++ Driver Code: <lang c>#include <iostream>

  1. include <string>
  2. include <vector>
  3. include <fstream>
  4. include <cerrno>
  1. include "Cimg.h"
  1. include "SL_Generated.h"

using namespace std; using namespace cimg_library;

char titleBuffer[200];

std::string get_file_contents(const char*);

int main(int argc, char ** argv) { int cores = 0; int maxSize = 700;

int drawSkip = 1; int drawWait = 0;

string inputFile = "test";

if(argc > 1) { inputFile = argv[1]; } if(argc > 2) { cores = atoi(argv[2]); }

if(argc > 3) { maxSize = atoi(argv[3]); }

if(argc > 4) { drawSkip = atoi(argv[4]);

if(drawSkip < 0) { drawWait = abs(drawSkip); drawSkip = 1; } }

sl_init(cores);

SLTimer drawTimer;

sprintf(titleBuffer, "Conway's Game of Life in SequenceL: %d Cores", cores);

int width = 0; int height = 0;

//Read input file-------------- Sequence<Sequence<int>> initialGrid;

if(inputFile != "test") { stringstream ss(get_file_contents(inputFile.c_str())); string stringItem; vector<int> elems; char delim = ',';

getline(ss, stringItem, delim); width = atoi(stringItem.c_str()); getline(ss, stringItem, delim); height = atoi(stringItem.c_str());

while(getline(ss, stringItem, delim)) { elems.push_back(atoi(stringItem.c_str())); }

//Sequence Pointer Constructor---- int gridDims[] = {height, width, 0}; Sequence<Sequence<int>> tempGrid( (void*)&elems[0], gridDims); initialGrid.hard_copy(tempGrid, 0); //----------------------------- } else { width = maxSize; height = maxSize; sl_stressTestInput(maxSize, cores, initialGrid); } //--------

Sequence<Sequence<int>> result;

const unsigned char black[] = {0};

CImg<unsigned char> visu(width * 4, height * 4, 1, 1, 0); CImgDisplay draw_disp(visu, titleBuffer); cout << "Conway's Game of Life in SequenceL" << endl << "Cores: " << cores << endl;

int generations = 0; double compTime = 0; double drawTime = 0; SLTimer t;

while(!draw_disp.is_closed()) { t.start(); sl_life(initialGrid, cores, result); generations++; initialGrid.hard_copy(result, 0); t.stop(); compTime += t.getTime();

drawTimer.start();

if(drawSkip > 0 && generations % drawSkip == 0) {

visu.fill(255);

for(int i = 1; i <= result.size(); i++) { for(int j = 1; j <= result[i].size(); j++) { if(result[i][j] == 1) visu.draw_circle((j-1) * 4, (i - 1) * 4, 2, black, 1); } }

visu.display(draw_disp);

int drawWidth = maxSize; int drawHeight = maxSize;

if(width < height) { drawWidth = ((double)drawHeight * ((double)width / (double)height)); } else { drawHeight = ((double)drawWidth * ((double)height / (double)width)); }

draw_disp.resize(drawWidth, drawHeight, false);

draw_disp.wait(drawWait); drawTimer.stop(); drawTime += drawTimer.getTime(); } }

cout << "Total Generations: " << generations << endl;

cout << "Average Compute Time: " << compTime / generations << " seconds" << endl;

cout << "Average Draw Time: " << drawTime / generations << " seconds" << endl;

sl_done();

return 0; }

std::string get_file_contents(const char *filename) {

 std::ifstream in(filename, std::ios::in | std::ios::binary);
 if (in)
 {
   std::string contents;
   in.seekg(0, std::ios::end);
   contents.resize(in.tellg());
   in.seekg(0, std::ios::beg);
   in.read(&contents[0], contents.size());
   in.close();
   return(contents);
 }
 throw(errno);

}</lang>

Usage:

SequenceL Intended Use:

life(int(2)); stressTestInput(int(0))

Running the program:

  • If no inputs are provided, a 700 element stress test is performed.
  • Argument 1 is the input file ("test" to run stress test).
  • Argument 2 is the optional number of cores which defaults to 0(all cores).
  • Argument 3 is the size to make the largest dimension of the display window.
  • Argument 4 is the number of frames to skip when drawing.

Sample Input:

Blinker:

5,5,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0

Output: http://i.imgur.com/9ZtKw1X.gifv

Stress Test Output:

This is the output for the 700 element stress test, which is an input of a 700X700 grid with a single line of live cells horizontally in the center.

Output: http://i.imgur.com/yKTrszV.gifv

SETL

Compiler: GNU SETL

This version uses a live cell set representation (set of coordinate pairs.) This example first appeared here. <lang setl>program life;

const

 initialMatrix =
   [".....",
    "..#..",
    "...#.",
    ".###.",
    "....."];

loop init

 s := initialLiveSet();

do

 output(s);
 nm := {[[x+dx, y+dy], [x, y]]: [x, y] in s, dx in {-1..1}, dy in {-1..1}};
 s := {c: t = nm{c} | 3 in {#t, #(t less c)}};

end;

proc output(s);

 system("clear");
 (for y in [0..24])
   (for x in [0..78])
     nprint(if [x, y] in s then "#" else " " end);
   end;
   print();
 end;
 select([], 250);

end proc;

proc initialLiveSet();

 return {[x,y]: row = initialMatrix(y), c = row(x) | c = '#'};

end proc;

end program;</lang>

Shen

Somewhat verbose but functional and type-checked implementation (tested with chibi-scheme and Shen/SBCL). Running this shows ten iterations of a toad. <lang Shen>(tc +)

(datatype subtype

 (subtype B A); X : B;
 _____________________
 X : A;)

(datatype integer

 if (integer? X)
 ___________
 X: integer;
 ________________________
 (subtype integer number);)

(datatype bit

 if (< X 2)
 _______
 X: bit;
 _____________________
 (subtype bit integer);)

(datatype row

 _________
 [] : row;
 
 C : bit; Row : row;
 ===================
 [C | Row] : row;)
 

(datatype universe

 ______________
 [] : universe;
 
 R : row; Uni : universe;
 ========================
 [R | Uni] : universe;)

(define conway-nth

 \\ returns value of x from row if it exists, else 0
 { number --> row --> bit }
 _ [] -> 0
 N _ -> 0 where (< N 0)
 0 [A|B] -> A
 N [A|B] -> (conway-nth (- N 1) B))

(define row-retrieve

 { number --> universe --> row }
 _ [] -> []
 0 [] -> []
 0 [A|B] -> A
 N [A|B] -> (row-retrieve (- N 1) B))

(define cell-retrieve

 { number --> number --> universe --> bit }
 X Y Universe -> (conway-nth X (row-retrieve Y Universe)))

(define neighbors

 \\ takes an X and Y, retrieves the number of neighbors
 { number --> number --> universe --> number }
 X Y Universe -> (let ++ (+ 1)
                      -- (/. X (- X 1))
                   (+ (cell-retrieve (++ X) Y Universe)
                      (cell-retrieve (++ X) (++ Y) Universe)
                      (cell-retrieve (++ X) (-- Y) Universe)
                      (cell-retrieve (-- X) Y Universe)
                      (cell-retrieve (-- X) (++ Y) Universe)
                      (cell-retrieve (-- X) (-- Y) Universe)
                      (cell-retrieve X (++ Y) Universe)
                      (cell-retrieve X (-- Y) Universe))))

(define handle-alive

 { number --> number --> universe --> bit }
 X Y Universe -> (if (or (= (neighbors X Y Universe) 2)
                         (= (neighbors X Y Universe) 3))
                     1 0))

(define handle-dead

 { number --> number --> universe --> bit }
 X Y Universe -> (if (= (neighbors X Y Universe) 3)
                     1 0))

(define next-row

 \\ first argument must be a previous row, second must be 0 when
 \\ first called, third must be a Y value and the final must be the
 \\ current universe
 { row --> number --> number --> universe --> row }
 [] _ _ _ -> []
 [1|B] X Y Universe -> (cons (handle-alive X Y Universe)
                             (next-row B (+ X 1) Y Universe))
 [_|B] X Y Universe -> (cons (handle-dead X Y Universe)
                             (next-row B (+ X 1) Y Universe)))

(define next-universe

 \\ both the first and second arguments must be the same universe,
 \\ the third must be 0 upon first call
 { universe --> number --> universe --> universe }
 [] _ _ -> []
 [Row|Rest] Y Universe -> (cons (next-row Row 0 Y Universe)
                                (next-universe Rest (+ Y 1) Universe)))

(define display-row

 { row --> number }
 [] -> (nl)
 [1|Rest] -> (do (output "* ")
                 (display-row Rest))
 [_|Rest] -> (do (output "  ")
                 (display-row Rest)))

(define display-universe

 { universe --> number }
 [] -> (nl 2)
 [Row|Rest] -> (do (display-row Row)
                   (display-universe Rest)))

(define iterate-universe

 { number --> universe --> number }
 0 _ -> (nl)
 N Universe -> (do (display-universe Universe)
                   (iterate-universe (- N 1)
                                     (next-universe Universe 0 Universe))))

(iterate-universe

10
[[0 0 0 0 0 0]
 [0 0 0 0 0 0]
 [0 0 1 1 1 0]
 [0 1 1 1 0 0]
 [0 0 0 0 0 0]
 [0 0 0 0 0 0]])</lang>

Sidef

Translation of: Perl

<lang ruby>var w = Num(`tput cols`) var h = Num(`tput lines`) var r = "\033[H"

var dirs = [[-1,-1], [-1, 0], [-1, 1], [ 0,-1],

           [ 0, 1], [ 1,-1], [ 1, 0], [ 1, 1]]

var universe = h.of { w.of {1.rand < 0.1} }

func iterate {

   var new = h.of { w.of(false) }
   static rx = (^h ~X ^w)
   for i,j in rx {
       var neighbor = 0
       for y,x in (dirs.map {|dir| dir »+« [i, j] }) {
           universe[y % h][x % w] && ++neighbor
           neighbor > 3 && break
       }
       new[i][j] = (universe[i][j]
                       ? (neighbor==2 || neighbor==3)
                       : (neighbor==3))
   }
   universe = new

}

STDOUT.autoflush(true)

loop {

   print r
   say universe.map{|row| row.map{|cell| cell ? '#' : ' '}.join }.join("\n")
   iterate()

}</lang>

Simula

Translation of: Scheme

<lang simula>COMMENT A PORT OF AN R6RS SCHEME IMPLEMENTATION OF CONWAY'S GAME OF LIFE TO SIMULA --- ASSUMES ; COMMENT ALL CELLS OUTSIDE THE DEFINED GRID ARE DEAD ;

BEGIN


COMMENT FIRST WE NEED CONS, CAR, CDR, LENGTH AND MAP TO SIMULATE SCHEME ;

CLASS ATOM;;

ATOM CLASS CELL(ALIVE); INTEGER ALIVE;;

ATOM CLASS LIST(A1, A2); REF(ATOM) A1, A2;;

REF(LIST) PROCEDURE CONS(A1, A2); REF(ATOM) A1, A2;

   CONS :- NEW LIST(A1, A2);

REF(ATOM) PROCEDURE CAR(LST); REF(LIST) LST;

   CAR :- LST.A1;

REF(ATOM) PROCEDURE CDR(LST); REF(LIST) LST;

   CDR :- LST.A2;

INTEGER PROCEDURE LENGTH(LST); REF(LIST) LST;

   LENGTH := IF LST == NONE THEN 0 ELSE 1 + LENGTH(CDR(LST));

REF(LIST) PROCEDURE MAP(F, LST); PROCEDURE F IS REF(ATOM) PROCEDURE F(ARG); REF(ATOM) ARG;; REF(LIST) LST;

   MAP :- IF LST == NONE THEN NONE ELSE CONS(F(CAR(LST)), MAP(F, CDR(LST)));


COMMENT NOW FOLLOWS THE PROBLEM SPECIFIC PART ;


COMMENT IF N IS OUTSIDE BOUNDS OF LIST, RETURN 0 ELSE VALUE AT N ; REF(ATOM) PROCEDURE NTH(N, LST); INTEGER N; REF(LIST) LST;

   NTH :- IF N > LENGTH(LST) THEN NEW CELL(0) ELSE
          IF N < 1 THEN NEW CELL(0) ELSE
          IF N = 1 THEN CAR(LST) ELSE NTH(N - 1, CDR(LST));


COMMENT RETURN THE NEXT STATE OF THE SUPPLIED UNIVERSE ; REF(LIST) PROCEDURE NEXTUNIVERSE(UNIVERSE); REF(LIST) UNIVERSE; BEGIN

   COMMENT VALUE AT (X, Y) ;
   INTEGER PROCEDURE VALUEAT(X, Y); INTEGER X, Y;
   BEGIN
       REF(ATOM) A;
       A :- NTH(Y, UNIVERSE);
       INSPECT A
           WHEN LIST DO
               VALUEAT := NTH(X, THIS LIST) QUA CELL.ALIVE
           OTHERWISE
               VALUEAT := 0;
   END VALUEAT;
   COMMENT SUM OF THE VALUES OF THE CELLS SURROUNDING (X, Y) ;
   INTEGER PROCEDURE NEIGHBORSUM(X, Y); INTEGER X, Y;
       NEIGHBORSUM :=
           VALUEAT(X - 1, Y - 1)
         + VALUEAT(X - 1, Y    )
         + VALUEAT(X - 1, Y + 1)
         + VALUEAT(X,     Y - 1)
         + VALUEAT(X,     Y + 1)
         + VALUEAT(X + 1, Y - 1)
         + VALUEAT(X + 1, Y    )
         + VALUEAT(X + 1, Y + 1);
   COMMENT NEXT STATE OF THE CELL AT (X, Y) ;
   INTEGER PROCEDURE NEXTCELL(X, Y); INTEGER X, Y;
   BEGIN
       INTEGER CUR, NS;
       CUR := VALUEAT(X, Y);
       NS := NEIGHBORSUM(X, Y);
       NEXTCELL := IF CUR = 1 AND (NS < 2 OR NS > 3) THEN 0 ELSE
                   IF CUR = 0 AND NS = 3 THEN 1 ELSE CUR;
   END NEXTCELL;
   COMMENT NEXT STATE OF ROW N ;
   REF(LIST) PROCEDURE ROW(N, OUT); INTEGER N; REF(LIST) OUT;
   BEGIN
       INTEGER W, O;
       W := LENGTH(CAR(UNIVERSE));
       O := LENGTH(OUT);
       ROW :- IF W = O THEN OUT ELSE ROW(N, CONS(NEW CELL(NEXTCELL(W - O, N)), OUT));
   END ROW;


   COMMENT A RANGE OF INTS FROM BOT TO TOP ;
   REF(LIST) PROCEDURE INTRANGE(BOT, TOP); INTEGER BOT, TOP;
       INTRANGE :- IF BOT > TOP THEN NONE ELSE CONS(NEW CELL(BOT), INTRANGE(BOT + 1, TOP));
   REF(ATOM) PROCEDURE LAMBDA(N); REF(ATOM) N;
       LAMBDA :- ROW(N QUA CELL.ALIVE, NONE);
   NEXTUNIVERSE :- MAP(LAMBDA, INTRANGE(1, LENGTH(UNIVERSE)));

END NEXTUNIVERSE;

COMMENT DISPLAY THE UNIVERSE ; PROCEDURE DISPLAY(LST); REF(LIST) LST; BEGIN

   WHILE LST =/= NONE DO
   BEGIN
       REF(LIST) LI;
       LI :- CAR(LST);
       WHILE LI =/= NONE DO
       BEGIN
           REF(CELL) CE;
           CE :- CAR(LI);
           OUTCHAR(IF CE.ALIVE = 1 THEN '#' ELSE '-');
           LI :- CDR(LI);
       END;
       OUTIMAGE;
       LST :- CDR(LST);
   END;

END DISPLAY;

COMMENT STARTING WITH SEED, SHOW REPS STATES OF THE UNIVERSE ; PROCEDURE CONWAY(SEED, REPS); REF(LIST) SEED; INTEGER REPS; BEGIN

   IF REPS > 0 THEN
   BEGIN
       DISPLAY(SEED);
       OUTIMAGE;
       CONWAY(NEXTUNIVERSE(SEED), REPS - 1);
   END;

END CONWAY;

REF(CELL) O, L; O :- NEW CELL(0); L :- NEW CELL(1);

COMMENT BLINKER IN A 3X3 UNIVERSE ; ! (CONWAY '((0 1 0)

           (0 1 0)
           (0 1 0)) 5) ;

CONWAY(CONS(CONS(O, CONS(L, CONS(O, NONE))),

      CONS(CONS(O, CONS(L, CONS(O, NONE))),
      CONS(CONS(O, CONS(L, CONS(O, NONE))),
      NONE))), 5);

COMMENT GLIDER IN AN 8X8 UNIVERSE ; !(CONWAY '((0 0 1 0 0 0 0 0)

          (0 0 0 1 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)) 30) ;

OUTIMAGE;

CONWAY(CONS(CONS(O, CONS(O, CONS(L, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),

      CONS(CONS(O, CONS(O, CONS(O, CONS(L, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),
      CONS(CONS(O, CONS(L, CONS(L, CONS(L, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),
      CONS(CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),
      CONS(CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),
      CONS(CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),
      CONS(CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),
      CONS(CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, CONS(O, NONE)))))))),
      NONE)))))))), 30);

END. </lang>

Output:
-#-
-#-
-#-

---
###
---

-#-
-#-
-#-

---
###
---

-#-
-#-
-#-


--#-----
---#----
-###----
--------
--------
--------
--------
--------

--------
-#-#----
--##----
--#-----
--------
--------
--------
--------

--------
---#----
-#-#----
--##----
--------
--------
--------
--------

--------
--#-----
---##---
--##----
--------
--------
--------
--------

--------
---#----
----#---
--###---
--------
--------
--------
--------

--------
--------
--#-#---
---##---
---#----
--------
--------
--------

--------
--------
----#---
--#-#---
---##---
--------
--------
--------

--------
--------
---#----
----##--
---##---
--------
--------
--------

--------
--------
----#---
-----#--
---###--
--------
--------
--------

--------
--------
--------
---#-#--
----##--
----#---
--------
--------

--------
--------
--------
-----#--
---#-#--
----##--
--------
--------

--------
--------
--------
----#---
-----##-
----##--
--------
--------

--------
--------
--------
-----#--
------#-
----###-
--------
--------

--------
--------
--------
--------
----#-#-
-----##-
-----#--
--------

--------
--------
--------
--------
------#-
----#-#-
-----##-
--------

--------
--------
--------
--------
-----#--
------##
-----##-
--------

--------
--------
--------
--------
------#-
-------#
-----###
--------

--------
--------
--------
--------
--------
-----#-#
------##
------#-

--------
--------
--------
--------
--------
-------#
-----#-#
------##

--------
--------
--------
--------
--------
------#-
-------#
------##

--------
--------
--------
--------
--------
--------
-------#
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##

--------
--------
--------
--------
--------
--------
------##
------##


180 garbage collection(s) in 0.1 seconds.

Smalltalk

This implementation has been developed using Cuis Smalltalk [1]. Here are different configurations: <lang smalltalk> "Blinker" GameOfLife withAliveCells: { 4@2. 4@3. 4@4. 3@3. 4@3. 5@3 } ofSize: 10@10.

"Toad" GameOfLife withAliveCells: { 2@4. 3@4. 4@4. 3@3. 4@3. 5@3 } ofSize: 10@10 </lang> This is the implementation: <lang Smalltalk> Object subclass: #GameOfLife

 instanceVariableNames: 'aliveCells boardSize'
 classVariableNames: 
 poolDictionaries: 
 category: 'GameOfLife'

GameOfLife class>>withAliveCells: aCollectionOfCells ofSize: aBoardSize

 self assertAll: aCollectionOfCells areInside: aBoardSize.
 ^self new initializeWithAliveCells: aCollectionOfCells ofSize: aBoardSize
 

GameOfLife class>>assertAll: aCollectionOfAliveCells areInside: aSize

 | origin |	
 origin := 0@0.
 aCollectionOfAliveCells do: [:aCell |
 (aCell between: origin and: aSize) ifFalse: [ self error: 'Cell ', aCell printString,' out of range' ]]

initializeWithAliveCells: aCollectionOfCells ofSize: aBoardSize

 aliveCells := aCollectionOfCells asSet.
 boardSize := aBoardSize

calculateNextGeneration

 aliveCells := self boardCellsSelect: [ :aCell | self shouldBeAliveOnNextGeneration: aCell ]

shouldBeAliveOnNextGeneration: aCell

 | numberOfAliveNeighbors |
 numberOfAliveNeighbors := self numberOfAliveNeighborsOf: aCell.
 ^numberOfAliveNeighbors = 3 or: [ self shouldSurvive: aCell with: numberOfAliveNeighbors]

shouldSurvive: aCell with: numberOfAliveNeighbors

 ^ (self isAlive: aCell) and: [ numberOfAliveNeighbors = 2 ]

isAlive: aCell

 ^aliveCells includes: aCell

isDead: aCell

 ^(self isAlive: aCell) not

boardCellsDo: aClosure

 0 to: boardSize x do: [ :x |
   0 to: boardSize y do: [ :y | aClosure value: x@y ]]

boardCellsSelect: aCondition

 | selectedCells |
 selectedCells := Set new.
 self boardCellsDo: [ :aCell | (aCondition value: aCell)  ifTrue: [ selectedCells add: aCell ]].
 ^selectedCells
 

numberOfAliveNeighborsOf: aCell

 ^aCell eightNeighbors count: [ :aNeighbor | self isAlive: aNeighbor ]

</lang> The implementation was developed using TDD. This are the tests used to implement it. <lang Smalltalk> TestCase subclass: #GameOfLifeTest

 instanceVariableNames: 
 classVariableNames: 
 poolDictionaries: 
 category: 'GameOfLife'

test01AliveCellWithLessThatTwoAliveCellsDies

 | gameOfLife |
 gameOfLife := GameOfLife withAliveCells: {1@1} ofSize: 3@3.
 gameOfLife calculateNextGeneration.
 self assert: (gameOfLife isDead: 1@1)

test02AliveCellWithTwoAliveNeighborsSurvives

 | gameOfLife |
 gameOfLife := GameOfLife withAliveCells: {1@1. 1@2. 2@1} ofSize: 3@3.
 gameOfLife calculateNextGeneration.
 self assert: (gameOfLife isAlive: 1@1).

test03AliveCellWithThreeAliveNeighborsSurvives

 | gameOfLife |
 gameOfLife := GameOfLife withAliveCells: {1@1. 1@2. 2@1. 2@2} ofSize: 3@3.
 gameOfLife calculateNextGeneration.
 self assert: (gameOfLife isAlive: 1@1).

test04DeadCellWithThreeAliveNeighborsBecomesAlive

 | gameOfLife |
 gameOfLife := GameOfLife withAliveCells: {1@1. 1@2. 2@1} ofSize: 3@3.
 gameOfLife calculateNextGeneration.
 self assert: (gameOfLife isAlive: 2@2).

test05DeadCellWithAliveNeighborsDifferentToThreeKeepsDead

 | gameOfLife |
 gameOfLife := GameOfLife withAliveCells: {1@2. 2@2. 3@2. 1@3} ofSize: 3@3.
 gameOfLife calculateNextGeneration.
 self assert: (gameOfLife isDead: 1@1).
 self assert: (gameOfLife isDead: 2@3).

test06CanNotCreateGameWithCellOutsideXOrigin

 self 
   should: [ GameOfLife withAliveCells: { 2@0. 1@0. -1@1 } ofSize: 3@3 ]
   raise: Error - MessageNotUnderstood 
   withMessageText: 'Cell -1@1 out of range'

test07CanNotCreateGameWithCellOutsideYOrigin

 self 
   should: [ GameOfLife withAliveCells: { 2@0. 1@0. 1@-1 } ofSize: 3@3 ]
   raise: Error - MessageNotUnderstood 
   withMessageText: 'Cell 1@-1 out of range'

test08CanNotCreateGameWithCellOutsideXLimit

 self 
   should: [ GameOfLife withAliveCells: { 2@0. 1@0. 4@1 } ofSize: 3@3 ]
   raise: Error - MessageNotUnderstood 
   withMessageText: 'Cell 4@1 out of range'

test09CanNotCreateGameWithCellOutsideYLimit

 self 
   should: [ GameOfLife withAliveCells: { 2@0. 1@0. 1@4 } ofSize: 3@3 ]
   raise: Error - MessageNotUnderstood 
   withMessageText: 'Cell 1@4 out of range'

</lang> If you want to have a visual representation, here is a view for it: <lang smalltalk> ImageMorph subclass: #GameOfLifeView

 instanceVariableNames: 'game'
 classVariableNames: 
 poolDictionaries: 
 category: 'GameOfLife'

GameOfLifeView class>>for: aGameOfLife

 ^self new initializeFor: aGameOfLife

GameOfLifeView class>>openFor: aGameOfLife

 ^(self for: aGameOfLife) open

GameOfLifeView class>>blinker

 ^GameOfLife withAliveCells: { 4@2. 4@3. 4@4. 3@3. 4@3. 5@3 } ofSize: 10@10
 	

GameOfLifeView class>>toad

 ^GameOfLife withAliveCells: { 2@4. 3@4. 4@4. 3@3. 4@3. 5@3 } ofSize: 10@10

GameOfLifeView class>>openBlinker

 ^self openFor: self blinker

GameOfLifeView class>>openToad

 ^self openFor: self toad  	

initializeFor: aGameOfLife

 game := aGameOfLife.
 self image: (Form extent: game boardSize * 5 depth: 2).

open

 self showBoard.
 self openInWorld.
 self startSteppingStepTime: 500

showBoard

 game boardCellsDo: [ :aPoint | 
   (game isAlive: aPoint)
     ifTrue: [ self form fillBlack: (aPoint*5 extent: 5@5) ]
     ifFalse: [ self form fillWhite: (aPoint*5 extent: 5@5) ]].

step

 game calculateNextGeneration.
 self showBoard.
 self redrawNeeded.

</lang>

SQL

Microsoft SQL here: http://www.sqlservercentral.com/articles/CTE/130407/

Works with: Oracle

<lang sql> -- save these lines in a file called -- setupworld.sql

-- turn off feedback for cleaner display

set feedback off

-- 3 x 3 world

-- alive has coordinates of living cells

drop table alive;

create table alive (x number,y number);

-- three alive up the middle -- * -- * -- *

insert into alive values (2,1); insert into alive values (2,2); insert into alive values (2,3);

commit;

-- save these lines in a file called newgeneration.sql

-- adjact contains one row for each pair of -- coordinates that is adjacent to a living cell

drop table adjacent;

create table adjacent (x number,y number);

-- add row for each of the 8 adjacent squares

insert into adjacent select x-1,y-1 from alive; insert into adjacent select x-1,y from alive; insert into adjacent select x-1,y+1 from alive; insert into adjacent select x,y-1 from alive; insert into adjacent select x,y+1 from alive; insert into adjacent select x+1,y-1 from alive; insert into adjacent select x+1,y from alive; insert into adjacent select x+1,y+1 from alive;

commit;

-- delete rows for squares that are outside the world

delete from adjacent where x<1 or y<1 or x>3 or y>3;

commit;

-- table counts is the number of live cells -- adjacent to that point

drop table counts;

create table counts as select x,y,count(*) n from adjacent a group by x,y;

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

-- delete the ones who die

delete from alive a where ((a.x,a.y) not in (select x,y from counts)) or ((select c.n from counts c where a.x=c.x and a.y=c.y) in (1,4,5,6,7,8));

-- insert the ones that are born

insert into alive a select x,y from counts c where c.n=3 and ((c.x,c.y) not in (select x,y from alive));

commit;

-- create output table

drop table output;

create table output as select rownum y,' ' x1,' ' x2,' ' x3 from dba_tables where rownum < 4;

update output set x1='*' where (1,y) in (select x,y from alive);

update output set x2='*' where (2,y) in (select x,y from alive);

update output set x3='*' where (3,y) in (select x,y from alive);

commit

-- output configuration

select x1||x2||x3 WLD from output order by y desc; </lang>

Running in sqlplus:

SQL> @setupworld
SQL> @newgeneration

WLD
---

***

SQL> @newgeneration

WLD
---
 *
 *
 *
SQL> @newgeneration

WLD
---

***

Swift

Translation of: Rust

<lang swift>struct Cell: Hashable {

 var x: Int
 var y: Int

}

struct Colony {

 private var height: Int
 private var width: Int
 private var cells: Set<Cell>
 init(cells: Set<Cell>, height: Int, width: Int) {
   self.cells = cells
   self.height = height
   self.width = width
 }
 private func neighborCounts() -> [Cell: Int] {
   var counts = [Cell: Int]()
   for cell in cells.flatMap(Colony.neighbors(for:)) {
     counts[cell, default: 0] += 1
   }
   return counts
 }
 private static func neighbors(for cell: Cell) -> [Cell] {
   return [
     Cell(x: cell.x - 1, y: cell.y - 1),
     Cell(x: cell.x,     y: cell.y - 1),
     Cell(x: cell.x + 1, y: cell.y - 1),
     Cell(x: cell.x - 1, y: cell.y),
     Cell(x: cell.x + 1, y: cell.y),
     Cell(x: cell.x - 1, y: cell.y + 1),
     Cell(x: cell.x,     y: cell.y + 1),
     Cell(x: cell.x + 1, y: cell.y + 1),
   ]
 }
 func printColony() {
   for y in 0..<height {
     for x in 0..<width {
       let char = cells.contains(Cell(x: x, y: y)) ? "0" : "."
       print("\(char) ", terminator: "")
     }
     print()
   }
 }
 mutating func run(iterations: Int) {
   print("(0)")
   printColony()
   print()
   for i in 1...iterations {
     print("(\(i))")
     runGeneration()
     printColony()
     print()
   }
 }
 private mutating func runGeneration() {
   cells = Set(neighborCounts().compactMap({keyValue in
     switch (keyValue.value, cells.contains(keyValue.key)) {
     case (2, true), (3, _):
       return keyValue.key
     case _:
       return nil
     }
   }))
 }

}

let blinker = [Cell(x: 1, y: 0), Cell(x: 1, y: 1), Cell(x: 1, y: 2)] as Set

var col = Colony(cells: blinker, height: 3, width: 3)

print("Blinker: ") col.run(iterations: 3)

let glider = [

 Cell(x: 1, y: 0),
 Cell(x: 2, y: 1),
 Cell(x: 0, y: 2),
 Cell(x: 1, y: 2),
 Cell(x: 2, y: 2)

] as Set

col = Colony(cells: glider, height: 8, width: 8)

print("Glider: ") col.run(iterations: 20)</lang>

Output:
Blinker: 
(0)
. 0 . 
. 0 . 
. 0 . 

(1)
. . . 
0 0 0 
. . . 

(2)
. 0 . 
. 0 . 
. 0 . 

(3)
. . . 
0 0 0 
. . . 

Glider: 
(0)
. 0 . . . . . . 
. . 0 . . . . . 
0 0 0 . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(1)
. . . . . . . . 
0 . 0 . . . . . 
. 0 0 . . . . . 
. 0 . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(2)
. . . . . . . . 
. . 0 . . . . . 
0 . 0 . . . . . 
. 0 0 . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(3)
. . . . . . . . 
. 0 . . . . . . 
. . 0 0 . . . . 
. 0 0 . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(4)
. . . . . . . . 
. . 0 . . . . . 
. . . 0 . . . . 
. 0 0 0 . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(5)
. . . . . . . . 
. . . . . . . . 
. 0 . 0 . . . . 
. . 0 0 . . . . 
. . 0 . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(6)
. . . . . . . . 
. . . . . . . . 
. . . 0 . . . . 
. 0 . 0 . . . . 
. . 0 0 . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(7)
. . . . . . . . 
. . . . . . . . 
. . 0 . . . . . 
. . . 0 0 . . . 
. . 0 0 . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(8)
. . . . . . . . 
. . . . . . . . 
. . . 0 . . . . 
. . . . 0 . . . 
. . 0 0 0 . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 

(9)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . 0 . 0 . . . 
. . . 0 0 . . . 
. . . 0 . . . . 
. . . . . . . . 
. . . . . . . . 

(10)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . 0 . . . 
. . 0 . 0 . . . 
. . . 0 0 . . . 
. . . . . . . . 
. . . . . . . . 

(11)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . 0 . . . . 
. . . . 0 0 . . 
. . . 0 0 . . . 
. . . . . . . . 
. . . . . . . . 

(12)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . 0 . . . 
. . . . . 0 . . 
. . . 0 0 0 . . 
. . . . . . . . 
. . . . . . . . 

(13)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . 0 . 0 . . 
. . . . 0 0 . . 
. . . . 0 . . . 
. . . . . . . . 

(14)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . 0 . . 
. . . 0 . 0 . . 
. . . . 0 0 . . 
. . . . . . . . 

(15)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . 0 . . . 
. . . . . 0 0 . 
. . . . 0 0 . . 
. . . . . . . . 

(16)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . 0 . . 
. . . . . . 0 . 
. . . . 0 0 0 . 
. . . . . . . . 

(17)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . 0 . 0 . 
. . . . . 0 0 . 
. . . . . 0 . . 

(18)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . 0 . 
. . . . 0 . 0 . 
. . . . . 0 0 . 

(19)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . 0 . . 
. . . . . . 0 0 
. . . . . 0 0 . 

(20)
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . . . 
. . . . . . 0 . 
. . . . . . . 0 
. . . . . 0 0 0

SystemVerilog

Note using non-blocking assignments, so that the code behaves as if every cell is updated in parallel on each clock edge. (I didn't need to use a clock here, but doing so looks more like standard verilog coding that is familiar to hardware designers). <lang SystemVerilog>module gol;

 parameter NUM_ROWS = 20;
 parameter NUM_COLS = 32;
 bit [NUM_COLS:1] cell[1:NUM_ROWS];
 bit clk;
 initial begin
   cell[10][10:8] = 3'b111;
   cell[11][10:8] = 3'b100;
   cell[12][10:8] = 3'b010;
   repeat(8) #5 clk = ~clk;
 end
 always @(posedge clk) begin
   foreach (cell[y,x]) begin
     automatic int count = $countones({ cell[y-1][x-1+:3], cell[y][x-1], cell[y][x+1], cell[y+1][x-1+:3] });
     if (count == 3) cell[y][x] <= 1'b1;
     else if (count != 2) cell[y][x] <= 1'b0;
   end
 end
 always @(negedge clk) begin
   $display("--");
   foreach (cell[y]) $display( "  %b", cell[y] );
 end

endmodule</lang>

Tcl

Works with: Tcl version 8.5

<lang tcl>package require Tcl 8.5

proc main {} {

   evolve 3 blinker [initialize_tableau {3 3} {{0 1} {1 1} {2 1}}]
   evolve 5 glider  [initialize_tableau {4 4} {{0 1} {1 2} {2 0} {2 1} {2 2}}]

}

proc evolve {generations name tableau} {

   for {set gen 1} {$gen <= $generations} {incr gen} {
       puts "$name generation $gen:"
       print $tableau
       set tableau [next_generation $tableau]
   }
   puts ""

}

proc initialize_tableau {size initial_life} {

   lassign $size ::max_x ::max_y 
   set tableau [blank_tableau]
   foreach point $initial_life {
       lset tableau {*}$point 1
   }
   return $tableau

}

proc blank_tableau {} {

   return [lrepeat $::max_x [lrepeat $::max_y 0]]

}

proc print {tableau} {

   foreach row $tableau {puts [string map {0 . 1 #} [join $row]]}

}

proc next_generation {tableau} {

   set new [blank_tableau]
   for {set x 0} {$x < $::max_x} {incr x} {
       for {set y 0} {$y < $::max_y} {incr y} {
           lset new $x $y [fate [list $x $y] $tableau]
       }
   }
   return $new

}

proc fate {point tableau} {

   set current [value $point $tableau]
   set neighbours [sum_neighbours $point $tableau]
   return [expr {($neighbours == 3) || ($neighbours == 2 && $current == 1)}]

}

proc value {point tableau} {

   return [lindex $tableau {*}$point]

}

proc sum_neighbours {point tableau} {

   set sum 0
   foreach neighbour [get_neighbours $point] {
       incr sum [value $neighbour $tableau]
   }
   return $sum

}

proc get_neighbours {point} {

   lassign $point x y
   set results [list]
   foreach x_off {-1 0 1} {
       foreach y_off {-1 0 1} {
           if { ! ($x_off == 0 && $y_off == 0)} {
               set i [expr {$x + $x_off}] 
               set j [expr {$y + $y_off}]
               if {(0 <= $i && $i < $::max_x) && (0 <= $j && $j < $::max_y)} {
                   lappend results [list $i $j]
               }
           }
       }
   }
   return $results

}

main</lang>

blinker generation 1:
. # .
. # .
. # .
blinker generation 2:
. . .
# # #
. . .
blinker generation 3:
. # .
. # .
. # .

glider generation 1:
. # . .
. . # .
# # # .
. . . .
glider generation 2:
. . . .
# . # .
. # # .
. # . .
glider generation 3:
. . . .
. . # .
# . # .
. # # .
glider generation 4:
. . . .
. # . .
. . # #
. # # .
glider generation 5:
. . . .
. . # .
. . . #
. # # #

UNIX Shell

Works with: Bourne Again SHell
Works with: Korn Shell
Works with: Z Shell

<lang bash># Shells only have 1-dimensional arrays, so each row is one string function main {

 typeset blinker=(000 111 000)
 run list 4 "${blinker[@]}"

}

function run {

 typeset mode=$1 # screen or list
 shift
 typeset -i limit=0
 if (( $1 > 1 )); then
   limit=$1
   shift
 fi
 if mode == screen ; then
   clear
 fi
 typeset universe=("$@")
 typeset -i generation=0
 while (( !limit || generation < limit )); do
   if mode == screen ; then
     printf '\e[H'
   else
     printf '\n'
   fi
   printf 'Generation %d\n' "$generation"
   disp "${universe[@]}" | tr '01' '.@'
   universe=($(next_generation "${universe[@]}"))
   (( generation += 1 ))
   sleep 0.125
 done

}

  1. display a matrix

function disp {

 # remove sed for more compact display
 printf '%s\n' "$@" | sed 's/./ &/g'

}

  1. center a matrix within a given size by padding with 0s

function center {

 typeset height=$1 width=$2
 shift 2
 typeset -i offset_i offset_j i j
 if (( $# > height || ${#1} > width )); then
   printf >&2 'Source larger than target.\n'
   return 1
 fi
 (( offset_i = (height - $#) / 2 ))
 (( offset_j = (width - ${#1}) / 2 ))
 typeset prefix zeroes suffix
 for (( j=0; j<width; ++j )); do
   zeroes+=0
   if (( j < offset_j )); then
     prefix+=0
   elif (( j >= offset_j+${#1} )); then
     suffix+=0
   fi
 done
 for (( i=0; i<offset_i; ++i )); do
   printf '%s\n' "$zeroes"
 done
 while (( $# )); do
   printf '%s%s%s\n' "$prefix" "$1" "$suffix"
   shift
   (( i++ ))
 done
 while (( i++ < height )); do
   printf '%s\n' "$zeroes"
 done

}

  1. compute the next generation
  2. the grid is finite; pass -t to treat as torus (wraparound), otherwise it's
  3. bounded by always-dead cells

next_generation() {

 typeset -i torus=0
 if $1 == -t ; then
   torus=1
   shift
 fi
 # cache cells in an associative array
 # (for fast lookup when counting neighbors)
 typeset -A cells
 typeset -i i=0 j=0 height=$# width=${#1}
 while (( $# )); do
   row=$1
   shift
   for (( j=0; j<${#row}; ++j )); do
     cells[$i,$j]=${row:$j:1}
   done
   (( i+=1 ))
 done
 typeset -i di dj ni nj n cell
 for (( i=0; i<height; ++i )); do
   for (( j=0; j<width; ++j )); do
     n=0
     for (( di=-1; di<2; ++di )); do
       (( ni = i + di ))
       if (( torus )); then
         (( ni = (ni + height) % height ))
       fi
       for (( dj=-1; dj<2; ++dj )); do
         (( nj = j + dj ))
         if (( torus )); then
           (( nj = (nj + width) % width ))
         fi
         if (( (di || dj) && ni >= 0 && nj >= 0 && ni < height && nj < width  )); then
           (( n += ${cells[$ni,$nj]} ))
         fi
       done
     done
     printf '%d' "$(( ( n == 3 ) || ( ${cells[$i,$j]} && n==2 ) ))"
   done
   printf '\n'
 done

}

main "$@"</lang>

Output:
Generation 0
...
@@@
...

Generation 1
.@.
.@.
.@.

Generation 2
...
@@@
...

Generation 3
.@.
.@.
.@.

Ursala

Three functions are defined: rule takes a pair (c,<n..>) representing a cell and its list of neighboring cells to the new cell, neighborhoods takes board of cells <<c..>..> to a structure <<(c,<n..>)..>..> explicitly pairing each cell with its neighborhood, and evolve(n) takes a board <<c..>..> to a sequence of n boards evolving from it.

<lang Ursala>#import std

  1. import nat

rule = -: ^(~&,~&l?(~&r-={2,3},~&r-={3})^|/~& length@F)* pad0 iota512

neighborhoods = ~&thth3hthhttPCPthPTPTX**K7S+ swin3**+ swin3@hNSPiCihNCT+ --<0>*+ 0-*

evolve "n" = next"n" rule**+ neighborhoods</lang> test program: <lang Ursala>blinker =

(==`O)**t -[ +++ OOO +++]-

glider =

(==`O)**t -[ +O++++ ++O+++ OOO+++ ++++++ ++++++]-

  1. show+

examples = mat0 ~&?(`O!,`+!)*** evolve3(blinker)-- evolve5(glider)</lang>

Output:
+++
OOO
+++

+O+
+O+
+O+

+++
OOO
+++

+O++++
++O+++
OOO+++
++++++
++++++

++++++
O+O+++
+OO+++
+O++++
++++++

++++++
++O+++
O+O+++
+OO+++
++++++

++++++
+O++++
++OO++
+OO+++
++++++

++++++
++O+++
+++O++
+OOO++
++++++

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.

<lang vedit>IT("Generation 0 ") IN IT(".O.") IN IT(".O.") IN IT(".O.")

  1. 9 = 2 // number of generations to calculate
  2. 10 = Cur_Line
  3. 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</lang>

Output:
Generation 0    
.O.
.O.
.O.

Generation 1    
...
OOO
...

Generation 2    
.O.
.O.
.O.

Wortel

Mapping over a matrix. <lang wortel>@let {

 life &m ~!* m &[a y] ~!* a &[v x] @let {
   neigh @sum [
     @`-x 1 @`-y 1 m  @`x @`-y 1 m  @`+x 1 @`-y 1 m
     @`-x 1 @`y    m                @`+x 1 @`y    m
     @`-x 1 @`+y 1 m  @`x @`+y 1 m  @`+x 1 @`+y 1 m
   ]
   @+ || = neigh 3 && v = neigh 2
 }
 blinker [
   [0 0 0 0 0]
   [0 0 0 0 0]
   [0 1 1 1 0]
   [0 0 0 0 0]
   [0 0 0 0 0]
 ]
 [[
   !^life 0 blinker
   !^life 1 blinker
   !^life 2 blinker
 ]]

}</lang>

Output:
[
 [[0 0 0 0 0]
  [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 1 0 0]
  [0 0 1 0 0]
  [0 0 1 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]
  [0 0 0 0 0]]
]

Different solution by using functions that operate on matrices. <lang wortel>@let {

 ; Translation of the APL game of life (http://catpad.net/michael/apl/).
 life &m @let {
   ; create functions that work on two matrices
   makemf  &f @[\@mapm @[\@mapm f ^@,] ^@,]
   addm    !makemf ^+
   orm     !makemf ^||
   andm    !makemf ^&&
   eqm     !makemf ^=
   ; bool matrix to number matrix
   tonum   *^*^@+
   
   ; create a matrix of value v in the shape of matrix m
   repm    &[v m] @rep #m &,@rep #m.0 v
   ; move a matrix in directions by padding zeroes
   movel   \!*~t0j
   mover   \!*~i0SO
   moveu   &m ~, &,@rep #m.0 0 !~t m
   moved   &m  , &,@rep #m.0 0 !~i m
   ; cache up and down
   mu      !moveu m
   md      !moved m
   ; calculate the neighbours
   neigh   !/addm [
     !movel mu  mu  !mover mu
     !movel m       !mover m
     !movel md  md  !mover md
   ]

   ; ((neigh = 2) AND m) OR (neigh = 3)
   ; (2 neighbours AND alive) OR (3 neighbours)
   !tonum !!orm !!andm m !!eqm neigh !!repm 2 m
                !!eqm neigh !!repm 3 m
 }
 blinker [
   [0 0 0 0 0]
   [0 0 0 0 0]
   [0 1 1 1 0]
   [0 0 0 0 0]
   [0 0 0 0 0]
 ]
 [[
   !^life 0 blinker
   !^life 1 blinker
   !^life 2 blinker
 ]]

}</lang>

Output:
[
 [[0 0 0 0 0]
  [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 1 0 0]
  [0 0 1 0 0]
  [0 0 1 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]
  [0 0 0 0 0]]
]

VBScript

I have used ANSI escape codes, so the program will not whork from W2000 to W8.1, where Microsoft did see fit to remove support to these codes. The game wraps around at borders, so the gliders are always alive. Must be invoked from cscript. <lang vb> option explicit const tlcr=3, tlcc=3 const maxdim=15

dim a(15,15) dim b(15,15) dim ans0:ans0=chr(27)&"[" dim gen,n

erase a 'glider a(0,1)=true:a(1,2)=true:a(2,0)=true:a(2,1)=true:a(2,2)=true 'blinker a(3,13)=true:a(4,13)=true:a(5,13)=true 'beacon a(11,1)=true:a(11,2)=true: a(12,1)=true:a(12,2)=true a(13,3)=true:a(13,4)=true: a(14,3)=true:a(14,4)=true

gen=0 doframe

do

 display 
 wscript.sleep(100)
 n=newgen

loop until n=0 display

sub cls() wscript.StdOut.Write ans0 &"2J"&ans0 &"?25l":end sub 'hide cursor too sub toxy(r,c,s) wscript.StdOut.Write ans0 & r & ";" & c & "f" & s :end sub function iif(a,b,c) if a then iif=b else iif=c end if :end function

sub doframe

 dim r,c,s

const frame="@" cls toxy 1,tlcc-1, "Conway's Game of Life" toxy tlcr-1,tlcc-1,string(maxdim+3,frame) s=frame&space(maxdim+1)&frame for r=0 to maxdim toxy tlcr+r,tlcc-1,s next toxy tlcr+maxdim+1,tlcc-1,string(maxdim+3,frame) end sub

sub display dim r,c const pix="#" for r=0 to maxdim

  for c=0 to maxdim

toxy tlcr+r,tlcc+c,iif (a(r,c),pix," ") next next toxy tlcr+maxdim+2,tlcc-1,gen & " " & n toxy tlcr+maxdim+3,tlcc-1,"" gen=gen+1 end sub

function newgen

 dim r,c,cnt,cp,cm,rp,rm

for r=0 to maxdim for c=0 to maxdim cp=(c+1) and maxdim 'wrap around cm=(c-1) and maxdim rp=(r+1) and maxdim rm=(r-1) and maxdim cnt=0 cnt=- a(rp,cp) - a(rp,c) - a(rp,cm) 'true =-1 cnt=cnt- a(r,cp)- a(r,cm) cnt=cnt- a(rm,cp)- a(rm,c) - a(rm,cm)

if a(r,c) then b(r,c)=iif (cnt=2 or cnt=3,true,false) else b(r,c)=iif (cnt=3,true,false) end if next next for r=0 to maxdim for c=0 to maxdim a(r,c)=b(r,c) newgen=newgen- b(r,c) next next end function </lang>

 Conway's Game of Life
 @@@@@@@@@@@@@@@@@@
 @                @
 @                @
 @                @
 @    #        #  @
 @  # #        #  @
 @   ##        #  @
 @                @
 @                @
 @                @
 @                @
 @                @
 @ ##             @
 @ #              @
 @    #           @
 @   ##           @
 @                @
 @@@@@@@@@@@@@@@@@@
 9 14

A fast version using a thechnique from Abrash's Black Book. Set your console to 34 rows minimum, as it uses a 32x32 cells world <lang vb> option explicit const pix="##" const cl_on=16 const cl_mnum=15 randomize timer const tlcr=2, tlcc=2 const maxdim =31 settitle "Conway's game of life"

dim a(31,31)

dim ans0:ans0=chr(27)&"[" dim gen,n gen=0 paintframe 'init1 'objects init2 400 'random

do

 n=nextgen
 toxy tlcr-1,tlcc+maxdim*2+4,gen & " " & n
 toxy tlcr,tlcc+maxdim*2+3,""
 gen=gen+1

loop until n=0

sub pause() wscript.stdout.write vbcrlf & "Press Enter":wscript.stdin.readline: end sub sub settitle(s) wscript.StdOut.Write chr(27)&"]0;"& s &chr(7):end sub sub cls() wscript.StdOut.Write ans0 &"2J"&ans0 &"?25l":end sub sub toxy(r,c,s) wscript.StdOut.Write ans0 & r & ";" & c & "f" & s :end sub function iif(a,b,c) if a then iif=b else iif=c end if :end function

sub init1 dim x update 0,1,1,x:update 1,2,1,x:update 2,0,1,x:update 2,1,1,x:update 2,2,1,x update 3,13,1,x:update 4,13,1,x:update 5,13,1,x update 11,1,1,x:update 11,2,1,x: update 12,1,1,x:update 12,2,1,x update 13,3,1,x:update 13,4,1,x: update 14,3,1,x:update 14,4,1,x end sub

sub init2 (n) dim i,r,c,x for i=1 to n

  do
    r=cint(rnd*maxdim)
    c=cint(rnd*maxdim)
  loop until (a(r,c) and cl_on)=0
  update r,c,1,x

next end sub

sub paintframe

 dim r,c,s
 const frame="@"
 cls
 'toxy 1,tlcc-1, "Conway's Game of Life"
 toxy tlcr-1,tlcc-1,string(maxdim*2+4,frame)
 s=frame&space(maxdim*2+2)&frame
 for r=0 to maxdim
   toxy tlcr+r,tlcc-1,s
 next
 toxy tlcr+maxdim+1,tlcc-1,string(maxdim*2+4,frame)

end sub

function nextgen()

 dim r,c,pre,cnt,a1,onoff,chg
 nextgen=0
 a1=a                                 'does a hard a copy of a
 for r=0 to maxdim
   for c=0 to maxdim
     if a1(r,c)then                'check only cells alive or having neighbors
       pre=a1(r,c) and cl_on
       cnt=a1(r,c) and cl_mnum
       'check life condition and update cell
       if pre<>0  and  (cnt<2 or cnt>3)  then
         update r,c,0,nextgen
       elseif pre=0  and cnt=3 then
         update r,c,1,nextgen
       end if
     end if
   next
  next

end function

sub update(r,c,onoff,nextgen) 'displays cell and update neighbors count in neighbors dim cp,cm,rp,rm,inc,mask

  mask=iif(onoff,cl_on,0)
  a(r,c)= (a(r,c) and cl_mnum) or mask       'update cell
  toxy tlcr+r,tlcc+c*2,iif (onoff,pix,"  ")  'display cell
  cp=(c+1) and maxdim                 'wrap around
  cm=(c-1) and maxdim
  rp=(r+1) and maxdim
  rm=(r-1) and maxdim
  if onoff then inc=1 else inc=-1
  'update count in neighbors
  a(rp,cp)=(a(rp,cp) and cl_on) or ((a(rp,cp) and cl_mnum)+inc)
  a(rp,c)=(a(rp,c) and cl_on) or ((a(rp,c) and cl_mnum)+inc)
  a(rp,cm)=(a(rp,cm) and cl_on) or ((a(rp,cm) and cl_mnum)+inc)
  a(r,cp)=(a(r,cp) and cl_on) or ((a(r,cp) and cl_mnum)+inc)
  a(r,cm)=(a(r,cm) and cl_on) or ((a(r,cm) and cl_mnum)+inc)
  a(rm,cp)=(a(rm,cp) and cl_on) or ((a(rm,cp) and cl_mnum)+inc)
  a(rm,c)=(a(rm,c) and cl_on) or ((a(rm,c) and cl_mnum)+inc)
  a(rm,cm)=(a(rm,cm) and cl_on) or ((a(rm,cm) and cl_mnum)+inc)
  nextgen=nextgen+1

end sub </lang>

Vlang

Translation of: Go

<lang vlang>import rand import strings import time

struct Field { mut: s [][]bool w int h int }

fn new_field(w int, h int) Field { s := [][]bool{len: h, init: []bool{len: w}} return Field{s, w, h} }

fn (mut f Field) set(x int, y int, b bool) { f.s[y][x] = b }

fn (f Field) next(x int, y int) bool { mut on := 0 for i := -1; i <= 1; i++ { for j := -1; j <= 1; j++ { if f.state(x+i, y+j) && !(j == 0 && i == 0) { on++ } } } return on == 3 || (on == 2 && f.state(x, y)) }

fn (f Field) state(xx int, yy int) bool { mut x, mut y := xx, yy for y < 0 { y += f.h } for x < 0 { x += f.w } return f.s[y%f.h][x%f.w] }

struct Life { mut: w int h int a Field b Field }

fn new_life(w int, h int) Life { mut a := new_field(w, h) for _ in 0..(w * h / 2) { a.set(rand.intn(w) or {0}, rand.intn(h) or {0}, true) } return Life{ a: a, b: new_field(w, h), w: w h: h, } }

fn (mut l Life) step() { for y in 0..l.h { for x in 0.. l.w { l.b.set(x, y, l.a.next(x, y)) } } l.a, l.b = l.b, l.a }

fn (l Life) str() string { mut buf := strings.new_builder(128) for y in 0..l.h { for x in 0..l.w { mut b := ' ' if l.a.state(x, y) { b = '*' } buf.write_string(b) } buf.write_string('\n') } return buf.str() }

fn main() { mut l := new_life(80, 15) for i := 0; i < 300; i++ { l.step() //println("------------------------------------------------") print('\x0c') println(l) time.sleep(time.second / 30) } }</lang>

Output:

Generation 300:

               **                                                   ***   *     
                *                                                         **    
                *           *                                             **    
                           ** **              **                           *    
                              **              **                                
                       ** *** * *                                               
                   ******  *                                                    
                   * *                                          **              
                   * * **                                      *  *             
                    **                                          * *      **     
             **      * *     *                                   *       **     
            *  *           ** **                                                
            * *            ** *                                                 
              **             *  

Wren

Translation of: Kotlin

<lang ecmascript>import "random" for Random import "timer" for Timer

var Rand = Random.new(0) // using a constant seed to produce same output on each run

// patterns var BLINKER = 0 var GLIDER = 1 var RANDOM = 2

class Field {

   construct new(w, h) {
       _w = w
       _h = h
       _s = List.filled(h, null)
       for (i in 0...h) _s[i] = List.filled(w, false)
   }
   [x, y]=(b) { _s[y][x] = b }
   state(x, y) {
       if (!(0..._w).contains(x) || !(0..._h).contains(y)) return false
       return _s[y][x]
   }
   next(x, y) {
       var on = 0
       for (i in -1..1) {
           for (j in -1..1) {
                if (state(x + i, y + j) && !(j == 0 && i == 0)) on = on + 1
           }
       }
       return on == 3 || (on == 2 && state(x, y))
   }

}

class Life {

   construct new(pattern) {
       if (pattern == BLINKER) {
           _w = 3
           _h = 3
           _a = Field.new(_w, _h)
           _b = Field.new(_w, _h)
           _a[0, 1] = true
           _a[1, 1] = true
           _a[2, 1] = true
       } else if (pattern == GLIDER) {
           _w = 4
           _h = 4
           _a = Field.new(_w, _h)
           _b = Field.new(_w, _h)
           _a[1, 0] = true
           _a[2, 1] = true
           for (i in 0..2) _a[i, 2] = true
       } else if(pattern == RANDOM) {
            _w = 80
            _h = 15
            _a = Field.new(_w, _h)
            _b = Field.new(_w, _h)
           for (i in 0...(_w * _h).floor / 2) {
               _a[Rand.int(_w), Rand.int(_h)] = true
           }
       }
   }
   step() {
       for (y in 0..._h) {
           for (x in 0..._w) _b[x, y] = _a.next(x, y)
       }
       var t = _a
       _a = _b
       _b = t
   }
   toString {
       var sb = ""
       for (y in 0..._h) {
           for (x in 0..._w) {
               var c = _a.state(x, y) ? "#" : "."
               sb = sb + c
           }
           sb = sb + "\n"
       }
       return sb
   }

}

var lives = [

   [Life.new(BLINKER),  3, "BLINKER"],
   [Life.new(GLIDER),   4, "GLIDER" ],
   [Life.new(RANDOM), 100, "RANDOM" ]

]

for (t in lives) {

   var game  = t[0]
   var gens  = t[1]
   var title = t[2]
   System.print("%(title):\n")
   for (i in 0..gens) {
       System.print("Generation: %(i)\n%(game)")
       Timer.sleep(30)
       game.step()
   }
   System.print()

}</lang>

Output:

Just shows generations 0 and 100 for RANDOM pattern:

BLINKER:

Generation: 0
...
###
...

Generation: 1
.#.
.#.
.#.

Generation: 2
...
###
...

Generation: 3
.#.
.#.
.#.


GLIDER:

Generation: 0
.#..
..#.
###.
....

Generation: 1
....
#.#.
.##.
.#..

Generation: 2
....
..#.
#.#.
.##.

Generation: 3
....
.#..
..##
.##.

Generation: 4
....
..#.
...#
.###


RANDOM:

Generation: 0
#.#.###.#...#...#..##.....#......#....#...#.....#...#..#..#.....##.##....#..####
..#...#....#.##..#..#...##.#.....#....#..##.#.###..#.#.#.#..#.##..#.#.......#.#.
###.###..##...#......#.#.#............#.......##.#..#...###.##..#...###...#..#..
.#.....#.#.#.#.#..###.#.#.######...##..##.###.####....#....#####..##...####.#..#
..##.###.#..###...#..#..##....##...#..##.##.#..###.#..#..#.#...##..#..###.......
.####..###.##..#..#...#..#..#.##..#..........##.#..#.....#.###.#...######.#..#..
...##...#.....##.....##.##..#..#####...##.###.#.###..#..#.#.....##.#..##....##.#
##...##.#...#.#...##.##..#.#..##.#....###.##.#.....#.##..#..#.##..#....##......#
....#.#..##.#..####..#..##....#####.#....#.#...#.#.###.#.#.#.#.#.....#...#.....#
..#..####..###..###..##.####.#....#.....#.###.#.#.###.####..#...#...#...#.##....
#.........##..#..##...###...#..#....#.###...#.##.....###..###..##....###.#..#...
.#..#..#......#...##.###.#...#.#...##.#.....#...#......##..#.....###...##..#.#..
.#.#.....##..#.##.....#.#.#..#.#..######.#....#..##...##.##.....#..##...#.##.##.
.#......###..#...###..........................##......#....####.#...#..#...#..#.
#..#.#......#...#...#...#..#..##...#.##...#.####.##......#....#..#.##.....#####.

Generation: 100
...............####......#......................................................
...............#..#.....#.#...................#.................................
........................#.#.................##..................................
.........................#..................##............##....................
............................................#.....#.......##....................
.............................................#.###..............................
...................................##...###.....#####...........................
........................##........#..#..###........#............................
.......................#..#...........#....##...................................
.......................#....#.......#....###....................................
........................######.....##....##.....................................
...........................#.##.....#..#..........................##.##.........
...........................#.#.......##...........................##.##.........
......##...................##...................................................
......##........................................................................

XPL0

<lang XPL0>def M=3; \array size char NowGen(M+2, M+2), \size with surrounding borders

       NewGen(M+2, M+2);

int X, Y, I, J, N, Gen; code ChOut=8, CrLf=9;

[for Y:= 0 to M+1 do \set up initial state

   for X:= 0 to M+1 do
       [NowGen(X,Y):= ^ ;  NewGen(X,Y):= ^ ];

NowGen(1,2):= ^#; NowGen(2,2):= ^#; NowGen(3,2):= ^#;

for Gen:= 1 to 3 do

       [for Y:= 1 to M do                      \show current generation
           [for X:= 1 to M do [ChOut(0, NowGen(X,Y));  ChOut(0,^ )];
           CrLf(0);
           ];
       CrLf(0);
       for Y:= 1 to M do                       \determine next generation
           for X:= 1 to M do
               [N:= 0;                         \count adjacent live (#) cells
               for J:= Y-1 to Y+1 do
                   for I:= X-1 to X+1 do
                       if NowGen(I,J) = ^# then N:= N+1;
               if NowGen(X,Y) = ^# then N:= N-1;       \don't count center
               NewGen(X,Y):= ^ ;                       \assume death
               if N=2 then NewGen(X,Y):= NowGen(X,Y)   \actually no change
               else if N=3 then NewGen(X,Y):= ^#;      \actually birth
               ];
       I:= NowGen;  NowGen:= NewGen;  NewGen:= I;      \swap arrays
       ];

]</lang>

Output:
      
# # # 
      

  #   
  #   
  #   

      
# # #

XSLT

So when the following templates <lang xml><xsl:template match="/table">

<xsl:apply-templates />

</xsl:template>

<xsl:template match="tr">

<xsl:apply-templates /> </xsl:template> <xsl:template match="td"> <xsl:variable name="liveNeighbours"> <xsl:apply-templates select="current()" mode="countLiveNeighbours" /> </xsl:variable> <xsl:choose> <xsl:when test="(current() = 'X' and $liveNeighbours = 2) or $liveNeighbours = 3"> <xsl:call-template name="live" /> </xsl:when> <xsl:otherwise> <xsl:call-template name="die" /> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="td" mode="countLiveNeighbours"> <xsl:variable name="currentX" select="count(preceding-sibling::td) + 1" /> <xsl:variable name="precedingRow" select="parent::tr/preceding-sibling::tr[1]" /> <xsl:variable name="followingRow" select="parent::tr/following-sibling::tr[1]" /> <xsl:variable name="neighbours" select="$precedingRow/td[$currentX - 1] | $precedingRow/td[$currentX] | $precedingRow/td[$currentX + 1] | preceding-sibling::td[1] | following-sibling::td[1] | $followingRow/td[$currentX - 1] | $followingRow/td[$currentX] | $followingRow/td[$currentX + 1]" /> <xsl:value-of select="count($neighbours[text() = 'X'])" /> </xsl:template> <xsl:template name="die"> _

</xsl:template>

<xsl:template name="live">

X

</xsl:template></lang> are applied against the document

<lang html>

_X_
_X_
_X_

</lang>

then the transformed XML document contains the new universe evolved by one tick:

<lang html>

___
XXX
___

</lang>

Z80 Assembly

Works with: zmac version 5nov2016

This code will run on an MSX computer if progammed on a cartride or on an emulator (like openMSX) if loaded as a .rom file

The code below will show the Gosper glider gun, but if INITLINES is set to 0 the code will show the blinker

<lang z80>;MSX Bios calls CHPUT equ 000A2H ;print character A CHGET equ 0009FH ;wait for keyboard input INITXT equ 0006CH ;init TEXT1 mode (40 x 24), based on TXTNAM,TXTCGP and LINL40 LDIRVM equ 0005CH ;write BC times MEM(HL++) to VRAM(DE++)

MSX system variables

TXTNAM equ 0F3B3H ;pattern name table TXTCGP equ 0F3B7H ;pattern generator table LINL40 equ 0F3AEH ;line length

defines

LIFE_CHAR equ 0xDB ;MSX all-pixels-on character

variables

screen equ 0E000H ;40x24 bytes scratch equ screen+(40*24) ;table for calculations


         org 04000H

HEADER ;first 16 bytes of the rom. (as specified by MSX standard)

         db "AB"             ;id
         dw Main             ;init
         dw 0                ;statement
         dw 0                ;device
         dw 0                ;text
         dw 0                ;reserved
         dw 0                ;reserved
         dw 0                ;reserved

init_tab1 db 0x18

         dc 7, 0x17 
         db " Conway's Game Of Life "
         dc 8, 0x17
         db 0x19
         db 0x16
         dc 38, " "
         db 0x16, 0x1A
         dc 38, 0x17
         db 0x1B

init_tab2 dc 41, 0x80

         dc 38, 0
         dc 41, 0x80

INITLINES equ 10 init_tab3 db " "

         db "                          X             "
         db "                        X X             "
         db "              XX      XX            XX  "
         db "             X   X    XX            XX  "
         db "  XX        X     X   XX                "
         db "  XX        X   X XX    X X             "
         db "            X     X       X             "
         db "             X   X                      "
         db "              XX                        "

Expand ld bc, 40

         ldir                ;copy top line
         push de
         ld bc, 40
         ldir                ;copy first middle line
         ex (sp), hl
         ld bc, 40*21
         ldir                ;repeat middle line
         pop hl
         ld bc, 40           ;copy bottom line
         ldir
         ret

InitGOL ;create empty screen

         ld hl, init_tab1
         ld de, screen
         call Expand
         ;Now add intial pattern

if INITLINES

         ld hl, init_tab3    ;glider gun start pattern
         ld de, init_tab3    ;de=hl, so ldi does not change RAM
         ld bc, 40*INITLINES
         ld ix, screen+40

InitGOLl ld a, (hl)

         cp 'X'
         jr nz, InitGOLe
         ld (ix), LIFE_CHAR

InitGOLe inc ix

         ldi                 ;hl++ and bc-- (with flag!)
         jp pe, InitGOLl          

else

         ld hl, screen+(4*40)+18
         ld a, LIFE_CHAR     ;blinker start pattern
         ld (hl), a
         inc hl
         ld (hl), a
         inc hl
         ld (hl), a

endif

         ret
         

DoGOL ld hl, init_tab2 ;initialize scratchpad (sums to zero, borders marked)

         ld de, scratch
         call Expand
         ;first loop: create sums in scratchpad
         ld bc, 40*24
         ld hl, screen
         ld de, screen       ;de=hl, so ldi does not change RAM
         ld ix, scratch          

DoGOLsuml ld a, (hl)

         cp LIFE_CHAR        ;if cell is alive increase sums of all surrounding cells
         jr nz, DoGOLsume
         inc (ix-41)
         inc (ix-40)
         inc (ix-39)
         inc (ix-1)
         inc (ix+1)
         inc (ix+39)
         inc (ix+40)
         inc (ix+41)

DoGOLsume inc ix

         ldi                 ;hl++, bc-- (with flag!)
         jp pe, DoGOLsuml
         ;second loop: update cell based on current state and sum
         ld bc, 40*24
         ld hl, screen
         ld de, screen       ;de=hl, so ldi does not change RAM
         ld ix, scratch

DoGOLupdl ld a, (ix)

         cp 0x7f             ;border -> keep the same
         jr nc, DoGOLupde
         cp 3                ;3 neighbors-> always live
         jr z, DoGOLlive
         cp 2
         jr z, DoGOLupde     ;2 -> stay the same          

DoGOLdie ld (hl), 0x20 ;1,4,5,6,7,8 -> always die

         jr DoGoLupde

DoGOLlive ld (hl), LIFE_CHAR DoGOLupde inc ix

         ldi                 ;hl++, bc-- (with flag!)
         jp pe, DoGOLupdl
         ret

Main

         call INITXT
         call InitGOL          

Mainloop ld hl, screen

         ld de, (TXTNAM)
         ld bc, 40*24
         call LDIRVM
         ;call CHGET
         call DoGOL
         jr Mainloop
         
         ;force 16k ROM size binary output

EndOfCode dc 0x8000 - EndOfCode, 0xFF

         end</lang>

Yabasic

This example does not show the output mentioned in the task description on this page (or a page linked to from here). Please ensure that it meets all task requirements and remove this message.
Note that phrases in task descriptions such as "print and display" and "print and show" for example, indicate that (reasonable length) output be a part of a language's solution.


Translation of: BASIC256

<lang Yabasic>// Conway's_Game_of_Life

X = 59 : Y = 35 : H = 4

open window X*H,Y*H backcolor 0, 0, 0

dim c(X,Y) : dim cn(X,Y) : dim cl(X,Y)

// Thunderbird methuselah c(X/2-1,Y/3+1) = 1 : c(X/2,Y/3+1) = 1 : c(X/2+1,Y/3+1) = 1 c(X/2,Y/3+3) = 1 : c(X/2,Y/3+4) = 1 : c(X/2,Y/3+5) = 1

s = 0 repeat

   clear window
   alive = 0 : stable = 1
   s = s + 1
   for y = 0 to Y-1 
       for x = 0 to X-1
           xm1 = mod(x-1+X, X) : xp1 = mod(x+1+X, X)
           ym1 = mod(y-1+Y, Y) : yp1 = mod(y+1+Y, Y)
           cn(x,y) = c(xm1,y) + c(xp1,y)
           cn(x,y) = c(xm1,ym1) + c(x,ym1) + c(xp1,ym1) + cn(x,y)
           cn(x,y) = c(xm1,yp1) + c(x,yp1) + c(xp1,yp1) + cn(x,y)
           if c(x,y) = 1 then
               if cn(x,y) < 2 or cn(x,y) > 3 then 
                   cn(x,y) = 0
               else 
                   cn(x,y) = 1
                   alive = alive + 1
               end if
           else 
               if cn(x,y) = 3 then 
                   cn(x,y) = 1
                   alive = alive + 1
               else
                   cn(x,y) = 0
               end if
           end if
           if c(x,y) then
               if cn(x,y) then
                   if cl(x,y) color 0, 0, 255          // adult
                   if not cl(x,y) color 0, 255, 0      // newborn
               else 
                   if cl(x,y) color 255, 0, 0          // old
                   if not cl(x,y) color 255, 255, 0    // shortlived
               end if 
               fill rect x*H,y*H,x*H+H,y*H+H
           end if
       next x
   next y
   pause 0.06
   // Copy arrays
   for i = 0 to X-1
       for j = 0 to Y-1
           if cl(i,j)<>cn(i,j) stable = 0
           cl(i,j) = c(i,j)
           c(i,j) = cn(i,j)
       next j
   next i  

until(not alive or stable)

if not alive then

   print "Died in ", s, " iterations"
   clear window

else

   print "Stabilized in ", s-2, " iterations"  

end if</lang>

zkl

<lang zkl>class Life{

  fcn init(n, r1,c1, r2,c2, etc){
     var N=n, cells=Data(n*n), tmp=Data(n*n),
       ds=T(T(-1,-1),T(-1,0),T(-1,1), T(0,-1),T(0,1), T(1,-1),T(1,0),T(1,1));
     icells:=vm.arglist[1,*];
     (N*N).pump(Void,cells.append.fpM("1-",0));	// clear board
     icells.pump(Void,Void.Read,fcn(row,col){ cells[row*N+col]=1 });
  }
  fcn get(row,col){
     if((0<=row<N) and (0<=col<N)) return(cells[row*N+col]);
     return(0);
  }
  fcn postToastie(row,col){
     n:=ds.reduce('wrap(n,[(r,c)]){n+get(r+row,c+col)},0);
     c:=get(row,col);
     ((n==2 and c==1) or n==3).toInt()
  }
  fcn cycle{
     tmp.clear();
     foreach row in (N){ foreach col in (N) { 
        tmp.append(postToastie(row,col)) } }
     t:=cells; cells=tmp; tmp=t;
  }
  fcn toString{
     cells.pump(0,String,fcn(c,rn){
        (if(c)"*" else "-") + (if(rn.inc()%N) "" else "\n")
     }.fp1(Ref(1)));
  }
  fcn toAnsi{
     cells.pump(0,"\e[H",fcn(c,rn){
        (if(c)"\e[07m  \e[m" else "  ") + (if(rn.inc()%N) "" else "\e[E")
     }.fp1(Ref(1)));
  }
  fcn dance(n=300){ do(n){ toAnsi().print(); Atomic.sleep(0.2); cycle(); } }

}</lang> The data structure is a Data, which is a linear block of bytes. <lang zkl>cells:=Life(4, 0,1, 1,1, 2,1); // blinker do(3){ cells.println("="*4); cells.cycle(); }

cells:=Life(30, 0,1, 1,2, 2,0, 2,1, 2,2); // glider cells.dance(100);</lang>

Output:

Just the glider (reformatted), if you have an ANSI terminal (eg xterm), you'll see the glider moving down the screen.

-*--    ----   -*--
-*--    ***-   -*--
-*--    ----   -*--
----    ----   ----
====    ====   ====

ZPL

<lang ZPL>program Life;

config var

    n : integer = 100;

region

    BigR = [0 .. n+1, 0 .. n+1];
    R    = [1 .. n,   1 .. n  ];

direction

    nw   = [-1, -1]; north = [-1, 0]; ne   = [-1, 1];
    west = [ 0, -1];                  east = [ 0, 1];
    sw   = [ 1, -1]; south = [ 1, 0]; se   = [ 1, 1];

var

    TW   : [BigR] boolean; -- The World
    NN   : [R]    integer; -- Number of Neighbours

procedure Life(); begin

    -- Initialize world
    [R]  repeat
         NN := TW@nw   + TW@north + TW@ne   +
               TW@west +            TW@east + 
               TW@sw   + TW@south + TW@se;
         TW := (TW & NN = 2) | ( NN = 3);
    until !(|<< TW);

end;</lang>

ZX Spectrum Basic

Play on emulator at full speed for reasonable performance.

The ZX Spectrum was shipped with a demo tape called Horizons, which included an implementation of Life; however, it relied on machine code. <lang zxbasic>10 REM Initialize 20 LET w=32*22 30 DIM w$(w): DIM n$(w) 40 FOR n=1 TO 100 50 LET w$(RND*w+1)="O" 60 NEXT n 70 REM Loop 80 FOR i=34 TO w-34 90 LET p$="": LET d=0 100 LET p$=p$+w$(i-1)+w$(i+1)+w$(i-33)+w$(i-32)+w$(i-31)+w$(i+31)+w$(i+32)+w$(i+33) 110 LET n$(i)=w$(i) 120 FOR n=1 TO LEN p$ 130 IF p$(n)="O" THEN LET d=d+1 140 NEXT n 150 IF (w$(i)=" ") AND (d=3) THEN LET n$(i)="O": GO TO 180 160 IF (w$(i)="O") AND (d<2) THEN LET n$(i)=" ": GO TO 180 170 IF (w$(i)="O") AND (d>3) THEN LET n$(i)=" " 180 NEXT i 190 PRINT AT 0,0;w$ 200 LET w$=n$ 210 GO TO 80</lang>