So this dude, Conway, made a "zero-player" game because he's a mathematician and that's a good enough reason. He thinks a living cell dies when it's lonely or overpopulated. Humans just get severely annoyed.
Anyway, I implemented this game in C++ and OpenGL(glut) for a low-input-high-output semester project. Some call me lazy and I respect the opinions of others.
Constructive criticism is welcome.
// g++ ConwayWork.cpp -lglut
#include <iostream>
#include <GL/glut.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
#define ROW 100
#define COLUMN 100
int x_pos = 0, y_pos = 0, W, H;
bool gen = false;
void timerDraw(int foo);
void initGL() //Initialize with the background color
{
glClearColor(0.08, 0.08, 0.08, 1.0);
}
class Life
{
private:
bool state; //True is alive. False is dead.
public:
Life()
{
state = false;
}
void make()
{
state = true;
}
void kill()
{
state = false;
}
bool isAlive()
{
return state;
}
friend void mouse(int button, int state, int x, int y);
friend void keyboard(unsigned char a,int b,int c);
};
class World
{
private:
Life colony[COLUMN][ROW];
public:
World()
{
colony[3][3].make();
colony[4][4].make();
colony[5][4].make();
colony[5][3].make();
colony[5][2].make();
}
void populateRandom()
{
for(int i = 0; i < COLUMN; i++)
for(int j = 0; j < ROW; j++)
if(rand()%2)
colony[i][j].make();
else
colony[i][j].kill();
}
void clear()
{
for(int i = 0; i < COLUMN; i++)
for(int j = 0; j < ROW; j++)
colony[i][j].kill();
}
void judgment()
{
World theDeparted;
for(int i = 0; i < COLUMN; i++)
for(int j = 0; j < ROW; j++)
if(!colony[i][j].isAlive() && neighbours(i, j) == 3) //If dead and 3 neighbours, create.
theDeparted.colony[i][j].make();
else if(colony[i][j].isAlive() && (neighbours(i, j) == 2 || neighbours(i, j) == 3) ) //If alive and two or 3 neighbours, continue to live.
theDeparted.colony[i][j].make();
else //Anything else, kill.
theDeparted.colony[i][j].kill();
*this = theDeparted;
}
int neighbours(int i, int j)
{
int n = 0;
if(i > 0 && j > 0 && i < COLUMN-1 && j < ROW-1) //Inside
{
if(colony[i-1][j-1].isAlive()) //Down left
n++;
if(colony[i-1][j].isAlive()) //Left
n++;
if(colony[i-1][j+1].isAlive()) //Up left
n++;
if(colony[i][j+1].isAlive()) //Up
n++;
if(colony[i+1][j+1].isAlive()) //Up right
n++;
if(colony[i+1][j].isAlive()) //Right
n++;
if(colony[i+1][j-1].isAlive()) //Down right
n++;
if(colony[i][j-1].isAlive()) //Down
n++;
return n;
}
else if(i == 0 && j == 0) //Lower left corner
{
if(colony[i][j+1].isAlive()) //Up
n++;
if(colony[i+1][j+1].isAlive()) //Up right
n++;
if(colony[i+1][j].isAlive()) //Right
n++;
return n;
}
else if(i == 0 && j == ROW-1) //Top left corner
{
if(colony[i+1][j-1].isAlive()) //Down right
n++;
if(colony[i][j-1].isAlive()) //Down
n++;
if(colony[i+1][j].isAlive()) //Right
n++;
return n;
}
else if(i == COLUMN-1 && j == ROW-1) //Top right corner
{
if(colony[i-1][j-1].isAlive()) //Down left
n++;
if(colony[i-1][j].isAlive()) //Left
n++;
if(colony[i][j-1].isAlive()) //Down
n++;
return n;
}
else if(i == COLUMN-1 && j == 0) //Lower right corner
{
if(colony[i-1][j].isAlive()) //Left
n++;
if(colony[i-1][j+1].isAlive()) //Up left
n++;
if(colony[i][j+1].isAlive()) //Up
n++;
return n;
}
else if(i == 0) //Left column
{
if(colony[i][j+1].isAlive()) //Up
n++;
if(colony[i+1][j+1].isAlive()) //Up right
n++;
if(colony[i+1][j].isAlive()) //Right
n++;
if(colony[i+1][j-1].isAlive()) //Down right
n++;
if(colony[i][j-1].isAlive()) //Down
n++;
return n;
}
else if(j == 0) //Bottom row
{
if(colony[i-1][j].isAlive()) //Left
n++;
if(colony[i-1][j+1].isAlive()) //Up left
n++;
if(colony[i][j+1].isAlive()) //Up
n++;
if(colony[i+1][j+1].isAlive()) //Up right
n++;
if(colony[i+1][j].isAlive()) //Right
n++;
return n;
}
else if(i == COLUMN-1) //Right column
{
if(colony[i-1][j-1].isAlive()) //Down left
n++;
if(colony[i-1][j].isAlive()) //Left
n++;
if(colony[i-1][j+1].isAlive()) //Up left
n++;
if(colony[i][j+1].isAlive()) //Up
n++;
if(colony[i][j-1].isAlive()) //Down
n++;
return n;
}
else if(j == ROW-1) //Top row
{
if(colony[i-1][j-1].isAlive()) //Down left
n++;
if(colony[i-1][j].isAlive()) //Left
n++;
if(colony[i+1][j].isAlive()) //Right
n++;
if(colony[i+1][j-1].isAlive()) //Down right
n++;
if(colony[i][j-1].isAlive()) //Down
n++;
return n;
}
}
friend void draw();
friend void mouse(int button, int state, int x, int y);
friend void keyboard(unsigned char a,int b,int c);
};
World pluto; //Create object.
void draw()
{
static double color1 = 0.03, color2 = 1, color3 = 0; //Colors for decoration only.
glClear(GL_COLOR_BUFFER_BIT);
for(int i = 0; i < COLUMN; i++)
{
for(int j = 0; j < ROW; j++)
if(pluto.colony[i][j].isAlive())
{
glBegin(GL_POLYGON); //Draw life square, size 10.
glColor3d(1, color2-color1, color1+color2);
glVertex2d(i*10,j*10);
glVertex2d(i*10+10,j*10);
glVertex2d(i*10+10,10*j-10);
glVertex2d(i*10,j*10-10);
glEnd();
//cout<<"@"; //Cout for command line output, this slows the program considerably.
}
//else
//cout<<" ";
// cout<<endl;
}
glBegin(GL_POLYGON); //Draw keyboard square size 10.
glColor3d(1, color3, 0);
glVertex2d(x_pos*10,y_pos*10);
glVertex2d(x_pos*10+10,y_pos*10);
glVertex2d(x_pos*10+10,10*y_pos-10);
glVertex2d(x_pos*10,y_pos*10-10);
glEnd();
glutSwapBuffers();
if(gen)
{
pluto.judgment(); //Show generation changes.
color1 += 0.01;
color2 -= 0.01;
color3 = 1;
}
else
color3 = 0;
glutTimerFunc(200,timerDraw,0);
}
void reshape(int w, int h)
{
W = w; //W and H for use by mousefunction only.
H = h;
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-10.0,COLUMN*10+10,-10.0,ROW*10+10,-1,1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
void mouse(int button, int state, int x, int y)
{
//Origin of window is top left, origin of OpenGL is bottom left. Y values thus corrected.
if(button == GLUT_LEFT_BUTTON && state == GLUT_UP && x*COLUMN/W > 0 && x*COLUMN/W < COLUMN && (H-y)*ROW/H > 0 && (H-y)*ROW/H < ROW)
{
if(pluto.colony[x*COLUMN/W][(H-y)*ROW/H].isAlive())
pluto.colony[x*COLUMN/W][(H-y)*ROW/H].kill();
else
pluto.colony[x*COLUMN/W][(H-y)*ROW/H].make();
}
}
void keyboard(unsigned char a,int b,int c)
{
switch(a)
{
case 'w': case 'W':
if(y_pos < ROW-1)
y_pos++;
break;
case 'a': case'A':
if(x_pos > 0)
x_pos--;
break;
case 's': case 'S':
if(y_pos > 0)
y_pos--;
break;
case 'd': case 'D':
if(x_pos < COLUMN-1)
x_pos++;
break;
case 'x': case 'X':
if(pluto.colony[x_pos][y_pos].isAlive())
pluto.colony[x_pos][y_pos].kill();
else
pluto.colony[x_pos][y_pos].make();
break;
case ' ':
gen = !gen;
break;
case 'r': case 'R':
pluto.populateRandom();
break;
case 'c': case 'C':
pluto.clear();
break;
default:
break;
}
}
void timerDraw(int foo)
{
glutMouseFunc(mouse);
glutKeyboardFunc(keyboard);
glutPostRedisplay();
}
int main(int argc, char** argv) //Mandatory arguments for OpenGL
{
srand (time(NULL)); //Seed the Random number generator.
cout<<"Use WASD keys for navigation, 'x' to alter state, 'r' for random population, 'c' to clear, Space to start.\nMouse can also be used, although it is slightly inaccurate.\n";
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutCreateWindow("CONWAY");
glutReshapeFunc(reshape);
glutDisplayFunc(draw);
glutSwapBuffers();
initGL();
glutMainLoop();
return 0;
}
congrats.
ReplyDelete