ZX-81 LIFE
----------
from Your Computer, January 1983

Life is what you make it, and Peter Whittle certainly puts some zest into the
generation game.

COMPLICATED PATTERN manipulation games such as John Conway's Life are ideally
suited for programming on to a computer with visual display. Generally
speaking, a lot of simple computation has to be performed to generate each
new pattern from the previous one. This computation normally takes the form
of checking the adjacent positions of each part of the pattern and then
applying simple rules in order to generate the new pattern or, in the case of
Life, the new generation.

This non-arithmetic computation is very inefficiently performed when written
in BASIC, involving many slow FOR-NEXT loops. With the game of Life on the
ZX-81 it typically takes 20 seconds or more per generation. However, this
type of computation is ideally suited for a fairly simple machine-code
routine.

The display of the ZX-81 can be looked on as an array of 768 squares
arranged in a grid 32 across by 24 down. The normal BASIC print statements
can only use the top 22 lines, the bottom two being used for report codes,
although the whole 24 lines are accessible to a machine-code routine. When
the total amount of memory exceeds 3.25K a clear screen is padded out with 24
by 32 spaces.

The computer blocks off 793 bytes of the memory to store this display, the
extra bytes being Newline characters to mark the end of each line. The
character at each position is coded with a number as listed at the back of
the ZX-81 handbook. The starting address of this display file is stored at
locations 16396 and 16397 and, in general, may move around in the memory - so
its position must be checked each time the routine is called.

The game of Life

Briefly, the game of Life is as follows. Imagine a rectangular array of
squares - in the case of the ZX-81 display, 24 by 32 in size. A pattern is
first of all set up on the array either by a series of suitable print
statements or by a more flexible program as suggested below. Certain rules
are then repetitively applied to the pattern which will, in general, change
the pattern at each step. If a suitable starting pattern is used a very
interesting development of shapes can be observed.

The rules to be observed are as follows: first, any square surrounded by less
than two, or more than three, occupied neighbouring squares will die of
loneliness or overcrowding respectively. Secondly, any square surrounded by
three occupied squares will become occupied, that is, live. Third, any square
surrounded by two occupied squares remains unchanged. As can be seen, for
each position on the array on which the game is to be played, the eight
immediately adjacent positions need to be examined to determine whether it
lives or dies.

With all the FOR-NEXT loops needed to program this in BASIC, it could take a
very long time to run. However, with the machine-code routine to be
described, even in SLOW mode where the microprocessor has to share its time
between executing the program and generating the display, each generation
still takes less than one second.

Loops are performed most efficiently in machine code by setting a count in
one of the registers normally b, c, d or e so that a, or accumulator may be
used for arithmetic and the hl pair for register indirect addressing. Each
time the program section is to be executed, the count is decremented by one
and then checked for zero with the JR Z or JR NZ instructions; do a relative
Jump if JR Z is zero or JR NZ is not zero respectively and the loop either
repeated or not.

The most efficient register to use is the b register because there is a
special instruction DJNZ which decrements b and tests for zero in one.
Another instruction type that is used in the program is the bit set and test
group.

In the game of Life the whole pattern is scanned and a new pattern is formed
according to the rules previously defined. In order to avoid saving this new
pattern in its own part of the memory and then transferring it into the
display file, the life/death decision is made and then the square marked in a
way that will be invisible to the status-checking routine when it is called
for the neighbouring squares. The newly-formed pattern must bc kept separate
so as not to interfere with the testing of adjacent squares. The square
marking is done by setting and testing particular bits of the word, coding
each position in the display.

On the ZX-8l, 0, the character we will use to define the pattern, is coded
34H or 00110100. Counting the bits from the right, starting at 0 we see that
bit 2 is a 1. The instruction BIT 2 will test this particular bit and set the
zero flag - if the bit is a zero - and reset it if the bit is a 1. The zero
flag can then be tested by a JR Z or JR NZ instruction. SET and RES will
similarly set or reset the particular bit specified.

The only other instructions that may be new to beginners in machine-code
programming - although, of course, familiar to regular readers of Your
Computer - are PUSH and POP. These use an area of memory set aside by the
computer-operating system for temporary storage. This is called the stack and
works on a last-in, first-out principle. Data in the form of 16-bit words is
entered or PUSHed into the stack and retrieved or POPped from the stack.

The stack pointer, a register we need not worry about here, automatically
keeps track of the current top-of-stack position. These instructions are used
to temporarily store data out of the way, while the computer gets on with
something else. For the readers who missed out, Your Computer ran a series on
machine code from August to November 1982.

The complete machine-code routine is shown in figure 1. Briefly, its
operation is as follows: the whole display is scanned and for each square the
bit-checking subroutine, Check, is called for each of the eight surrounding
squares, with a count of the number of live ones found and kept in the A
register, program location 16525 to 16561.

The count is then checked and bit 0 set or reset accordingly - 16563 to 16582.
Incidentally, this bit setting and resetting will produce an intermediate
pattern of Ps and s, that is, the codes 00110101 and 00000001 in the display
file. Once the whole array has been processed, it is scanned once more and
for each square, bit 0 is tested to determine its new status and a 0, or 52
substituted for death - a 0 - or life - the letter O - respectively - 16594
to 16621. And that is all there is to it. The program is loaded into the
first REM statement as suggested by Sinclair, so type out the following;
remember to follow the first REM with 110 spaces, approximately 4 lines.

	   1 REM
	  10 LET L=16514
	  20 PRINT L,
	  30 INPUT I
	  40 POKE L,I
	  50 PRINT PEEK L
	  60 LET L=L+1
	  70 GO TO 20

On running this program it will print out the location. You then type in the
decimal numbers as listed in figure 1. Note that some instructions consist of
two or more numbers. The screen printout will show that they have been
entered properly. When the screen is full type CONT to continue. When you get
to 16622 type STOP. The machine-code routine will now be loaded in the REM
statement. All it needs now is a BASIC set-up and operating program with some
user-friendly embellishments.
