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

/***********************************************************
重温了结构体和链表,模仿写了个控制台的贪吃蛇程序.实现了
基本的一些功能.其他功能就不想浪费时间了,适可而止吧.
个人觉得最主要的代码是
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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值