前言
一开始写的时候并没有太把结构当一回事,所以第二次修改时,就重新整理了一下程序,不过不知道有没有把程序变得优美一点,如果没有,请原谅啦,下次再努力一点。
代码
先将代码贴出来,如下所示
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#define SNAKE_HEAD 'H'
#define SNAKE_BODY 'X'
#define BLANK_CELL ' '
#define SNAKE_FOOD '$'
#define WALL_CELL '*'
enum moveDirect {
UP='W',DOWN='S',LEFT='A',RIGHT='D'
};
struct snakePoint {
int x;
int y;
struct snakePoint* next;
};
void snakeMove(int x,int y);
void putMoney(void);
void output(void);
int gameover(void);
void updateMap(void);
void updateBody(int new_x,int new_y);
int checkEat(int x,int y);
char moveAI();
void swap(int *a,int *b);
int isLegal(char ch);
void insertToSnake();
char background[12][12]= {"************",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"************"
};
char map[12][12];
int snakeX[5]= {1,2,3,4,5};
int snakeY[5]= {1,1,1,1,1};
int snakeLength=5;
struct snakePoint* snake;
int moneyX;
int moneyY;
int hasNotEat=1;
int main(void) {
snake=(struct snakePoint*)malloc(sizeof(struct snakePoint));
snake->x=snakeX[4];
snake->y=snakeY[4];
snake->next=NULL;
struct snakePoint* temp_next=snake;
for(int i=3; i>=0; --i) {
struct snakePoint* temp=malloc(sizeof(struct snakePoint));
temp->x=snakeX[i];
temp->y=snakeY[i];
temp->next=NULL;
temp_next->next=temp;
temp_next=temp;
}
srand(time(NULL));
putMoney();
updateMap();
output();
int temp_x,next_x;
int temp_y,next_y;
char ch;
while(!gameover()) {
ch=getch();
if(!isLegal(ch)) {
continue;
}
int new_x=snake->x;
int new_y=snake->y;
switch(ch) {
case UP:
new_y=snake->y-1;
break;
case DOWN:
new_y=snake->y+1;
break;
case LEFT:
new_x=snake->x-1;
break;
case RIGHT:
new_x=snake->x+1;
break;
}
if(checkEat(new_x,new_y)) {
insertToSnake();
hasNotEat=0;
} else {
updateBody(new_x,new_y);
}
if(!hasNotEat) {
putMoney();
}
updateMap();
output();
}
return 0;
}
char moveAI_BFS() {
}
void insertToSnake() {
struct snakePoint* temp=malloc(sizeof(struct snakePoint));
temp->x=moneyX;
temp->y=moneyY;
temp->next=snake;
snake=temp;
}
int isLegal(char ch) {
if(ch=='W'&&snake->x==snake->next->x&&snake->y==snake->next->y+1) {
return 0;
} else if(ch=='S'&&snake->x==snake->next->x&&snake->y==snake->next->y-1) {
return 0;
} else if(ch=='A'&&snake->next->x+1==snake->x&&snake->next->y==snake->y) {
return 0;
} else if(ch=='D'&&snake->next->x-1==snake->x&&snake->next->y==snake->y) {
return 0;
} else if(ch!='W'&&ch!='S'&&ch!='A'&&ch!='D'){
return 0;
}
return 1;
}
void updateBody(int new_x,int new_y) {
struct snakePoint* temp=snake;
while(temp!=NULL) {
swap(&new_x,&(temp->x));
swap(&new_y,&(temp->y));
temp=temp->next;
}
}
int gameover(void) {
if(snake->x==0||snake->x==11) {
return 1;
} else if(snake->y==0||snake->y==11) {
return 1;
}
struct snakePoint* temp=snake->next;
while(temp!=NULL) {
if(snake->x==temp->x&&snake->y==temp->y) {
return 1;
}
temp=temp->next;
}
return 0;
}
void updateMap(void) {
for(int i=0; i<12; ++i) {
for(int j=0; j<12; ++j) {
map[i][j]=background[i][j];
}
}
struct snakePoint* temp=snake;
map[temp->y][temp->x]=SNAKE_HEAD;
temp=temp->next;
while(temp!=NULL) {
map[temp->y][temp->x]=SNAKE_BODY;
temp=temp->next;
}
map[moneyY][moneyX]=SNAKE_FOOD;
}
void output(void) {
system("cls");
for(int i=0; i<12; ++i) {
for(int j=0; j<12; ++j) {
printf("%c",map[i][j]);
}
printf("\n");
}
}
void putMoney(void) {
int legal=1;
struct snakePoint* temp=snake;
do {
moneyX=1+rand()%10;
moneyY=1+rand()%10;
while(temp!=NULL) {
if(moneyX==temp->x&&moneyY==temp->y) {
legal=0;
break;
}
temp=temp->next;
}
} while(!legal);
hasNotEat=1;
}
int checkEat(int x,int y) {
if(x==moneyX&&y==moneyY) {
return 1;
}
return 0;
}
void swap(int *a,int *b) {
int temp=*a;
*a=*b;
*b=temp;
}
解释
我首先觉得贪吃蛇应该作为链表的形式存储,每当移动一格,便将链表中元素的值往后移一个单位,比如原来头的坐标就赋给头后一位的元素,最后将新的坐标赋给头,当吃了食物以后,就插入一个新的元素(坐标为食物)进入链表中。
代码结构
首先先设置一个空白的地图(即背景),使用二维数组的形式存储
char background[12][12]= {"************",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"* *",
"************"
};
接着再声明一个地图
char map[12][12];
我的想法是,每一次用户输入时都更新一次地图,先将地图设置为背景,接着将蛇添加进去,再将食物添加进去,所以我声明了两个函数:
void updateMap(void) {
for(int i=0; i<12; ++i) {
for(int j=0; j<12; ++j) {
map[i][j]=background[i][j];
}
}
struct snakePoint* temp=snake;
map[temp->y][temp->x]=SNAKE_HEAD;
temp=temp->next;
while(temp!=NULL) {
map[temp->y][temp->x]=SNAKE_BODY;
temp=temp->next;
}
map[moneyY][moneyX]=SNAKE_FOOD;
}
void output(void) {
system("cls");
for(int i=0; i<12; ++i) {
for(int j=0; j<12; ++j) {
printf("%c",map[i][j]);
}
printf("\n");
}
}
前者用于将更新后的蛇和食物添加进去,后者将地图打印出来
接着声明一个枚举类型,分别对应上下左右
enum moveDirect {
UP='W',DOWN='S',LEFT='A',RIGHT='D'
};
每次输入后都检查输入是否正确,当蛇头转向蛇头后一格时判为非法,当输出除了WASD以外的字符也是非法的,要求重新输入
int isLegal(char ch) {
if(ch=='W'&&snake->x==snake->next->x&&snake->y==snake->next->y+1) {
return 0;
} else if(ch=='S'&&snake->x==snake->next->x&&snake->y==snake->next->y-1) {
return 0;
} else if(ch=='A'&&snake->next->x+1==snake->x&&snake->next->y==snake->y) {
return 0;
} else if(ch=='D'&&snake->next->x-1==snake->x&&snake->next->y==snake->y) {
return 0;
} else if(ch!='W'&&ch!='S'&&ch!='A'&&ch!='D'){
return 0;
}
return 1;
}
接着在主程序之中将每次的输入都进行判断
ch=getch();
if(!isLegal(ch)) {
continue;
}
int new_x=snake->x;
int new_y=snake->y;
switch(ch) {
case UP:
new_y=snake->y-1;
break;
case DOWN:
new_y=snake->y+1;
break;
case LEFT:
new_x=snake->x-1;
break;
case RIGHT:
new_x=snake->x+1;
break;
}
if(checkEat(new_x,new_y)) {
insertToSnake();
hasNotEat=0;
} else {
updateBody(new_x,new_y);
}
if(!hasNotEat) {
putMoney();
}
updateMap();
output();
感想
感觉程序这样划分清晰明了很多了啦,不过不知道这样写好不好啦。