我们为贪吃蛇的节点设置为一个结构体,构成贪吃蛇的身子的话我们使用链表,链表的每一个节点是一个结构体
显示贪吃蛇身子的一个节点


我们这边node就表示一个蛇的身体 就是一小节
输出结果如下

显示贪吃蛇完整身子

效果如下

代码实现


这个hasSnakeNode(hang,lie)这个函数就是来判断当前这个坐标是否为蛇的身子的坐标,坐标带进去,如果符合return 1;那么返回1 到地图这里 1 的话就是ture 使hasSnakeNode这个函数生效,然后打印[ ]蛇身。那么函数封装的好处就是在于我们可以进行多个节点的判断

宏观的看,每个坐标都会进入到hasSnakeNode(hang,lie)进行判断,如果行列坐标等于蛇身子的行列坐标,那么就返回1 我们会去想p的下一项是哪里操作的 请看main函数node1.next=&next2,这个是关键,才能遍历链表,暂时是静态的写链表,下一次我们用动态添加的方法进行添加节点
代码
#include <curses.h>
struct snack{
int hang;
int lie;
struct snack *next;
};
struct snack node1 = {2,2,NULL};
struct snack node2 = {2,3,NULL};
struct snack node3 = {2,4,NULL};
void initgame()
{
initscr();
keypad(stdscr,1);
}
int hasSnackNode(int i,int j)
{
struct snack *p;
p = &node1;
while(p != NULL){
if(p->hang==i && p->lie==j){
return 1;
}
p=p->next;
}
return 0;
}
void gamepic()
{
int hang;
int lie;
for(hang=0;hang<20;hang++){
if(hang == 0){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
if(hang>=0 && hang<=19){
for(lie=0;lie<=20;lie++){
if(lie==0||lie==20){
printw("|");
}else if(hasSnackNode(hang,lie)){
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(hang == 19){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
}
printw("by shijintao");
}
int main()
{
initgame();
node1.next = &node2;
node2.next = &node3;
gamepic();
getch();
endwin();
return 0;
}
但是这个太土了我们要进行优化
我们用封装函数的方法
显示贪吃蛇完整身子
优化代码
#include <curses.h>
#include <stdlib.h>
struct snake{
int hang;
int lie;
struct snake *next;
};
struct snake *head;//全局变量
struct snake *tail;//全局变量
void initgame()
{
initscr();
keypad(stdscr,1);
}
int hasSnakeNode(int i,int j)
{
struct snake *p;
p = head; //现在头节点是head 不是node1了 而且这个head是通过initSnake影响的,因为head是全局变量,所以可以使用head
while(p != NULL){
if(p->hang==i && p->lie==j){
return 1;
}
p=p->next;
}
return 0;
}
void gamepic()
{
int hang;
int lie;
for(hang=0;hang<20;hang++){
if(hang == 0){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
if(hang>=0 && hang<=19){
for(lie=0;lie<=20;lie++){
if(lie==0||lie==20){
printw("|");
}else if(hasSnakeNode(hang,lie)){
printw("[]");
}
else{
printw(" ");
}
}
printw("\n");
}
if(hang == 19){
for(lie=0;lie<20;lie++){
printw("--");
}
printw("\n");
}
}
printw("by shijintao");
}
void addNode()
{
struct snake *new;
new =(struct snake *)malloc(sizeof(struct snake));
new->hang=tail->hang; //最先开始tail的值等于head
new->lie=tail->lie+1;
tail->next = new;
tail = new;//每次改变tail的值
new->next = NULL;
}
void initSnake()
{
head = (struct snake *)malloc(sizeof(struct snake));
head->hang=2;
head->lie=2;
head->next=NULL;
tail = head;
addNode();
}
int main()
{
initgame();
initSnake();
gamepic();
getch();
endwin();
return 0;
}
代码优化的点:
将原先死板添加的,变成动态的添加节点,并进行封装,减少代码冗余
void initSnake()
{
head = (struct snake *)malloc(sizeof(struct snake));
head->hang=2;//这些都是设置初始值
head->lie=2;
head->next=NULL;
tail = head;//蛇的初始状态头节点也是尾节点
addNode(); //如果你不加这个的话 蛇的身子就只有一个,我觉得加一个也就是比较好看
}
void addNode()
{
struct snake *new;
new =(struct snake *)malloc(sizeof(struct snake));
new->hang=tail->hang; //这个只是单纯的向右边加入,不考虑方向,以后回头来看不要被误导
new->lie=tail->lie+1;
tail->next = new;
tail = new;//可以这样想每次新节点插入后这个tail的值(行和列)都会回到最上方全局变量的地方然后,tail的值是不会被刷新的,是一直被影响的,被上一个节点影响,随后保存信息,因为他是全局变量
new->next = NULL;
}
initSnake()这个函数直接就是把蛇的头节点,也就是蛇的初始位置,hang、lie 都默认的设置好,就像我们玩贪吃蛇初始有个蛇停在那边,这个函数就是这个作用。
这两个函数搭配使用组成了蛇的身子,我们都说用动态创建链表要用到指针,且链表都是有头节点和尾节点,为了不容易出现错误 我们将头指针和尾指针设置为全局变量。
头节点是指针,我们需要为指针赋予一个内存空间,因为后面我们需要在尾点后方插入新的节点,那么我们需要将新节点每次开辟一个空间。
最先开始尾节点就是头节点
addNode是添加新节点到尾节点后边
我们将添加新节点,还有初始化贪吃蛇的行列,封装成了函数,直接调用函数即可在尾部添加新节点
