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
Blitz3D/2D version
(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