基于Ncurse实现贪吃蛇 C语言

一、编程思路

在这里插入图片描述

大概思路:

	1、打印出界面(40*40)
		initscr();//ncurses界面的初始化函数
		GraphInterface();//打印界面
		
		getch();//当用户按下某个字符时,函数自动读取,无需按回车
		endwin();//恢复终端机原来的状态
	2、初始化蛇身
		2.1 确定蛇身的初始位置(一个节点)
		2.2 添加蛇神的节点(总共3-4个)

	3、识别键盘,开始对进行蛇进行移动
		3.1移动蛇身

			3.1.1 如向右移动,向右添加一个节点,左边删除一个节点
			3.1.2 如向左移动,向左添加一个节点,右边删除一个节点
			3.1.3 如向上移动,向上添加一个节点,下边删除一个节点
			3.1.4 如向下移动,向下添加一个节点,上边删除一个节点
		
		3.2 移动完蛇身,要进行界面的刷新
			(1)再打印一次页面
			(2)move(0,0);加载到打印函数里面
	4、创建线程th1,让蛇身初始移动方向向右(每半秒刷一次)
	5、创建线程th2,不断检测按键来改变蛇的移动方向
	6、主函数要在程序结束之前有个while(1);防止程序退出;
	7、初始化食物位置,random()随机
	8、界面初始化中,找到食物的位置,打印食物
	9、判断食物是否被蛇碰到,碰到的话添加一个节点
	10、判断食物死亡的情况,两种:边界和碰到自己蛇身

二、代码

#include <stdio.h>
#include <ncurses.h>
#include <stdlib.h>
#include <pthread.h>

#define 	UP 		 1
#define 	DOWN 	-1
#define 	LIGHT 	 2
#define 	RIGHT 	-2

int graphLength = 0; 
int graphWide = 0;
int keyValue;
int dir = 0;

struct Snake
{
	int hang;
	int lie;
	struct Snake *next;
};

struct Snake food;
struct Snake *head = NULL;
struct Snake *tail = NULL;

//蛇食物的位置(随机)
void initFood()
{
	int x=rand()%20;//随机位置
	int y=rand()%20;

	food.hang = x;
	food.lie  = y;
}

int judgeFoodPosition(int hang,int lie)
{
	if(food.hang == hang && food.lie == lie){
		return 1;
	}
	return 0;
}


//确定蛇身的初始位置
int  judgeSnakePositon(int j,int i)
{
	struct Snake *p;
	p = head;

	while(p != NULL){
		//致命的错误 (p->hang = j)少了个等于号
		if(p->hang == j && p->lie == i){			
			return 1;
		}
		p = p->next;	
	}
	return 0;
}

void printInterPointrt(int hang)
{
	
	for (graphWide = 0; graphWide < 40;graphWide++){
		if (graphWide == 0 || graphWide == 39){
			printw("|");
		}
		else if(judgeSnakePositon(hang,graphWide)){	
			printw("O");
		}
		else if( judgeFoodPosition(hang,graphWide)){
			printw("*");
		}
		else
			printw(" ");	
	}
	printw("\n");
}

//整个界面
void GraphInterface()
{
	//是界面一直保存在原来的位置,没有这个就会每刷新一次,界面玩下显示(显示每次的位置都在变化)
	move(0,0);
	for (graphLength = 0; graphLength  < 20; graphLength++){
		if (graphLength == 0){
			for (graphWide = 0; graphWide < 40;graphWide++){
				printw("~");
			}
			printw("\n");
			printInterPointrt(graphLength);

		}
		
		else if (graphLength == 19){
			printInterPointrt(graphLength);
			for (graphWide = 0; graphWide < 39;graphWide++){
				printw("~");
			}		
		}
		else {
			printInterPointrt(graphLength);
		}
		
	}
	printw("\n");
	printw("KEY_VALUE:%d\n",keyValue);
	printw("Food Position:%d %d\n",food.hang,food.lie);
	//printw("This is ncurses interface\n");
}

//删除蛇身的头节点
void deleteSnakeNode()
{
	struct Snake *p = head;
	head = head->next;
	free(p);
}


//添加蛇身节点
void addSnakeBody()
{
	struct Snake *new = (struct Snake*)malloc(sizeof(struct Snake));
	
	switch(dir){
			case DOWN:
				new->hang = tail->hang + 1;
				new->lie = tail->lie;
				break;
			case UP:
				new->hang = tail->hang - 1;
				new->lie = tail->lie ;
				break;
			case LIGHT:
				new->hang = tail->hang;
				new->lie = tail->lie - 1;
				break;
			case RIGHT:
				new->hang = tail->hang;
				new->lie = tail->lie + 1;
				break;//0405
		}
	
	new->next = NULL;

	//尾插法
	tail->next = new;
	tail = new;

}


//蛇的初始位置
void SnakeInitPosition()
{
	dir = RIGHT;//添加的两个节点为右节点

	head = (struct Snake *)malloc(sizeof(struct Snake));
	head->hang	= 0;
	head->lie = 1;
	head->next = NULL;

	tail = head;

	addSnakeBody();
	addSnakeBody();
}

//蛇死亡的情况
int judgeSnakedie()
{
	struct Snake *p;//struct snake p;//致命大小写
	p = head;

	if(tail->lie == 39 || tail->lie == 0 || tail->hang < 0 || tail->hang == 20){
		return 1;//碰墙后,蛇的位置回初始地
	}
	while(p->next != NULL){//(p != NULL)则每次都会重合,p从head走到tail时必定会相撞
		if(p->hang == tail->hang && p->lie == tail->lie){
			return 1;//碰到蛇身,蛇回到初始位置
		}
		p=p->next;
	}

	return 0;
}

//蛇身的变化实现
void moveSnakeBody()
{
	addSnakeBody();	
	deleteSnakeNode();
	if( judgeFoodPosition(tail->hang,tail->lie) ){
		addSnakeBody();//蛇吃到食物,添加一个节点
		initFood(); //重新刷新食物位置(改变食物的位置)
	}
	if(judgeSnakedie()){
		SnakeInitPosition();//碰墙后,蛇的位置回初始地
	}
}

//检测按键,改变蛇身的位置
void* changeSnakePosition()
{
	while(1){			
		moveSnakeBody();//添加一个节点,再删除一个节点,
		GraphInterface();//刷新界面
		usleep(300000);//每隔250ms自己向右移动一格
		//refresh 函数的作用就是刷新物理屏幕
		refresh();
	}

}

//控制蛇只能单方向转动(上下只能执行左右转,左右是只能执行上下转)
void conDirtion(int dir1)
{	
	//abs() 函数用于求整数的绝对值
	if (abs(dir) != abs(dir1)){
		dir = dir1;
	}
}

void* testButtonValue()
{
	
	while(1){
		keyValue = getch();
		switch(keyValue){
			case KEY_DOWN:
				conDirtion(DOWN);
				break;
			case KEY_UP:
				conDirtion(UP);
				break;
			case KEY_LEFT:
				conDirtion(LIGHT);
				break;
			case KEY_RIGHT:
				conDirtion(RIGHT);
				break;//0405
		}
	}
	
}

void NcurseGraphInit()
{
	initscr();//设定所有curses用到的函数的初值
	keypad(stdscr,1);//获取功能键,即上下左右键

	noecho();//oecho(),把无关的东西不要显示在界面
	
}


int main(void)
{
	pthread_t th1;
	pthread_t th2;
	NcurseGraphInit();
	SnakeInitPosition();
	initFood();
	GraphInterface();
	//changeSnakePosition();卡在这里了

	//创建两个线程
	pthread_create(&th1,NULL,changeSnakePosition,NULL);//不断移动蛇身,刷新界面
	pthread_create(&th2,NULL,testButtonValue,NULL);//不断检测键值,打印键值

	//死循环,防止退出界面
	while(1);//没有死循环,创建两个线程之后这个程序有三个资源在竞争CPU,
			//当到main竞争到资源时执行的getch();endwin();就会退出

	getch();//当用户按下某个字符时,函数自动读取,无需按回车
	endwin();//恢复终端机原来的状态

	return 0;
}
/*
	initscr();//ncurses界面的初始化函数
    printw("This is a curses window.\n");//在nucurse 模式下的printf
    getch();//等待用户输入,如果没有这句话,程序就会退出,看不到运行的结果,看不到printw("This is a curses window.\n");
    endwin();//程序退出,调用函数来恢复shell终端的显示,如果没有这句话,shell终端自就会乱码,坏掉
	

*/

三、运行效果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值