Nelze vybrat více než 25 témat
Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
572 řádky
12 KiB
572 řádky
12 KiB
#include "gameoflife.h"
|
|
|
|
GameOfLife::GameOfLife(int _x, int _y) {
|
|
init();
|
|
x = _x;
|
|
y = _y;
|
|
allocate();
|
|
}
|
|
|
|
GameOfLife::GameOfLife(std::string file) {
|
|
init();
|
|
load(file);
|
|
}
|
|
|
|
GameOfLife::GameOfLife(int _x, int _y, int r_life, int r_dead) {
|
|
init();
|
|
fillRandom(_x, _y, r_life, r_dead);
|
|
}
|
|
|
|
void GameOfLife::init() {
|
|
view3d = true;
|
|
feld = 0;
|
|
x = y = 0;
|
|
generation = 0;
|
|
thickness = 0.5f;
|
|
cellwidth = 1.0f;
|
|
torus = true;
|
|
fullcelluse = true;
|
|
radius = 0.3f;
|
|
height = 1.0f;
|
|
parts = 12;
|
|
sectobuild = 0.91f;
|
|
b_secdone = 0.0f;
|
|
secpertick = 1.0f;
|
|
t_secdone = 0.0f;
|
|
editmode = false;
|
|
|
|
// Calc cylinder sinvals
|
|
sinval = new float[parts];
|
|
cosval = new float[parts];
|
|
|
|
for(int i=0; i<parts; i++) {
|
|
sinval[i] = radius * sin(segl::deg2rad(360.0f/parts*i));
|
|
cosval[i] = radius * cos(segl::deg2rad(360.0f/parts*i));
|
|
}
|
|
|
|
quad = gluNewQuadric();
|
|
}
|
|
|
|
void GameOfLife::allocate() {
|
|
feld = new State*[x];
|
|
for(int i=0; i<x; i++) {
|
|
feld[i] = new State[y];
|
|
|
|
// clean it
|
|
for(int j=0; j<y; j++)
|
|
feld[i][j] = dead;
|
|
}
|
|
}
|
|
|
|
void GameOfLife::cleanup() {
|
|
if(feld) {
|
|
for(int i=0; i<x; i++) {
|
|
delete[](feld[i]);
|
|
}
|
|
delete(feld);
|
|
feld = 0;
|
|
}
|
|
}
|
|
|
|
void GameOfLife::renderBrett() {
|
|
float x1 = cellwidth*x / 2.0f;
|
|
float y1 = thickness / 2.0f;
|
|
float z1 = cellwidth*y / 2.0f;
|
|
|
|
// Brettquader
|
|
GLfloat mat_diffuse[] = { 1.0f, 0.0f, 0.0f, 1.0f };
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
|
|
glColor3f(1.0f, 0.0f, 0.0f);
|
|
glBegin(GL_QUADS);
|
|
// Platte
|
|
glNormal3f(0.0f, 1.0f, 0.0f);
|
|
glVertex3f(-x1, y1, -z1);
|
|
glVertex3f( x1, y1, -z1);
|
|
glVertex3f( x1, y1, z1);
|
|
glVertex3f(-x1, y1, z1);
|
|
|
|
// Boden
|
|
glNormal3f(0.0f,-1.0f, 0.0f);
|
|
glVertex3f(-x1, -y1, -z1);
|
|
glVertex3f( x1, -y1, -z1);
|
|
glVertex3f( x1, -y1, z1);
|
|
glVertex3f(-x1, -y1, z1);
|
|
|
|
// Seiten
|
|
glNormal3f(0.0f, 0.0f, 1.0f);
|
|
glVertex3f(-x1, -y1, z1);
|
|
glVertex3f( x1, -y1, z1);
|
|
glVertex3f( x1, y1, z1);
|
|
glVertex3f(-x1, y1, z1);
|
|
|
|
glNormal3f(0.0f, 0.0f,-1.0f);
|
|
glVertex3f(-x1, -y1,-z1);
|
|
glVertex3f( x1, -y1,-z1);
|
|
glVertex3f( x1, y1,-z1);
|
|
glVertex3f(-x1, y1,-z1);
|
|
|
|
glNormal3f(-1.0f, 0.0f, 0.0f);
|
|
glVertex3f(-x1, -y1, z1);
|
|
glVertex3f(-x1, y1, z1);
|
|
glVertex3f(-x1, y1,-z1);
|
|
glVertex3f(-x1, -y1,-z1);
|
|
|
|
glNormal3f(1.0f, 0.0f, 0.0f);
|
|
glVertex3f( x1, -y1, z1);
|
|
glVertex3f( x1, y1, z1);
|
|
glVertex3f( x1, y1,-z1);
|
|
glVertex3f( x1, -y1,-z1);
|
|
glEnd();
|
|
|
|
//Gitter
|
|
glPushMatrix();
|
|
|
|
|
|
mat_diffuse[0] = 0.0f;
|
|
mat_diffuse[1] = 1.0f;
|
|
mat_diffuse[2] = 0.0f;
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
|
|
|
|
glColor3f(0.0f, 1.0f, 0.0f);
|
|
for(int a=0; a<1; a++) {
|
|
glTranslatef(0.0f, 0.01f, 0.0f);
|
|
glBegin(GL_LINES);
|
|
glNormal3f(0.0f, 1.0f, 0.0f);
|
|
for(float i=-x1; i<=x1; i+=cellwidth) {
|
|
glVertex3f(i, y1, -z1);
|
|
glVertex3f(i, y1, z1);
|
|
}
|
|
|
|
for(float i=-z1; i<=z1; i+=cellwidth) {
|
|
glVertex3f(-x1, y1, i);
|
|
glVertex3f( x1, y1, i);
|
|
}
|
|
glEnd();
|
|
}
|
|
glPopMatrix();
|
|
}
|
|
|
|
void GameOfLife::renderStein(State s) {
|
|
float sin1, sin2 = sinval[0], cos1, cos2 = cosval[0];
|
|
|
|
float height2 = 0.0f;
|
|
switch(s) {
|
|
case alife:
|
|
height2 = height;
|
|
break;
|
|
case born:
|
|
height2 = height * (b_secdone/sectobuild);
|
|
break;
|
|
case dies:
|
|
height2 = height * ((sectobuild-b_secdone)/sectobuild);
|
|
break;
|
|
case dead:
|
|
// unlikely to happen...
|
|
height2 = 0.0f;
|
|
break;
|
|
}
|
|
if(height2<0.001f)
|
|
return;
|
|
|
|
glColor3f(0.2f, 0.2, 0.9f);
|
|
|
|
// for(float i=0, step=360.0f/parts; i<360.0f; i+= step) {
|
|
for(int i=0; i<parts; i++) {
|
|
sin1 = sin2;
|
|
cos1 = cos2;
|
|
sin2 = sinval[(i+1)%parts];
|
|
cos2 = cosval[(i+1)%parts];
|
|
// sin2 = radius * sin(deg2rad(i+step));
|
|
// cos2 = radius * cos(deg2rad(i+step));
|
|
GLfloat mat_diffuse[] = { 0.2f, 0.2, 0.9f, 1.0f };
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
|
|
|
|
/*
|
|
glPushMatrix();
|
|
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
|
|
gluCylinder(quad, radius, radius, height2, 12, 1);
|
|
glTranslatef(0.0f, 0.0f, height2);
|
|
gluDisk(quad, 0.0f, radius, 12, 1);
|
|
glPopMatrix();
|
|
*/
|
|
|
|
glBegin(GL_QUADS);
|
|
glNormal3f(0.0f, 0.0f,-1.0f);
|
|
glVertex3f(-radius, 0.0f, -radius);
|
|
glVertex3f(-radius, height2,-radius);
|
|
glVertex3f( radius, height2,-radius);
|
|
glVertex3f( radius, 0.0f, -radius);
|
|
|
|
glNormal3f(0.0f, 0.0f, 1.0f);
|
|
glVertex3f( radius, 0.0f, radius);
|
|
glVertex3f( radius, height2, radius);
|
|
glVertex3f(-radius, height2, radius);
|
|
glVertex3f(-radius, 0.0f, radius);
|
|
|
|
glNormal3f(-1.0f, 0.0f, 0.0f);
|
|
glVertex3f(-radius, 0.0f, -radius);
|
|
glVertex3f(-radius, 0.0f, radius);
|
|
glVertex3f(-radius, height2, radius);
|
|
glVertex3f(-radius, height2,-radius);
|
|
|
|
glNormal3f( 1.0f, 0.0f, 0.0f);
|
|
glVertex3f( radius, 0.0f, radius);
|
|
glVertex3f( radius, 0.0f, -radius);
|
|
glVertex3f( radius, height2,-radius);
|
|
glVertex3f( radius, height2, radius);
|
|
|
|
glNormal3f(0.0f, 1.0f, 0.0f);
|
|
glVertex3f(-radius, height2, radius);
|
|
glVertex3f( radius, height2, radius);
|
|
glVertex3f( radius, height2,-radius);
|
|
glVertex3f(-radius, height2,-radius);
|
|
|
|
|
|
glEnd();
|
|
/*
|
|
glBegin(GL_TRIANGLES);
|
|
// Boden Unten
|
|
glNormal3f(0.0f,-1.0f, 0.0f);
|
|
glVertex3f(0.0f, 0.0f, 0.0f);
|
|
glVertex3f(sin1, 0.0f, cos1);
|
|
glVertex3f(sin2, 0.0f, cos2);
|
|
|
|
// Boden Oben
|
|
glNormal3f(0.0f, 1.0f, 0.0f);
|
|
glVertex3f(0.0f, height2, 0.0f);
|
|
glVertex3f(sin1, height2, cos1);
|
|
glVertex3f(sin2, height2, cos2);
|
|
|
|
//Seite
|
|
glNormal3f((sin1+sin2)/2.0f, 0.0f, (cos1+cos2)/2.0f);
|
|
glVertex3f(sin1, 0.0f, cos1);
|
|
glVertex3f(sin2, 0.0f, cos2);
|
|
glVertex3f(sin2, height2, cos2);
|
|
|
|
glNormal3f((sin1+sin2)/2.0f, 0.0f, (cos1+cos2)/2.0f);
|
|
glVertex3f(sin2, height2, cos2);
|
|
glVertex3f(sin1, height2, cos1);
|
|
glVertex3f(sin1, 0.0f, cos1);
|
|
glEnd();
|
|
*/
|
|
}
|
|
}
|
|
|
|
void GameOfLife::translateTo(int _x, int _y) {
|
|
glTranslatef(-cellwidth/2.0f*x+cellwidth*_x+cellwidth/2.0f, thickness/2.0f, -cellwidth/2.0f*y+cellwidth*_y+cellwidth/2.0f);
|
|
}
|
|
|
|
void GameOfLife::lockStates() {
|
|
for(int i=0; i<x; i++) {
|
|
for(int j=0; j<y; j++) {
|
|
if(feld[i][j]==dies)
|
|
feld[i][j] = dead;
|
|
else if(feld[i][j]==born)
|
|
feld[i][j] = alife;
|
|
}
|
|
}
|
|
}
|
|
|
|
void GameOfLife::set3D(bool on) {
|
|
view3d = on;
|
|
}
|
|
|
|
bool GameOfLife::load(std::string file) {
|
|
std::ifstream data(file.c_str());
|
|
if(!data)
|
|
return false;
|
|
|
|
std::string tmp;
|
|
data >> x;
|
|
data >> y;
|
|
data >> torus;
|
|
if(x<=0 || y <=0)
|
|
return false;
|
|
|
|
cleanup();
|
|
allocate();
|
|
int j=0;
|
|
getline(data, tmp); // Remove \n
|
|
while(getline(data, tmp) && j<y) {
|
|
for(int i=0; i<x && i<(int)tmp.length(); i++) {
|
|
feld[i][j] = (tmp[i]=='1') ? born : dead;
|
|
}
|
|
j++;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool GameOfLife::save(std::string file) {
|
|
std::ofstream data(file.c_str());
|
|
if(!data)
|
|
return false;
|
|
|
|
data << x << " " << y << " " << (torus?1:0) << std::endl;
|
|
for(int j=0; j<y; j++) {
|
|
for(int i=0; i<x; i++) {
|
|
data << ((feld[i][j]==alife||feld[i][j]==born) ? '1' : '0');
|
|
}
|
|
data << std::endl;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void GameOfLife::fillRandom(int _x, int _y, int r_life, int r_dead) {
|
|
cleanup();
|
|
|
|
x = _x;
|
|
y = _y;
|
|
allocate();
|
|
|
|
srand(time(0));
|
|
if(r_life+r_dead==0) {
|
|
r_life = rand()%100 + 1;
|
|
r_dead = rand()%100 + 1;
|
|
}
|
|
|
|
float ratio = r_life/(float)(r_life+r_dead);
|
|
|
|
for(int i=0; i<x; i++) {
|
|
for(int j=0; j<y; j++) {
|
|
if((rand()%100)/100.0f < ratio) {
|
|
feld[i][j] = born;
|
|
} else {
|
|
// should be set to dead, but to be sure...
|
|
feld[i][j] = dead;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// void GameOfLife::toggle(int _x, int _y, State stat) {
|
|
// if(feld && _x>=0 && _x<x && _y>=0 && _y<y) {
|
|
// feld[_x][_y] = stat;
|
|
// }
|
|
// }
|
|
|
|
// const bool** GameOfLife::getFeld() {
|
|
// return (const bool**)feld;
|
|
// }
|
|
|
|
void GameOfLife::setEditMode(bool e) {
|
|
editmode = e;
|
|
if(e) {
|
|
lockStates();
|
|
} else {
|
|
|
|
}
|
|
}
|
|
|
|
void GameOfLife::move(int up, int right) {
|
|
if(up>0)
|
|
setpos.y = ((int)setpos.y+y+1)%y;
|
|
else if(up<0)
|
|
setpos.y = ((int)setpos.y+y-1)%y;
|
|
if(right>0)
|
|
setpos.x = ((int)setpos.x+x+1)%x;
|
|
else if(right<0)
|
|
setpos.x = ((int)setpos.x+x-1)%x;
|
|
|
|
}
|
|
|
|
void GameOfLife::toggle() {
|
|
if(feld[(int)setpos.x][(int)setpos.y]==born||feld[(int)setpos.x][(int)setpos.y]==alife) {
|
|
feld[(int)setpos.x][(int)setpos.y] = dead;
|
|
} else {
|
|
feld[(int)setpos.x][(int)setpos.y] = alife;
|
|
}
|
|
}
|
|
|
|
void GameOfLife::render(float sec) {
|
|
if(!feld)
|
|
return;
|
|
|
|
// Cylinder-building-timer
|
|
if(b_secdone<=sectobuild) {
|
|
b_secdone += sec;
|
|
if(b_secdone>=sectobuild) {
|
|
lockStates();
|
|
}
|
|
}
|
|
|
|
// Tick-timer
|
|
t_secdone += sec;
|
|
if(t_secdone>=secpertick) {
|
|
tick();
|
|
t_secdone = 0.0f;
|
|
b_secdone = 0.0f;
|
|
}
|
|
|
|
if(view3d) {
|
|
renderBrett();
|
|
|
|
for(int j=0; j<y; j++) {
|
|
for(int i=0; i<x; i++) {
|
|
if(feld[i][j]!=dead) {
|
|
glPushMatrix();
|
|
translateTo(i, j);
|
|
renderStein(feld[i][j]);
|
|
glPopMatrix();
|
|
}
|
|
if(editmode) {
|
|
if(i==setpos.x && j==setpos.y) {
|
|
glPushMatrix();
|
|
float mat_diffuse[3] = { 0.0f, 1.0f, 0.0f };
|
|
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
|
|
translateTo(i, j);
|
|
glTranslatef(0.0f, 0.01f, 0.0f);
|
|
glBegin(GL_QUADS);
|
|
glColor3f(0.0f, 1.0f, 0.0f);
|
|
glNormal3f(0.0f, 1.0f, 0.0f);
|
|
glVertex3f(-cellwidth/2.0f, 0.0f, cellwidth/2.0f);
|
|
glVertex3f( cellwidth/2.0f, 0.0f, cellwidth/2.0f);
|
|
glVertex3f( cellwidth/2.0f, 0.0f,-cellwidth/2.0f);
|
|
glVertex3f(-cellwidth/2.0f, 0.0f,-cellwidth/2.0f);
|
|
glEnd();
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
SDL_Surface *screen = SDL_GetVideoSurface();
|
|
float wperp = screen->w /(float)x;
|
|
float hperp = screen->h /(float)y;
|
|
float border;
|
|
|
|
glPushMatrix();
|
|
if(wperp<hperp) {
|
|
glTranslatef(0.0f, (hperp-wperp)*y/2.0f, 0.0f);
|
|
hperp = wperp;
|
|
} else {
|
|
glTranslatef((wperp-hperp)*x/2.0f, 0.0f, 0.0f);
|
|
}
|
|
|
|
border = 0.0f;
|
|
|
|
glBegin(GL_QUADS);
|
|
for(int j=0; j<y; j++) {
|
|
for(int i=0; i<x; i++) {
|
|
if(feld[i][j]==alife||feld[i][j]==born) {
|
|
glColor3f(0.0f, 0.0f, 1.0f);
|
|
} else {
|
|
glColor3f(1.0f, 0.0f, 0.0f);
|
|
}
|
|
glVertex2f(hperp*i+border, hperp*j+border);
|
|
glVertex2f(hperp*i+border, hperp*(j+1)-border);
|
|
glVertex2f(hperp*(i+1)-border, hperp*(j+1)-border);
|
|
glVertex2f(hperp*(i+1)-border, hperp*j+border);
|
|
}
|
|
}
|
|
glEnd();
|
|
|
|
if(editmode) {
|
|
glBegin(GL_QUADS);
|
|
glColor3f(0.0f, 1.0f, 0.0f);
|
|
glVertex2f(hperp*setpos.x+border, hperp*setpos.y+border);
|
|
glVertex2f(hperp*setpos.x+border, hperp*(setpos.y+1)-border);
|
|
glVertex2f(hperp*(setpos.x+1)-border, hperp*(setpos.y+1)-border);
|
|
glVertex2f(hperp*(setpos.x+1)-border, hperp*setpos.y+border);
|
|
glEnd();
|
|
|
|
}
|
|
|
|
|
|
// glTranslatef(0.0f, 0.0f, 0.1f);
|
|
glColor3f(0.0f, 0.0f, 0.0f);
|
|
glBegin(GL_LINES);
|
|
for(float i=0; i<x; i+=1.0f) {
|
|
glVertex2f(i*hperp, 0);
|
|
glVertex2f(i*hperp, y*hperp);
|
|
}
|
|
|
|
for(float i=0; i<y; i+=1.0f) {
|
|
glVertex2f(0, i*hperp);
|
|
glVertex2f(x*hperp, i*hperp); }
|
|
|
|
glEnd();
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
|
|
|
|
float GameOfLife::getTickSec() {
|
|
return secpertick;
|
|
}
|
|
|
|
float GameOfLife::getBuildSec() {
|
|
return sectobuild;
|
|
}
|
|
|
|
void GameOfLife::setTickSec(float s) {
|
|
std::cout << "Set to " << s << std::endl;
|
|
secpertick = s;
|
|
}
|
|
|
|
void GameOfLife::setBuildSec(float s) {
|
|
sectobuild = s;
|
|
}
|
|
|
|
void GameOfLife::setTorus(bool t) {
|
|
torus = t;
|
|
}
|
|
|
|
unsigned long GameOfLife::getGeneration() {
|
|
return generation;
|
|
}
|
|
|
|
void GameOfLife::tick() {
|
|
if(sectobuild>secpertick)
|
|
lockStates();
|
|
|
|
int near;
|
|
int x1, y1;
|
|
for(int i=0; i<x; i++) {
|
|
for(int j=0; j<y; j++) {
|
|
near = 0;
|
|
for(int a=i-1; a<=(i+1); a++) {
|
|
for(int b=j-1; b<=(j+1); b++) {
|
|
if((a==i && b==j) || (!torus && (a<0 || b<0 || a>=x || b>=y)))
|
|
continue;
|
|
if(torus) {
|
|
x1 = (a+x)%x;
|
|
y1 = (b+y)%y;
|
|
} else {
|
|
x1 = a;
|
|
y1 = b;
|
|
}
|
|
|
|
if(feld[x1][y1]==alife || (fullcelluse && (feld[x1][y1]==dies)))
|
|
near++;
|
|
}
|
|
}
|
|
|
|
if(feld[i][j]==alife) {
|
|
if(near!=2 && near!=3)
|
|
feld[i][j] = dies;
|
|
} else if(feld[i][j]==dead) {
|
|
if(near==3)
|
|
feld[i][j] = born;
|
|
}
|
|
}
|
|
}
|
|
if(sectobuild<0.1f)
|
|
lockStates();
|
|
generation++;
|
|
}
|
|
|
|
void GameOfLife::clear() {
|
|
for(int i=0; i<x; i++) {
|
|
for(int j=0; j<y; j++) {
|
|
feld[i][j] = dead;
|
|
}
|
|
}
|
|
}
|
|
|
|
GameOfLife::~GameOfLife() {
|
|
cleanup();
|
|
delete[](sinval);
|
|
delete[](cosval);
|
|
}
|