Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 02:23 17 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : Conway's Game of Life written by ChatGPT5 (and me) for PicoMite

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10350
Posted: 06:04pm 15 Aug 2025
Copy link to clipboard 
Print this post

Currently set for 80x60 but you can change CS to alter this. Run at 378MHz for best effect.

' Conway's Game of Life  PicoMite + ILI9341 (320x240)
' Byte-per-cell grids + fast MEMORY SET clear + framebuffer single-blit per tick
.
' Toroidal edges, diff-only drawing, sparse seeding by default.
' NOTE: PEEK/POKE/MEMORY SET BYTE must NOT have '(' right after BYTE.

Option EXPLICIT
Option BASE 0
Option DEFAULT INTEGER

' ---------- Display / grid ----------
Const W = MM.HRES, H = MM.VRES
Const CS = 4                              ' cell size (pixels
Const COLS = W \ CS                       ' 160
Const ROWS = H \ CS                       ' 120
Const NPIX = ROWS * COLS                  ' 19,200 bytes per grid

' Colours (RGB888; firmware maps to FB palette automatically)
Const COL_OFF = RGB(0,0,0)
Const COL_ON  = RGB(255,255,255)

' ---------- Tunables ----------
Dim delayMs% : delayMs% = 1
Dim seedPct% : seedPct% = 12             ' sparser starts; try 815

' ---------- Tiny heap: INTEGER array as raw byte heap ----------
' Return byte OFFSETS (0 valid). Keep absolute BASE address for MEMORY SET/PEEK/
POKE.
Const HEAP_BYTES = (2 * NPIX) + 4096
Const HEAP_ELEMS = (HEAP_BYTES + 7) \ 8
Dim HEAP%(HEAP_ELEMS - 1)
Dim HEAP_SIZE% : HEAP_SIZE% = HEAP_ELEMS * 8
Dim HEAP_PTR%  : HEAP_PTR%  = 0
Dim HEAP_BASE% : HEAP_BASE% = Peek(VARADDR HEAP%(0))   ' address of first elemen
t (bytes)

Function MMALLOC%(bytes%)
 ' 4-byte align
 bytes% = ((bytes% + 3) \ 4) * 4
 If HEAP_PTR% + bytes% > HEAP_SIZE% Then
   MMALLOC% = -1                         ' -1 = failure (0 is a valid first off
set)
   Exit Function
 EndIf
 MMALLOC% = HEAP_PTR%
 HEAP_PTR% = HEAP_PTR% + bytes%
End Function

' ---------- Current/Next byte grids ----------
Dim curOff%, nxtOff%
Dim paused% : paused% = 0

' Fast clear of a whole grid using MEMORY SET BYTE (absolute address).
Sub ZERO_GRID(baseOff%)
 Memory SET BYTE HEAP_BASE% + baseOff%, 0, NPIX
End Sub

' ---------- Framebuffer setup ----------
FRAMEBUFFER CREATE                        ' create FB F matched to LCD
FRAMEBUFFER WRITE F                       ' send graphics to FB
CLS COL_OFF

' ---------- Drawing (diff-only into FB) ----------
Sub DrawCell(c%, r%, isAlive%)
 Local x%, y%
 x% = c% * CS : y% = r% * CS
 If isAlive% Then
   Box x%, y%, CS, CS, 0, COL_ON,  COL_ON     ' x,y,w,h,[lw],[c],[fill]
 Else
   Box x%, y%, CS, CS, 0, COL_OFF, COL_OFF
 EndIf
End Sub

Sub ClearFB
 CLS COL_OFF
End Sub

' ---------- Indexing helper ----------
Function CellIdx%(r%, c%)
 CellIdx% = r% * COLS + c%
End Function

' ---------- Seeds / clear ----------
Sub SeedRandom(pct%)
 Local r%, c%, v%, ci%, baseCur%
 ZERO_GRID curOff%
 ZERO_GRID nxtOff%
 ClearFB
 baseCur% = HEAP_BASE% + curOff%
 For r% = 0 To ROWS - 1
   For c% = 0 To COLS - 1
     v% = ((Rnd * 100) < pct%)
     If v% Then
       ci% = CellIdx%(r%, c%)
       Poke BYTE baseCur% + ci%, 1
       DrawCell c%, r%, 1
     EndIf
   Next c%
 Next r%
End Sub

Sub ClearBoard
 ZERO_GRID curOff%
 ClearFB
End Sub

' ---------- One generation (inline neighbours, absolute PEEK/POKE) ----------
Sub StepLife
 Local r%, c%, rm1%, rp1%, cm1%, cp1%
 Local baseCur%, baseNxt%, rowUab%, rowMab%, rowDab%, outRowAb%
 Local n%, isAlive%, newv%
 Static count%
 Memory SET BYTE HEAP_BASE% + nxtOff%, 0, NPIX   ' fast clear next

 baseCur% = HEAP_BASE% + curOff%
 baseNxt% = HEAP_BASE% + nxtOff%

 For r% = 0 To ROWS - 1
   rm1% = r% - 1 : If rm1% < 0 Then rm1% = ROWS - 1
   rp1% = r% + 1 : If rp1% = ROWS Then rp1% = 0

   rowUab%   = baseCur% + rm1% * COLS
   rowMab%   = baseCur% +  r%  * COLS
   rowDab%   = baseCur% + rp1% * COLS
   outRowAb% = baseNxt% + r% * COLS
   For c% = 0 To COLS - 1
     cm1% = c% - 1 : If cm1% < 0 Then cm1% = COLS - 1
     cp1% = c% + 1 : If cp1% = COLS Then cp1% = 0

     ' 8 neighbours (absolute byte reads; no parentheses after BYTE)
     n%  = PEEK(BYTE rowUab% + cm1%)
     n% = n% + PEEK(BYTE rowUab% + c%)
     n% = n% + PEEK(BYTE rowUab% + cp1%)
     n% = n% + PEEK(BYTE rowMab% + cm1%)
     n% = n% + PEEK(BYTE rowMab% + cp1%)
     n% = n% + PEEK(BYTE rowDab% + cm1%)
     n% = n% + PEEK(BYTE rowDab% + c%)
     n% = n% + PEEK(BYTE rowDab% + cp1%)

     isAlive% = PEEK(BYTE rowMab% + c%)

     If isAlive% Then
       newv% = (n% = 2) Or (n% = 3)
     Else
       newv% = (n% = 3)
     EndIf
     If newv% Then Poke BYTE outRowAb% + c%, 1
     If newv% <> isAlive% Then
        DrawCell c%, r%, newv%
       EndIf
   Next c%
 Next r%

 SwapBuffers
 Inc count%
 Text 0,0,Str$(count%),,,2,RGB(red)
 FRAMEBUFFER WAIT
 FRAMEBUFFER COPY F, N
End Sub

' ---------- Buffer swap ----------
Sub SwapBuffers
 Local t% : t% = curOff% : curOff% = nxtOff% : nxtOff% = t%
End Sub

' ---------- Init & main loop ----------
Randomize Timer

curOff% = MMALLOC%(NPIX) : If curOff% < 0 Then Print "MMALLOC% failed for cur":
End
nxtOff% = MMALLOC%(NPIX) : If nxtOff% < 0 Then Print "MMALLOC% failed for nxt":
End
SeedRandom seedPct%
FRAMEBUFFER COPY F, N                  ' show initial frame

' Controls: SPACE pause/resume | R random | C clear | S step (paused) | +/- spee
d | Q quit
Do
 If Not paused% Then
   StepLife
   If delayMs% > 0 Then Pause delayMs%
 Else
   Pause 10
 EndIf

 Select Case Inkey$
   Case " "       : paused% = 1 - paused%
   Case "r","R"   : SeedRandom seedPct% : FRAMEBUFFER COPY F, N
   Case "c","C"   : ClearBoard : FRAMEBUFFER COPY F, N
   Case "s","S"   : If paused% Then StepLife
   Case "+"       : If delayMs% > 0 Then delayMs% = delayMs% - 1
   Case "-"       : delayMs% = delayMs% + 1
   Case "q","Q"   : Exit Do
 End Select
Loop

FRAMEBUFFER CLOSE
CLS COL_OFF
Print "Game of Life ended."
End

Edited 2025-08-16 04:05 by matherp
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3390
Posted: 12:13am 16 Aug 2025
Copy link to clipboard 
Print this post

Several instances of comment lines wrapping and giving syntax errors. Fixed those, and it runs with no errors but nothing appears on the lcd. Should it work with this:

option list
PicoMite MMBasic RP2350A Edition V6.01.00b8
OPTION SYSTEM SPI GP18,GP19,GP16
OPTION FLASH SIZE 4194304
OPTION COLOURCODE ON
OPTION CPUSPEED (KHz) 378000
OPTION LCDPANEL ILI9488, LANDSCAPE,GP21,GP20,GP17
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2668
Posted: 12:44am 16 Aug 2025
Copy link to clipboard 
Print this post

By putting a Print in each Sub / Function to identify where it stops found:-
Function MMALLOC%(bytes%)
Print "Function MMALLOC%"
' 4-byte align
bytes% = ((bytes% + 3) \ 4) * 4
If HEAP_PTR% + bytes% > HEAP_SIZE% Then
  MMALLOC% = -1                         ' -1 = failure (0 is a valid first offset)
  Exit Function
EndIf
MMALLOC% = HEAP_PTR%
HEAP_PTR% = HEAP_PTR% + bytes%
Print "HEAP_PTR%";HEAP_PTR%, "bytes%"; bytes%,  "HEAP_SIZE%";HEAP_SIZE%
End Function

Is as far as it gets.
> RUN
Function MMALLOC%
HEAP_PTR% 4800  bytes% 4800     HEAP_SIZE% 13696
>

So lack of memory in the RP2040 doesn't appear to be the issue.
> option list
PicoMite MMBasic RP2040 Edition V6.00.03
OPTION SYSTEM SPI GP18,GP19,GP20
OPTION FLASH SIZE 16777216
OPTION COLOURCODE ON
OPTION CPUSPEED (KHz) 378000
OPTION DISPLAY 55, 133
OPTION LCDPANEL ILI9341, LANDSCAPE,GP15,GP14,GP13,GP16

Edit.
Similar on RP2350A VGA using MODE 1 and 2

Edit 2
Corrected a few more wrapped lines, but Life is short!

Edit 3
This appears to work.
' Conway's Game of Life  PicoMite + ILI9341 (320x240)
' Byte-per-cell grids + fast MEMORY SET clear + framebuffer single-blit per tick.
' Toroidal edges, diff-only drawing, sparse seeding by default.
' NOTE: PEEK/POKE/MEMORY SET BYTE must NOT have '(' right after BYTE.

Option EXPLICIT
Option BASE 0
Option DEFAULT INTEGER

' ---------- Display / grid ----------
Const W = MM.HRES, H = MM.VRES
Const CS = 4                              ' cell size (pixels
Const COLS = W \ CS                       ' 160
Const ROWS = H \ CS                       ' 120
Const NPIX = ROWS * COLS                  ' 19,200 bytes per grid

' Colours (RGB888; firmware maps to FB palette automatically)
Const COL_OFF = RGB(0,0,0)
Const COL_ON  = RGB(255,255,255)

' ---------- Tunables ----------
Dim delayMs% = 1
Dim seedPct% = 20             ' sparser starts; try 815

' ---------- Tiny heap: INTEGER array as raw byte heap ----------
' Return byte OFFSETS (0 valid). Keep absolute BASE address for MEMORY SET/PEEK/POKE.
Const HEAP_BYTES = (2 * NPIX) + 4096
Const HEAP_ELEMS = (HEAP_BYTES + 7) \ 8
Dim HEAP%(HEAP_ELEMS - 1)
Dim HEAP_SIZE% = HEAP_ELEMS * 8
Dim HEAP_PTR%  = 0
Dim HEAP_BASE% = Peek(VARADDR HEAP%(0))   ' address of first element(bytes)

Function MMALLOC%(bytes%)
' 4-byte align
bytes% = ((bytes% + 3) \ 4) * 4
If HEAP_PTR% + bytes% > HEAP_SIZE% Then
  MMALLOC% = -1                         ' -1 = failure (0 is a valid first offset)
  Exit Function
EndIf
MMALLOC% = HEAP_PTR%
HEAP_PTR% = HEAP_PTR% + bytes%
Print "HEAP_PTR%";HEAP_PTR%, "bytes%"; bytes%,  "HEAP_SIZE%";HEAP_SIZE%
End Function

' ---------- Current/Next byte grids ----------
Dim curOff%, nxtOff%
Dim paused% = 0

' Fast clear of a whole grid using MEMORY SET BYTE (absolute address).
Sub ZERO_GRID(baseOff%)
Memory SET BYTE HEAP_BASE% + baseOff%, 0, NPIX
End Sub

' ---------- Framebuffer setup ----------
FRAMEBUFFER CREATE                        ' create FB F matched to LCD
FRAMEBUFFER WRITE F                       ' send graphics to FB
CLS COL_OFF

' ---------- Drawing (diff-only into FB) ----------
Sub DrawCell(c%, r%, isAlive%)
Local x%, y%
x% = c% * CS : y% = r% * CS
If isAlive% Then
  Box x%, y%, CS, CS, 0, COL_ON, COL_ON     ' x,y,w,h,[lw],[c],[fill]
Else
  Box x%, y%, CS, CS, 0, COL_OFF, COL_OFF
EndIf
End Sub

Sub ClearFB
CLS COL_OFF
End Sub

' ---------- Indexing helper ----------
Function CellIdx%(r%, c%)
CellIdx% = r% * COLS + c%
End Function

' ---------- Seeds / clear ----------
Sub SeedRandom(pct%)
Local r%, c%, v%, ci%, baseCur%
ZERO_GRID curOff%
ZERO_GRID nxtOff%
ClearFB
baseCur% = HEAP_BASE% + curOff%
For r% = 0 To ROWS - 1
  For c% = 0 To COLS - 1
    v% = ((Rnd * 100) < pct%)
    If v% Then
      ci% = CellIdx%(r%, c%)
      Poke BYTE baseCur% + ci%, 1
      DrawCell c%, r%, 1
    EndIf
  Next c%
Next r%
End Sub

Sub ClearBoard
ZERO_GRID curOff%
ClearFB
End Sub

' ---------- One generation (inline neighbours, absolute PEEK/POKE) ----------
Sub StepLife
Local r%, c%, rm1%, rp1%, cm1%, cp1%
Local baseCur%, baseNxt%, rowUab%, rowMab%, rowDab%, outRowAb%
Local n%, isAlive%, newv%
Print "Sub StepLife",
Static count%
Memory SET BYTE HEAP_BASE% + nxtOff%, 0, NPIX   ' fast clear next

baseCur% = HEAP_BASE% + curOff%
baseNxt% = HEAP_BASE% + nxtOff%

For r% = 0 To ROWS - 1
  rm1% = r% - 1 : If rm1% < 0 Then rm1% = ROWS - 1
  rp1% = r% + 1 : If rp1% = ROWS Then rp1% = 0

  rowUab%   = baseCur% + rm1% * COLS
  rowMab%   = baseCur% +  r%  * COLS
  rowDab%   = baseCur% + rp1% * COLS
  outRowAb% = baseNxt% + r% * COLS
  For c% = 0 To COLS - 1
    cm1% = c% - 1 : If cm1% < 0 Then cm1% = COLS - 1
    cp1% = c% + 1 : If cp1% = COLS Then cp1% = 0

    ' 8 neighbours (absolute byte reads; no parentheses after BYTE)
    n%  = PEEK(BYTE rowUab% + cm1%)
    n% = n% + PEEK(BYTE rowUab% + c%)
    n% = n% + PEEK(BYTE rowUab% + cp1%)
    n% = n% + PEEK(BYTE rowMab% + cm1%)
    n% = n% + PEEK(BYTE rowMab% + cp1%)
    n% = n% + PEEK(BYTE rowDab% + cm1%)
    n% = n% + PEEK(BYTE rowDab% + c%)
    n% = n% + PEEK(BYTE rowDab% + cp1%)

    isAlive% = PEEK(BYTE rowMab% + c%)

    If isAlive% Then
      newv% = (n% = 2) Or (n% = 3)
      newv% = (n% = 3)
    EndIf
    If newv% Then Poke BYTE outRowAb% + c%, 1
    If newv% <> isAlive% Then
       DrawCell c%, r%, newv%
      EndIf
  Next c%
Next r%

SwapBuffers
Inc count%
Text 0,0,Str$(count%),,,2,RGB(red) :Print count%
FRAMEBUFFER WAIT
FRAMEBUFFER COPY F, N
End Sub

' ---------- Buffer swap ----------
Sub SwapBuffers
'Print "Sub SwapBuffers"
Local t% : t% = curOff% : curOff% = nxtOff% : nxtOff% = t%
End Sub

' ---------- Init & main loop ----------
Randomize Timer

curOff% = MMALLOC%(NPIX) : If curOff% < 0 Then Print "MMALLOC% failed for cur" :End
nxtOff% = MMALLOC%(NPIX) : If nxtOff% < 0 Then Print "MMALLOC% failed for nxt" :End
SeedRandom seedPct%
FRAMEBUFFER COPY F, N                  ' show initial frame

' Controls: SPACE pause/resume | R random | C clear | S step (paused) | +/- speed | Q quit
Do
 If Not paused% Then
   StepLife
   If delayMs% > -1 Then Pause delayMs%
 Else
   Pause 10
 EndIf

 Select Case Inkey$
   Case " "       : paused% = 1 - paused%
   Case "r","R"   : SeedRandom seedPct% : FRAMEBUFFER COPY F, N
   Case "c","C"   : ClearBoard : FRAMEBUFFER COPY F, N
   Case "s","S"   : If paused% Then StepLife
   Case "+"       : If delayMs% > 0 Then delayMs% = delayMs% - 1
   Case "-"       : delayMs% = delayMs% + 1
   Case "q","Q"   : Exit Do
 End Select
Loop

FRAMEBUFFER CLOSE
CLS COL_OFF
Print "Game of Life ended."
End

Add MODE 2 to the start and it runs on VGA.
Very slow in MODE 1 even with OPTION RESOLUTION 640x480, 378000
Edited 2025-08-16 16:30 by phil99
 
Volhout
Guru

Joined: 05/03/2018
Location: Netherlands
Posts: 5138
Posted: 06:27am 16 Aug 2025
Copy link to clipboard 
Print this post

I have to admit, if there is one thing that is good in AI, it is that we, as humans, start thinking.... a lot....
It keeps us busy..

If isAlive% Then
     newv% = (n% = 2) Or (n% = 3)
     newv% = (n% = 3)
   EndIf


Volhout
PicomiteVGA PETSCII ROBOTS
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2668
Posted: 06:43am 16 Aug 2025
Copy link to clipboard 
Print this post

I puzzled over that for a while and concluded when isAlive% = 1 then newv% = 1 if either n%=2 or n%=3 and newv% = 0 otherwise.
if isAlive% = 0 then newv% = 1 if n%=3 and newv% = 0 otherwise.

Edit
There is meant to be an ELSE between the lines. My copy / paste error.
    If isAlive% Then
      newv% = (n% = 2) Or (n% = 3)
    Else
      newv% = (n% = 3)
    EndIf

Edit 2
Yep, that's how it works.
> n%=0 :newv% = (n% = 2) Or (n% = 3) : ?newv%
0
> n%=4 :newv% = (n% = 2) Or (n% = 3) : ?newv%
0
> n%=3 :newv% = (n% = 2) Or (n% = 3) : ?newv%
1
> n%=2 :newv% = (n% = 2) Or (n% = 3) : ?newv%
1
> n%=1 :newv% = (n% = 2) Or (n% = 3) : ?newv%
0
>

Edited 2025-08-16 17:09 by phil99
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10350
Posted: 07:28am 16 Aug 2025
Copy link to clipboard 
Print this post

Sorry: forgot to set OPTION DISPLAY before I did the listing. Corrected version attached.
If you want to stop the game ending in a fixed loop add a tiny bit of randomness

     If isAlive% Then
       newv% = (n% = 2) Or (n% = 3)
     Else
       newv% = (n% = 3)
     EndIf
     If Rnd<0.001 Then newv% = Not newv% 'add random element


' Conway's Game of Life  PicoMite + ILI9341 (320x240)
' Byte-per-cell grids + fast MEMORY SET clear + framebuffer single-blit per tick.
' Toroidal edges, diff-only drawing, sparse seeding by default.
' NOTE: PEEK/POKE/MEMORY SET BYTE must NOT have '(' right after BYTE.

Option EXPLICIT
Option BASE 0
Option DEFAULT INTEGER

' ---------- Display / grid ----------
Const W = MM.HRES, H = MM.VRES
Const CS = 4                              ' cell size (pixels
Const COLS = W \ CS                       ' 160
Const ROWS = H \ CS                       ' 120
Const NPIX = ROWS * COLS                  ' 19,200 bytes per grid

' Colours (RGB888; firmware maps to FB palette automatically)
Const COL_OFF = RGB(0,0,0)
Const COL_ON  = RGB(255,255,255)

' ---------- Tunables ----------
Dim delayMs% : delayMs% = 1
Dim seedPct% : seedPct% = 12             ' sparser starts; try 815

' ---------- Tiny heap: INTEGER array as raw byte heap ----------
' Return byte OFFSETS (0 valid). Keep absolute BASE address for MEMORY SET/PEEK/POKE.
Const HEAP_BYTES = (2 * NPIX) + 4096
Const HEAP_ELEMS = (HEAP_BYTES + 7) \ 8
Dim HEAP%(HEAP_ELEMS - 1)
Dim HEAP_SIZE% : HEAP_SIZE% = HEAP_ELEMS * 8
Dim HEAP_PTR%  : HEAP_PTR%  = 0
Dim HEAP_BASE% : HEAP_BASE% = Peek(VARADDR HEAP%(0))   ' address of first element(bytes)

Function MMALLOC%(bytes%)
' 4-byte align
bytes% = ((bytes% + 3) \ 4) * 4
If HEAP_PTR% + bytes% > HEAP_SIZE% Then
  MMALLOC% = -1                         ' -1 = failure (0 is a valid first offSet )
  Exit Function
EndIf
MMALLOC% = HEAP_PTR%
HEAP_PTR% = HEAP_PTR% + bytes%
End Function

' ---------- Current/Next byte grids ----------
Dim curOff%, nxtOff%
Dim paused% : paused% = 0

' Fast clear of a whole grid using MEMORY SET BYTE (absolute address).
Sub ZERO_GRID(baseOff%)
Memory SET BYTE HEAP_BASE% + baseOff%, 0, NPIX
End Sub

' ---------- Framebuffer setup ----------
FRAMEBUFFER CREATE                        ' create FB F matched to LCD
FRAMEBUFFER WRITE F                       ' send graphics to FB
CLS COL_OFF

' ---------- Drawing (diff-only into FB) ----------
Sub DrawCell(c%, r%, isAlive%)
Local x%, y%
x% = c% * CS : y% = r% * CS
If isAlive% Then
  Box x%, y%, CS, CS, 0, COL_ON,  COL_ON     ' x,y,w,h,[lw],[c],[fill]
Else
  Box x%, y%, CS, CS, 0, COL_OFF, COL_OFF
EndIf
End Sub

Sub ClearFB
CLS COL_OFF
End Sub

' ---------- Indexing helper ----------
Function CellIdx%(r%, c%)
CellIdx% = r% * COLS + c%
End Function

' ---------- Seeds / clear ----------
Sub SeedRandom(pct%)
Local r%, c%, v%, ci%, baseCur%
ZERO_GRID curOff%
ZERO_GRID nxtOff%
ClearFB
baseCur% = HEAP_BASE% + curOff%
For r% = 0 To ROWS - 1
  For c% = 0 To COLS - 1
    v% = ((Rnd * 100) < pct%)
    If v% Then
      ci% = CellIdx%(r%, c%)
      Poke BYTE baseCur% + ci%, 1
      DrawCell c%, r%, 1
    EndIf
  Next c%
Next r%
End Sub

Sub ClearBoard
ZERO_GRID curOff%
ClearFB
End Sub

' ---------- One generation (inline neighbours, absolute PEEK/POKE) ----------
Sub StepLife
Local r%, c%, rm1%, rp1%, cm1%, cp1%
Local baseCur%, baseNxt%, rowUab%, rowMab%, rowDab%, outRowAb%
Local n%, isAlive%, newv%
Static count%
Memory SET BYTE HEAP_BASE% + nxtOff%, 0, NPIX   ' fast clear next

baseCur% = HEAP_BASE% + curOff%
baseNxt% = HEAP_BASE% + nxtOff%

For r% = 0 To ROWS - 1
  rm1% = r% - 1 : If rm1% < 0 Then rm1% = ROWS - 1
  rp1% = r% + 1 : If rp1% = ROWS Then rp1% = 0

  rowUab%   = baseCur% + rm1% * COLS
  rowMab%   = baseCur% +  r%  * COLS
  rowDab%   = baseCur% + rp1% * COLS
  outRowAb% = baseNxt% + r% * COLS
  For c% = 0 To COLS - 1
    cm1% = c% - 1 : If cm1% < 0 Then cm1% = COLS - 1
    cp1% = c% + 1 : If cp1% = COLS Then cp1% = 0

    ' 8 neighbours (absolute byte reads; no parentheses after BYTE)
    n%  = PEEK(BYTE rowUab% + cm1%)
    n% = n% + PEEK(BYTE rowUab% + c%)
    n% = n% + PEEK(BYTE rowUab% + cp1%)
    n% = n% + PEEK(BYTE rowMab% + cm1%)
    n% = n% + PEEK(BYTE rowMab% + cp1%)
    n% = n% + PEEK(BYTE rowDab% + cm1%)
    n% = n% + PEEK(BYTE rowDab% + c%)
    n% = n% + PEEK(BYTE rowDab% + cp1%)

    isAlive% = PEEK(BYTE rowMab% + c%)

    If isAlive% Then
      newv% = (n% = 2) Or (n% = 3)
    Else
      newv% = (n% = 3)
    EndIf
    If newv% Then Poke BYTE outRowAb% + c%, 1
    If newv% <> isAlive% Then
       DrawCell c%, r%, newv%
      EndIf
  Next c%
Next r%

SwapBuffers
Inc count%
Text 0,0,Str$(count%),,,2,RGB(red)
FRAMEBUFFER WAIT
FRAMEBUFFER COPY F, N
End Sub

' ---------- Buffer swap ----------
Sub SwapBuffers
Local t% : t% = curOff% : curOff% = nxtOff% : nxtOff% = t%
End Sub

' ---------- Init & main loop ----------
Randomize Timer

curOff% = MMALLOC%(NPIX) : If curOff% < 0 Then Print "MMALLOC% failed for cur":End
nxtOff% = MMALLOC%(NPIX) : If nxtOff% < 0 Then Print "MMALLOC% failed for nxt":End
SeedRandom seedPct%
FRAMEBUFFER COPY F, N                  ' show initial frame

' Controls: SPACE pause/resume | R random | C clear | S step (paused) | +/- speed | Q quit
Do
If Not paused% Then
  StepLife
  If delayMs% > 0 Then Pause delayMs%
Else
  Pause 10
EndIf

Select Case Inkey$
  Case " "       : paused% = 1 - paused%
  Case "r","R"   : SeedRandom seedPct% : FRAMEBUFFER COPY F, N
  Case "c","C"   : ClearBoard : FRAMEBUFFER COPY F, N
  Case "s","S"   : If paused% Then StepLife
  Case "+"       : If delayMs% > 0 Then delayMs% = delayMs% - 1
  Case "-"       : delayMs% = delayMs% + 1
  Case "q","Q"   : Exit Do
End Select
Loop

FRAMEBUFFER CLOSE
CLS COL_OFF
Print "Game of Life ended."
End

Edited 2025-08-16 17:39 by matherp
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2668
Posted: 07:40am 16 Aug 2025
Copy link to clipboard 
Print this post

Thanks for that. I noticed it eventually settles into an almost static state with just a few cells flipping back and forth.

Edit.
Adding Peter's extra line improves the lifespan of Life.

If Rnd<0.001 Then newv% = Not newv% 'add random element

On a Pico 1 LCD it is about 8700 iterations and a Pico 2 VGA 12600 and still evolving.
Edited 2025-08-16 22:15 by phil99
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025