/* life.c */ /* © Copyright 2005 Dauger Research, Inc. Our lawyers made us say this: DISCLAIMER: We provide the following on an "AS IS" basis. Use it at your own risk. */ #include #include #include #include void fractionalsleep(double sleepRequest); void fractionalsleep(double sleepRequest) {/* like sleep(), except that it accepts fractions of a second */ if (sleepRequest>0) { struct timespec request; double intSleep; request.tv_nsec=(1e9*modf(sleepRequest, &intSleep)); request.tv_sec=(long)intSleep; nanosleep(&request, NULL); } } #ifndef Byte #define Byte unsigned char #endif /* Defines array structure and access */ typedef struct LifeArrayStruct { Byte *array; long rowBytes; /* access with array[col+rowBytes*row] */ long columnSize; /* <= rowBytes-2 */ long rowSize; Byte buffer[4]; /* allocation must be at least sizeof(Byte)*(rowSize+2)*(columnSize+2) */ } LifeArrayStruct, *LifeArrayPtr, **LifeArrayHandle; #include LifeArrayPtr NewLifeArray(long columnSize, long rowSize); LifeArrayPtr NewLifeArray(long columnSize, long rowSize) {LifeArrayPtr out=NULL; if ((columnSize>0)&&(rowSize>0)) { long rowBytes=columnSize+2; long allocation=sizeof(LifeArrayStruct)+rowBytes*(rowSize+2)*sizeof(Byte); out=malloc(allocation); if (out) { memset(out, 0, allocation); out->rowBytes=rowBytes; out->columnSize=columnSize; out->rowSize=rowSize; out->array=&out->buffer[1+out->rowBytes]; } } return out; } void propagatelife(LifeArrayPtr out, LifeArrayPtr in); /* assumed to be equal in size */ void propagatelife(LifeArrayPtr out, LifeArrayPtr in) {/* Propogates life according to rules by J. Conway in 1970 */ if (out&&in) { long row=in->rowSize; while (row--) { long column=in->columnSize; Byte *outRow=&out->array[row*out->rowBytes]; Byte *inRow=&in->array[row*in->rowBytes]; /* Hey you! Vectorize this! */ while (column--) { long neighborCount=(inRow[column-1]?1:0)+(inRow[column+1]?1:0); neighborCount+=(inRow[column+in->rowBytes-1]?1:0)+(inRow[column+in->rowBytes]?1:0)+(inRow[column+in->rowBytes+1]?1:0); neighborCount+=(inRow[column-1-in->rowBytes]?1:0)+(inRow[column-in->rowBytes]?1:0)+(inRow[column+1-in->rowBytes]?1:0); switch (neighborCount) { default: case 0: case 1: /* not enough */ case 4: case 5: case 6: case 7: case 8: case 9: /* too much */ outRow[column]=0; /* die */ break; case 2: if (!(inRow[column])) { outRow[column]=0; /* stay dead */ break; } case 3: /* just right */ if (!(outRow[column]=inRow[column]+1)) outRow[column]=0xff; /* live */ break; } } } } } void maintainboundaryconditions(LifeArrayPtr in); void maintainboundaryconditions(LifeArrayPtr in) {/* Maintains periodic boundary conditions */ if (in) { long row=in->rowSize; /* copy ends of rows */ while (row--) { Byte *rowP=&in->array[row*in->rowBytes]; rowP[-1]=rowP[in->columnSize-1]; rowP[in->columnSize]=rowP[0]; } /* copy first and last rows */ {long column=in->columnSize+2; Byte *firstRow=&in->array[-1]; Byte *lastRow=&in->array[(in->rowSize-1)*in->rowBytes-1]; while (column--) { firstRow[column-in->rowBytes]=lastRow[column]; lastRow[column+in->rowBytes]=firstRow[column]; } } } } long fprintresult(FILE *stream, LifeArrayPtr in); long fprintresult(FILE *stream, LifeArrayPtr in) {long out=0; if (in) {/* fprintf the array */ long column; for (column=0; columncolumnSize; column++) { long row; for (row=0; rowrowSize; row++) { char c=in->array[in->rowBytes*row+column]; switch (c) { case 0: c=' '; break; case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: out++; case 1: out++; c+='0'-1; break; default: c='*'; break; } if (stream) fprintf(stream, "%c", c); } if (stream) fprintf(stream, "\n"); } } return out>>1; } void saveresult(char *filename, LifeArrayPtr in); void saveresult(char *filename, LifeArrayPtr in) {/* save the array into a file */ if (filename) { FILE *fp=fopen(filename, "a+"); if (fp) { fprintresult(fp, in); fclose(fp); } } } long genArray[]={0x0247, 0x07d9, 0x09be, 0x0fb9, 0x17d9, 0x1f4e, 0x1fdc, 0x27df, 0x8957}; void addmaterial(LifeArrayPtr in); void addmaterial(LifeArrayPtr in) {/* when called add material to the life array */ if (in) { long rowstart=(rand()%(in->rowSize-6)); long colstart=(rand()%(in->columnSize-6)); if (rowstart<0) rowstart=-rowstart; if (colstart<0) colstart=-colstart; rowstart++; colstart++; { long j=4, s=(rand()&3)?0:(rand()%(sizeof(genArray)/sizeof(long))); if (s<0) s=0; s=genArray[s]; printf("adding material %x\n", s); sleep(1); /**/ if (rand()&1) {/* flip */ s=((s&0xf000L)>>12)| ((s&0x0f00L)>>4)| ((s&0x0f0L)<<4)| ((s&0x0fL)<<12); } if (rand()&1) {/* flip */ s=((s&0x8888L)>>3)| ((s&0x4444L)>>1)| ((s&0x2222L)<<1)| ((s&0x1111L)<<3); } while (j--) { long i=4; while (i--) { in->array[i+colstart+(rowstart+j)*in->rowBytes]|=(s&1)<<2; s>>=1; } } } } } #define RowDimension 80 #define ColumnDimension 22 void performcalculation(); void performcalculation() { /* allocate */ LifeArrayPtr arrayA, arrayB; arrayA=NewLifeArray(ColumnDimension, RowDimension); arrayB=NewLifeArray(ColumnDimension, RowDimension); if (arrayA&&arrayB) { long frameCount=0; long countdown=8; /* set initial conditions */ {long row=RowDimension; while (row--) { Byte *rowArray=&arrayA->array[row*arrayA->rowBytes]; long column=ColumnDimension; while (column--) { rowArray[column]=rand()&1; } } } fprintresult(stdout, arrayA); while (frameCount<5000) { LifeArrayPtr lastArray=frameCount&1?arrayB:arrayA; LifeArrayPtr nextArray=frameCount&1?arrayA:arrayB; long activecellcount; maintainboundaryconditions(lastArray); propagatelife(nextArray, lastArray); system("clear"); printf("\fFrame %d \n", frameCount); activecellcount=fprintresult(stdout, nextArray); fractionalsleep(0.125); if (activecellcount*100<(ColumnDimension*RowDimension)) { if (!countdown) { addmaterial(nextArray); countdown=16; } else countdown--; } else countdown=32; frameCount++; } } /* deallocate */ if (arrayA) free(arrayA); if (arrayB) free(arrayB); } int main(void) { { long throwoutcount=time(NULL)&0x3ffL; printf("Initializing random number generator by throwing out %d random numbers...\n", throwoutcount); while (throwoutcount--) rand(); } printf("Beginning calculation... (first random is %d)\n", rand()); performcalculation(); return 0; }