这里发生的事情是,我想要在控制台中安装一个生命游戏程序。 初始化“字段”的参数可以在 mainMenu() 中更改。 全部完成后,返回1,开始绘制。 当我们从绘图返回时,我们回到 mainMenu()。 这种情况在无限 while 循环中永远发生。 所有功能均在单独测试时有效。 有问题的是 border()、init() 等。 请帮助我,我错过了什么,我是 C 初学者,并且非常感谢这里的任何线索。
(fileIn() 无法正常工作,但这不是这里的问题。)
#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;
}
在您的设置函数中,您可以在
malloc(size * sizeof(Cell))
类型上使用分配 Cell**
,如果您想创建 Cell 指针数组,则应该使用 sizeof(Cell*)
或 sizeof(*field)
。