|
25 Years of Programming
An open source source for C, C++, OWL, BASIC, MDB, XLS, DOT, and more... |
Home Projects Up Sitemap Search Blog Forum+Chat About Us Privacy Terms of Use Feedback FAQ Images Services Ads Donate Humor |
|
|
Life.cpp: The Game of Life,
|
|
/* life.cpp 5-22-97
Copyright (C)1995-1997 Steven Whitney.
Initially published by http://25yearsofprogramming.com.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License (GPL)
Version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Game of Life, a cellular automaton, originated by John Conway.
This is only partially converted to C++. Some of its methods are still C.
The Windows version WLIFE2D.CPP has every feature from here except grow1d().
------
TO DO:
change FILE to streams
get rid of strtok
change printf to cout or constreams
change char* to strings
change gets() to getline()
maybe break 1d into a separate smaller program, life1d.
give the sets in life.rul an id#, in place of the C:, for reference.
will have to read through file once at pgm start for count.
------
Notes:
--all notes and all non-version-specific to do are now in complex.doc
--grow() routines are modified from avgpic.c (avgpic is now a function in SDib)
--A thorough search for the DeSmet C predecessor to this program turned up nothing.
If there ever was one, it is lost. Restoring this version to DeSmet might not be
too difficult.
*/
#include <dos.h>
#include <graphics.h>
#pragma hdrstop
#include "c:\bcs\my.h"
#include "c:\bcs\mylib.cpp"
/////////////////////////////////////////////////////////////////////////////
// global variables
BOOL beepon = FALSE; // whether to use sound
long population; // count of "on" cells
int lowx, highx, lowy, highy; // boundaries of "calculate" square
int colortally[16]; // holds tally for each of 16 colors
int s[10], b[10]; // if neighborcount == any value in array,
// point either (s)urvives or is (b)orn
//---------------------------------------------------------------------------
// survive() determines whether a point survives, based on its rule
BOOL survive(int neighborcount)
{
for(int i = 0 ; s[i] != -1 ; i++)
if(neighborcount == s[i])
return(TRUE);
return(FALSE);
}
//---------------------------------------------------------------------------
// born() determines whether a point is born, based on its rule
BOOL born(int neighborcount)
{
for(int i = 0 ; b[i] != -1 ; i++)
if(neighborcount == b[i])
return(TRUE);
return(FALSE);
}
//---------------------------------------------------------------------------
// curblink() blinks the cursor by toggling the pixel
void curblink()
{
int color;
static int oldcolor;
switch(color = getpixel(getx(),gety()))
{
case WHITE: // only possible if set previously
putpixel(getx(),gety(),oldcolor); // restore original color
break;
default:
putpixel(getx(),gety(),WHITE); // show "cursor"
break;
}
oldcolor = color;
}
//---------------------------------------------------------------------------
// editscreen() manually modify or set up display screen
// modified from main() from editpic.c
// put bar() back in, to clear or fill a screen area.
void editscreen()
{
BOOL draw = FALSE; // MODE: CURSOR DRAWS OR JUST MOVES
int newlowx = lowx; // coordinates of a "defined" area that is
int newhighx = highx; // used for fills
int newlowy = lowy; // and optionally for defining "calc" area.
int newhighy = highy;
moveto(getmaxx()/2,getmaxy()/2);
curblink(); // start with cursor on
while(1) // DO FOREVER. EXIT IS IN LOOP
{
int ch = ci(); // wait for user input
curblink(); // turn cursor off during any activity
switch(ch)
{
// UNSHIFTED KEYPAD NUMBERS USED AS ARROW KEYS
case UP: // shouldn't matter whether numlock is on/off
case('8'): // 8 up
case 18: // ^R
if(draw)
linerel(0,-1);
else
moverel(0,-1);
break;
case DOWN:
case('2'): // 2 down
case 3: // ^C
if(draw)
linerel(0,1);
else
moverel(0,1);
break;
case RIGHT:
case('6'): // 6 right
case 6: // ^F
if(draw)
linerel(1,0);
else
moverel(1,0);
break;
case LEFT:
case('4'): // 4 left
case 1: // ^A
if(draw)
linerel(-1,0);
else
moverel(-1,0);
break;
case PGDN:
case('3'): // 3 down-right
if(draw)
linerel(1,1);
else
moverel(1,1);
break;
case HOME:
case('7'): // 7 up-left
if(draw)
linerel(-1,-1);
else
moverel(-1,-1);
break;
case PGUP:
case('9'): // 9 up-right
if(draw)
linerel(1,-1);
else
moverel(1,-1);
break;
case END:
case('1'): // 1 down-left
if(draw)
linerel(-1,1);
else
moverel(-1,1);
break;
case FIVE:
case('5'): // GO TO CENTER OF SCREEN
moveto(getmaxx()/2,getmaxy()/2);
break;
case INS:
case '0': // TOGGLE DRAW/MOVE MODE
draw = !draw;
break;
case DEL:
case '.': // TOGGLE BETWEEN GREEN AND BLACK
if(getcolor() == LIGHTGREEN)
{
setcolor(BLACK);
setfillstyle(SOLID_FILL,BLACK);
}
else
{
setcolor(LIGHTGREEN);
setfillstyle(SOLID_FILL,LIGHTGREEN);
}
break;
case '*': // CLEAR SCREEN
clearviewport();
break;
case 't': // set top left of defined area
newlowx = getx();
newlowy = gety();
break;
case 'b': // set bottom right of defined area
newhighx = getx();
newhighy = gety();
break;
case 'c': // make "defined" area the calc area
if(newlowx < newhighx) // validate before changing
{
lowx = newlowx;
highx = newhighx;
}
if(newlowy < newhighy)
{
lowy = newlowy;
highy = newhighy;
}
break;
case 'f': // fill selected area with draw color
bar(newlowx,newlowy,newhighx,newhighy);
break;
case 'q': // quit
return; // leaves cursor off
case 's': // save screen to .pic
picsave("life.pic");
break;
case 'l': // load file to start over
picload("life.pic");
break;
default:
break;
} // END SWITCH
curblink(); // cursor back on while idle
} // END WHILE(1)
} // END editscreen()
//---------------------------------------------------------------------------
// grow1d() calc. successive 1-dimensional generations until stopped
// instead of counting neighbors, must look for specific pattern in
// surrounding neighborhood. (i.e. it is NOT outer-totalistic)
// successive generations appear on successive lines going down screen.
// At screen bottom, next generation starts over at top.
BOOL grow1d()
{
int screenline = 1; // screen display line being computed (0-479)
int lineabove = 0; // screen display line being referred to
int maxx = getmaxx()+1; // now it's the NUMBER of points in a screen line (640)
int maxy = getmaxy()+1; // now it's the NUMBER of lines in a screen (480)
// always use printable digits as the chars, NOT, for example char(1) (ctl-A)
// because char(0) is a null.
string s[14];
s[0] = "11111";
s[1] = "11110";
s[2] = "11100";
s[3] = "11010";
s[4] = "11000";
s[5] = "10111";
s[6] = "10110";
s[7] = "10010";
s[8] = "01111";
s[9] = "01110";
s[10] = "00111";
s[11] = "00100";
s[12] = "00011";
s[13] = "00000";
while(1)
{
for(int x = 0 ; x < maxx ; x++)
{
string neighborhood;
int testx = wrap(x - 2,0,getmaxx()); // point 2 to left
neighborhood += ((getpixel(testx,lineabove) == BLACK) ? "0" : "1");
//---inside here is for 3-cell neighborhood
testx = wrap(x - 1,0,getmaxx()); // point to left
neighborhood += ((getpixel(testx,lineabove) == BLACK) ? "0" : "1");
neighborhood += ((getpixel(x,lineabove) == BLACK) ? "0" : "1"); // (the point itself)
testx = wrap(x + 1,0,getmaxx()); // point to right
neighborhood += ((getpixel(testx,lineabove) == BLACK) ? "0" : "1");
//---
testx = wrap(x + 2,0,getmaxx()); // point 2 to right
neighborhood += ((getpixel(testx,lineabove) == BLACK) ? "0" : "1");
int color = BLACK;
for(int i = 0 ; i < 14 ; i++)
if(neighborhood == s[i])
{
color = LIGHTGREEN;
break;
}
putpixel(x,screenline,color);
}
// wrap the lines independently of each other (one hits bottom before the other)
if(++screenline == maxy)
screenline = 0;
if(++lineabove == maxy)
lineabove = 0;
if(kbhit()) // ESC exits
switch(tolower(getch()))
{
case 27:
return(FALSE);
case 's':
picsave("life.pic");
break;
case 'l': // load file to start over
picload("life.pic");
break;
case 'b': beepon = !beepon; nosound(); break;
}
} // end while(1)
} // end grow1d()
//-------------------------------------------------------------------
// grow2d() compute and display the next generation (2-dimensional)
// returns TRUE on "success", FALSE on error or if user aborted
BOOL grow2d()
{
BOOL keepgoing = TRUE; // value returned (whether to come right back)
int i, j, neighborcount, color;
int maxx;
int screenline; // screen display line being worked on (0-479)
int linesize; // number of chars in a buffer line
char *ptr[3]; // pointers to buffers containing line data
char *temp; // for pointer swapping
maxx = getmaxx()+1; // now it's the NUMBER of points in a screen line (640)
linesize = maxx+2; // 1 pixel beyond each edge
for(i = 0 ; i < 3 ; i++) // allocate space for the line buffers
if((ptr[i] = (char *)malloc(linesize)) == NULL)
{
for(j = 0 ; j < i ; j++) // free any already-allocated buffers
if(ptr[j])
free(ptr[j]);
setcolor(WHITE); // still won't show if area is already white
outtextxy(0,0,"Out of memory.");
return(FALSE);
}
setmem(ptr[0],linesize,0); // zero out imaginary line above screen top
setmem(ptr[1],linesize,0); // and zero out the others to avoid garbage
setmem(ptr[2],linesize,0); // 1st & last chars MUST be zeroed at minimum
// read actual screen lines 0 and 1
// into arrays 1 and 2
for(i = lowx ; i <= highx ; i++) // read points 0-639 (at most)
{
ptr[1][i+1] = getpixel(i,lowy); // fill array elements 1-640 (max)
ptr[2][i+1] = getpixel(i,lowy+1); // out of 0-641 available
} // leaving offscreen endpoints alone
for(screenline = lowy ; screenline <= highy ; screenline++)
{
// calculate values for array line 1 directly to screen line 0
for(i = lowx+1 ; i <= highx+1 ; i++) // for i = 1 to 640
{
neighborcount = 0;
if(ptr[0][i-1]) neighborcount++; // above left
if(ptr[0][i]) neighborcount++; // above
if(ptr[0][i+1]) neighborcount++; // above right
if(ptr[1][i-1]) neighborcount++; // point to left
// (ptr[1][i]) // just for reference, this is the point itself
if(ptr[1][i+1]) neighborcount++; // point to right
if(ptr[2][i-1]) neighborcount++; // below left
if(ptr[2][i]) neighborcount++; // point below
if(ptr[2][i+1]) neighborcount++; // below right
color = BLACK;
if(ptr[1][i]) // if point already alive,
{ // see if it remains alive
if(survive(neighborcount))
color = YELLOW;
else
population--;
}
else // if cell is dead,
{ // see whether it is born
if(born(neighborcount))
{
color = YELLOW;
population++;
}
}
putpixel(i-1,screenline,color);
if(beepon)
sound((int)((population % 15000)+50));
}
temp = ptr[0]; // save top line, we're through with it
ptr[0] = ptr[1]; // line scrolls up, become top line
ptr[1] = ptr[2]; // line becomes the one being averaged
ptr[2] = temp; // we're about to overwrite data in this
// because we need a new bottom line
if(screenline < (highy-1)) // if not last pass,
for(j = lowx ; j <= highx ; j++) // read points 0-639
ptr[2][j+1] = getpixel(j,screenline+2);
else // for last pass, must create
setmem(ptr[2],linesize,0); // imaginary line below screen bottom
} // end for(process all screen lines)
if(kbhit()) // only allow these actions between whole screenfuls
switch(tolower(getch()))
{
case 27: // ESC exits
keepgoing = FALSE;
break;
case 's': // save .pic file
picsave("life.pic");
break;
case 'b': beepon = !beepon; nosound(); break;
case 'p': getch(); break; // temporary pause
case 'e': editscreen(); break;
}
for(i = 0 ; i < 3 ; i++)
free(ptr[i]);
return(keepgoing);
} // end grow2d()
//---------------------------------------------------------------------------
// determine commonest color among neighbors
// starts search at a random point within colortally[] and loops around
// through beginning if necessary. Thus, if two or
// more colors tie for the mode, the choice of "winner" will be random,
// not determined by placement.
int calcmode()
{
int mode;
int highcount = 0;
int start = random(16); // 0-15
int i = start;
do
{
if(colortally[i] > highcount)
{
highcount = colortally[i];
mode = i;
}
if(++i == 16)
i = 0;
}
while(i != start);
return(mode);
}
//-------------------------------------------------------------------
// 2-dimensional using color
// returns TRUE on "success", FALSE on error or if user aborted
// color game rules are always hard programmed. they can't be saved,
// loaded, or edited. If you want multiple rule SETS, (so that a point
// can be calculated differently depending on its current state),
// add additional functions and select one.
// Don't clutter this one up any further with choices.
BOOL colorgrow()
{
int i, j, k, neighborcount, neighborsum, color, setcount;
int colorset[16];
int tc; // temp, holds color of points tested
int screenline; // screen display line being worked on (0-479)
int linesize; // number of chars in a buffer line
char *ptr[3]; // pointers to buffers containing line data
char *temp; // for pointer swapping
BOOL keepgoing = TRUE; // value returned (whether to come right back)
int maxx = getmaxx()+1; // now it's the NUMBER of points in a screen line (640)
linesize = maxx+2; // 1 pixel beyond each edge
for(i = 0 ; i < 3 ; i++) // allocate space for the line buffers
if((ptr[i] = (char *)malloc(linesize)) == NULL)
{
for(j = 0 ; j < i ; j++) // free any already-allocated buffers
if(ptr[j])
free(ptr[j]);
setcolor(WHITE); // still won't show if area is already white
outtextxy(0,0,"Out of memory.");
return(FALSE);
}
setmem(ptr[0],linesize,0); // zero out imaginary line above screen top
setmem(ptr[1],linesize,0); // and zero out the others to avoid garbage
setmem(ptr[2],linesize,0); // 1st & last chars MUST be zeroed at minimum
// read actual screen lines 0 and 1
// into arrays 1 and 2
for(i = lowx ; i <= highx ; i++) // read points 0-639 (at most)
{
ptr[1][i+1] = getpixel(i,lowy); // fill array elements 1-640 (max)
ptr[2][i+1] = getpixel(i,lowy+1); // out of 0-641 available
} // leaving offscreen endpoints alone
for(screenline = lowy ; screenline <= highy ; screenline++)
{
// calculate values for array line 1 directly to screen line 0
for(i = lowx+1 ; i <= highx+1 ; i++) // for i = 1 to 640
{
// compute all the various statistics we might use for rules
for(j = 0 ; j < 16 ; j++) // zero out tally values
colortally[j] = 0;
neighborsum = neighborcount = 0;
tc = (int)(ptr[0][i-1]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
tc = (int)(ptr[0][i]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
tc = (int)(ptr[0][i+1]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
tc = (int)(ptr[1][i-1]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
// (ptr[1][i]) // just for reference, this is the point itself
tc = (int)(ptr[1][i+1]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
tc = (int)(ptr[2][i-1]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
tc = (int)(ptr[2][i]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
tc = (int)(ptr[2][i+1]);
colortally[tc]++;
if(tc) { neighborcount++; neighborsum += tc; }
// every color can have its own rule set
switch(color = (int)(ptr[1][i])) // point's current color
{
case 0: // if cell is dead, see whether it is born
// point is born as the color of which there are 3 neighbors
// if 3 of more than one color, the one to use is chosen at random.
for(k = 0 ; k < 16 ; k++)
colorset[k] = 0;
setcount = 0;
for(k = 1 ; k < 16 ; k++)
if((colortally[k] == 3))
colorset[setcount++] = k;
if(setcount)
{
color = colorset[random(setcount)];
population++;
}
break;
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
// if(neighborcount == 2 || neighborcount == 3)
if((colortally[color] == 2) || (colortally[color] == 3))
{
color = color;
}
else
{
color = 0;
}
if(color == 0)
population--;
break;
} // end switch(color)
putpixel(i-1,screenline,color);
if(population < 0) population = 0;
if(beepon)
sound((int)((population % 15000)+50));
}
temp = ptr[0]; // save top line, we're through with it
ptr[0] = ptr[1]; // line scrolls up, become top line
ptr[1] = ptr[2]; // line becomes the one being averaged
ptr[2] = temp; // we're about to overwrite data in this
// because we need a new bottom line
if(screenline < (highy-1)) // if not last pass,
for(j = lowx ; j <= highx ; j++) // read points 0-639
ptr[2][j+1] = getpixel(j,screenline+2);
else // for last pass, must create
setmem(ptr[2],linesize,0); // imaginary line below screen bottom
} // end for(process all screen lines)
if(kbhit()) // only allow these actions between whole screenfuls
switch(tolower(getch()))
{
case 27: keepgoing = FALSE; break; // ESC exits
case 's': picsave("life.pic"); break; // save .pic file
case 'b': beepon = !beepon; nosound(); break;
case 'p': getch(); break; // temporary pause
case 'e': editscreen(); break;
}
for(i = 0 ; i < 3 ; i++)
free(ptr[i]);
return(keepgoing);
} // end colorgrow()
//---------------------------------------------------------------------------
// randscreen() plots random dots to start a game
void randscreen(
int dimension, // one or two-dimensional
long number, // number of points to plot
int vertsize, // space in which to squeeze random points
int horisize, // space in which to squeeze random points
int gametype) // determines whether to randomize colors
{
int x, y;
long i;
int xadj = (getmaxx()/2) - (horisize/2);
int yadj = (getmaxy()/2) - (vertsize/2);
switch(dimension)
{
case 1:
for(i = 0L ; i < number ; i++) // random top line
{
x = random(horisize)+xadj;
if(!getpixel(x,0))
population++;
putpixel(x,0,LIGHTGREEN);
}
break;
case 2:
for(i = 0L ; i < number ; i++) // random whole screen
{
x = random(horisize)+xadj;
y = random(vertsize)+yadj;
if(!getpixel(x,y))
population++;
putpixel(x,y,(gametype == 5)? random(15)+1 : LIGHTGREEN);
}
break;
}
} // end randscreen()
//---------------------------------------------------------------------------
// randomrules() assign survive/birth rules randomly
void randomrules()
{
int k, m;
BOOL found;
// Fill from 1 to 9 slots in s[] with values from 0-8 without repeating any value.
// first fill in s[]
int j = random(9) + 1; // from 1 to 9 blanks filled in
for(int i = 0 ; i < j ; i++)
{
do
{
k = random(9); // a neighborcount value 0-8
found = FALSE;
for(m = 0 ; m < i ; m++) // already assigned?
if(s[m] == k)
{
found = TRUE;
break;
}
}
while(found);
s[i] = k; // put value in its slot
}
s[i] = -1; // mark array end
j = random(9) + 1; // next fill in b[]
for(i = 0 ; i < j ; i++)
{
do
{
k = random(9); // a neighborcount value 0-8
found = FALSE;
for(m = 0 ; m < i ; m++) // already assigned?
if(b[m] == k)
{
found = TRUE;
break;
}
}
while(found);
b[i] = k; // put value in its slot
}
b[i] = -1; // mark array end
} // end randomrules()
//---------------------------------------------------------------------------
// browserules() browse and load rule set from file life.rul
// assumes display is in text mode
// use "skip" to bring up screen at same location as it was left last time.
void browserules()
{
int i;
char survive[80], born[80], comment[128], *temp;
ifstream infile("life.rul");
if(!infile)
aborts("File LIFE.RUL not found.");
while(1) // only way to exit is to choose a rule set
{
if(infile.fail()) // used up file
{
infile.close();
infile.open("life.rul"); // restart from beginning
continue; // restart loop
}
infile.getline(survive,sizeof(survive));
infile.getline(born,sizeof(born));
infile.getline(comment,sizeof(comment));
if(infile.fail()) // premature end of file
aborts("File LIFE.RUL corrupt. Repair and rerun.");
infile >> ws;
clrscr();
cout << survive << endl << born << endl << comment << endl; // display rule set
cout << "\n<CR> to accept, any other key for next: ";
if(getch() == 13) // load the rule set
{
i = 0;
strtok(survive," "); // tokenize and ignore text "Survive:"
while(temp = strtok(NULL," ")) // load s[] array
s[i++] = atoi(temp);
s[i] = -1; // mark array end
strtok(born," "); // tokenize and ignore text "Born:"
i = 0;
while(temp = strtok(NULL," ")) // load b[] array
b[i++] = atoi(temp);
b[i] = -1; // mark array end
break;
}
} // end while(1)
} // end browserules()
//---------------------------------------------------------------------------
// editrules() show current rule set and allow entering a different one
// assumes already in text mode upon entry
void editrules()
{
int i;
char buf[80], *temp;
clrscr();
printf("Current Rules:\n\n");
printf("Survive: ");
for(i = 0 ; s[i] != -1 ; i++)
printf(" %d",s[i]);
printf("\nBorn: ");
for(i = 0 ; b[i] != -1 ; i++)
printf(" %d",b[i]);
printf("\n\nEnter new SURVIVAL counts (Ex: # # #) (or CR for no change):\n");
gets(buf);
if(strlen(buf))
{
i = 0;
s[i++] = atoi(strtok(buf," ")); // tokenize & load s[] array
while((temp = strtok(NULL," ")) && (i < 9)) // prevent s[i] overrun
s[i++] = atoi(temp);
s[i] = -1; // mark array end
}
printf("\nEnter new BORN counts (Ex: # # #) (or CR for no change):\n");
gets(buf);
if(strlen(buf))
{
i = 0;
b[i++] = atoi(strtok(buf," ")); // tokenize
while((temp = strtok(NULL," ")) && (i < 9)) // load b[] array
b[i++] = atoi(temp);
b[i] = -1; // mark array end
}
} // end editrules()
//---------------------------------------------------------------------------
// main
int main()
{
randomize();
string::set_case_sensitive(0);
string::set_paranoid_check(1);
int i;
int dimension; // 1 or 2
int setup; // setup option chosen
int gametype = 0; // how rules are assigned
BOOL edited = FALSE; // whether user has modified rule set
long startpoints = 0L; // number of initial random points
int x0, y0; // screen origin
int vertsize, horisize; // size of square holding random points
int maxx, maxy; // maximum screen dimensions
char filename[80], buf[128], ch;
FILE *infile = NULL;
ofstream outfile;
s[9] = b[9] = -1; // maximum end-of-array markers
s[0] = b[0] = -1; // initially marks as "none assigned"
do
{
printf("\n1-Dimensional or 2-Dimensional? (1 or 2): ");
gets(buf);
dimension = atoi(buf);
}
while((dimension != 1) && (dimension != 2));
if(dimension == 2)
{
do
{
printf("\nGame Type:\n");
puts("\n1 = Standard Life (survive=2,3)(born=3)");
puts("2 = Randomly assign survival and birth rules");
puts("3 = Manually assign rules");
puts("4 = Browse and load rule set from file");
puts("5 = Color game");
printf("\nEnter game type: ");
gets(buf);
gametype = atoi(buf);
}
while((gametype < 1) || (gametype > 5));
switch(gametype) // these assignments only need to be done once
{
case 1: // standard Life
s[0] = 2; s[1] = 3; s[2] = -1;
b[0] = 3; b[1] = -1;
break;
case 3: // manually assign rules
editrules(); // routine is for assignment OR changing (later)
break;
case 4: // browse and load from file
browserules();
break;
}
} // end if(dimension == 2)
do
{
puts("\nSetup Options:\n");
puts("0 - Exit");
puts("1 - Load File");
puts("2 - Random Screen");
puts("3 - Manual Setup\n");
printf("Enter choice: ");
gets(buf);
setup = atoi(buf);
printf("\n\n");
}
while((setup < 0) || (setup > 3));
switch(setup)
{
case 0: return(0);
case 1: // load from file (make sure it's there)
do
{
printf("\nFull file name to load, or <CR> to quit: ");
gets(filename);
if(!strlen(filename))
return(0);
infile = fopen(filename,"rb");
}
while(!infile);
fclose(infile);
break;
case 2: // random screen
do
{
puts("This option plots a number of random points");
puts("into a square at the screen center");
puts("that is X dots high by Y dots wide.");
puts("For FULL screen, enter 0 (zero) for both X and Y.");
puts("For example: 1000,0,0");
puts("Please enter, separated by commas:");
printf("\nNumber of points, width, height: ");
gets(buf);
if(!strlen(buf))
return(0);
i = sscanf(buf,"%ld,%d,%d",&startpoints,&horisize,&vertsize);
}
while(i != 3);
break;
case 3: // manual setup
break;
}
puts("\nWhile running:");
puts("S Saves current screen to file LIFE.PIC, then continues.");
puts("<ESC> Stops processing. Then press...");
puts("R Starts a new game with current parameters");
puts("Any other key exits to DOS.\n");
printf("\n");
initgraf(); // 640x480
highx = maxx = getmaxx(); // initialize variables
highy = maxy = getmaxy();
lowx = lowy = 0; // defaults
x0 = maxx/2;
y0 = maxy/2;
setcolor(LIGHTGREEN);
setfillstyle(SOLID_FILL,LIGHTGREEN);
while(1) // starting point of each new run
{
if(gametype == 2)
randomrules(); // assign rules randomly
population = 0L;
clearviewport();
outfile.open("life.pop");
outfile << "Survive:"; // store to file for reference
for(i = 0 ; s[i] != -1 ; i++)
outfile << " " << s[i];
outfile << "\nBorn:";
for(i = 0 ; b[i] != -1 ; i++)
outfile << " " << b[i];
outfile << endl;
switch(setup)
{
case 1:
picload(filename); // must initgraph before this point
editscreen(); // allow editing screen before start
break;
case 2: // random screen
if((vertsize <= 0) || (vertsize > maxy))
vertsize = maxy;
if((horisize <= 0) || (horisize > maxx))
horisize = maxx;
randscreen(dimension,startpoints,vertsize,horisize,gametype);
// set "calculate" area to be 2x the random-plot area in each dimension,
// but don't allow calculate area to enlarge automatically.
lowx = max(x0 - horisize,0);
highx = min(x0 + horisize,maxx);
lowy = max(y0 - vertsize,0);
highy = min(y0 + vertsize,maxy);
break;
case 3: // manual setup
editscreen();
break;
}
// starting population - remember: excludes multiply-hit pixels.
outfile << population << endl;
switch(dimension)
{
case 1:
grow1d(); // it just cycles until user aborts
break;
case 2:
if(gametype == 5)
while(colorgrow())
outfile << population << endl;
else
while(grow2d())
outfile << population << endl;
break;
}
nosound();
outfile.close();
gotoxy(1,1); // apparently ok in graphics mode
// only if random or manually set
if(gametype != 5) // no save for color game
if((gametype == 2) || (gametype == 3) || edited)
{
printf("To add this rule set to file, enter any comment, or <CR> to skip:\n");
gets(buf);
if(strlen(buf))
{
outfile.open("life.rul",ios::app);
outfile << "Survive:";
for(i = 0 ; s[i] != -1 ; i++)
outfile << " " << s[i];
outfile << "\nBorn:";
for(i = 0 ; b[i] != -1 ; i++)
outfile << " " << b[i];
outfile << "\nC: " << buf << endl;
outfile.close();
}
}
printf("<Q>uit, <E>dit rules, <B>rowse rules, <C>ontinue: ");
ch = tolower(getch());
if(ch == 'q')
break;
if(gametype != 5) // no editing or browsing for color
if((ch == 'e') || (ch == 'b'))
{
restorecrtmode();
if(ch == 'e')
{
editrules();
edited = TRUE;
}
else
{
browserules();
edited = FALSE;
}
setgraphmode(VGAHI);
}
} // end while(1)
closegraph();
return(0);
}
|
|
|
|
|
|