I have not coded Conway’s life in many years – I thought it would be fun to try on the Z80. First I implemented it in C on the Raspberry Pi. It uses an array to both keep track of prior generations (to determine if the pattern is still evolving) and the same array to figure out the neighbour count.
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
unsigned char *grid;
const int rows=48, cols=160, maxt=3;
int same;
void* calc_grid(int *t) {
int i, j, q;
for (i=rows+rows-*t*rows/maxt-1; i>=rows+rows-(*t+1)*rows/maxt; i--) {
for (j=cols+cols-1; j>=cols; j--) {
if ( (grid[(i-rows)*cols+j-cols] & 64) ) { /* for each cell that is alive, add 1 to all the neighbours in every (8) adjacent cell */
grid[((i-1) % rows)*cols + (j-1) % cols] += 1;
grid[((i-1) % rows)*cols + (j ) % cols] += 1;
grid[((i-1) % rows)*cols + (j+1) % cols] += 1;
grid[((i ) % rows)*cols + (j-1) % cols] += 1;
grid[((i ) % rows)*cols + (j+1) % cols] += 1;
grid[((i+1) % rows)*cols + (j-1) % cols] += 1;
grid[((i+1) % rows)*cols + (j ) % cols] += 1;
grid[((i+1) % rows)*cols + (j+1) % cols] += 1;
}
}
}
}
void* shift_grid(int *t) {
int i, j;
for (i=*t*rows/maxt; i<(*t+1)*rows/maxt; i++) {
for (j=0; j<cols; j++) { /* for every cell take the 7th bit and the lower 4 bits (total) - empty cell =3 - live cell = 64+2 or 64+3 - then mark the 8th bit as live for next gen*/
if ((grid[i*cols+j] & 79) == 3 || (grid[i*cols+j] & 79) == 66 || (grid[i*cols+j] & 79) == 67) grid[i*cols+j] |= 128;
grid[i*cols+j] = (grid[i*cols+j] >> 1) & 240; /* shift to the right one bit, and keep the top 4 bits 128+64+32+16 to see what was going on in prior gens */
if ( same == 1 && ((grid[i*cols+j] & 64)>>2) != (grid[i*cols+j] & 16) ) /* compare the 7th bit to the 5th bit- if those are not the same, then the pattern is changing */
same=0;
}
}
}
int main() {
time_t qt;
srand((unsigned) time(&qt));
pthread_t thr[maxt];
int c, x, y, i, j, gen, t, rc;
grid = malloc(rows*cols*sizeof(char));
for ( c=0; c<1000; c++) {
// printf("Try: %d\n", c);
for (i=0; i<rows; i++)
for (j=0; j<cols; j++)
grid[i*cols+j] = 64 * (rand() % 2); /* initialize the array with random numbers in the 7th bit */
for (gen=0; gen<20000; gen++) {
for (t=0; t<maxt; t++) {
calc_grid(&t);
}
same=1;
for (t=0; t<maxt; t++) {
shift_grid(&t);
}
//if (same==1) break;
printf("Gen: %d\n", gen );
for (i=0; i<rows; i++) {
for (j=0; j<cols; j++)
putc( (grid[i*cols+j] & 64 ) ? '*': ' ', stdout);
putc('\n', stdout);
}
getc(stdin);
}
}
/* print out survivor */
printf("Gen: %d\n", gen );
for (i=0; i<rows; i++) {
for (j=0; j<cols; j++)
putc( (grid[i*cols+j] & 64 ) ? '*': ' ', stdout);
putc('\n', stdout);
}
free(grid);
}
I’ve made it very similar on the z80 in terms of the algorithm that is implemented. The grid it uses is smaller.
org 0100h
; to do a given cell, we need to do IX-1, IX+1, IX-81, IX-80, IX-79, IX+79, IX+80, IX+81
; board is 78x24 with an extra space all around so 80x26 - 2080 elements
ld a,0ffh ; do at most 255 generations
top: push af
ld hl,c_home
call my_write_string
call print_board
call calc_n
call calc_g
pop af
dec a
jr nz,top
ld hl,c_home
call my_write_string
call print_board
ret
calc_g: ; calculate the next generation
ld de, board
calc_g_loop:
ld b, 080h
ld a,(de)
ld c,a
and b
jr z,no_128
ld (de),a
jr end_calc_g
no_128: ; continue with calcs
ld a,c
ld b,79
and b
ld b,3
cp b
jr z, set_128
ld b,66
cp b
jr z, set_128
ld b,67
cp b
jr z, set_128
ld a,c
jr shift_mask
set_128:
ld a,c
ld b,128
or b
shift_mask:
ld b,224
and b
srl a
ld (de), a
end_calc_g:
inc de
ld hl,b_done
sbc hl,de
ret z
jr calc_g_loop
calc_n:
ld ix, board
ld de, board
ld c,040h
ld b,080h
calc_n_loop:
ld a,(ix+0)
and b
jr nz,calc_x ; found a 128 - skip calc
ld a,(ix+0)
and c
jr z,calc_x ; only increment if its currently alive
inc (ix-1)
inc (ix+1)
inc (ix-79)
inc (ix-80)
inc (ix-81)
inc (ix+79)
inc (ix+80)
inc (ix+81)
calc_x: inc ix
inc de
ld hl,b_done
sbc hl,de
ret z
jr calc_n_loop
; print_board: routine to print out board - uses a, bc, de, hl
print_board:
ld de, board
print_nl:
ld c, 00h
print_loop:
ld a,(de)
ld b,040h
and b
jr z,space_char
ld b,'@'
jr end_char
space_char:
ld b,' '
end_char:
call my_write_char
inc de
inc c
ld a,80
sub c
jr nz,print_loop
ld hl,crlf
call my_write_string
ld hl,b_done
sbc hl,de
ret z
jr print_nl
; puts a single char (byte value) on serial output
; call with char to send in B register; also uses A register
my_write_char:
in a,(3)
and 001h
jp z, my_write_char
ld a,b
out (2),a
ret
my_write_string:
in a,(3)
and 001h
jr z,my_write_string
ld a,(hl)
and a
ret z
out (2),a
inc hl
jr my_write_string
crlf: defm 0dh,0ah,0h
c_home: defm 01bh,"[H",0h
b_junk: defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
board: defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,64,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,64,64,00,00,00,00,00,00,00,00,64,00,00,00,00,00,64,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,64,64,00,00,00,00,00,00,00,00,64,00,00,00,64,00,64,64,00,00,00,00,64,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,64,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,64,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,64,00,64,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,64,64,00,00,00,64,64,64,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,64,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
defm 128,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00
defm 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,128
b_done: defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
defm 128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128
end