LIFE
by Nicholas Campbell
--------------------
Last updated: 21st September 1998
Welcome to the game of LIFE! This instruction file is to get you started with
LIFE and to tell you more about the rules and history of LIFE. There are also
lots of examples of patterns for you to examine yourself.
What is LIFE?
-------------
LIFE is one of the most famous mathematical games of all time. It was devised
by a British mathematician called John Conway in 1970, but came to
prominence the following year after an article about LIFE appeared in the
Scientific American magazine. It involves the use of counters on a grid, in
which there are lots of cells. There are only three rules to LIFE:
* If a counter has less than two neighbouring counters, it dies of starvation.
* If a counter has more than three neighbouring counters, it dies of
overcrowding.
* A new counter is created in a cell with three neighbouring counters.
Even though these rules may seem basic, LIFE can form an enormous range of
patterns, often from just a few counters. Each new pattern is called a
generation, and some patterns can continue for over a thousand generations!
This is why it has fascinated people for so long. Remember that when Conway
first developed LIFE, he didn't have the use of computers, and had to work out
each generation manually! Now you're about to see what LIFE is all about...
You'll soon see that my version of LIFE uses counters that look like little
blobs. From now on, I'll refer to counters as blobs - I like thinking about
them in this way.
What makes this version of LIFE different from others?
------------------------------------------------------
Throughout my time using the CPC, I have seen several versions of LIFE running.
However, I thought that whilst it was fascinating watching these blobs
generating, it wasn't actually all that interesting to look at, so I wrote my
own version, which used six different colours of blob to make LIFE more
colourful and exciting. You'll notice this as soon as you run LIFE!
Another thing is that my version of LIFE is written in only ten lines of BASIC!
Yes, I know I'm cheating because the program itself is entirely in machine
code (try LISTing the program and see it for yourself), but it is quite short
and only takes 3K of space on the disc. It is also reasonably fast and
efficient, as far as I know - each generation takes, on average, just 0.62
seconds to calculate and display.
This version of LIFE does have one problem in that the grid is only 40 x 24
cells in size, making for a total of 960 cells. This may seem a lot, but it is
quite restrictive for some larger patterns.
How do I run LIFE?
------------------
LIFE is run from BASIC by entering RUN"LIFE" at the Ready prompt, and once
the program has loaded, wait for about 12 seconds as the program reads the
machine code data needed for LIFE.
After this, the screen will turn blank and the message, "LIFE ¤ Nicholas
Campbell 1998" will appear at the bottom of the screen. There will also be a
cursor at the top-left of the screen.
What are the controls for LIFE?
-------------------------------
The cursor is moved using the cursor keys. You can add and remove blobs using
the COPY key. When you've finished designing the first generation of blobs, you
can start generating LIFE by pressing the SPACE bar. Pressing any other key
stops the blobs from generating, and allows you to edit the pattern again.
It's often interesting to see what becomes of a random set of blobs - you never
know what might happen! To do this, press R, and the grid will be replaced with
blobs chosen at random.
Finally, if you want to start again and clear the screen of blobs, press C. Any
blobs on the screen will be cleared, and you can then create a new pattern.
Unfortunately, LIFE doesn't have an option to return to BASIC. I know this is
annoying, but I wouldn't have been able to fit the program into ten lines
otherwise!
What sort of patterns are there?
--------------------------------
If you try running some random patterns using the R key, you'll notice that the
pattern will eventually stabilise after a certain amount of time, leaving
behind some small patterns which do not change. These can be divided into two
categories - still lifes and oscillators.
Still lifes are patterns which remain the same in each generation - they are
stable. The most frequent of these is the block. You'll also encounter the
beehive fairly regularly. Less often, you'll meet the tub, the boat, the
loaf and the pond. There are also many larger still lifes, but these are made
"artificially" - you won't see them being formed from random patterns.
o oo
oo oo o oo o o o o
oo o o o o o o o o o o
oo o o oo oo
block beehive tub boat loaf pond
Oscillators are patterns which return to their original form after a number of
generations. The most common of these is the blinker, but you might also see
others, such as the toad and the beacon. Other smaller oscillators have been
found, but these don't occur naturally. They include the clock, the figure of
eight and the tumbler, which turns itself upside-down every seven generations.
ooo oo oo
o o ooo oo oo
o o oo o o ooo o o
ooo o o o o o o ooo o o o o
o oo o ooo o o o o
ooo oo oo
blinker toad beacon clock figure of 8 tumbler
Another common oscillator, the pulsar, can be created from the pattern below.
ooooo
o o
Other, much larger (and much more impressive!) oscillators have been created,
such as the cross, the octagon, the "clock II", the galaxy and the
pentadecathlon - an oscillator which returns to its original form after fifteen
generations.
oo
oo
oooo oo oooooo oo
o o o o oooo oooooo oo
ooo ooo o o oo o o oo
o o o o oo o o o oo oo o o
o o o o o o o oo oo oo oo oooo oo
ooo ooo o o o o o oo oo oo o o
o o o o oooo oo
oooo oo oo oooooo
oo oo oooooo
oo
cross octagon clock II galaxy pentadecathlon
Try them all out for yourself and see what they're like!
There are also patterns which are referred to as methuselahs. They start off as
being small, but they last for an extremely long number of generations.
Unfortunately, my version of LIFE, with its small grid, doesn't have enough
space to allow them to fulfil the number of generations they would otherwise go
on for. Three well-known examples are the R-pentomino, the acorn, and rabbits,
which can go on for an amazing 17331 generations!
oo o o ooo
oo o ooo o
o oo ooo o
R-pentomino acorn rabbits
Finally, we'll come to the subject of spaceships. These are patterns which move
across the screen without evolving into other patterns. The most common one is
the glider, which moves across the screen diagonally.
o
o
ooo
glider
Another extremely curious thing which was discovered was the still life known
as the eater, which has the ability to swallow objects such as gliders and then
return to its original form. Try it with a glider, like this:
o
o
ooo
oo
o o
o
oo
Other small spaceships include the lightweight, mediumweight and heavyweight
spaceships, which move horizontally along the screen.
o o o
o o o
o o o o o o
oooo ooooo oooooo
LWSS MWSS HWSS
There are a huge number of other still lifes and oscillators, but most of these
are too big to contain within the grid used by my version of LIFE! There are
some catalogues and glossaries available on the World Wide Web - see the URLs
below.
Where can I find more about LIFE?
---------------------------------
The April 1990 issue of Amstrad Computer User had an article on LIFE, with a
BASIC and a machine code program written by "Auntie" John Kennedy, to compare
how much faster LIFE is when it's written in machine code! The article was just
an introduction to LIFE, with a few patterns to try out. As for the program,
it's in MODE 1, even though it's in monochrome, and it has a 40 x 25 grid,
consisting of 1000 cells - that's 40 more than my version. The advantage is
that it is rather fast at calculating each generation!
If you want to try another version of LIFE, the May 1989 issue of Amstrad
Action (issue 44) had a type-in written by John Fitzpatrick. It's in MODE 2 and
is quite slow, but it has a large grid (160 x 92; 14720 cells!), which is quite
sufficient.
If you're connected to the Internet, there are several websites, mostly written
by mathematicians, about LIFE. Note that many of them make use of LIFE programs
written in Java! Some of the better ones are listed below (those marked with an
asterisk are recommended by me):
TUTORIALS
---------
http://serendip.brynmawr.edu/playground/life.html
http://simon.cs.cornell.edu/home/xliu/life.html
http://www.brunel.ac.uk/depts/AI/alife/al-gamel.htm *
http://www.xs4all.nl/~ranx/gameoflife/
ENTHUSIASTS' WEBSITES
---------------------
http://www.astro.virginia.edu/~eww6n/math/Life.html
http://www.cs.jhu.edu/~callahan/lifepage.html *
http://www.mindspring.com/~alanh/life/
http://www.uni-bielefeld.de/~achim/gol.html *
GLOSSARIES
----------
http://www.cs.jhu.edu/~callahan/lexicon.html *
http://www.halcyon.com/hkoenig/LifeInfo/LifeInfo.html
NEWSLETTERS
-----------
http://home.earthlink.net/~hilery/life/
If any of these URLs are incorrect, or they no longer exist, or if you have a
website about LIFE and it isn't here, then tell me about it! I want to make
this information as accurate as I can.
I might also think about putting my own LIFE website on the World Wide Web! If
you want more information, you can e-mail me at n.a.campbellàdurham.ac.uk.
What is the copyright information on LIFE?
------------------------------------------
LIFE itself isn't a trademark, as every LIFE-based CPC program I've seen is
always entitled LIFE. This particular version of LIFE was written by Nicholas
Campbell in 1998.
With your LIFE program, you may also find the following files:
LIFE . - the LIFE program
LIFE .ASM - the source code for the LIFE program
LIFE .TXT - this instruction file
You have my permission to freely distribute LIFE, either with or without both
the source code and this instruction file, to anyone. It would be preferable if
you included the instruction file, though, as it would make things easier for
the people you distribute it to! However, any alterations you make to the code
are only for your own personal use, and you must not distribute any code which
has been altered!
The LIFE program is provided as a BASIC listing. This is so that fanzines can
print the listing if they want to, for their readers to type out (although it's
quite tricky!). They have my permission to do so, as long as they tell me about
it first!
NOTICE TEXTE n° 2 (21.51 Ko)
;LIFE - 10-Liner version v1.0
;All code and graphics (c) Nicholas Campbell 1998
;This program is public domain and may be freely distributed, but if you want
;to alter the program in any way, it is ONLY for your own personal use!
org &8000
nolist
;initialise the screen colours and mode
xor a ;set the screen to MODE 0
call &bc0e
ld b,0 ;set the border to black (colour 0)
ld c,b ;BC contains the border colour
call &bc38
ld d,0 ;start with ink 0
ld hl,ink_data
.change_inks
push de ;store the ink number
push hl ;store the table address
ld a,(hl) ;get the colour for that ink from the table
ld b,a ;BC contains the ink colour
ld c,a
ld a,d ;A contains the ink to set
call &bc32
pop hl ;get the table address
pop de ;get the ink number
inc hl ;select the next ink
inc d
ld a,d ;are all the inks set to the correct colours?
cp 14
jr nz,change_inks ;if not, go and change the next ink
ld a,1 ;reset the x- and y-coordinates to the top
ld (ybyte),a ;left-hand corner of the screen
ld (xbyte),a
;display the little message at the bottom of the screen
ld de,&0619 ;the message starts at column 6, row 25 (at the
;bottom of the screen)
call calc_scraddr ;calculate the screen address
ld b,30 ;the message is 30 characters long
ld hl,message
.print_string
ld a,(hl)
push bc ;store the length of the string
push hl ;store the string address
call print_sprite
ld hl,&c002 ;DE contains the screen address on exit
add hl,de ;go to the next column
ld (scraddr),hl ;store the new screen address
pop hl ;get the string address
pop bc ;get the length of the string
inc hl ;move to the next character in the string
djnz print_string
;the screen editor where blobs can be added and removed. Use the cursor keys
;and COPY to move the cursor. C clears the screen, R fills the screen with
;random blobs, and SPACE starts generating blobs (press any key to stop)
.editor
ld de,(ybyte) ;get the x- and y-coordinates for the cursor
call calc_scraddr ;calculate the screen address
ld a,1 ;display the cursor (sprite number 1)
call print_sprite
ld bc,8000 ;this routine slows the cursor down. Changing the
.delay ;value of BC will alter the speed of the cursor
dec bc
ld a,b ;a quick way to check whether BC is zero. If both
or c ;B and C are zero, then the zero flag is reset
jr nz,delay
;check if the user has pressed any of the keys
or a ;up arrow
call &bb1e
jr nz,move_up
ld a,2 ;down arrow
call &bb1e
jr nz,move_down
ld a,8 ;left arrow
call &bb1e
jr nz,move_left
ld a,1 ;right arrow
call &bb1e
jr nz,move_right
.press_copy
ld a,9 ;COPY
call &bb1e
call nz,place_blob
ld a,50 ;R
call &bb1e
call nz,random_grid
ld a,62 ;C
call &bb1e
call nz,disp_clear_grid
ld a,47 ;SPACE
call &bb1e
call nz,start
jr editor ;go back to check the keys again
.move_up
ld a,(ybyte) ;get the y-coordinate
cp 1 ;is the cursor already at the top of the screen?
jr z,editor ;yes, so return
call show_blob ;no, so display the blob under the cursor (if
;there is one)
dec a ;move the cursor to the previous row
ld (ybyte),a ;store the new y-coordinate
jr press_copy
.move_down
ld a,(ybyte)
cp 24 ;is the cursor already at the bottom of the
jr z,editor ;screen?
call show_blob
inc a ;move the cursor to the next row
ld (ybyte),a ;store the new y-coordinate
jr press_copy
.move_left
ld a,(xbyte) ;get the x-coordinate
cp 1 ;is the cursor already at the left of the screen?
jr z,editor
call show_blob
dec a ;move the cursor to the previous column
ld (xbyte),a ;store the new x-coordinate
jr press_copy
.move_right
ld a,(xbyte)
cp 40 ;is the cursor already at the left of the screen?
jp z,editor
call show_blob
inc a ;move the cursor to the next column
ld (xbyte),a ;store the new x-coordinate
jr press_copy
;place a blob at the current x- and y-coordinates
.place_blob
ld a,9 ;wait until the user lifts their finger off the
call &bb1e ;COPY key. This prevents the blob being removed
jr nz,place_blob ;again
call calc_gridaddr ;calculate the grid address
;if it isn't necessary to check the COPY key, then JumP here
.place_blob2
ld a,(hl) ;if there is already a blob under the cursor,
or a ;then remove it
jr nz,reset_blob
.select_colour
ld a,(blob_colour) ;each colour is chosen in sequence - 2=red,
;3=orange, 4=yellow, 5=green, 6=blue, 7=purple
ld (hl),a ;place a blob underneath the cursor
inc a ;select the next colour
ld (blob_colour),a
cp 8 ;the next colour after purple is red!
ret nz
ld a,2
ld (blob_colour),a
ret
;remove a blob at the current x- and y-coordinates
.reset_blob
xor a
ld (hl),a
ret
;show the blob under the cursor (if there is one)
.show_blob
push af ;store the x- or y-coordinate to change later
call calc_gridaddr ;calculate the grid address
push hl ;store the grid address
call calc_scraddr ;calculate the screen address
pop hl ;get the grid address
ld a,(hl) ;print the blob under the cursor (if there is
call print_sprite ;one)
pop af ;get the x- or y-coordinate
ret
;print a sprite at the screen address in scraddr - corrupts A, BC, DE and HL
;Entry - A contains sprite number
;NOTE - scraddr must be calculated beforehand!
.print_sprite
;first of all, work out the location of the sprite
inc a
ld hl,sprite_data-16
ld de,16 ;each sprite is 16 bytes long
ld b,a
.calc_spriteaddr
add hl,de ;go to the next sprite
djnz calc_spriteaddr ;HL now contains the sprite address
ld bc,&0808 ;there are 8 lines in the sprite (B), and &800
;to add after each line (C)
ld de,(scraddr) ;get the screen address
.sprite_loop
ld a,(hl) ;
ld (de),a ;this method is quicker than the LDI instruction,
inc e ;even though it uses more memory!
inc hl ;
ld a,(hl)
ld (de),a
dec e
inc hl
ld a,d ;a quick way of adding &800 to DE to go to the
add c ;next line down. C=8, so adding 8 to D is the
ld d,a ;same as adding &800 to DE! (Thanks to Simon
;Matthews and BTL for that one!)
djnz sprite_loop
ret
;calculate the screen address and store it in scraddr - corrupts BC, DE and HL
;Entry - D contains x-coordinate, E contains y-coordinate
;Exit - HL and scraddr both contain screen address
.calc_scraddr
;work out the column number
ld hl,&bfaf
ld b,0
ld a,d ;multiply the x-coordinate by 2 and subtract 1
add a
dec a
ld c,a
add hl,bc
;work out the row number
ld b,e ;B contains the y-coordinate
ld de,80 ;each row is 80 bytes long
.scraddr_loop
add hl,de ;go to the next row
djnz scraddr_loop
ld (scraddr),hl ;store the screen address
ret
;calculate the grid address using the x- and y-coordinates in ybyte - corrupts
;BC, DE and HL
;Exit - HL contains grid address
.calc_gridaddr
ld hl,grid-41
ld de,(ybyte) ;get the x- and y-coordinates
push de ;store them
ld b,0
ld c,d
add hl,bc
ld b,e ;B contains the y-coordinate
ld de,40 ;each row is 40 bytes long
.gridaddr_loop
add hl,de ;go to the next row
djnz gridaddr_loop
pop de ;restore the x- and y-coordinates
ret
;fill the grid with random blobs and display the result - corrupts A, BC, DE
;and HL
.random_grid
ld b,6 ;repeat this process six times to ensure the grid
;is actually done randomly!
.random_loop
ld hl,grid ;move to the start of the grid
ld de,(ybyte) ;get the current coordinates of the cursor
push de ;store them
ld de,&0101 ;start at the top left-hand corner of the screen
ld (ybyte),de
.random_loop2
ld a,r ;get a random value from the R register
and 1 ;make it equal either 0 or 1
call nz,place_blob2 ;if it's 1, then place a blob at the current
;grid address
inc d ;go to the next column
inc hl
ld a,d
cp 41 ;are we at the right of the screen?
jr nz,random_loop2 ;no, so go back and select another blob
ld d,1 ;yes, so go back to the left of the screen
inc e ;go to the next row
ld a,e
cp 25 ;are we at the bottom of the screen?
jr nz,random_loop2 ;no, so go back and select another blob
pop de ;yes, so restore the cursor coordinates to what
ld (ybyte),de ;they were before
djnz random_loop ;this process has to be repeated six times!
jr display_grid ;display the grid
;clear the grid and clear the screen as well - corrupts A, BC, DE and HL
.disp_clear_grid
call clear_grid
jr display_grid
;display the grid on the screen - corrupts A, BC, DE and HL
.display_grid
ld de,&c000 ;the screen starts at &C000
ld (scraddr),de
ld hl,grid
ld bc,960 ;the grid consists of 960 cells
.display_loop
ld a,(hl) ;get the colour of the blob under the cursor (if
;there is one)
push bc ;store the number of cells still to be printed
push hl ;store the grid address
call print_sprite ;print the blob
ld hl,&c002 ;DE contains the screen address on exit
add hl,de ;go to the next column
ld (scraddr),hl ;store the new screen address
pop hl ;get the grid address
pop bc ;get the number of cells still to be printed
dec bc ;that's one less cell to be printed!
inc hl ;go to the next cell
ld a,b ;have we printed all 960 cells?
or c
jr nz,display_loop ;no, so print the next cell
ret ;yes, so return
;clear the grid - corrupts BC, DE and HL
.clear_grid
ld hl,grid ;
ld (hl),0 ;this is a quick method of filling a section of
ld de,grid+1 ;memory with zeroes - try working it out for
ld bc,959 ;yourself to see how it works!
ldir ;
ret
;OK! This is where we get serious and things start to get somewhat exciting, as
;the blobs start to generate more blobs, and some other blobs die. The rules of
;LIFE are explained further on
.start
call &bb1b ;clear the keyboard buffer
jr c,start
push de ;store the current cursor coordinates
.start_loop
ld hl,grid ;store the grid in another section of memory
ld de,grid2
ld bc,960
ldir
call clear_grid ;clear the grid
ld hl,grid2 ;use the grid which was already stored
ld de,&0101 ;start at the top left-hand corner of the screen
.start_loop2
xor a ;reset the counter
ld (counter),a
push de ;store the x- and y-coordinates for the current
;blob
push hl ;store the grid address for the current blob
;each blob has to be checked in turn and the number of blobs surrounding it
;must be calculated
dec d ;go to the top-left cell
dec e
ld bc,-41 ;alter the grid address so that it's looking at
add hl,bc ;the top-left cell
call check_cell ;check the top-left cell
call check_cell ;check the top cell
call check_cell ;check the top-right cell
dec d ;go to the left cell
dec d
dec d
inc e
ld bc,37 ;alter the grid address so that it's now looking
add hl,bc ;at the left cell
call check_cell ;check the left cell
inc d ;the central cell is ignored
inc hl
call check_cell ;check the right cell
dec d
dec d
dec d
inc e
add hl,bc ;alter the grid address so that it's now looking
;at the bottom-left cell
call check_cell ;check the bottom-left cell
call check_cell ;check the bottom cell
call check_cell ;check the bottom-right cell
pop hl ;get the grid address for the current blob
pop de ;get the x- and y-coordinates for the current
;blob
;the rules of LIFE:
;* If a blob has less than two neighbours, it dies of starvation
;* If a blob has more than three neighbours, it dies of overcrowding
;* A new blob is created in a cell with three neighbours
ld a,(hl) ;if the cell is empty, then don't bother checking
or a ;to see if there are two neighbours
jr z,empty_cell
ld a,(counter)
cp 2 ;if there are two neighbours, then place a blob
call z,new_blob ;in the cell
.empty_cell
ld a,(counter) ;if there are three neighbours, then place a blob
cp 3 ;in the cell
call z,new_blob
inc d
inc hl ;go to the next cell
ld a,d
cp 41 ;are we at the right of the screen?
jr nz,start_loop2 ;no, so check the next cell
ld d,1 ;yes, so go back to the leftmost cell
inc e ;go to the cell below it
ld a,e
cp 25 ;are we at the bottom of the screen?
jr nz,start_loop2 ;no, so check the next cell
call display_grid ;yes, so display the new-look grid on the screen!
call &bb09 ;check if the user has pressed any keys
jr nc,start_loop
pop de ;restore the cursor coordinates to what they were
ret ;before and return
.check_cell
ld a,d ;check that the x-coordinates are not off the
or a ;screen, and if they are, go to the next cell
jr z,next_blob
cp 41
jr z,next_blob
ld a,e ;check that the y-coordinates are not off the
or a ;screen, and if they are, go to the next cell
jr z,next_blob
cp 25
jr z,next_blob
ld a,(hl) ;check if there is a blob in the current cell
or a
jr z,next_blob
ld a,(counter) ;if there is, increase the counter
inc a
ld (counter),a
.next_blob
inc d ;increase the x-coordinate
inc hl ;automatically go to the next cell
ret
.new_blob
push hl ;store the grid address
ld bc,-960 ;change to the other grid (the one which
add hl,bc ;was cleared)
call select_colour ;place a blob at this address
pop hl ;go back to the current grid (the one which was
ret ;stored)
.blob_colour
db 2 ;stores the colour for the next blob - 2=red,
;3=orange, 4=yellow, 5=green, 6=blue, 7=purple
.ink_data ;ink colours
db 0,26,6,3,15,24,12,18,9,11,2,8,4,13
;now for the sprite data. There is a total of 29 sprites (including the blank
;one), each of which is 16 bytes long, so that's 464 bytes of data. All of this
;must be entered correctly, otherwise some of the sprites may look corrupted
.sprite_data
;sprite 0 is blank, and sprite 1 is the cursor
ds 16
db 192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192
;sprites 2-7 are the six colours of blob
db 4,8,12,196,12,132,12,76,12,12,12,76,140,140,68,8
db 16,32,48,196,48,144,48,100,48,48,48,100,152,152,68,32
db 80,160,240,148,240,208,240,180,240,240,240,180,120,120,20,160
db 84,168,252,129,252,212,252,169,252,252,252,169,86,86,1,168
db 65,130,195,133,195,193,195,135,195,195,195,135,75,75,5,130
db 69,138,207,145,207,197,207,155,207,207,207,155,103,103,17,138
;the remaining sprites are the characters for the message at the bottom of the
;screen. It isn't necessary to store a sprite for each ASCII character, because
;we only need a few of them, not all of them!
db 140,0,140,0,140,0,140,0,140,0,140,0,140,12,0,0 ;red L
db 120,240,20,160,20,160,20,160,20,160,20,160,120,240,0,0 ;yellow I
db 86,252,86,0,86,0,86,168,86,0,86,0,86,0,0,0 ;green F
db 75,195,75,0,75,0,75,130,75,0,75,0,75,195,0,0 ;blue E
db 226,128,128,226,192,192,192,226,192,192,128,226,226,128,0,0 ;(c)
db 226,226,226,226,226,192,226,192,226,192,226,226,226,226,0,0 ;N
db 0,0,81,128,0,0,81,128,81,128,81,128,81,128,0,0 ;i
db 0,0,0,0,81,128,226,226,226,0,226,226,81,128,0,0 ;c
db 226,0,226,0,226,128,226,226,226,226,226,226,226,226,0,0 ;h
db 0,0,0,0,81,128,226,226,226,226,226,226,81,128,0,0 ;o
db 81,128,81,128,81,128,81,128,81,128,81,128,81,128,0,0 ;l
db 0,0,0,0,81,128,0,226,81,192,226,226,81,192,0,0 ;a
db 0,0,0,0,81,192,226,0,81,128,0,226,226,128,0,0 ;s
db 81,128,226,226,226,0,226,0,226,0,226,226,81,128,0,0 ;C
db 0,0,0,0,81,128,226,192,226,192,226,226,226,226,0,0 ;m
db 0,0,0,0,226,128,226,226,226,226,226,128,226,0,226,0 ;p
db 226,0,226,0,226,128,226,226,226,226,226,226,226,128,0,0 ;b
db 0,0,0,0,81,128,226,226,226,128,226,0,81,192,0,0 ;e
db 81,128,226,128,81,128,81,128,81,128,81,128,81,128,0,0 ;1
db 81,128,226,226,226,226,81,192,0,226,226,226,81,128,0,0 ;9
db 81,128,226,226,226,226,81,128,226,226,226,226,81,128,0,0 ;8
;the message is stored in terms of the sprite number, not as the ASCII
;character, so the red L is sprite number 12, the yellow I is sprite number 13,
;and so on... nice, huh?
.message
db 8,9,10,11,0,0,12,0,13,14,15,16,17,18,19,20,0
db 21,19,22,23,24,25,18,18,0,26,27,27,28
.ybyte
db 0 ;the y-coordinate
.xbyte
db 0 ;the x-coordinate
.counter ;the counter for working out how many neighbours
db 0 ;a cell has
.scraddr ;the screen address, used by some of the routines
dw 0
.grid ds 960 ;the grid where the 960 cells are stored
.grid2 ds 960 ;another grid used for temporary storage in the
;start routine