Skip to content

Improve 1DLIFE.BAS: Less memory, more speed, constant printing#12

Open
HedAurabesh wants to merge 2 commits into
Nakazoto:mainfrom
HedAurabesh:main
Open

Improve 1DLIFE.BAS: Less memory, more speed, constant printing#12
HedAurabesh wants to merge 2 commits into
Nakazoto:mainfrom
HedAurabesh:main

Conversation

@HedAurabesh

Copy link
Copy Markdown

This improves the 1-D Life code in several ways, as outlined in my YouTube comment on running this code on the Centurion.

The new code improves the following:

  • Instead of two arrays, only uses one array
  • Instead of a binary state (life/death) stores a 2-bit state (past & future life/death)
  • Instead of writing twice to the array, only writes once
  • Instead of looping to find the neighbors, uses a mathematical expression.

Due to this, the code runs ~2x faster, has less lines of code and does not create a pause before printing a line, since printing and updates are now the same.

The state is encoded with 2 bits:

  • 0 = Stay Dead
  • 1 = Be Born
  • 2 = Die
  • 3 = Stay Alive

So the past & future life/death state can be extracted via dividing by two (past) or by taking the modulo (future).

The general flow is:

Initialize the array X with random values from [0, 3]
For each cell in X:
  IF cell was alive PRINT "X" ELSE " ";
  IF cell was alive AND has (2 || 4) neighbors THEN set X[C] = 3 (Lives) ELSE 2 (Dies)
  IF cell was dead AND has (2 || 3) neighbors THEN set X[C] = 0 (Stays dead) ELSE 1 (Gets born)

The neighbour count is the value S computed as:
S = (X[C-2] / 2) + (X[C-1] / 2) + (X[C+1] % 2) + (X[C+2] % 2)

Do note how the already modified left-neighbors use the past state (division), while the unmodified cells use the present/future state (modulo)

This improves the 1-D Life code in several ways, as outlined in my YouTube comment on running this code on the Centurion.

The new code improves the following:
- Instead of two arrays, only uses one array
- Instead of a binary state (life/death) stores a 2-bit state (past & future life/death)
- Instead of writing twice to the array, only writes once
- Instead of looping to find the neighbors, uses a mathematical expression.

Due to this, the code runs ~2x faster, has less lines of code and does not create a pause before printing a line, since printing and updates are now the same.

The state is encoded with 2 bits:
* 0 = Stay Dead  (was dead)
* 1 = Be Born      (was dead)
* 2 = Die             (was alive)
* 3 = Stay Alive   (was alive)

So the past & future state can be extracted via dividing by two (past) or by taking the modulo (future).

The general flow is:

* Initialize the array X with random values from [0, 3]
* For each cell in X:
* > IF cell was alive PRINT "X" ELSE " ";
* > IF cell was alive AND has (2 || 4) neighbors THEN set X[C] = 3 (Lives) ELSE 2 (Dies)
* > IF cell was dead AND has (2 || 3) neighbors THEN set X[C] = 0 (Stays dead) ELSE 1 (Gets born)

The neighbour count is the value S computed as:
S = (X[C-2] / 2) + (X[C-1] / 2) + (X[C+1] % 2) + (X[C+2] % 2)

Do note how the already modified left-neighbors use the past state (division), while the unmodified cells use the present/future state (modulo)
@HedAurabesh

HedAurabesh commented Jul 13, 2026

Copy link
Copy Markdown
Author

Also note: If MOD is not available, it can be replaced by bitwise AND -- or unrolled into a loop:

120 LET ALIVE = X(I) AND 1

If divisions by two is slow -- and SHR is not available -- one can unroll the computation of S with an IF statement:

200 LET S = 0
201 IF X(I-2) > 1 THEN LET S = S+1
202 IF X(I-1) > 1 THEN LET S = S+1
203 LET S = S + (X(I+1) AND 1)
204 LET S = S + (X(I+2) AND 1)

Of course, for maximum compatibility, the above has to be unrolled into "IF-THEN-GOTO-LINE" statements.

Changed the code to be more portable

* Made it so the array starts with 1 instead of 0
* Consistent use of LET in all assignments
* Replaced the MOD with an arithmetic version, as neither MOD nor bitwise AND are universally present (looking at you Spectrum Basic)
@HedAurabesh

Copy link
Copy Markdown
Author

I updated the code in this pull request to be more portable.

Most notably, arrays now start with index 1 and the MOD function (which isn't universal) was replaced with its slower, but portable arithmetic variant.

Things I learned: In Spectrum Basic "AND" is not a bitwise AND -- but a weird hack for a specific use case of "AND".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant