控制台 简单 双链表贪吃蛇的实现

来源:互联网 发布:springmvc 与nginx 编辑:程序博客网 时间:2024/05/17 03:32
/***********************************************************重温了结构体和链表,模仿写了个控制台的贪吃蛇程序.实现了基本的一些功能.其他功能就不想浪费时间了,适可而止吧.个人觉得最主要的代码是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         10typedef 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 --;}elseprintf("警告!吃自己");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 --;}elseprintf("警告!吃自己");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++;}elseprintf("警告!吃自己");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 ++;}elseprintf("警告!吃自己");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;}