Skip to main content

                         THE WAY OF LIFE
                       By Stefan Posthuma

 It had been quite a long day at work, it had started off with an
early-morning  meeting  in a smelly room,  full  of  smoking  and
droning people.  I had a headache for the rest of the  day,  idly
staring  at  my computer screen,  browsing through  some  network
news,  polishing up some programs I had been working  on.  Dinner
afterwards  with some clients that wasn't  particularly  exciting
too.  Well,  at  least  the food was good.  The drive  back  from
Amsterdam was a long one,  road construction causing queues  even
at  10  in  the evening.  I pulled into  the  parking  lot  while
observing that old lady that always seemed to walk her  dog.  The
contradiction between these two was remarkable.  The old lady was
bent and grey, the dog an energetic, and somewhat nervous inbreed
that  was yapping frantically at the dark silhouette of  my  car.
It's eyes lit up in my headlights and I slowed down to allow  the
old  lady to pass,  she was trying to control the struggling  dog
while  talking to it.  What she said was drowned in the loud  Dr.
Jeep playing on my car CD player.
 I  felt the engine stop as I turned the key and the CD slid  out
of the player when I removed the little panel.  I locked the door
and  walked towards the brightly lit entrance of  the  appartment
building.  At the door,  the fumbling with the keys,  opening the
mailbox  finding  a  pile  of junkmail  that  I  dropped  in  the
container next to the elevator.  I wondered why the light in  the
stairway was always on, it seemed a waste of energy to me.
 I  unlocked  the  door of my place on the third  floor  and  the
familiar  smell  of  incence  and garlic  made  me  feel  welcome
immediately. I dropped my briefcase on the table and did my usual
round.  Yes,  VCR recorded the stuff that had been on that night,
both  hamsters  were alive and kicking,  puttering  around  their
cages.  The  little light on the answering machine was  blinking,
people  had  called.  Better water that plant,  it  looks  a  bit
dehydrated.  I opened the door of one of the hamster cage next to
the telephone,  the little animal immediately getting out,  ready
to roam.
 "Hi,  this is Caroline.", the answering machine said as I walked
to the fridge.
 "It's about Friday night, I can't make it."
 "Shit", I said while opening a beer.
 "Call me okay?".
 Some  beeping  sounds,   "Yo  Stef.  Eric  here.  I  did  it,  5
generations per second at 4000 cells. Beat that, sucker!"
 I  sat down by the phone and punched  Caroline's  number.  While
talking  to  her,  I watched the hamster crawl into  the  box  of
hamster food, I was too late to stop it. She laughed about it.
 Damn, date postponed for two weeks. Ah well, can't have it all.
 I watched in fascination as the hamster tried to get out of  the
box again. Obviously, it hadn't accounted for pouches filled with
hamsterfood  being  able  to  fit through the  hole  and  it  was
struggling fiercely to get out.
 "Eric. So tell me the deal. Five generations huh?".
 "Yeah,  I figured out this really smart algorithm. It caches the
neighbour counts for three rows, making it some 15% faster."
 "Cool", I said. "Now let me try. I'll get back to you."
 "You'll  never  make  it!  By the way,  I  had  some  help  from
Hubert J."
 "Right. Well, just wait and see."
 I  hung  up the phone and watched the  hamster  finally  release
itself from the box.  It immediately hurried back to the cage  to
store the prize it just got.  I made a mental note not to feed it
for a couple of days.
 That  Friday night when I should have been out with  Caroline  I
wrote the game of Life. A pretty fast one too.

 So  what the hell is the game of Life you  might  wonder.  Well,
picture a screen full of little blocks. Every block can be either
on or off,  or in Life terms alive or dead.  A block is called  a
cell by the way. Right. So what's the big deal?
 Well, by applying certain rules to these cells, we can have them
die  and being born on our screen.  These rules are  simple.  You
scan  the screen,  and for every cell,  you count the  number  of
alive neighbours it has.  If a cell has two or three  neighbours,
it stays alive, otherwise it dies. Also, if there isn't a cell in
the  spot  you  are  looking  at,   and  there  are  three  cells
surrounding the empty spot,  a cell gets 'born', i.e. you put one
there.  This sounds a bit silly,  but if you keep displaying  the
results  of these rules on the screen,  you get some  fascinating
patterns and animations on your screen.
 The  way it works is that you have a field with let's say  bytes
that  are either 0 (dead) or $FF (alive).  If you want to make  a
scan,  called a generation,  you look at the first one, count its
neighbours  and store the result (it lives or dies or gets  born)
in another field. This to make sure that changes that are made to
the field don't influence the other cells. I mean if a cell dies,
and  you  would delete it in the  current  field,  the  neighbour
counts for the surrounding cells would change and things would go
wrong.
 So after you have scanned the entire field, you clear the screen
and  draw the field you have just created.  Then you  repeat  the
process,  starting  from  the  second  field.  Now  this  is  the
traditional and slow way.  I mean having to count the  neighbours
for  each cell every time is a pretty slow process and  redrawing
the entire field every time is madness.
 I thought about it a bit and came up with the following. Why not
have  a  field that for each cell has a count of  the  number  of
living  neighbours that cell has?  In that case you only have  to
look  at the number and decide whether or not the cell  lives  or
dies.  I  look at the screen memory to see if there is a cell  or
not.  The  only  trick  here is to keep track of  the  number  of
neighbours of each cell.  If a cell gets born, you add one to the
neighbour count of the surrounding cells, and if a cell dies, you
subtract one.  Also, while going through the field, I keep a list
of changes that have to be made to the screen.  The only thing  I
do really, is keep a list of screen addresses where cells have to
be toggled.
 That's it really, time for some code.

 First  some equates I use.  Number of lines and columns  on  the
screen plus the size of a scanline.  The field is actually 50  by
82  because  the cells at the edges are  always  0  (dead).  This
causes Life to fail around the edges,  but there is no other  way
really.  Some people make it wrap around,  but this is too  slow,
you have to look at the position all the time then.  This is  why
COLS2  is defined,  the actual width of the field to be  scanned.
This  also means that there are 46 lines of cells on the  screen.
The  top and bottom two lines are used for status  messages.  You
must  have figured that the cells are 8 by 8 pixels.  The  system
font used is 16 pixels, two rows of cells.

LINES           EQU     50
COLS            EQU     80
COLS2           EQU     COLS+2
SCANLINE        EQU     80

 Then I declare two macros,  used to adjust the neighbour  counts
for cells when one gets born or one dies.  A1 has to point to the
current cell in the field.

* SUBSTRACT 1 FROM ALL THE CELLS AROUND A1
SUB_AROUND      MACRO
                SUBQ.B  #1,-1(A1)
                SUBQ.B  #1,1(A1)
                SUBQ.B  #1,-COLS2-1(A1)
                SUBQ.B  #1,-COLS2(A1)
                SUBQ.B  #1,-COLS2+1(A1)
                SUBQ.B  #1,COLS2-1(A1)
                SUBQ.B  #1,COLS2(A1)
                SUBQ.B  #1,COLS2+1(A1)
                ENDM

* ADD 1 TO ALL THE CELLS AROUND A1
ADD_AROUND      MACRO
                ADDQ.B  #1,-1(A1)
                ADDQ.B  #1,1(A1)
                ADDQ.B  #1,-COLS2-1(A1)
                ADDQ.B  #1,-COLS2(A1)
                ADDQ.B  #1,-COLS2+1(A1)
                ADDQ.B  #1,COLS2-1(A1)
                ADDQ.B  #1,COLS2(A1)
                ADDQ.B  #1,COLS2+1(A1)
                ENDM

 In the real source, a lot of stuff follows to set up things, the
main  loop and the editor used.  This is trivial  stuff,  I  will
continue at the actual loop that does a generation of Life.

 GENCOUNT  is  a generation counter that is used to  display  the
number of generations per second.  This handled by the VBL, after
70 vbls (monchrome) it will display this number.
 USE_FIELD contains the address of the current Life field. FIELD1
and FIELD2 are the fields.
 SCREEN is obvious of course,  DRAW_LIST is the list of cells  to
be toggled on screen.

 First  of  all,  swap  the  fields and store  the  used  one  in
USE_FIELD.

DO_IT           ADDQ.W  #1,GENCOUNT
                MOVE.L  USE_FIELD(PC),A0
                CMP.L   #FIELD1,A0
                BNE.S   .1
                LEA     FIELD2(PC),A1
                BRA.S   .2
.1              LEA     FIELD1(PC),A1
.2              MOVE.L  A1,USE_FIELD

 Then skip the edge, 82 on top plus one on the left.

                LEA     COLS+3(A0),A0           ADJUST
                LEA     COLS+3(A1),A1

 The first two lines contain the status line, so these have to be
skipped. D1 and D2 are filled with important compare values, it's
faster to compare with a data register than it is with a constant
value.  2  and 3 are the crucial number of cells.  D3 counts  the
columns  on the screen,  and D4 counts the lines.  D5 is used  to
clear values.

                MOVE.L  SCREEN(PC),A2
                LEA     SCANLINE*16(A2),A2      SKIP STATUSLINE
                LEA     DRAW_LIST(PC),A3
                MOVEQ   #2,D1                   TEST VALUES
                MOVEQ   #3,D2
                MOVEQ   #COLS-1,D3              COLUMN COUNTER
                MOVEQ   #LINES-1,D4             LINE COUNTER
                MOVEQ   #0,D5

 The the loop follows.  A2 is the screen address and we test this
to see if there is a cell or not. If there is a cell, we move the
number  of neighbours into D0 and compare this with 2 and  3,  D1
and D2. This to see if the cell will stay alive.

THE_LOOP:       TST.B   (A2)            CELL ON SCREEN?
                BEQ.S   NOCELL
CELL:           MOVE.B  (A0),D0         NR OF SURROUNDING CELLS
                CMP.B   D1,D0           TWO?
                BEQ.S   NEXTCELL        FINE
                CMP.B   D2,D0           THREE?
                BEQ.S   NEXTCELL

 Here the cell dies.  We subtract the neighbour counters for  the
surrounding  cells and put the screen addres in the draw list  to
be toggled later.

DIE:            SUB_AROUND              NO, DECREASE COUNTERS
                MOVE.L  A2,(A3)+        PUT IN DRAWLIST
                BRA.S   NEXTCELL

 Now  there  is  no cell on the screen.  We  get  the  number  of
surrounding cells.  First BEQ.S if the number is zero,  this will
happen a lot.  In this case we skip everything and jump  straight
to the end of the loop. Then we compare the number with D2 to see
if  there are three surrounding cells.  If not,  skip  the  birth
code.

NOCELL:         MOVE.B  (A0),D0         GET NR OF SURR. CELLS
                BEQ.S   N1              SKIP 0 CELLS (FASTER)
                CMP.W   D2,D0           THREE CELLS SURROUND?
                BNE.S   NEXTCELL        NO WAY

 This is where a cell is born, just add one to all the neighbours
and put the screen address in the draw list.

BIRTH:          ADD_AROUND
                MOVE.L  A2,(A3)+                PUT IN DRAWLIST

 Here  we  add  the original number of neighbours  to  the  value
present. We can't move it since the value might have been altered
by other cells around it dying or getting born.

NEXTCELL:       ADD.B   D0,(A1)                 TRANSPORT VALUE

 Clear  the  used cell,  increase the field address  pointer  and
screen  address.  After one row has been  done,  increase  screen
address  and skip the edge of the fields.  Then the last DBRA  is
for the row counter, D4.

N1:             MOVE.B  D5,(A0)+                CLEAR USED CELL
                ADDQ.L  #1,A1
                ADDQ.L  #1,A2                   INC. SCREEN ADDR.
                DBRA    D3,THE_LOOP             NOT YET AT EDGE
                MOVE.W  #COLS-1,D3
                LEA     SCANLINE*7(A2),A2
                ADDQ.L  #2,A1                   SKIP EDGES
                ADDQ.L  #2,A0
                DBRA    D4,THE_LOOP

 The generation has been completed.  Now we calculate the  number
of  cells  by  subtracting  the DRAW_LIST  address  from  A3  and
dividing it by four, it contains longwords. The routine DRAW_THEM
actually draws and erases the cells in DRAW_LIST.

                SUB.L   #DRAW_LIST,A3           GET NR. OF CELLS
                MOVE.L  A3,D6
                LSR.W   #2,D6                   DIVIDE BY FOUR
                SUBQ.W  #1,D6
                BSR     DRAW_THEM               DRAW THE CELLS
                BRA     RUNLOOP                 BACK TO START!

 This  routine  goes through the DRAW_LIST and  uses  the  screen
addresses there to toggle the cells.  It takes the first byte  on
screen,  NOTs it and puts this value in the 8  scanlines.  Notice
the REPT 8 for loop-elimination.

DRAW_THEM:      LEA     DRAW_LIST(PC),A0
                TST.W   D6
                BPL.S   .1
                RTS
.1              MOVE.L  (A0)+,A1
                MOVE.B  (A1),D0
                NOT.B   D0
VAL             SET     0
                REPT    8
                MOVE.B  D0,VAL(A1)
VAL             SET     VAL+SCANLINE
                ENDR
                DBRA    D6,.1
                RTS

 Well,  that's it really.  Very simple if you ask me. Have a look
at  LIFEMONO.S in the PROGRAMS folder on this disk for  the  full
source. Monochrome only.

 When  I  was at the DeltaForce ICC #2 in July 1991  (or  was  it
June?) Tim was finishing off the main menu for the Ooh Crikey Wot
a Scorcher demo.  Now he was adding nice bits like the little man
falling  out of the ship and he also wanted to add a  helpscreen.
Now to make this a bit more than just a screen full of  text,  we
decided  it  needed some kind of animation or  something  in  the
background.  I then suggested using Life and so we did.  I didn't
bring my original source,  so I had to rewrite it from scratch. I
also  got the idea to have cells not immediately  disappear  when
they died, but to let them shrink or something. The cell would be
marked  as  dead for the algorithm to work properly (so  a  dying
cell could be replaced by a live one at any stage) but it  worked
out beautifully.  Since this was in lo-res, and I still wanted to
used  bytes  (lazy  git)  there were only  40*25  =  2000  cells,
resulting in an incredibly fast Life.  I actually had to slow  it
down a bit (to 3 VBLs) to make it a reasonable speed.
 That  was the last of Life programming for me until a friend  of
mine from the States (the first ever USA demo crew I know)  asked
me  if I wanted to do a guest screen for their demo.  Now I  have
little  or  no time to code these days so I polished up  the  old
Life  source a bit.  Added some status  lines,  some  colors,  an
editor and another screen was born.

 If  you run the version on this ST NEWS disk,  you will  get  an
empty  field with a cursor in the left-hand corner.  This  cursor
can  be moved with the cursor keys (how imaginative) and you  can
toggle  cells  on screen using the space bar.  If  you  used  the
keypad, you will move the cursor and draw cells at the same time.
Press F1 and the game will begin.  Play around with it a  little.
By  placing a few random cells here and there,  you can get  some
fascinating   results.   Sometimes  it  can  take   hundreds   of
generations  before the colony stabilizes i.e.  all cells die  or
the patterns keep repeating themselves.  If you have a  repeating
pattern,   adding   or  deleting  one  cell  can   have   drastic
consequences,  the  whole thing quickly disappearing  or  blowing
itself up into a myriad of patterns.  Also,  sometimes cells just
get  'swallowed' by a pattern.  You can make crawlers  that  move
across the screen:

       *
        *
     ****

 This is the simplest one,  it will travel diagonally down and to
the right. If it bumps into something it will mostly disrupt that
object.  There  are  entire  studies dedicated to  this  kind  of
patterns,  people have come up with the most amazing stuff.  Like
'guns'  that  emit  one  of  these  crawlers  at  intervals,  and
'absorbers'  that  can absorb a crawler.  Thus you can  have  two
pulsating  patterns  with crawlers  moving  between  them.  Also,
people have made huge crawlers,  patterns made out of hundreds of
cells that move across the screen,  sometimes even accompanied by
smaller 'sattelites'.
 One  day I will make a Life where the cells are  represented  by
much smaller units than bytes (pixels maybe?) and I can try  some
really wild patterns. These can be found in magazines and stuff.

 So much for Life.

Disclaimer
The text of the articles is identical to the originals like they appeared in old ST NEWS issues. Please take into consideration that the author(s) was (were) a lot younger and less responsible back then. So bad jokes, bad English, youthful arrogance, insults, bravura, over-crediting and tastelessness should be taken with at least a grain of salt. Any contact and/or payment information, as well as deadlines/release dates of any kind should be regarded as outdated. Due to the fact that these pages are not actually contained in an Atari executable here, references to scroll texts, featured demo screens and hidden articles may also be irrelevant.