/* life4.c
 * unrolled pointer version for HI-TECH 4.11 C Cross Compiler
 * by Andre Adrian, DL1ADR, 2026-05-05
 *
 * compile:
 * zc -S -O -c life4.c
 */

#include <stdio.h>
#include <string.h>

#define XSZ 50  /* grid size rows */
#define YSZ 70  /* grid size columns */
#define DD 0    /* is death, becomes death */
#define LL 1    /* is live, becomes live */
#define DL 2    /* is death, becomes live */
#define LD 3    /* is live, becomes death */

void putch(int c) {
    putchar(c);
}

char getche(void) {
    return getchar();
}

void cputs(char* s) {
    while(*s)
        putch(*s++);
}

/* secure gets() */
char* sgets(char* s, int size) {
    char* s1 = s;
    static char c;

    while((c=getche())!='\r' && c!='\n' && --size) {
        *s++ = c;
    }
    *s = 0;
    if(s == s1)
        return((char *)0);
    return(s1);
}

/* print unsigned number */
/* for div/mod algorithm see HI-TECH fbcd.c _fibcd() */
void prbcdu(unsigned n) {
    static char s[6];

    strcpy(s, "00000");
    while (n>=10000) {
        n-=10000;
        ++s[0];
    }
    while (n>=1000) {
        n-=1000;
        ++s[1];
    }
    while (n>=100) {
        n-=100;
        ++s[2];
    }
    while (n>=10) {
        n-=10;
        ++s[3];
    }
    s[4]+=n;
    cputs(s);
}

void TAB(int x) {
    while(--x) {
        putch(' ');
    }
}

static unsigned G=0, P=0;
static unsigned char E=0, L, X, Y, X1, X2, X3, X4, Y1, Y2, Y3, Y4;
static char A[XSZ+1][YSZ+1], B[32][32];
static char *pX, *pY, *p;

int main() {
    register unsigned char C=0;
    TAB(34); cputs("LIFE\n");
    TAB(15); cputs("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"
                    "\n\n"
                    "ENTER YOUR PATTERN:\n");
    for (;;) {
        sgets(B[C], sizeof(B[0]));
        if (B[C][0]=='D') {
            break;
        }
        ++C;
    }
    --C; L=0;
    for(X=0; X<=C-1; ++X) {
        if (strlen(B[X])>L)
            L=strlen(B[X]);
    }
    X1=(XSZ>>1)-(C>>1); X2=X1+C;
    Y1=(YSZ>>1)-(L>>1); Y2=Y1+L;
    for (X=0; X<=C; ++X) {
        for (Y=0; Y<strlen(B[X]); ++Y) {
            if (B[X][Y]=='*') {
                A[X1+X][Y1+Y]=1; ++P;
            }
        }
    }
    cputs("\n\n");
    for(;;) {
        X4=2; X3=XSZ-2; Y4=2; Y3=YSZ-2;
        for (X=1; X<=X1-1; ++X) putch('\n');
        putch('\n');
        pX=&A[X1][0];
        for (X=X1; X<=X2; ++X, pX+=(YSZ+1)) {
            TAB(Y1);
            pY=pX+Y1;
            for (Y=Y1; Y<=Y2; ++Y, ++pY) {
                if (*pY==DD || *pY==LD) {
                    *pY=DD; putch(' '); continue;
                }
                *pY=LL; putch('*');
                if (X<X3) X3=X;
                if (X>X4) X4=X;
                if (Y<Y3) Y3=Y;
                if (Y>Y4) Y4=Y;
            }
            putch('\n');
        }
        for (X=X2+1; X<=XSZ-1; ++X) putch('\n');
        cputs("GENERATION: "); prbcdu(G);
        cputs("\t\tPOPULATION: "); prbcdu(P);
        if (E) {
            cputs(" INVALID "); prbcdu(E);
        }
        if (P==0) break;
        sleep(1);
        X1=X3; X2=X4; Y1=Y3; Y2=Y4; ++G; P=0; E=0;
        if (X1<2) { X1=2; E=1; }
        if (X2>XSZ-2) { X2=XSZ-2; E+=2; }
        if (Y1<2) { Y1=2; E+=4; }
        if (Y2>YSZ-2) { Y2=YSZ-2; E+=8; }
        pX=&A[X1-1][0];
        for (X=X1-1; X<=X2+1; ++X, pX+=(YSZ+1)) {
            pY=pX+Y1-1;
            for (Y=Y1-1; Y<=Y2+1; ++Y, ++pY) {
                C=0;
                p=pY-(YSZ+1)-1; if (*p&1) ++C;
                ++p; if (*p&1) ++C;
                ++p; if (*p&1) ++C;
                p+=(YSZ+1); if (*p&1) ++C;
                --p;
                --p; if (*p&1) ++C;
                p+=(YSZ+1); if (*p&1) ++C;
                ++p; if (*p&1) ++C;
                ++p; if (*p&1) ++C;
                if (*pY==DD) goto L570;
                if ((C<2) || (C>3)) {
                    *pY=LD; continue;
                }
                ++P; continue;
L570:
                if(C==3) {
                    *pY=DL; ++P;
                }
            }
        }
        --X1; --Y1; ++X2; ++Y2;
    }
}
