[bb] Conway's Life Algorithm by Gary B [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:40

Previous topic - Next topic

BlitzBot

Title : Conway's Life Algorithm
Author : Gary B
Posted : 1+ years ago

Description : This is a small, fast implementation of Conway's life algorithm.
I have well documented it, and I am fairly pleased with it.
It could be made heaps faster with an external DLL, but then it wouldn't be all Blitz Code would it :)
I hope that someone finds it useful.


Code :
Code: blitzbasic
; Conway's Game of Life
; Coded by Gary Barnes - The Control Key (June 2005)
; I did it because I could, and it was interesting.
; A little raw, but optimised for speed
; It isn't very fancy and could stand tarting up a little
; Still it fair blitzters along given that it is updating 
; 960,000 array elements And 480,000 pixels Each display redraw

; Maybe someone will find it useful, or at least mildly interesting

Global w = 800
Global h = 600 ; size of a board (increase the size If you like)


Graphics w,h
SetBuffer BackBuffer() 


Dim tG(w,h)			; this generation
Dim nG(w,h)			; next generation

h=h-1				; set height for life array - 1 less than the screen height to avoid boundary problems
w=w-1				; set width - look above

SeedRnd MilliSecs()	; reset the random number generator	

Color 255,255,255	; set the colour of the writepixel fast routine for later
Plot 0,0
tcol = ReadPixel(0,0)

ClsColor 0,0,64		; I liked white on blue, change it at will

Repeat				; main program loop
   For y = 1 To H	; seed this generation array randomly
       For x = 1 To W
           z = Rnd(1,10)	; change from 10 to whatever you like - 2 is too crowded 
           If z = 1 Then tG(x,y) = 1 ; between 10 and 50 odd gives a pleasing result
       Next
   Next

   Repeat
      If Rnd(0,99) > 90 Then		; sets a 10% chance of reseeding a small part of the current generation matrix
         rsx = Rnd(10,w-20)
         rsy = Rnd(10,h-20)
  
         For p = 0 To 9				; do it 10 times 
             rx = Rnd(rsx,rsx+5)
             ry = Rnd(rsy,rsy+5)
             tg(rx,ry) = 1
         Next 
      EndIf
      Gosub paintscreen				; draw it
      dummy = GetKey()				; get something from the keyboard buffer
      If dummy = 32 Then WaitKey()	; it is space so pause the program
      If dummy = 27 Then End 		; it is escape so stop
   Forever 
Forever

End

.PaintScreen
For y = 1 To H
    For x = 1 To W
        sum = 0 
        sum = sum + tg(x-1,y-1) + tg(x,y-1) + tg(x+1,y-1) 	; life needs to know how many neighbours a cell has
        sum = sum + tg(x-1,y)   + tg(x+1,y) 				; this routine just adds up the number of occupied cells
        sum = sum + tg(x-1,y+1) + tg(x,y+1) + tg(x+1,Y+1)   ; around the one of interest - tg(x,y)
        Select sum                                          ; implement the algorithm
               Case 2  : If tg(x,y) = 1 Then ng(x,y) = 1 	; if the cell is alive and it has two neighbours it stays alive
               Case 3  : ng(x,y) = 1                        ; if any cell has three neighbours it bursts into life or stays alive   
               Default : ng(x,y) = 0						; for any other sum, the cells dies if it is alive
        End Select											; that is it - life game all done
	Next
Next


Cls															; clear the screen as we only write pixels if we have to
LockBuffer													; as the little routine is optimised for speed
For y = 1 To H
    For x = 1 To W
        If tg(x,y) > 0 Then WritePixelFast x,y,tcol
        tg(x,y) = ng(x,y)									; copy the next generation to the current generation to display later
    Next
Next
UnlockBuffer	; you have to lock then unlock the screen buffer otherwise writepixelfast won't work !
Flip			; all done display the new page and return						

Return


Comments :


Gary B(Posted 1+ years ago)

 Hi GroupI have revisited the code and this version is smaller and faster than the version above.Of course it compiles to the same size.I hope you enjoy the newer version.; Conway's Game of Life; Coded by Gary Barnes - The Control Key (June 2005); Smaller and faster than the previous versionGlobal w = 800Global h = 600Graphics w,hSetBuffer BackBuffer() Dim tG(w,h)   Dim nG(w,h)   h=h-1w=w-1SeedRnd MilliSecs()Color 255,255,255Plot 0,0tcol = ReadPixel(0,0)ClsColor 0,0,64For y = 1 To H    For x = 1 To W        z = Rnd(1,10)        If z = 1 Then tG(x,y) = 1    NextNextRepeat   If Rnd(0,99) > 90 Then      rsx = Rnd(10,w-20)      rsy = Rnd(10,h-20)        For p = 0 To 9          rx = Rnd(rsx,rsx+5)          ry = Rnd(rsy,rsy+5)          tg(rx,ry) = 1      Next    EndIf   Cls   LockBuffer   For y = 1 To H       For x = 1 To W           sum = 0            sum = sum + tg(x-1,y-1) + tg(x,y-1) + tg(x+1,y-1) + tg(x-1,y) + tg(x+1,y) + tg(x-1,y+1) + tg(x,y+1) + tg(x+1,Y+1)           If sum = 2 Then ng(x,y) = tg(x,y)                              If sum = 3 Then ng(x,y) = 1                                  If tg(x,y) > 0 Then WritePixelFast x,y,tcol     Next   Next   UnlockBuffer   Flip   For y = 1 To H       For x = 1 To W           tg(x,y) = ng(x,y)       Next   Next   Dim nG(w,h)     dummy = GetKey()   If dummy > 0 Then                  If dummy = 32 Then WaitKey()         If dummy = 27 Then End          EndIfForever End


Rck(Posted 1+ years ago)

 
Code: BASIC
; Conway's Game of Life
; Coded by Gary Barnes - The Control Key (June 2005)
; Smaller and faster than the previous version

;comments, format, interactivity Martin Ahrens (October 2005)


;this simulation starts out paused, use space to toggle simulation's active condition
;use the mouse
	;left click add to current position
	;right click delete current position
	;middle click clear entire board
;use Esc to quit the program



Global w = 800
Global h = 600

Graphics w,h,0,1 ;setup fullscreen with above width and height

Dim tG(w, h)
Dim nG(w, h)

;decrement width and height accounting for 0 to (n-1) nature of screens
w = w - 1
h = h - 1

SeedRnd MilliSecs()

;create white life pixel, red mouse cursor ,and blue background
Color 255, 255, 255
Plot 0, 0
tcol = ReadPixel(0, 0)

Color 255, 0, 0
Plot 0, 0
curcol = ReadPixel(0, 0)

ClsColor 0, 0, 64


;init the board with a 10% coverage density
For y = 1 To H
	For x = 1 To W
		z = Rnd(1, 100)
		If z <= 0 Then tG(x,y) = 1
	Next
Next

;run main life simulation
Repeat
	
	;get keys for pause and escape
	dummy = GetKey()
	If dummy > 0 Then
		If dummy = 32 Then toSim = Not(toSim) ;space toggles simulation action
		
		If (dummy = 65) Or (dummy = 97) Then
			;randomly populate 10 life units away from board edges
			rsx = Rnd(10, w - 20)
			rsy = Rnd(10, h - 20)
			
			For p = 0 To 9
				rx = Rnd(rsx, rsx + 5)
				ry = Rnd(rsy, rsy + 5)
				tg(rx, ry) = 1
			Next
		EndIf
		
		If dummy = 27 Then End
	EndIf
	
	;mouse interaction
	msx = MouseX()
	msy = MouseY()
	If MouseDown(1) Then ;left click to add life unit
		If toSim Then
			ng(msx, msy) = 1
		Else
			tg(msx, msy) = 1
		EndIf
	EndIf
	If MouseDown(2) Then ;right click delete life unit
		tg(msx, msy) = 0
	EndIf
	If MouseDown(3) Then ;mid mouse clear out board
		For y = 0 To H
			For x = 0 To W
				tg(x, y) = 0
			Next
		Next
	EndIf
	
	
	;predict next state and draw every life unit
	Cls
	LockBuffer
	For y = 1 To H
		For x = 1 To W
			If toSim Then
				sum = 0
				sum = sum + tg(x-1,y-1) + tg(x,y-1) + tg(x+1,y-1) + tg(x-1,y) + tg(x+1,y) + tg(x-1,y+1) + tg(x,y+1) + tg(x+1,Y+1)
				If sum = 2 Then ng(x,y) = tg(x,y)
				If sum = 3 Then ng(x,y) = 1
			EndIf
			If tg(x, y) > 0 Then WritePixelFast x, y, tcol
		Next
	Next
	WritePixelFast msx, msy, curcol
	UnlockBuffer
	
	Flip(True) ;can be set to false for overspeed
	
	;set current state to next state, clear out next state
	If toSim Then
		For y = 1 To H
			For x = 1 To W
				tg(x,y) = ng(x,y)
			Next
		Next
		Dim nG(w,h)
	EndIf
	
Forever
I added comments and modifications for user interaction to this one, directions are at top


Subirenihil(Posted 1+ years ago)

 Nice! :) [/i]

Filax

Code: BASIC
; Conway's Game of Life - Enhanced version with zoom and navigation
; Original by Gary Barnes, restructured and improved in 2025

; Code cleaning and zoom/pan scroll functions added by Filax (C)2025


Global w = 800
Global h = 600
Global tcol

Dim tG(w,h)    ; This generation
Dim nG(w,h)    ; Next generation

; Variables for virtual camera
Global camX# = w / 2    ; X position of camera center
Global camY# = h / 2    ; Y position of camera center
Global camZoom# = 1.0   ; Zoom factor (1.0 = normal view)

Function Main()
    Graphics w, h, 32, 2
    SetBuffer BackBuffer()
    
    ; Adjust dimensions to avoid border issues
    h = h - 1
    w = w - 1
    
    ; Initialization
    SeedRnd MilliSecs()
    SetupGraphics()
    InitializeGrid()
    
    ; Main loop
    While Not KeyHit(1)    ; Until ESC key is pressed
        HandleInput()       ; Handle controls
        If Rnd(0,99) > 90 Then RandomSeed()
        UpdateGeneration()
        RenderScreen()
        
        If KeyHit(57) Then WaitKey()    ; Pause with SPACE, wait for keypress to resume
    Wend
    
    End
End Function

Function SetupGraphics()
    Color 255, 255, 255
    Plot 0, 0
    tcol = ReadPixel(0, 0)
    ClsColor 0, 0, 64
End Function

Function InitializeGrid()
    ; Initialize grid with higher density: 1 in 5 chance instead of 1 in 10
    For y = 1 To h
        For x = 1 To w
            If Rnd(1,5) = 1 Then tG(x,y) = 1
        Next
    Next
End Function

Function RandomSeed()
    Local rsx = Rnd(10, w-20)
    Local rsy = Rnd(10, h-20)
    
    ; Add more points (15 instead of 10)
    For p = 0 To 14
        Local rx = Rnd(rsx, rsx+5)
        Local ry = Rnd(rsy, rsy+5)
        tG(rx,ry) = 1
    Next
End Function

Function UpdateGeneration()
    For y = 1 To h
        For x = 1 To w
            Local sum = CountNeighbors(x, y)
            Select sum
                Case 2: If tG(x,y) = 1 Then nG(x,y) = 1 Else nG(x,y) = 0
                Case 3: nG(x,y) = 1
                Default: nG(x,y) = 0
            End Select
        Next
    Next
End Function

Function CountNeighbors(x, y)
    Local sum = 0
    ; Check borders to avoid out-of-bounds access
    For dy = -1 To 1
        For dx = -1 To 1
            If dx <> 0 Or dy <> 0 Then
                Local nx = x + dx
                Local ny = y + dy
                If nx >= 1 And nx <= w And ny >= 1 And ny <= h Then
                    sum = sum + tG(nx,ny)
                EndIf
            EndIf
        Next
    Next
    Return sum
End Function

Function RenderScreen()
    Cls
    LockBuffer
    
    ; Calculate visible limits with zoom and camera position
    Local viewWidth# = w / camZoom
    Local viewHeight# = h / camZoom
    Local xMin = Max(1, Floor(camX - viewWidth / 2))
    Local xMax = Min(w, Ceil(camX + viewWidth / 2))
    Local yMin = Max(1, Floor(camY - viewHeight / 2))
    Local yMax = Min(h, Ceil(camY + viewHeight / 2))
    
    For y = yMin To yMax
        For x = xMin To xMax
            If tG(x,y) > 0 Then
                ; Project grid coordinates to screen space
                Local screenX# = (x - (camX - viewWidth / 2)) * camZoom
                Local screenY# = (y - (camY - viewHeight / 2)) * camZoom
                If screenX >= 0 And screenX < w And screenY >= 0 And screenY < h Then
                    WritePixelFast screenX, screenY, tcol
                EndIf
            EndIf
            tG(x,y) = nG(x,y)    ; Copy next generation
        Next
    Next
    
    UnlockBuffer
    Flip
End Function

Function HandleInput()
    ; Camera movement
    If KeyDown(200) Then camY = camY - 5 / camZoom ; Up
    If KeyDown(208) Then camY = camY + 5 / camZoom ; Down
    If KeyDown(203) Then camX = camX - 5 / camZoom ; Left
    If KeyDown(205) Then camX = camX + 5 / camZoom ; Right
    
    ; Zoom with keys
    If KeyHit(78) Then camZoom = camZoom * 1.1  ; '+' key (zoom in)
    If KeyHit(74) Then camZoom = camZoom / 1.1  ; '-' key (zoom out)
    
    ; Zoom with mouse
    If MouseHit(1) Then ZoomAtPoint(MouseX(), MouseY(), 2.0) ; Left click: zoom in
    
    ; Add points with middle click
    If MouseHit(3) Then AddPointAtMouse(MouseX(), MouseY())
    
    ; Zoom out with right click
    If MouseHit(2) Then ZoomAtPoint(MouseX(), MouseY(), 0.5) ; Right click: zoom out
    
    ; Limit zoom and position
    camZoom = Max(0.1, Min(camZoom, 10.0))
    camX = Max(w / camZoom / 2, Min(camX, w - w / camZoom / 2))
    camY = Max(h / camZoom / 2, Min(camY, h - h / camZoom / 2))
End Function

Function ZoomAtPoint(mx%, my%, zoomFactor#)
    ; Convert screen coordinates to grid coordinates
    Local viewWidth# = w / camZoom
    Local viewHeight# = h / camZoom
    Local gridX# = camX - viewWidth / 2 + (mx / Float(w)) * viewWidth
    Local gridY# = camY - viewHeight / 2 + (my / Float(h)) * viewHeight
    
    ; Adjust camera to center on this point after zooming
    camZoom = camZoom * zoomFactor
    camZoom = Max(0.1, Min(camZoom, 10.0))
    
    viewWidth = w / camZoom
    viewHeight = h / camZoom
    
    camX = gridX
    camY = gridY
    
    ; Limit position
    camX = Max(w / camZoom / 2, Min(camX, w - w / camZoom / 2))
    camY = Max(h / camZoom / 2, Min(camY, h - h / camZoom / 2))
End Function

Function AddPointAtMouse(mx%, my%)
    ; Convert screen coordinates to grid coordinates
    Local viewWidth# = w / camZoom
    Local viewHeight# = h / camZoom
    Local gridX = Floor(camX - viewWidth / 2 + (mx / Float(w)) * viewWidth)
    Local gridY = Floor(camY - viewHeight / 2 + (my / Float(h)) * viewHeight)
    
    ; Add a cell if within bounds
    If gridX >= 1 And gridX <= w And gridY >= 1 And gridY <= h Then
        tG(gridX, gridY) = 1
    EndIf
End Function

; Utility functions
Function Max#(a#, b#)
    If a > b Then Return a Else Return b
End Function

Function Min#(a#, b#)
    If a < b Then Return a Else Return b
End Function

Function Floor#(x#)
    Return Int(x)
End Function

Function Ceil#(x#)
    If x = Int(x) Then Return x
    Return Int(x) + 1
End Function

Main()