Speed Test: Conways Life

BlitzMax Forums/BlitzMax Programming/Speed Test: Conways Life

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

Conways Life comes to Max.

(Note: 2 versions here for speed testers)

On my rig the Max version hammers the Blitz3D/2D equivalent. Try watching the gliders. The FPS and timers will indicate this as well.

BlitzMax version
Rem
 MaxLife - a fast implementation of Conway's Life in BlitzMax.
  by Mike Keith, Feb 2002
  Re-coded for BlitzMax by jb, Feb 2005
 
 Optimizations implemented here include:
 (1) Cell neighbors are not counted each time; rather, the state and number of
   neighbors each cell has are kept continually updated in an array.  This array only
   needs to be updated when a cell changes.
 (2) When neighbors _do_ have to be updated, it's done with an average of 4.5 operations
   instead of 9, via pseudo-SIMD.
 (3) Single cells and groups of 4x1 cells that are not alive and have no neighbors
   are quickly skipped.
 (4) The world is tiled, and tiles that do not need to be copied or updated are quickly skipped.
   (Skipping the copy is the big win here.)

 Overall speed depends on how many active cells there are.
EndRem

Strict
Framework BRL.GLMax2D
Import BRL.Retro
Import BRL.System



Const xres=512,yres=384

Graphics xres,yres
SetClsColor 0,20,70
	
Const col=$ffff, BlockSize = 40
Global stride,arraysize, back, offset,val,x,y, changed

arraysize = xres*yres/4
Global world1[arraysize+1],world2[arraysize+1]
Global table[32+1],ClearAction[32+1],SetAction[32+1],DrawAction[32+1]
Global xresb,yresb,occupied

xresb = xres/blocksize; yresb = yres/blocksize
Global BlockState1[xresb+1,yresb+1],BlockState2[xresb+1,yresb+1],haschanged[xresb+1,yresb+1],foo[2+1]

Global GenStop=99999

stride = xres/4
'back = BackBuffer()

For Local i=0 To 31; ReadData DrawAction[i]; Next
DefData 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0
DefData 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0

For Local i=0 To 31
	Local state = i/16
	Local nxt = DrawAction[i]
	
	If (state=0 And nxt=1) Then SetAction[i] = 1
	If (state=1 And nxt=0) Then ClearAction[i] = 1
Next

''font = LoadImageFont("Verdana",14)
''SetImageFont font

' Set up initial population here.  A few different ones can be selected below by setting
' "If 0" to "If 1".  Of course we need a better interface for inputting patterns...

' This is "rabbits".  It only has 9 live cells, yet lasts for 17,331 generations.
' Its final state is a period-2 oscillator, and during its evolution it emits 39 gliders.
If 1
	set 0,0
	set 1,0
	set 0,1
	set 0,2
	set -1,1
	set 1,4
	set 1,5
	set 1,6
	set 0,5
	GenStop=17331
EndIf

' This one is the F pentomino, which lasts for 1103 generations

If 0
	set 0,0
	set 1,0
	set 0,1
	set 0,2
	set -1,1
	GenStop=1103
EndIf

' A beautiful Nx1 pattern whose population grows without bound (the smallest
'  such Nx1 pattern known).  Of course the finite grid limits it to a finite size.

If 0
	Local s$ = "********.*****...***......*******.*****9"
	For Local i=1 To 100
		Local t$ = Mid$(s,i,1)
		If t="9" Then Exit
		If t="*" Then set i-20,0
	Next
EndIf

' Random soup.  Unlike the other patterns above, the FPS will start low and gradually
' rise, since the soup tends to thin itself out.

If 0
	For x=blocksize To xres-blocksize
		For y=blocksize To yres-blocksize
			If Rand(0,100)<50 Then set x-xres/2,y-yres/2
		Next
	Next
EndIf

CopyWorld


Global lasttime = MilliSecs()
Global starttime=MilliSecs()
Global time

bglSetSwapInterval 0 ' flip false

While Not KeyHit(KEY_ESCAPE)
	Global gen=0 , fps
	Cls

	SetColor 80,80,40
	glPolygonMode(GL_BACK, GL_LINE)
	DrawRect blocksize-1,blocksize-1,(xres-blocksize-1)/blocksize*blocksize+2,(yres-blocksize-1)/blocksize*blocksize+2
	glPolygonMode(GL_BACK, GL_FILL)

	SetColor $3a,$b1,$fc
	glDisable GL_TEXTURE_2D
	glBegin GL_POINTS
	NextGen
	glEnd
	glEnable GL_TEXTURE_2D
	
	If (gen Mod 50 = 0)
		Local now = MilliSecs()
		fps = 50000.0/(now - lasttime)
		lasttime = now
	EndIf
	
	SetColor $44,$ef,$29
	DrawText fps+" fps",xres-200,10
	DrawText "Gen. "+gen,60,10
	
	gen:+1
	If gen<=GenStop
		time=MilliSecs()-starttime
	EndIf

	DrawText "Total Time (millisecs): "+time,20,yres-22
	Flip
	FlushMem


Wend
End




'----------------------------------------------------------------------
Function set(x,y)
	x:+xres/2
	y:+yres/2
	offset = y*stride + x/4
	Local m = x Mod 4
	Select m
		Case 0 ; SetCell0 offset
		Case 1 ; SetCell1 offset
		Case 2 ; SetCell2 offset
		Case 3 ; SetCell3 offset
	End Select
	blockstate1[x/blocksize,y/blocksize] = 1
End Function

'----------------------------------------------------------------------
Function CopyWorld()
	For Local i=0 Until arraysize
		world2[i] = world1[i]
	Next
End Function

'----------------------------------------------------------------------
Function SetCell0(offset)
	world1[offset] = world1[offset] + $10010000
	world1[offset-stride] = world1[offset-stride] + $01010000
	world1[offset+stride] = world1[offset+stride] + $01010000
	world1[offset-1] = world1[offset-1] + 1
	world1[offset-stride-1] = world1[offset-stride-1] + 1
	world1[offset+stride-1] = world1[offset+stride-1] + 1
	changed = 1
End Function

'----------------------------------------------------------------------
Function SetCell1(offset)
	world1[offset] = world1[offset] + $01100100
	world1[offset-stride] = world1[offset-stride] + $01010100
	world1[offset+stride] = world1[offset+stride] + $01010100
	changed = 1
End Function

'----------------------------------------------------------------------
Function SetCell2(offset)
	world1[offset] = world1[offset] + $00011001
	world1[offset-stride] = world1[offset-stride] + $00010101
	world1[offset+stride] = world1[offset+stride] + $00010101
	changed = 1	
End Function

'----------------------------------------------------------------------
Function SetCell3(offset)
	world1[offset] = world1[offset] + $00000110
	world1[offset-stride] = world1[offset-stride] + $00000101
	world1[offset+stride] = world1[offset+stride] + $00000101
	world1[offset+1] = world1[offset+1] + $01000000
	world1[offset-stride+1] = world1[offset-stride+1] + $01000000
	world1[offset+stride+1] = world1[offset+stride+1] + $01000000
	changed = 1
End Function

'----------------------------------------------------------------------
Function ClearCell0(offset)
	world1[offset] = world1[offset] - $10010000
	world1[offset-stride] = world1[offset-stride] - $01010000
	world1[offset+stride] = world1[offset+stride] - $01010000
	world1[offset-1] = world1[offset-1] - 1
	world1[offset-stride-1] = world1[offset-stride-1] - 1
	world1[offset+stride-1] = world1[offset+stride-1] - 1
	changed = 1
End Function

'----------------------------------------------------------------------
Function ClearCell1(offset)
	world1[offset] = world1[offset] - $01100100
	world1[offset-stride] = world1[offset-stride] - $01010100
	world1[offset+stride] = world1[offset+stride] - $01010100
	changed = 1
End Function

'----------------------------------------------------------------------
Function ClearCell2(offset)
	world1[offset] = world1[offset] - $00011001
	world1[offset-stride] = world1[offset-stride] - $00010101
	world1[offset+stride] = world1[offset+stride] - $00010101
	changed = 1
End Function

'----------------------------------------------------------------------
Function ClearCell3(offset)
	world1[offset] = world1[offset] - $00000110
	world1[offset-stride] = world1[offset-stride] - $00000101
	world1[offset+stride] = world1[offset+stride] - $00000101
	world1[offset+1] = world1[offset+1] - $01000000
	world1[offset-stride+1] = world1[offset-stride+1] - $01000000
	world1[offset+stride+1] = world1[offset+stride+1] - $01000000
	changed = 1
End Function

'----------------------------------------------------------------------
Function Process0()
	Local k = val Shr 24
	If SetAction[k]
		SetCell0 offset
	ElseIf ClearAction[k]
		ClearCell0 offset
	EndIf
	If DrawAction[k]
		glVertex2f x,y
		occupied=1
	EndIf
End Function

'----------------------------------------------------------------------
Function Process1()
	Local k = (val Shr 16) & $ff
	If SetAction[k]
		SetCell1 offset
	ElseIf ClearAction[k]
		ClearCell1 offset
	EndIf
	If DrawAction[k]
		glVertex2f x+1,y
		occupied=1
	EndIf
End Function

'----------------------------------------------------------------------
Function Process2()
	Local k = (val Shr 8) & $ff
	If SetAction[k]
		SetCell2 offset
	ElseIf ClearAction[k]
		ClearCell2 offset
	EndIf
	If DrawAction[k]
		glVertex2f x+2,y
		occupied=1
	EndIf
End Function

'----------------------------------------------------------------------
Function Process3()
	Local k = val & $ff
	If SetAction[k]
		SetCell3(offset)
	ElseIf ClearAction[k]
		ClearCell3 offset
	EndIf
	If DrawAction[k]
		glVertex2f x+3,y
		occupied=1
	EndIf
End Function

'----------------------------------------------------------------------
Function Process4Cells()
	val = world2[offset]
	If (val & $ff000000) Process0
	If (val & $00ff0000) Process1
	If (val & $0000ff00) Process2
	If (val & $000000ff) Process3
End Function

'----------------------------------------------------------------------

Function NextGen()
	Global x1,y1
	' Copy blockstates
	For y=0 Until yresb
		For x=0 Until xresb
			blockstate2[x,y] = blockstate1[x,y]
		Next
	Next
	y1 = 1
	For Local yo=BlockSize Until yres-Blocksize Step blocksize
		x1 = 1
		For Local xo=BlockSize Until xres-Blocksize Step blocksize
			' check if this block is empty and surrounded by empties.  If so, do nothing
			Local occ = blockstate2[x1,y1]+blockstate2[x1-1,y1]+blockstate2[x1+1,y1]
			occ:+blockstate2[x1,y1-1]+blockstate2[x1-1,y1-1]+blockstate2[x1+1,y1-1]
			occ:+blockstate2[x1,y1+1]+blockstate2[x1-1,y1+1]+blockstate2[x1+1,y1+1]
			changed = 0
			If occ
				occupied = 0
				Local lasty = yo+blocksize-1
				Local off = yo*stride + (xo Shr 2)
				For y=yo To lasty
					If world2[off+0] Then offset=off+0 ; x=xo+00 ; Process4Cells
					If world2[off+1] Then offset=off+1 ; x=xo+04 ; Process4Cells
					If world2[off+2] Then offset=off+2 ; x=xo+08 ; Process4Cells
					If world2[off+3] Then offset=off+3 ; x=xo+12 ; Process4Cells
					If world2[off+4] Then offset=off+4 ; x=xo+16 ; Process4Cells
					If world2[off+5] Then offset=off+5 ; x=xo+20 ; Process4Cells
					If world2[off+6] Then offset=off+6 ; x=xo+24 ; Process4Cells
					If world2[off+7] Then offset=off+7 ; x=xo+28 ; Process4Cells
					If world2[off+8] Then offset=off+8 ; x=xo+32 ; Process4Cells
					If world2[off+9] Then offset=off+9 ; x=xo+36 ; Process4Cells
					off:+stride
				Next
				blockstate1[x1,y1] = occupied
			EndIf
			If changed
				haschanged[x1,y1] = 1
				haschanged[x1-1,y1] = 1
				haschanged[x1+1,y1] = 1
				haschanged[x1,y1-1] = 1
				haschanged[x1-1,y1-1] = 1
				haschanged[x1+1,y1-1] = 1
				haschanged[x1,y1+1] = 1
				haschanged[x1-1,y1+1] = 1
				haschanged[x1+1,y1+1] = 1
			EndIf
			x1:+1
		Next
		y1:+1
	Next
	y1 = 1
	For Local yo=BlockSize Until yres-Blocksize Step blocksize
		x1 = 1
		For Local xo=BlockSize Until xres-Blocksize Step blocksize
			If haschanged[x1,y1]
				Local addr = yo*stride + (xo Shr 2)
				For y=1 To blocksize
					world2[addr] = world1[addr]
					world2[addr+1] = world1[addr+1]
					world2[addr+2] = world1[addr+2]
					world2[addr+3] = world1[addr+3]
					world2[addr+4] = world1[addr+4]
					world2[addr+5] = world1[addr+5]
					world2[addr+6] = world1[addr+6]
					world2[addr+7] = world1[addr+7]
					world2[addr+8] = world1[addr+8]
					world2[addr+9] = world1[addr+9]
					addr:+stride
				Next
			EndIf 
			x1:+1
		Next
		y1:+1
	Next
End Function



Blitz3D/2D version
; BlitzLife - a fast implementation of Conway's Life in Blitz Basic.
;  by Mike Keith, Feb 2002
;
; Optimizations implemented here include:
; (1) Cell neighbors are not counted each time; rather, the state and number of
;   neighbors each cell has are kept continually updated in an array.  This array only
;   needs to be updated when a cell changes.
; (2) When neighbors _do_ have to be updated, it's done with an average of 4.5 operations
;   instead of 9, via pseudo-SIMD.
; (3) Single cells and groups of 4x1 cells that are not alive and have no neighbors
;   are quickly skipped.
; (4) The world is tiled, and tiles that do not need to be copied or updated are quickly skipped.
;   (Skipping the copy is the big win here.)
;
; Overall speed depends on how many active cells there are.  The program uses FLIP FALSE
;  so as to go as fast as possible; change this to TRUE if you want to limit it to monitor
;  refresh rate.  At max speed it's often hard to see period-2 oscillators change at all!

Const xres=512,yres=384

Graphics xres,yres,16

Const col=$ffff, BlockSize = 40
Global stride,arraysize, back, offset,val,x,y, changed

arraysize = xres*yres/4
Dim world1(arraysize),world2(arraysize)
Dim table(32),ClearAction(32),SetAction(32),DrawAction(32)
Global xresb,yresb,occupied

xresb = xres/blocksize: yresb = yres/blocksize
Dim BlockState1(xresb,yresb),BlockState2(xresb,yresb),haschanged(xresb,yresb),foo(2)

Global GenStop=99999

stride = xres/4
back = BackBuffer()

For i=0 To 31: Read DrawAction(i): Next
Data 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0
Data 0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0

For i=0 To 31
	state = i/16
	nxt = DrawAction(i)
	
	If (state=0 And nxt=1) Then SetAction(i) = 1
	If (state=1 And nxt=0) Then ClearAction(i) = 1
Next

font = LoadFont("Verdana",14,True)
SetFont font

; Set up initial population here.  A few different ones can be selected below by setting
; "If 0" to "If 1".  Of course we need a better interface for inputting patterns...

; This is "rabbits".  It only has 9 live cells, yet lasts for 17,331 generations.
; Its final state is a period-2 oscillator, and during its evolution it emits 39 gliders.

If 1
set(0,0)
set(1,0)
set(0,1)
set(0,2)
set(-1,1)
set(1,4)
set(1,5)
set(1,6)
set(0,5)
GenStop=17331
EndIf

; This one is the F pentomino, which lasts for 1103 generations

If 0
set(0,0)
set(1,0)
set(0,1)
set(0,2)
set(-1,1)
GenStop=1103
EndIf

; A beautiful Nx1 pattern whose population grows without bound (the smallest
;  such Nx1 pattern known).  Of course the finite grid limits it to a finite size.

If 0
s$ = "********.*****...***......*******.*****9"
For i=1 To 100
	t$ = Mid$(s,i,1)
	If t="9" Then Exit
	If t="*" Then set(i-20,0)
Next
EndIf

; Random soup.  Unlike the other patterns above, the FPS will start low and gradually
; rise, since the soup tends to thin itself out.

If 0
For x=blocksize To xres-blocksize: For y=blocksize To yres-blocksize
If Rand(0,100)<50 Then set(x-xres/2,y-yres/2)
Next: Next
EndIf

CopyWorld

gen = 0
Global lasttime = MilliSecs()
Global starttime=MilliSecs()
Global time

While Not KeyHit(1)
	SetBuffer BackBuffer()
	ClsColor 0,20,70
	Cls
	LockBuffer BackBuffer()
	NextGen
	UnlockBuffer BackBuffer()
	
	Color 80,80,40
	Rect blocksize-1,blocksize-1,(xres-blocksize-1)/blocksize*blocksize+2,(yres-blocksize-1)/blocksize*blocksize+2,False
	
	Color 200,200,0
	If (gen Mod 50 = 0)
		now = MilliSecs()
		fps = 50000.0/(now - lasttime)
		lasttime = now
	EndIf
	
	Text xres-200,10,fps+" fps"
	Text 60,10,"Gen. "+Str$(gen)
	
	gen = gen+1
	If gen<=GenStop
		time=MilliSecs()-starttime
	EndIf
	
	Text 20,yres-22,"Total Time (millisecs): "+Str(time)
	Flip False

Wend
End

;----------------------------------------------------------------------
Function set(x,y)

	x = x + xres/2
	y = y + yres/2
	offset = y*stride + x/4
	m = x Mod 4

	If (m=0) 
		SetCell0(offset)
	ElseIf (m=1) 
		SetCell1(offset)
	ElseIf (m=2) 
		SetCell2(offset)
	ElseIf (m=3) 
		SetCell3(offset)
	EndIf
	
	blockstate1(x/blocksize,y/blocksize) = 1
	
End Function

;----------------------------------------------------------------------
Function CopyWorld()

	For i=0 To arraysize-1
		world2(i) = world1(i)
	Next
	
End Function
;----------------------------------------------------------------------
Function SetCell0(offset)

	world1(offset) = world1(offset) + $10010000
	world1(offset-stride) = world1(offset-stride) + $01010000
	world1(offset+stride) = world1(offset+stride) + $01010000

	world1(offset-1) = world1(offset-1) + 1
	world1(offset-stride-1) = world1(offset-stride-1) + 1
	world1(offset+stride-1) = world1(offset+stride-1) + 1
	
	changed = 1

End Function

;----------------------------------------------------------------------
Function SetCell1(offset)
	
	world1(offset) = world1(offset) + $01100100
	world1(offset-stride) = world1(offset-stride) + $01010100
	world1(offset+stride) = world1(offset+stride) + $01010100

	changed = 1

End Function

;----------------------------------------------------------------------
Function SetCell2(offset)

	world1(offset) = world1(offset) + $00011001
	world1(offset-stride) = world1(offset-stride) + $00010101
	world1(offset+stride) = world1(offset+stride) + $00010101
	
	changed = 1	

End Function

;----------------------------------------------------------------------
Function SetCell3(offset)

	world1(offset) = world1(offset) + $00000110
	world1(offset-stride) = world1(offset-stride) + $00000101
	world1(offset+stride) = world1(offset+stride) + $00000101

	world1(offset+1) = world1(offset+1) + $01000000
	world1(offset-stride+1) = world1(offset-stride+1) + $01000000
	world1(offset+stride+1) = world1(offset+stride+1) + $01000000

	changed = 1

End Function

;----------------------------------------------------------------------
Function ClearCell0(offset)

	world1(offset) = world1(offset) - $10010000
	world1(offset-stride) = world1(offset-stride) - $01010000
	world1(offset+stride) = world1(offset+stride) - $01010000

	world1(offset-1) = world1(offset-1) - 1
	world1(offset-stride-1) = world1(offset-stride-1) - 1
	world1(offset+stride-1) = world1(offset+stride-1) - 1

	changed = 1

End Function

;----------------------------------------------------------------------
Function ClearCell1(offset)

	world1(offset) = world1(offset) - $01100100
	world1(offset-stride) = world1(offset-stride) - $01010100
	world1(offset+stride) = world1(offset+stride) - $01010100

	changed = 1

End Function

;----------------------------------------------------------------------
Function ClearCell2(offset)

	world1(offset) = world1(offset) - $00011001
	world1(offset-stride) = world1(offset-stride) - $00010101
	world1(offset+stride) = world1(offset+stride) - $00010101

	changed = 1

End Function

;----------------------------------------------------------------------
Function ClearCell3(offset)

	world1(offset) = world1(offset) - $00000110
	world1(offset-stride) = world1(offset-stride) - $00000101
	world1(offset+stride) = world1(offset+stride) - $00000101

	world1(offset+1) = world1(offset+1) - $01000000
	world1(offset-stride+1) = world1(offset-stride+1) - $01000000
	world1(offset+stride+1) = world1(offset+stride+1) - $01000000

	changed = 1

End Function

;----------------------------------------------------------------------
Function Process0()

	k = val Shr 24
	If (SetAction(k))
		SetCell0(offset)
	ElseIf (ClearAction(k))
		ClearCell0(offset)
	EndIf
	
	If (DrawAction(k)) Then WritePixel x,y,col: occupied=1

End Function

;----------------------------------------------------------------------
Function Process1()

	k = (val Shr 16) And $ff
	If (SetAction(k))
		SetCell1(offset)
	ElseIf (ClearAction(k))
		ClearCell1(offset)
	EndIf
	
	If (DrawAction(k)) Then WritePixel x+1,y,col: occupied=1

End Function

;----------------------------------------------------------------------
Function Process2()

	k = (val Shr 8) And $ff
	If (SetAction(k))
		SetCell2(offset)
	ElseIf (ClearAction(k))
		ClearCell2(offset)
	EndIf
	
	If (DrawAction(k)) Then WritePixel x+2,y,col: occupied=1

End Function

;----------------------------------------------------------------------
Function Process3()

	k = val And $ff
	If (SetAction(k))
		SetCell3(offset)
	ElseIf (ClearAction(k))
		ClearCell3(offset)
	EndIf
	
	If (DrawAction(k)) Then WritePixel x+3,y,col: occupied=1
	
End Function

;----------------------------------------------------------------------
Function Process4Cells()

	val = world2(offset)
	If (val And $ff000000) Then Process0()				
	If (val And $00ff0000) Then Process1()
	If (val And $0000ff00) Then Process2()
	If (val And $000000ff) Then Process3()

End Function

;----------------------------------------------------------------------

Function NextGen()
	
	; Copy blockstates
	
	For y=0 To yresb-1
		For x=0 To xresb-1
			blockstate2(x,y) = blockstate1(x,y)
		Next
	Next
	
	y1 = 1
	For yo=BlockSize To yres-Blocksize-1 Step blocksize
	x1 = 1
	For xo=BlockSize To xres-Blocksize-1 Step blocksize
	
	; check if this block is empty and surrounded by empties.  If so, do nothing
	
	occ = blockstate2(x1,y1)+blockstate2(x1-1,y1)+blockstate2(x1+1,y1)
	occ = occ + blockstate2(x1,y1-1)+blockstate2(x1-1,y1-1)+blockstate2(x1+1,y1-1)
	occ = occ + blockstate2(x1,y1+1)+blockstate2(x1-1,y1+1)+blockstate2(x1+1,y1+1)
	changed = 0
	
	If (occ)
		occupied = 0
		lasty = yo+blocksize-1
		off = yo*stride + (xo Shr 2)
		For y=yo To lasty
		
			If (world2(off)) Then offset=off: x=xo: Process4Cells()
			If (world2(off+1)) Then offset=off+1: x=xo+4: Process4Cells()
			If (world2(off+2)) Then offset=off+2: x=xo+8: Process4Cells()
			If (world2(off+3)) Then offset=off+3: x=xo+12: Process4Cells()
			If (world2(off+4)) Then offset=off+4: x=xo+16: Process4Cells()
			If (world2(off+5)) Then offset=off+5: x=xo+20: Process4Cells()
			If (world2(off+6)) Then offset=off+6: x=xo+24: Process4Cells()
			If (world2(off+7)) Then offset=off+7: x=xo+28: Process4Cells()
			If (world2(off+8)) Then offset=off+8: x=xo+32: Process4Cells()
			If (world2(off+9)) Then offset=off+9: x=xo+36: Process4Cells()
			
			off = off + stride			
		Next	
				
		blockstate1(x1,y1) = occupied
	EndIf
	
	If (changed)
		haschanged(x1,y1) = 1
		haschanged(x1-1,y1) = 1
		haschanged(x1+1,y1) = 1
		haschanged(x1,y1-1) = 1
		haschanged(x1-1,y1-1) = 1
		haschanged(x1+1,y1-1) = 1
		haschanged(x1,y1+1) = 1
		haschanged(x1-1,y1+1) = 1
		haschanged(x1+1,y1+1) = 1
	EndIf
	x1 = x1+1
	Next
	y1 = y1+1
	Next
	
	y1 = 1
	For yo=BlockSize To yres-Blocksize-1 Step blocksize
	x1 = 1
	For xo=BlockSize To xres-Blocksize-1 Step blocksize
		If (haschanged(x1,y1))
			addr = yo*stride + (xo Shr 2)
			For y=1 To blocksize
				world2(addr) = world1(addr)
				world2(addr+1) = world1(addr+1)
				world2(addr+2) = world1(addr+2)
				world2(addr+3) = world1(addr+3)
				world2(addr+4) = world1(addr+4)
				world2(addr+5) = world1(addr+5)
				world2(addr+6) = world1(addr+6)
				world2(addr+7) = world1(addr+7)
				world2(addr+8) = world1(addr+8)
				world2(addr+9) = world1(addr+9)
				addr = addr + stride
			Next
		EndIf 
	x1 = x1+1
	Next
	y1 = y1+1
	Next

End Function