Hi, for my abstract data structure class i wanted some training with objects and linked lists. Therefore i programmed a little "game of life" programm.
It is doing what it is supposed to do, but I feel like i made a huge mess.
I hope someone can point out some design flaws and help me do better in the future.
Anyways, here is some code:
The grid is a 2d Array that prints the Cells according to the alive-state:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
|
void Spielplan::drawSpielplan(){
system("CLS"); // <--- Superbad... i know :)
for (int j = 0 ; j < maxSize ; j++){
cout << j<<"\t";
for (int i = 0 ; i < maxSize ; i++){
if (coordinates[j][i] == '*'){
}else if (coordinates[j][i] == 'X'){
}else {
coordinates[j][i] = '.';
}
cout << coordinates[j][i]<<" ";
}
cout << endl;
}
}
|
I use a class cell which is inherited from the class spielplan (to acces the 2d array) Within the class i use a struct for each cell with a boolean for alive, some coordinates and a pointer to the next cell.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
#include "spielplan.h"
class ListOfCells: public Spielplan{
private:
const static int maxSize = 20;
bool found;
struct cell{
bool alive;
int x,y;
cell *next;
};
cell *head;
cell *tmp;
cell *curr;
cell *headCpy;
cell *tmpCpy;
cell *currCpy;
public:
ListOfCells();
void addCell(int x, int y);
void updateCell(int x, int y);
void killCell(int x, int y);
bool searchForCell(int x, int y);
void spawnCells();
void copyList();
void copyListBack();
void killAllCells();
bool searchForAliveCell(int x, int y);
void printList(); //only for debuging
void printListCpy(); //only for debuging
};
|
Now the code that spawns some initial cells and starts the calculation what cell to spawn/kill. Basicly what it does, it creates a linked List for each coordinate in the grid, every cell in this list starts out as dead. Then it spawns an initial poulation of cells.
After we have our first generation of cells it will deepcopy the entire list into a new list.
After the copy it starts the calculation of what to spawn/kill with the data from the initial list.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
void ListOfCells::spawnCells(){
for (int i = 0 ; i < maxSize ; i++){
for (int j = 0 ; j < maxSize ; j++){
addCell(i,j);
}
}
drawSpielplan();
bool newCell = false;
srand(time(0));
signed int x,y;
//Initial cell
x = rand() % 20, y = rand() % 20;
updateCell(x,y);
int generations = 1;
//cout << "Starting Cell created at: " << x << " " << y << endl;
while (generations < 300){
while (generations < 15){
while (!newCell){
int switchCase = rand()%8;
switch (switchCase){
case 0: if (x == 19 || y == 19){
x=x, y=y;
}else {
x++, y++;
}break;
case 1: if (x == 19 || y == 0){
x=x, y=y;
}else {
x++, y--;
}break;
case 2: if (x == 0 || y == 0){
x=x, y=y;
}else {
x--, y--;
}break;
case 3:if (x == 0 || y == 19){
x=x, y=y;
}else {
x--, y++;
}break;
case 4:if (y == 19){
x=x, y=y;
}else {
x, y++;
}break;
case 5:if (y == 0){
x=x, y=y;
}else {
x, y--;
}break;
case 6:if (x == 19){
x=x, y=y;
}else {
x++, y;
}break;
case 7:if (x == 0){
x=x, y=y;
}else {
x--, y;
}break;
}
if (!searchForAliveCell(x,y)){
updateCell(x,y);
newCell = true;
//cout << "Cell spawned at: " << x << " " << y << endl;
drawSpielplan();
generations++;
}
else{
//cout << "Cell allready in List" << endl;
}
}
newCell = false;
}
cout << "Generations: " << generations << endl;
generations++;
copyList();
killAllCells();
copyListBack();
drawSpielplan();
}
}
|
Based on the rules in the game of live it will analyse each cell and update its alive/dead state in the corresponing data inside the copied list.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
int aliveCounter = 0;
void ListOfCells::killAllCells(){
curr = head;
currCpy = headCpy;
while (curr != NULL){
aliveCounter = 0;
if (curr->alive){
int x = curr->x;
int y = curr->y;
if(searchForAliveCell(x, y-1)){
aliveCounter ++;
}
if(searchForAliveCell(x, y+1)){
aliveCounter ++;
}
if(searchForAliveCell(x+1, y)){
aliveCounter ++;
}
if(searchForAliveCell(x+1, y+1)){
aliveCounter ++;
}
if(searchForAliveCell(x+1, y-1)){
aliveCounter ++;
}
if(searchForAliveCell(x-1, y)){
aliveCounter ++;
}
if(searchForAliveCell(x-1, y+1)){
aliveCounter ++;
}
if(searchForAliveCell(x-1, y-1)){
aliveCounter ++;
}
if (aliveCounter >3){
currCpy->alive = false;
Spielplan::updateSpielplan(x, y, '.');
}else if (aliveCounter >= 2 && aliveCounter <= 3){
currCpy->alive = true;
Spielplan::updateSpielplan(x, y, '*');
}else if (aliveCounter < 2){
currCpy->alive = false;
Spielplan::updateSpielplan(x, y, '.');
}
}else{
int x = curr->x;
int y = curr->y;
if(searchForAliveCell(x, y-1)){
aliveCounter ++;
}
if(searchForAliveCell(x, y+1)){
aliveCounter ++;
}
if(searchForAliveCell(x+1, y)){
aliveCounter ++;
}
if(searchForAliveCell(x+1, y+1)){
aliveCounter ++;
}
if(searchForAliveCell(x+1, y-1)){
aliveCounter ++;
}
if(searchForAliveCell(x-1, y)){
aliveCounter ++;
}
if(searchForAliveCell(x-1, y+1)){
aliveCounter ++;
}
if(searchForAliveCell(x-1, y-1)){
aliveCounter ++;
}
if (aliveCounter == 3){
currCpy->alive = true;
Spielplan::updateSpielplan(x, y, '*');
}
}
curr = curr->next;
currCpy = currCpy->next;
}
//cout << "Kill all Cells exited" << endl;
}
|
After the function went through the whole list and copied all entries to the Copy-list, all the data from the copylist is copied back into the original list updateing all the cells with their current state.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
void ListOfCells::copyListBack(){
curr = head;
currCpy = headCpy;
while (currCpy->next != NULL){
curr->alive = currCpy->alive;
curr->x = currCpy->x;
curr->y = currCpy->y;
//cout << "COPYLIST Current x/y:\t"<< curr->x << "/"<<curr->y <<endl;
//cout << "COPYLIST CurrCpy x/y:\t"<< currCpy->x << "/"<<currCpy->y <<endl;
curr = curr->next;
currCpy = currCpy->next;
}
}
|
This is basicly it, like i said i feel like this is a huge mess. I am pretty sure that the linked list is not the perfect datastructure for this, because most operations performed on it are search operations i should probably use a binary search tree or better hash table.
Anyways i would be so happy if someone could point out some of my bad decissions and help me write/design cleaner programs.