admin管理员组文章数量:1336321
I want a Game of Life program in the console.
The parameters to initialize the 'field' can be changed in the mainMenu(). When all is done, it returns 1, and the drawing begins. When we return from draw, we get back to mainMenu(). This happens for ever in an infinite while loop. All functions work when tested separately. Problematic ones are border(), init(), etc.
What am I missing? I'm a beginner in C.
(fileIn() doesn't work proper, but that's not the issue here.)
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <conio.h>
//structure for storing the state of each cell
typedef struct Cell{
bool state, nState;
}Cell;
char path[50];
int rule;
Cell** setup(int width, int height){
//create field
int size = (width+2)*(height+2);
Cell** field = malloc(size * sizeof(Cell));;
if (field == NULL){
printf("Malloc Error!");
exit(-1);
}
return field;
}
void clrscr(){
printf("\e[1;1H\e[2J");
}
void welcome(){
clrscr();
printf("This program was created by:\033[1;31m\n U+0466.\033[1;m\n");
sleep(2);
}
void display(Cell* c, int width, int height){
clrscr();
int size = (width+2)*(height+2);
printf("\n");
for (int i = 0; i <(width*2-32)/2; i++)
printf(" ");
printf("\033[1;31mThe Game of Life on a %dx%d grid.\033[1;m", width, height);
//draw the field
for (int i = 0; i < size; i++){
if (i % (width+2) == 0)
printf("\n");
//skip border
if (i < width+2){
printf("X ");
continue;}
else if (i >= (size-(width+2))){
printf("X ");
continue;}
else if ((i+1) % (width+2) == 0){
printf("X ");
continue;}
else if ((i) % (width+2) == 0){
printf("X ");
continue;}
(c[i].state)? printf("O ") : printf(" ");
}
}
int fileIn(int* width, int *height){
//get path from user
printf("\033[1;31m");
printf("Please enter file path: ");
printf("\033[1;m");
scanf("%s", path);
//open file
FILE *fptr = fopen(path, "r");
if (fptr == NULL){
return -1;
}
//find the dimenisons of the field
char ch;
int h = 0;
int w = 0;
int wmax = 0;
for (ch = getc(fptr); ch != EOF; ch = getc(fptr)){
//0 or 1
if ((ch == 48)|(ch == 49)){
w++;
}
//linebreak
else if (ch == 10){
if (w!=0)
h++;
if (w > wmax){
wmax = w;
}
w = 0;
}
}
if ((wmax > 0)|(height > 0)){
*width = wmax;
*height = h + 1;
}
return 0;
}
void fileOut(Cell* c, int width, int height){
FILE *fptr = NULL;
fptr = fopen("out.txt", "w+");
//create a header
for (int i = 1; i <= width; i++)
fprintf(fptr, "-");
fprintf(fptr, "\nThe Game of Life, by U+O466\n");
for (int i = 1; i <= width; i++)
fprintf(fptr, "-");
//write file
int size = (width+2)*(height+2);
for (int i = 0; i < size; i++){
//skip border
if (i < width+2)
continue;
else if (i >= (size-(width+2)))
continue;
else if ((i+1) % (width+2) == 0)
continue;
else if ((i-3) % (width+2) == 0)
continue;
//write states
else if (i % (width+2) == 0)
fprintf(fptr, "\n");
((c+i)->state)? fprintf(fptr, "1"):fprintf(fptr, "0");
}
fclose(fptr);
}
void initFile(Cell* c, int w, int h){
int size = (w+2)*(h+2);
FILE* fptr = fopen(path, "r");
char ch;
//init to 0, than fill with data
for (int i = 0; i < size; i++)
(c+i)->state = 0;
for (int j = 1; j < h+1; j++){
for (int i = 1; i < w+1; i++){
ch = getc(fptr);
if (ch == 49){
(c+j*(w+2)+i)->state = 1;
}
//linebreak - doesnt handle 'empty' rows properly
else if ((ch == 10)){
break;
}
}
}
}
void initAuto(Cell* c, int width, int height){
//populate first row with 0, set center as 1
for (int i = 0; i < width+1; i++)
(c+i)->state = 0;
(width%2 == 0)? ((c+((width+1)/2))->state = 1) : ((c+(width/2))->state = 1);
for (int j = 1; j < height+1; j++){
for (int i = 1; i < width+1; i++){
char pat = 0;
//find out current pattern
pat |= ((c+(j*(width+2))+i-1)->state << 2 );
pat |= ((c+(j*(width+2))+i)->state << 1 );
pat |= ((c+(j*(width+2))+i+1)->state);
//set next rows state, based on the rule
(c+((j+1)*(width+2))+i)->state = (rule >> pat) & 1;
}
}
}
void init(Cell* c, int w, int h, int mode){
int size = (w+2)*(h+2);
switch (mode){
case 0:
case 1:
for (int i = 0; i < size; i++)
(c+i)->state = mode;
break;
case 2:
for (int i = 0; i < size; i++)
(c+i)->state = rand()%2;
break;
case 3:
initAuto(c, w, h);
break;
case 4:
initFile(c, w, h);
break;
}
}
void border(Cell *c, int w, int h, int mode){
w+=2;
h+=2;
for (int j = 0; j < h; j++){
for (int i = 0; i < w; i++){
if ((i==0) | (i == w-1) | (j==0) | (j == h-1)){
switch (mode){
case 0: //dead
case 1: //alive
(c+(w*j)+i)->state = mode;
break;
case 2: //tiling - corners not handled
if (i==0)
(c+(w*j))->state = (c+(w*j)+i-1)->state;
else if (i == w-1)
(c+(w*j)+i)->state = (c+(w*j)+1)->state;
if (j==0)
(c+i)->state = (c+(w*(h-2))+i)->state;
else if (j == h-1)
(c+(w*(h-1))+i)->state = (c+w+i)->state;
break;
}
(c+(w*j)+i)->nState = (c+(w*j)+i)->state;
}
}
}
}
void update(Cell* c, int w, int h){
w = w + 2;
h = h + 2;
int size = w*h;
for (int j = 1; j < h - 1; j++){
for (int i = 1; i < w + 1; i++){
//reset counter, then count neighbors
int nbors = 0;
nbors +=(c+(j-1)*w+(i-1))->state + //up-left
(c+(j-1)*w+(i)) ->state + //up
(c+(j-1)*w+(i+1))->state + //up-right
(c+(j) *w+(i-1))->state + //left
(c+(j) *w+(i+1))->state + //right
(c+(j+1)*w+(i-1))->state + //down-left
(c+(j+1)*w+(i)) ->state + //down
(c+(j+1)*w+(i+1))->state; //down-right
//decide next state based on current (rule: B3/S23)
if ((c+(j*w)+i)->state)
(c+(j*w)+i)->nState = (nbors == 3 || nbors == 2);
else if (nbors == 3)
(c+(j*w)+i)->nState = 1;
else
(c+(j*w)+i)->nState = 0;
}
}
//update all cells
for (int i = 0; i < size; i++)
(c+i)->state = (c+i)->nState;
}
int menu(char* opts[], char msg[]){
system("cls");
printf("\033[1;31m");
printf("%s\n", msg);
printf("\033[1;m");
//print options
printf("(0) Return\n");
int i = 0;
while (opts[i] != NULL){
printf("(%d) %s\n", i+1, opts[i]);
i++;
}
//get answer
printf("\033[1;31mPlease choose an option! (0-%d):\033[1;m ", i);
int choice;
scanf("%d", &choice);
//if answer is not an option, try again
if (choice > i){
menu(opts, msg);
}
return choice-1;
}
int draw(Cell* c, int width, int height, int borderM){
char ch;
bool playing = false;
while(1){
display(c, width, height);
printf("\033[1;31m\n0: Return\nTab: Continue\nSpace: Play\nEsc: Exit\033[1;m ");
ch = getch();
if (ch == 27)
return -1;
else if(ch == 9){
update(c, width, height);
border(c, width, height, borderM);
continue;
}
else if (ch == 48){
return 0;
}
else if (ch == 32){
playing = true;
while (playing){
display(c, width, height);
update(c, width, height);
border(c, width, height, borderM);
printf("\033[1;31m\nPress [Space] to stop!\033[1;m ");
sleep(1);
if (kbhit()) {
ch = getch();
if (ch == 32)
playing = false;
}
}
}
}
return 1;
}
int mainMenu(int* width, int* height, int* borderM, int* initM){
//def menu options
char* initOpts[] = {"Dead", "Alive", "Random", "Automaton", "File", NULL};
char* borderOpts[] = {"Dead", "Alive", "Infinite", NULL};
//print main menu
clrscr();
printf("\033[1;31mMage of File by U+0466\n\033[1;m");
printf("(0) Exit\n");
printf("(1) Size: %d x %d\n", *width, *height);
if (*initM == 3) //automaton rule printing
printf("(2) Starting state: %s (Rule %d)\n", initOpts[*initM], rule);
else if (*initM == 4) //file path printing
printf("(2) Starting state: %s\n", path);
else
printf("(2) Starting state: %s\n", initOpts[*initM]);
printf("(3) Border mode: %s\n", borderOpts[*borderM]);
printf("(4) Play\n");
printf("\033[1;31mPlease choose an option! (0-4):\033[1;m ");
//get answers
int opt;
scanf(" %d", &opt);
int ans;
//create submenus
switch (opt){
case 0: return -1;
case 1: clrscr();
printf("\033[1;31mEnter Width and Height:\033[1;m \n");
scanf("%d %d", width, height);
break;
case 2:
ans = menu(initOpts, "How do you want to populate the field?");
if (ans == 3){
clrscr();
printf("\033[1;31mEnter rule for Cellular Automaton (0-255):\033[1;m ");
scanf("%d", &rule);
*initM = ans;
}
else if (ans == 4){
clrscr();
int tmp = fileIn(width, height);
while (tmp == -1){
printf("\033[1;31mInvalid file, try again?\033[1;m (Y/N) ");
char ans;
scanf("%c", &ans);
if (ans == 89)
tmp = fileIn(width, height);
else if(ans == 78)
break;
}
if (tmp != -1)
*initM = 4;
}
else
*initM = ans;
break;
case 3:
ans = menu(borderOpts, "How do you want to set the border?");
if (ans != -1)
*borderM = ans;
break;
case 4:
return 1;
}
return 0;
}
int main(){
int width = 20, height = 30;
int borderM = 1, initM = 2;
Cell** field;
field = NULL;
int state = 0;
//welcome();
while (1){
switch (state){
case -1:
free(field);
printf("Good Bye!");
return 0;
case 0:
state = mainMenu(&width, &height, &borderM, &initM);
if (state == 1){
free(field);
field = setup(width, height);
init(*field, width, height, initM);
border(*field, width, height, borderM);
}
break;
case 1:
state = draw(*field, width, height, borderM);
break;
}
}
return 0;
}
I want a Game of Life program in the console.
The parameters to initialize the 'field' can be changed in the mainMenu(). When all is done, it returns 1, and the drawing begins. When we return from draw, we get back to mainMenu(). This happens for ever in an infinite while loop. All functions work when tested separately. Problematic ones are border(), init(), etc.
What am I missing? I'm a beginner in C.
(fileIn() doesn't work proper, but that's not the issue here.)
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <conio.h>
//structure for storing the state of each cell
typedef struct Cell{
bool state, nState;
}Cell;
char path[50];
int rule;
Cell** setup(int width, int height){
//create field
int size = (width+2)*(height+2);
Cell** field = malloc(size * sizeof(Cell));;
if (field == NULL){
printf("Malloc Error!");
exit(-1);
}
return field;
}
void clrscr(){
printf("\e[1;1H\e[2J");
}
void welcome(){
clrscr();
printf("This program was created by:\033[1;31m\n U+0466.\033[1;m\n");
sleep(2);
}
void display(Cell* c, int width, int height){
clrscr();
int size = (width+2)*(height+2);
printf("\n");
for (int i = 0; i <(width*2-32)/2; i++)
printf(" ");
printf("\033[1;31mThe Game of Life on a %dx%d grid.\033[1;m", width, height);
//draw the field
for (int i = 0; i < size; i++){
if (i % (width+2) == 0)
printf("\n");
//skip border
if (i < width+2){
printf("X ");
continue;}
else if (i >= (size-(width+2))){
printf("X ");
continue;}
else if ((i+1) % (width+2) == 0){
printf("X ");
continue;}
else if ((i) % (width+2) == 0){
printf("X ");
continue;}
(c[i].state)? printf("O ") : printf(" ");
}
}
int fileIn(int* width, int *height){
//get path from user
printf("\033[1;31m");
printf("Please enter file path: ");
printf("\033[1;m");
scanf("%s", path);
//open file
FILE *fptr = fopen(path, "r");
if (fptr == NULL){
return -1;
}
//find the dimenisons of the field
char ch;
int h = 0;
int w = 0;
int wmax = 0;
for (ch = getc(fptr); ch != EOF; ch = getc(fptr)){
//0 or 1
if ((ch == 48)|(ch == 49)){
w++;
}
//linebreak
else if (ch == 10){
if (w!=0)
h++;
if (w > wmax){
wmax = w;
}
w = 0;
}
}
if ((wmax > 0)|(height > 0)){
*width = wmax;
*height = h + 1;
}
return 0;
}
void fileOut(Cell* c, int width, int height){
FILE *fptr = NULL;
fptr = fopen("out.txt", "w+");
//create a header
for (int i = 1; i <= width; i++)
fprintf(fptr, "-");
fprintf(fptr, "\nThe Game of Life, by U+O466\n");
for (int i = 1; i <= width; i++)
fprintf(fptr, "-");
//write file
int size = (width+2)*(height+2);
for (int i = 0; i < size; i++){
//skip border
if (i < width+2)
continue;
else if (i >= (size-(width+2)))
continue;
else if ((i+1) % (width+2) == 0)
continue;
else if ((i-3) % (width+2) == 0)
continue;
//write states
else if (i % (width+2) == 0)
fprintf(fptr, "\n");
((c+i)->state)? fprintf(fptr, "1"):fprintf(fptr, "0");
}
fclose(fptr);
}
void initFile(Cell* c, int w, int h){
int size = (w+2)*(h+2);
FILE* fptr = fopen(path, "r");
char ch;
//init to 0, than fill with data
for (int i = 0; i < size; i++)
(c+i)->state = 0;
for (int j = 1; j < h+1; j++){
for (int i = 1; i < w+1; i++){
ch = getc(fptr);
if (ch == 49){
(c+j*(w+2)+i)->state = 1;
}
//linebreak - doesnt handle 'empty' rows properly
else if ((ch == 10)){
break;
}
}
}
}
void initAuto(Cell* c, int width, int height){
//populate first row with 0, set center as 1
for (int i = 0; i < width+1; i++)
(c+i)->state = 0;
(width%2 == 0)? ((c+((width+1)/2))->state = 1) : ((c+(width/2))->state = 1);
for (int j = 1; j < height+1; j++){
for (int i = 1; i < width+1; i++){
char pat = 0;
//find out current pattern
pat |= ((c+(j*(width+2))+i-1)->state << 2 );
pat |= ((c+(j*(width+2))+i)->state << 1 );
pat |= ((c+(j*(width+2))+i+1)->state);
//set next rows state, based on the rule
(c+((j+1)*(width+2))+i)->state = (rule >> pat) & 1;
}
}
}
void init(Cell* c, int w, int h, int mode){
int size = (w+2)*(h+2);
switch (mode){
case 0:
case 1:
for (int i = 0; i < size; i++)
(c+i)->state = mode;
break;
case 2:
for (int i = 0; i < size; i++)
(c+i)->state = rand()%2;
break;
case 3:
initAuto(c, w, h);
break;
case 4:
initFile(c, w, h);
break;
}
}
void border(Cell *c, int w, int h, int mode){
w+=2;
h+=2;
for (int j = 0; j < h; j++){
for (int i = 0; i < w; i++){
if ((i==0) | (i == w-1) | (j==0) | (j == h-1)){
switch (mode){
case 0: //dead
case 1: //alive
(c+(w*j)+i)->state = mode;
break;
case 2: //tiling - corners not handled
if (i==0)
(c+(w*j))->state = (c+(w*j)+i-1)->state;
else if (i == w-1)
(c+(w*j)+i)->state = (c+(w*j)+1)->state;
if (j==0)
(c+i)->state = (c+(w*(h-2))+i)->state;
else if (j == h-1)
(c+(w*(h-1))+i)->state = (c+w+i)->state;
break;
}
(c+(w*j)+i)->nState = (c+(w*j)+i)->state;
}
}
}
}
void update(Cell* c, int w, int h){
w = w + 2;
h = h + 2;
int size = w*h;
for (int j = 1; j < h - 1; j++){
for (int i = 1; i < w + 1; i++){
//reset counter, then count neighbors
int nbors = 0;
nbors +=(c+(j-1)*w+(i-1))->state + //up-left
(c+(j-1)*w+(i)) ->state + //up
(c+(j-1)*w+(i+1))->state + //up-right
(c+(j) *w+(i-1))->state + //left
(c+(j) *w+(i+1))->state + //right
(c+(j+1)*w+(i-1))->state + //down-left
(c+(j+1)*w+(i)) ->state + //down
(c+(j+1)*w+(i+1))->state; //down-right
//decide next state based on current (rule: B3/S23)
if ((c+(j*w)+i)->state)
(c+(j*w)+i)->nState = (nbors == 3 || nbors == 2);
else if (nbors == 3)
(c+(j*w)+i)->nState = 1;
else
(c+(j*w)+i)->nState = 0;
}
}
//update all cells
for (int i = 0; i < size; i++)
(c+i)->state = (c+i)->nState;
}
int menu(char* opts[], char msg[]){
system("cls");
printf("\033[1;31m");
printf("%s\n", msg);
printf("\033[1;m");
//print options
printf("(0) Return\n");
int i = 0;
while (opts[i] != NULL){
printf("(%d) %s\n", i+1, opts[i]);
i++;
}
//get answer
printf("\033[1;31mPlease choose an option! (0-%d):\033[1;m ", i);
int choice;
scanf("%d", &choice);
//if answer is not an option, try again
if (choice > i){
menu(opts, msg);
}
return choice-1;
}
int draw(Cell* c, int width, int height, int borderM){
char ch;
bool playing = false;
while(1){
display(c, width, height);
printf("\033[1;31m\n0: Return\nTab: Continue\nSpace: Play\nEsc: Exit\033[1;m ");
ch = getch();
if (ch == 27)
return -1;
else if(ch == 9){
update(c, width, height);
border(c, width, height, borderM);
continue;
}
else if (ch == 48){
return 0;
}
else if (ch == 32){
playing = true;
while (playing){
display(c, width, height);
update(c, width, height);
border(c, width, height, borderM);
printf("\033[1;31m\nPress [Space] to stop!\033[1;m ");
sleep(1);
if (kbhit()) {
ch = getch();
if (ch == 32)
playing = false;
}
}
}
}
return 1;
}
int mainMenu(int* width, int* height, int* borderM, int* initM){
//def menu options
char* initOpts[] = {"Dead", "Alive", "Random", "Automaton", "File", NULL};
char* borderOpts[] = {"Dead", "Alive", "Infinite", NULL};
//print main menu
clrscr();
printf("\033[1;31mMage of File by U+0466\n\033[1;m");
printf("(0) Exit\n");
printf("(1) Size: %d x %d\n", *width, *height);
if (*initM == 3) //automaton rule printing
printf("(2) Starting state: %s (Rule %d)\n", initOpts[*initM], rule);
else if (*initM == 4) //file path printing
printf("(2) Starting state: %s\n", path);
else
printf("(2) Starting state: %s\n", initOpts[*initM]);
printf("(3) Border mode: %s\n", borderOpts[*borderM]);
printf("(4) Play\n");
printf("\033[1;31mPlease choose an option! (0-4):\033[1;m ");
//get answers
int opt;
scanf(" %d", &opt);
int ans;
//create submenus
switch (opt){
case 0: return -1;
case 1: clrscr();
printf("\033[1;31mEnter Width and Height:\033[1;m \n");
scanf("%d %d", width, height);
break;
case 2:
ans = menu(initOpts, "How do you want to populate the field?");
if (ans == 3){
clrscr();
printf("\033[1;31mEnter rule for Cellular Automaton (0-255):\033[1;m ");
scanf("%d", &rule);
*initM = ans;
}
else if (ans == 4){
clrscr();
int tmp = fileIn(width, height);
while (tmp == -1){
printf("\033[1;31mInvalid file, try again?\033[1;m (Y/N) ");
char ans;
scanf("%c", &ans);
if (ans == 89)
tmp = fileIn(width, height);
else if(ans == 78)
break;
}
if (tmp != -1)
*initM = 4;
}
else
*initM = ans;
break;
case 3:
ans = menu(borderOpts, "How do you want to set the border?");
if (ans != -1)
*borderM = ans;
break;
case 4:
return 1;
}
return 0;
}
int main(){
int width = 20, height = 30;
int borderM = 1, initM = 2;
Cell** field;
field = NULL;
int state = 0;
//welcome();
while (1){
switch (state){
case -1:
free(field);
printf("Good Bye!");
return 0;
case 0:
state = mainMenu(&width, &height, &borderM, &initM);
if (state == 1){
free(field);
field = setup(width, height);
init(*field, width, height, initM);
border(*field, width, height, borderM);
}
break;
case 1:
state = draw(*field, width, height, borderM);
break;
}
}
return 0;
}
Share
Improve this question
edited Nov 23, 2024 at 16:33
halfer
20.3k19 gold badges109 silver badges202 bronze badges
asked Nov 20, 2024 at 18:43
c51p152c51p152
92 bronze badges
7
|
Show 2 more comments
1 Answer
Reset to default 1In your setup function you use assign malloc(size * sizeof(Cell))
on a Cell**
type, if you wanted to make an array of Cell pointers you should use sizeof(Cell*)
or sizeof(*field)
.
本文标签: cCalling functions on array make the program to exitStack Overflow
版权声明:本文标题:c - Calling functions on array make the program to exit - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742336602a2455750.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
Cell** field = malloc(size * sizeof(Cell));;
- why does it have two semicolons? It seem to be allocating space for array ofCell
, but is assigning the result toCell**
instead ofCell*
. This type confusion alone can cause all sorts of bugs. – Eugene Sh. Commented Nov 20, 2024 at 18:49init(*field, ...)
? Why do you dereference the pointer here? It's the same asfield[0]
. And at that point, ``field[0]` doesn't actually point anywhere, so you pass an uninitialized pointer. I concur with @EugeneSh., you're using pointer-to-pointer in the wrong way. It should be onlyCell *
, notCell **
. – Some programmer dude Commented Nov 20, 2024 at 18:54