/***********************************************************
重温了结构体和链表,模仿写了个控制台的贪吃蛇程序.实现了
基本的一些功能.其他功能就不想浪费时间了,适可而止吧.
个人觉得最主要的代码是
1)
判断指定一点是否在链表中
bool is_include(const pSnake p,int row,int col );
这个函数在蛇移动,蛇的显示,和重新种植苹果中都有用到.
2)
移动时,将蛇的前一个结点位置赋值给后一个结点.最后改变头部.
移动之前,记录蛇的尾部结点的位置,方便增加蛇的结点.
******************************************************/
#include<malloc.h>
#include<stdlib.h>
#include<stdio.h>
#include<time.h>
//#include<stdbool.h>
#define APPLE '@'
#define SNAKEHEAD '+'
#define SNAKETAIL '-'
#define SIZE 10
typedef struct{
int row;
int col;
} Pos;
struct SNAKE;
typedef struct SNAKE{
Pos locate;
struct SNAKE *next;
struct SNAKE *pre;
}Snake,*pSnake;
Pos apple; //苹果位置
Pos last; //存放蛇每次移动前的最后一个位置,用于增加蛇的长度
bool exitSnake = false;
bool is_same( const Pos* pFirstPos, const Pos* pSecondPos ){
if( (pFirstPos->row == pSecondPos->row) && (pFirstPos->col == pSecondPos->col)){
return true;
}
else
{
return false;
}
}
//判断指定一点是否在链表中
bool is_include(const pSnake p,int row,int col )
{
pSnake pos = p->next ;
while( pos->next != NULL )
{
if((row == pos->locate.row) && (col == pos->locate.col ))
{
return true;
}
pos = pos->next;
}
if((row == pos->locate.row) && (col == pos->locate.col))//处理最后一个点,pos->next == NULL 的那个坐标
return true;
return false;
}
void init_snake( pSnake p)
{
pSnake head = (pSnake)malloc(sizeof(Snake));//创建蛇的头部
pSnake tail = (pSnake)malloc(sizeof(Snake));//创建初始化,蛇的尾部
int row = 5;
int col = 5;
int direction = rand() % 4;//方向:0~4
head->locate.col = col;
head->locate.row = row;
head->next = tail;
tail->pre = head;
p->next = head;
p->pre = tail;
head->pre = p;
tail->next = NULL;
switch(direction)
{
case 0://尾巴在头上边
tail->locate.row = row -1;
tail->locate.col = col;
break;
case 1:
//尾巴在头左边
tail->locate.row = row;
tail->locate.col = col -1;
break;
default:
//尾巴在头右边
tail->locate.row = row;
tail->locate.col = col + 1;
break;
}
}
void plant_apple(pSnake p)//当吃到apple,从新随机产生一个apple
{
do
{
apple.row = rand() % (SIZE -2);
apple.col = rand() % (SIZE -2);
}
while(is_include(p,apple.row,apple.col));
}
void show_map(pSnake p)
{
int row = 0;
int col = 0;
for(row = 0; row < SIZE; row++)
{
for(col = 0; col < SIZE; col++)
{
if((row == apple.row) && (col == apple.col))
{
printf("%c",APPLE);
}
else if( is_include(p->next,row,col) )//打印蛇尾
{
printf("%c",SNAKETAIL);
}
else if((row == p->next->locate.row) && (col == p->next->locate.col))//打印头部
{
printf("%c",SNAKEHEAD);
}
else
{
printf(" ");
}
}
printf("\n");
}
}
void move_snake(pSnake p)
{
// int move;//如果等于1则代表可以移动,为0则说明蛇头吃自己
pSnake head = p->next;
head->pre = p;
pSnake tail ;//定位到最尾部,方便移动是数据交换
// pSnake pos;
int direction = 0;
int row = 0;
int col = 0;
printf("请输入移动方向 : (8表示向上,4表示向左,2表示向下,6表示向右, 5表示退出游戏 )\n");
scanf("%d",&direction);
switch(direction)
{
case 8://向上移动,头坐标row减一 (尾部跟着头部,即为头部原来的坐标)
//且移动后头部的位置不在链表中,则执行移动
if(!is_include(p,head->locate.row-1,head->locate.col) )
{
if(head->locate.row == 0 )
head->locate.row = 10;
tail = p->pre ;//获取蛇尾部指针
last.row = tail->locate.row ;//保存蛇最尾部的点,用于增加蛇的长度
last.col = tail->locate.col ;
while(tail != head)
{
tail->locate.row = tail->pre->locate.row;
tail->locate.col = tail->pre->locate.col;
tail = tail->pre ;
}
head->locate.row --;
}
else
printf("警告!吃自己");
break;
case 4://向左移动,头坐标col减一
if( !is_include(p,head->locate.row,head->locate.col-1) )
{
if(head->locate.col == 0)
head->locate.col = 10;
tail = p->pre ;//获取蛇尾部指针
last.row = tail->locate.row ;//保存最后一个点,用于增加蛇的长度
last.col = tail->locate.col ;
while(tail != head)
{
tail->locate.row = tail->pre->locate.row;
tail->locate.col = tail->pre->locate.col;
tail = tail->pre ;
}
head->locate.col --;
}
else
printf("警告!吃自己");
break;
case 2://下移row++
if(!is_include(p,head->locate.row+1,head->locate.col) )
{
if((head->locate.row + 1) == SIZE )
head->locate.row = -1;
tail = p->pre ;//获取蛇尾部指针
last.row = tail->locate.row ;//保存最后一个点,用于增加蛇的长度
last.col = tail->locate.col ;
while(tail != head)
{
tail->locate.row = tail->pre->locate.row;
tail->locate.col = tail->pre->locate.col;
tail = tail->pre ;
}
head->locate.row++;
}
else
printf("警告!吃自己");
break;
case 6://右移col++
if(!is_include(p,head->locate.row,head->locate.col+1) )
{
if(head->locate.col + 1 == SIZE )
head->locate.col = -1;
tail = p->pre ;//获取蛇尾部指针
last.row = tail->locate.row ;//保存最后一个点,用于增加蛇的长度
last.col = tail->locate.col ;
while(tail != head)
{
tail->locate.row = tail->pre->locate.row;
tail->locate.col = tail->pre->locate.col;
tail = tail->pre ;
}
head->locate.col ++;
}
else
printf("警告!吃自己");
break;
case 5:
exitSnake = true;
printf("真无聊!!\n");
break;
default:
printf("输入数字无效");
break;
}
if( is_same(&apple,&head->locate ) || is_same(&apple,&head->next->locate) )//如果吃到苹果,重新种植苹果,尾部增加
{
plant_apple(p);
pSnake pnew = (pSnake)malloc(sizeof(Snake));
pnew->locate.row = last.row ;
pnew->locate.col = last.col ;
//插入到链表尾部
p->pre->next = pnew;
pnew->pre = p->pre;
p->pre = pnew;
pnew->next = NULL;
}
}
int main()
{
pSnake head = (pSnake)malloc(sizeof( Snake ));
srand(time(0));
init_snake(head);//初始化蛇
plant_apple(head);//种植苹果
show_map(head);//显示蛇
while(1)
{
if(exitSnake)
return 0;
printf("头(%d %d) ",head->next->locate.row ,head->next->locate.col);
printf("尾(%d %d)\n ",head->pre->locate.row ,head->pre->locate.col);
move_snake(head);//移动蛇时坐标的改变
show_map(head);//显示蛇
}
return 0;
}
控制台 简单 双链表贪吃蛇的实现
最新推荐文章于 2021-10-11 22:43:21 发布