/* * Game of Life * * By Richard Heathfield * * email: binary@eton.powernet.co.uk * * Legal Rules: * Do what you like with it, but don't pretend you wrote it. * Ascribe credit to me where appropriate. * Copyright Richard Heathfield 1999-2003. * * Compiler Rules: * 16-bit MS-DOS compiler required. Use LARGE memory model. * * Game Rules: * An empty cell in contact with two bods will spawn a bod. * A bod next to no other bods will die. * A bod next to one or two other bods will survive. * A bod next to more than two other bods will die. * Detection of bods wraps around. * * Runtime Rules: * Get 50 lines in your DOS screen like this: MODE CON LINES=50 * * That's it. Enough rules! Enjoy! * */ #define XMAX 80 #define YMAX 50 #define BLACK 0 #define BLUE 1 #define RED 4 #define YELLOW 14 #define WHITE 15 #define BOD 0x01 #define NEW_BOD 0x02 #define SPACE 0x20 #define BODS_AT_START 1200 #define MIN_BODS_AROUND 2 #define MAX_BODS_AROUND 3 #define PARENT_BODS 3 #define MUTANT_RATE 10000 #define SCREENBASE (char *)0xb8000000L #define KEYBASE ((char *)0x00000417L) #define PrintBod(x, y, c) *(SCREENBASE + (y) * (XMAX * 2) + (x) * 2) = c /* #define IsBod(x, y) (*(SCREENBASE + (y) * (XMAX * 2) + (x) * 2) == BOD) */ #define IsBod(x, y) (*(SCREENBASE + (y) * (XMAX * 2) + (x) * 2) != SPACE) #define ClearBod(x, y) *(SCREENBASE + (y) * (XMAX * 2) + (x) * 2) = SPACE #define Colour(x, y, c, d) *(SCREENBASE + (y) * (XMAX * 2) + (x) * 2 + 1) = (((c) << 4) | (d)) typedef struct GENERATION { char BodSpace[XMAX][YMAX]; } GENERATION; long atol(char *s) { long num = 0; while(*s) { num *= 10; num += ((*s) & 0x30); ++s; } return num; } void ClearScreen(void) { int y, x; for(y = 0; y < YMAX; y++) { for(x = 0; x < XMAX; x++) { ClearBod(x, y); Colour(x, y, BLUE, YELLOW); } } } /* gratuitously undefined behaviour - it seems to work rather nicely! */ long Random(long *SeedValue) { long HiWord, LoWord; *SeedValue ^= 0xFFFFFFFFL; *SeedValue >>= 1L; *SeedValue += (long)SeedValue; *SeedValue *= 11L; *SeedValue ^= HiWord; HiWord = (*SeedValue & 0xFFFF0000L) >> 16L; *SeedValue ^= LoWord; LoWord = (*SeedValue & 0x0000FFFFL) << 16L; *SeedValue = HiWord + LoWord; return *SeedValue; } long DoFirstGeneration(long *Seed) { int i, x, y; for(i = 0; i < BODS_AT_START; i++) { x = (int)(Random(Seed) % XMAX); y = (int)(Random(Seed) % YMAX); PrintBod(x, y, BOD); } return 0; } int CountAdjacentBods(int x, int y) { int BodCount = 0; /* Deal with all x - 1 */ if(x > 0) { if(y > 0) { if(IsBod(x - 1, y - 1)) { ++BodCount; } } else { if(IsBod(x - 1, YMAX - 1)) { ++BodCount; } } if(IsBod(x - 1, y)) { ++BodCount; } if(y < YMAX - 1) { if(IsBod(x - 1, y + 1)) { ++BodCount; } } else { if(IsBod(x - 1, 0)) { ++BodCount; } } } else /* x = 0 */ { if(y > 0) { if(IsBod(XMAX - 1, y - 1)) { ++BodCount; } } else { if(IsBod(XMAX - 1, YMAX - 1)) { ++BodCount; } } if(IsBod(XMAX - 1, y)) { ++BodCount; } if(y < YMAX - 1) { if(IsBod(XMAX - 1, y + 1)) { ++BodCount; } } else { if(IsBod(XMAX - 1, 0)) { ++BodCount; } } } /* Deal with all x */ if(y > 0) { if(IsBod(x, y - 1)) { ++BodCount; } } else { if(IsBod(x, YMAX - 1)) { ++BodCount; } } if(y < YMAX - 1) { if(IsBod(x, y + 1)) { ++BodCount; } } else { if(IsBod(x, 0)) { ++BodCount; } } /* Deal with all x + 1 */ if(x < XMAX - 1) { if(y > 0) { if(IsBod(x + 1, y - 1)) { ++BodCount; } } else { if(IsBod(x + 1, YMAX - 1)) { ++BodCount; } } if(IsBod(x + 1, y)) { ++BodCount; } if(y < YMAX - 1) { if(IsBod(x + 1, y + 1)) { ++BodCount; } } else { if(IsBod(x + 1, 0)) { ++BodCount; } } } else { if(y > 0) { if(IsBod(0, y - 1)) { ++BodCount; } } else { if(IsBod(0, YMAX - 1)) { ++BodCount; } } if(IsBod(0, y)) { ++BodCount; } if(y < YMAX - 1) { if(IsBod(0, y + 1)) { ++BodCount; } } else { if(IsBod(0, 0)) { ++BodCount; } } } return BodCount; } void ReadGeneration(GENERATION *Gen) { int y, x, BodCount; long Seed; for(y = 0; y < YMAX; y++) { for(x = 0; x < XMAX; x++) { BodCount = CountAdjacentBods(x, y); if(IsBod(x, y)) { if(BodCount >= MIN_BODS_AROUND && BodCount <= MAX_BODS_AROUND) { Gen->BodSpace[x][y] = BOD; } else { Gen->BodSpace[x][y] = SPACE; } } else { if(PARENT_BODS == BodCount) { Gen->BodSpace[x][y] = NEW_BOD; } else { if(PARENT_BODS - 1 == BodCount && Random(&Seed) % MUTANT_RATE == 0) { Gen->BodSpace[x][y] = NEW_BOD; } else { Gen->BodSpace[x][y] = SPACE; } } } } } } void DoNextGeneration(GENERATION *Gen) { int x = 0; int y = 0; for(y = 0; y < YMAX; y++) { for(x = 0; x < XMAX; x++) { if(SPACE != Gen->BodSpace[x][y]) { PrintBod(x, y, Gen->BodSpace[x][y]); if(NEW_BOD == Gen->BodSpace[x][y]) { Colour(x, y, RED, WHITE); } else { Colour(x, y, BLUE, YELLOW); } } else { ClearBod(x, y); Colour(x, y, BLUE, YELLOW); } } } } int main(int argc, char *argv[]) { char KeyFlags = *KEYBASE; long Seed; long Delay = 0; long LoopCount = 0; static GENERATION BodGen; if(argc > 1) { Delay = atol(argv[1]); } else { Delay = 100; } ClearScreen(); DoFirstGeneration(&Seed); while(*KEYBASE == KeyFlags) { ReadGeneration(&BodGen); DoNextGeneration(&BodGen); for(LoopCount = 0; LoopCount < Delay; LoopCount++) { Random(&Seed); } } return 0; }