C-贪吃蛇

为了敲键盘及时响应,需要用到ncurse

ncurse上下左右键的获取

vi /usr/include/curses.h进入curses.h头文件,输入KEY_UP进入以下界面

 这些称为curses的功能键,使用keypad可以在stdscr中接受键盘的功能键。

#include <curses.h>
int main()
{
        //char c;//char 1 byte 8 bit 128 change to int
        int key;
        initscr();
        keypad(stdscr,1);

        while(1){
                key = getch();
                switch(key){
                        case KEY_DOWN:
                        printw("DOWN\n");
                        break;
                        case KEY_UP:
                        printw("UP\n");
                        break;
                        case KEY_LEFT:
                        printw("LEFT\n");
                        break;
                        case KEY_RIGHT:
                        printw("RIGHT\n");
                        break;
                }
        }
        endwin();
        return 0;
}

地图规划

void gamePic()
{
        int row;
        int line;
        for(row=0;row<20;row++){
                if(row==0){
                        for(line=0;line<20;line++){
                                printw("--");
                        }
                        printw("\n");
                }
                if(row>=0 && row<=19){
                        for(line=0;line<=20;line++){
                                if(line==0 || line==20){
                                        printw("|");
                                }else{
                                        printw("  ");
                                }
                        }
                        printw("\n");
                }
                if(row==19){
                        for(line=0;line<20;line++){
                                printw("--");
                        }
                        printw("\n");
                }
        }
        printw("by Andy");
}

全部代码

#include <curses.h>
#include <stdlib.h>

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

struct Snake
{
	int row;
	int line;
	struct Snake* next;
};

struct Snake* head = NULL;
struct Snake* tail = NULL;
int key;
int dir;

struct Snake food;

void initFood()//初始化食物节点
{
	int x = rand() % 20;//随机出现位置
	int y = rand() % 20;
	food.row = x;
	food.line = y;
}

void initNcurse()//初始化curses图形库
{
	initscr();
	keypad(stdscr,1);//使用keypad可以在stdscr中接受键盘的功能键
	noecho();//对于输出的功能键的值不做出回应,以免界面溢出
}

int hasSnakeNode(int i,int j)//传参:行号,列号
{
	struct Snake* p;
	p = head;
	while(p != NULL){
		if(p->row==i && p->line==j){
			return 1;//gamePic中打印一个节点"[]"
		}
		p=p->next;
	}
	return 0;
}

int hasFood(int i,int j)//打印食物
{
    if(food.row==i && food.line==j){
        return 1;
    }
    return 0;
}

void gamePic()//打印图形界面
{
	int row;
	int line;
	move(0,0);
	for(row=0;row<20;row++){
		//第0行为20个"--"
		if(row==0){
			for(line=0;line<20;line++){
				printw("--");
			}
			printw("\n");
		}
		//第0-19行为左右两边一个"|",中间21个"  "(空格)为了对齐第一行
		if(row>=0 && row<=19){//一共打印20行
			for(line=0;line<=20;line++){
				if(line==0 || line==20){
                    printw("|");//打印两边
                }else if(hasSnakeNode(row,line)){
					printw("[]");//打印蛇的身体
				}else if(hasFood(row,line)){
					printw("##");//打印食物
				}
				else{
                    printw("  ");//打印中间
                }
            }
            printw("\n");
		}
		//打印第19行,与第一行一样
		if(row==19){
            for(line=0;line<20;line++){
                printw("--");
            }
            printw("\n");
			printw("by Andy,key = %d\n",key);//打印作者名字以及方向键的值
        }
	}
}

void addNode()//加节点
{
	struct Snake* new = (struct Snake*)malloc(sizeof(struct Snake));//开辟新节点空间
	new->next = NULL;
	switch(dir){//根据用户按的功能键的方向来决定如何添加一个节点
		case UP://列不变,行减一的位置添加
			new->row = tail->row - 1;
		    new->line = tail->line;
			break;
		case DOWN:
            new->row = tail->row + 1;
            new->line = tail->line;
            break;
		case LEFT:
            new->row = tail->row;
            new->line = tail->line - 1;
            break;
		case RIGHT:
            new->row = tail->row;
            new->line = tail->line + 1;
            break;
	}
	tail->next = new;
	tail = new;//新节点变成尾部
}

void deleteNode()//删除节点
{
	struct Snake* p;
	p = head;
	head = head->next;
	free(p);
}

void initSnake()//初始化蛇的身体
{
	struct Snake* p;//使用链表
	dir = RIGHT;//初始化方向为右
	while(head != NULL){
		p = head;
		head = head->next;
		free(p);//遍历节点,释放空节点内存
	}
	initFood();//初始化食物
	head = (struct Snake*)malloc(sizeof(struct Snake));//为头节点开辟空间
	head->row = 1;//第一行
	head->line = 1;//第一列
	head->next = NULL;//防止野指针
	tail = head;//头插法
	addNode();//加4个节点
	addNode();
	addNode();
	addNode();
}

int ifSnakeDie()//蛇死亡的条件
{
	struct Snake* p;
	p = head;
	if(tail->row < 0 || tail->line == 0 || tail->row == 20 || tail->line == 20){//四个边界
        return 1;
    }
	while(p->next != NULL){
		if(p->row == tail->row && p->line == tail->line){//头咬到尾巴
			return 1;
		}
		p = p->next;
	}
	return 0;
}

void moveSnake()//蛇的移动
{
	addNode();
	if(hasFood(tail->row,tail->line)){
		initFood();
	}
	else{
		deleteNode();
	}
	if(ifSnakeDie()){
		initSnake();
	}
}

void* refreshBox()//刷新界面
{
	while(1){
        moveSnake();//蛇移动
        gamePic();//重新打印界面
        refresh();//刷新覆盖原界面
        usleep(100000);//0.1s
    }
}

void turn(int direction)//绝对值解决方向问题
{
	if(abs(dir) != abs(direction)){
		dir = direction;
	}
}

void* changeDir()//根据用户按的功能键走位
{
	while(1){
        key = getch();
        switch(key){
            case KEY_DOWN:
                turn(DOWN);//转向
                break;
            case KEY_UP:
                turn(UP);
                break;
            case KEY_LEFT:
                turn(LEFT);
                break;
            case KEY_RIGHT:
                turn(RIGHT);
                break;
        }
    }
}

int main()
{
	initNcurse();//第一步:搭建curses环境
	initSnake();//第三步:打印蛇的身体
	gamePic();//第二步:打印图形界面
	pthread_t th1;//线程1
	pthread_t th2;//线程2
	pthread_create(&th1,NULL,refreshBox,NULL);//运行线程1:不断刷新界面
	pthread_create(&th2,NULL,changeDir,NULL);//运行线程2:不断改变方向
	while(1);//让线程一直进行
	getch();//让程序一直重复输入功能键还能执行
	endwin();//curses函数
	return 0;
}

当然还可以有其他改进......

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

run sun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值