linux 贪吃蛇学习之libcurses库实现

ncurses学习:http://www.php.cn/manual/view/1042.html
ncurses库需要包含头文件ncurses.h,链接的时候需要使用-lncurses选项

initscr();//开启curses模式
endwin();//关闭curses模式

cbreak模式:除delete,ctrl等控制键外,其他的输入字符被立即读取
nocbreak模式:字符先缓存,再输出

nl() and nonl():
输入时,是否将 RETURN 键对应于 NEWLINE (\n);
输出时,是否将 NEWLINE (\n)对应于 RETURN 键;
系统预设是开启的

游标的控制:
move(x,y): 将游标移动至 x,y 的位置.
getyx(win,x,y): 得到目前游标的位置. (请注意! 是 x,y 而不是&x,&y )

如何在萤幕上显示字元:
addch(ch): 显示某个字元.
addstr(str): 显示一串字串.
printw(format,str): 类似 printf().

echochar(ch): 显示某个字元.
addch(ch): 显示某个字元.
mvaddch(y,x,ch): 在(x,y) 上显示某个字元. 相当於呼叫move(y,x);addch(ch);
addstr(str): 显示一串字串.
mvaddstr(y,x,str): 在(x,y) 上显示一串字串. 相当於呼叫move(y,x);addstr(str);
printw(format,str): 类似 printf() , 以一定的格式输出至萤幕.
mvprintw(y,x,format,str): 在(x,y) 位置上做 printw 的工作. 相当於呼叫 move(y,x);printw(format,str);

raw(); // 设置模式为raw模式,所有的输入不需要输入回车就可以传递给程序
keypad();//允许用户终端的键盘,允许getch()函数获取功能键
noecho();//不回显用户输入的内容

如何从键盘上读取字元:
getch(): 从键盘读取一个字元. (注意! 传回的是整数值)
getstr(): 从键盘读取一串字元.
scanw(format,&arg1,&arg2…): 如同 scanf, 从键盘读取一串字元.
如何改变萤幕显示字元的属性:

为了使输出的萤幕画面更为生动美丽, 我们常须要在萤幕上做一些如反白, 闪烁等变化. curses 定义了一些特殊的属性, 透过这些定义, 我们也可以在 curses 程式控制萤幕的输出变化.
attron(mod): 开启属性.
attroff(mod): 关闭属性.

curses.h 里头定义了一些属性, 如:
A_UNDERLINE: 加底线.
A_REVERSE: 反白.
A_BLINK: 闪烁.
A_BOLD: 高亮度.
A_NORMAL: 标准模式(只能配合 attrset() 使用)
//光标是否可现
curs_set ( int $visibility )
0 = Cursor invisible
1 = Cursor normal
2 = Cursor visible

start_color();// 开启颜色
init_pair(1, COLOR_WHITE, COLOR_BLACK); //初始化颜色对,比如说颜色方案1,前景色是的色,背景色是黑色

mvaddstr(10, 10, “hello”);//在屏幕上(10, 10)坐标输出字符串hello
attroff(CLOLOR_PAIR(1)); //关闭颜色方案1
refresh(); //每次在屏幕绘制之后,需要调用refresh()刷新屏幕

mvprintw(); //在指定位置格式化输出
getch(); //接收键盘上的输入一个字符,wgetch()
getstr(char *str); //从当前光标位置接收一个字符串
wgetstr(WINDOW *win,char *str); //w都是指windows,指在指定窗口的光标当前位置接收一个字符串
mvgetstr(int y, int x, char *str); //指在默认窗口指定的Y行X列位置接收输入一个字符串

有关清除萤幕的函式:
clear() and erase(): 将整个萤幕清除. (请注意配合refresh() 使用)
wclear();//擦除窗口

clrtoeol(); //擦除从光标当前位置到行尾的内容
move(int y, int x);//移动光标到y行x列

mvinch: Move position and get attributed character at new position
//移动位置并在新位置获得带属性字符

常用的curses函数:
初始化相关:
initscr();         //curses程序初始化必须
cbreak();         //关闭字符流的缓冲
nonl();           //输入资料时, 按下 RETURN 键是否被对应为 NEWLINE 字元 ( 如 \n ).
noecho();          //关闭字符回显
keypad(stdscr,TRUE);   //可以使用键盘上的一些特殊字元, 如上下左右
refresh();         //刷新物理屏幕
int endwin(void); //关闭所有窗口

移动光标、输出相关:
int move(int new_y, int new_x); //移动stdcsr的光标位置
addch(ch); //显示某个字元.
mvaddch(y,x,ch); //在(x,y) 上显示某个字元.
addstr(str); //显示一串字串.
mvaddstr(y,x,str); //在(x,y) 上显示一串字串.
printw(format,str); //类似 printf() , 以一定的格式输出至萤幕.
mvprintw(y,x,format,str); //在(x,y) 位置上做 printw 的工作

前缀w用于窗口(添加一个WINDOWS指针参数),mv用于光标移动(在该位置执行操作addch或printw)(添加两个坐标值参数),mvw用于在窗口(如stdscr)中移动光标。组成如下函数:
addch, waddch, mvaddch, mvwaddch
printw, wprintw, mvprintw, mvwprintw

键盘输入:
//与标准io库的getchar, gets, scanf类似
int getch();
int getstr(char *string);
int getnstr(char *string, int number);   //建议使用
scanw(format,&arg1,&arg2…): //如同 scanf, 从键盘读取一串字元.
清除屏幕;
int erase(void); //在屏幕的每个位置写上空白字符
int clear(void); //使用一个终端命令来清除整个屏幕

1,定义

#define SNAKE_SYMBOL	'@'		/* snake body and food symbol */
#define FOOD_SYMBOL		'*'
#define MAX_NODE		30		/* maximum snake nodes */
#define DFL_SPEED		50		/* snake default speed */
#define TOP_ROW		5			/* top_row */
#define BOT_ROW		LINES - 1
#define LEFT_EDGE	0
#define RIGHT_EDGE	COLS - 1
 
typedef struct node			/* Snake_node structure */
{
	int x_pos;
	int y_pos;
	struct node *prev;
	struct node *next;
} Snake_Node;
 
struct position				/* food position structure */
{
	int x_pos;
	int y_pos;
} ;

2,代码实现

#include<stdio.h>
#include<stdlib.h>
#include<ncurses.h>
#include<sys/time.h>
#include<signal.h>
#include"snake.h"
 
struct position food;		/* food position */
Snake_Node *head, *tail;	/* double linked list's head and tail */
int x_dir = 1, y_dir = 0;	/* init dirction of the snake moving */
int ttm = 5, ttg = 5;			/* two timers defined to control speed */
 
void main(void)
{
	Init_Disp();			/* init and display the interface */
	Food_Disp();			/* display food */
	DLL_Snake_Create();		/* create double linked list and display snake*/
	signal(SIGALRM, Snake_Move);
	set_ticker(DFL_SPEED);
	Key_Ctrl();				/* using keyboard to control snake */
	Wrap_Up();				/* turn off the curses */
}
 
/* Function: Init_Disp()
 * Usage: init and display the interface
 * Return: none
 */
void Init_Disp()
{
	char wall = ' ';
	int i, j;
	initscr();
	cbreak();				/* put termial to CBREAK mode */
	noecho();
	curs_set(0);			/* set cursor invisible */
 
	/* display some message about title and wall */
	attrset(A_NORMAL);		/* set NORMAL first */
	attron(A_REVERSE);		/* turn on REVERSE to display the wall */
	for(i = 0; i < LINES; i++)
	{
		mvaddch(i, LEFT_EDGE, wall);
		mvaddch(i, RIGHT_EDGE, wall);
	}
	for(j = 0; j < COLS; j++)
	{
		mvaddch(0, j, '=');
		mvaddch(TOP_ROW, j, wall);
		mvaddch(BOT_ROW, j, wall);
	}
	attroff(A_REVERSE);		/* turn off REVERSE */
	mvaddstr(1, 2, "Game: snake    version: 1.0    date: 2011/08/22");
	mvaddstr(2, 2, "Author: Dream Fly	Blog: blog.csdn.net/jjzhoujun2010");
	mvaddstr(3, 2, "Usage: Press 'f' to speed up, 's' to speed down,'q' to quit.");
    mvaddstr(4, 2, "       Nagivation key controls snake moving.");
	refresh();
}
 
/* Function: Food_Disp()
 * Usage: display food position
 * Return: none
 */
void Food_Disp()
{
	srand(time(0));
	food.x_pos = rand() % (COLS - 2) + 1;
	food.y_pos = rand() % (LINES - TOP_ROW - 2) + TOP_ROW + 1;
	mvaddch(food.y_pos, food.x_pos, FOOD_SYMBOL);/* display the food */
	refresh();
}
 
/* Function: DLL_Snake_Create()
 * Usage: create double linked list, and display the snake first node
 * Return: none
 */
void DLL_Snake_Create()
{
	Snake_Node *temp = (Snake_Node *)malloc(sizeof(Snake_Node));
	head = (Snake_Node *)malloc(sizeof(Snake_Node));
	tail = (Snake_Node *)malloc(sizeof(Snake_Node));
	if(temp == NULL || head == NULL || tail == NULL)
		perror("malloc");
	temp->x_pos = 5;
	temp->y_pos = 10;
	head->prev =NULL;
	tail->next = NULL;
	head->next = temp;
	temp->next = tail;
	tail->prev = temp;
	temp->prev = head;
	mvaddch(temp->y_pos, temp->x_pos, SNAKE_SYMBOL);
	refresh();
}
 
/* Function: Snake_Move()
 * Usage: use Navigation key to control snake moving, and judge
 * if the snake touch the food.
 * Return:
 */
void Snake_Move()
{
	static int length = 1;		/* length of snake */
	int Length_Flag = 0;		/* default snake's length no change */
	int moved = 0;
	signal(SIGALRM, SIG_IGN);
	/* judge if the snake crash the wall */
	if((head->next->x_pos == RIGHT_EDGE-1 && x_dir == 1) 
		|| (head->next->x_pos == LEFT_EDGE+1 && x_dir == -1)
		|| (head->next->y_pos == TOP_ROW+1 && y_dir == -1)
		|| (head->next->y_pos == BOT_ROW-1 && y_dir == 1))
	{
		gameover(1);
	}
	/* judge if the snake crash itself */
	if(mvinch(head->next->y_pos + y_dir, head->next->x_pos + x_dir) == '@')
		gameover(2);
 
	if(ttm > 0 && ttg-- == 1)
	{
		/* snake moves */
		DLL_Snake_Insert(head->next->x_pos + x_dir, head->next->y_pos + y_dir);
		ttg = ttm;		/* reset */
		moved = 1;		/* snake can move */
	}
	if(moved)
	{
		/* snake eat the food */
		if(head->next->x_pos == food.x_pos && head->next->y_pos == food.y_pos)
		{
			Length_Flag = 1;
			length++;
			/* Mission Complete */
			if(length >= MAX_NODE)
				gameover(0);
			/* reset display the food randomly */
			Food_Disp();
		}
		if(Length_Flag == 0)
		{
			/* delete the tail->prev node */
			mvaddch(tail->prev->y_pos, tail->prev->x_pos, ' ');
			DLL_Snake_Delete_Node();
		}
		mvaddch(head->next->y_pos, head->next->x_pos, SNAKE_SYMBOL);
		refresh();
	}
	signal(SIGALRM, Snake_Move);
}
 
/* Function: set_ticker(number_of_milliseconds)
 * Usage: arrange for interval timer to issue SIGALRM's at regular intervals
 * Return: -1 on error, 0 for ok
 * arg in milliseconds, converted into whole seconds and microseconds
 * note: set_ticker(0) turns off ticker
 */
int set_ticker(int n_msecs)
{
	struct itimerval new_timeset;
	long n_sec, n_usecs;
 
	n_sec = n_msecs / 1000;					/* int second part */
	n_usecs = (n_msecs % 1000) * 1000L;		/* microsecond part */
 
	new_timeset.it_interval.tv_sec = n_sec;	/* set reload */
	new_timeset.it_interval.tv_usec = n_usecs;
 
	new_timeset.it_value.tv_sec = n_sec;	/* set new ticker value */
	new_timeset.it_value.tv_usec = n_usecs;
 
	return setitimer(ITIMER_REAL, &new_timeset, NULL);
}
 
/* Function: Wrap_Up()
 * Usage: turn off the curses
 * Return: none
 */
void Wrap_Up()
{
	set_ticker(0);		/* turn off the timer */
	getchar();
	endwin();
	exit(0);
}
 
/* Function: Key_Ctrl()
 * Usage: using keyboard to control snake action; 'f' means speed up,
 * 's' means speed down, 'q' means quit, navigation key control direction.
 * Return: none
 */
void Key_Ctrl()
{
	int c;
	keypad(stdscr, true);		/* use little keyboard Navigation Key */
	while(c = getch(), c != 'q')
	{
		if(c == 'f')
		{
			if(ttm == 1)
				continue;
			ttm--;
		}
		else if(c == 's')
		{
			if(ttm == 8)
				continue;
			ttm++;
		}
		if(c == KEY_LEFT)
		{
			if(tail->prev->prev->prev != NULL && x_dir == 1 && y_dir == 0)
				continue; /* it can't turn reverse when snake have length */
			x_dir = -1;
			y_dir = 0;
		}
		else if(c == KEY_RIGHT)
		{
			if(tail->prev->prev->prev != NULL && x_dir == -1 && y_dir == 0)
				continue;
			x_dir = 1;
			y_dir = 0;
		}
		else if(c == KEY_UP)
		{
			if(tail->prev->prev->prev != NULL && x_dir == 0 && y_dir == 1)
				continue;
			x_dir = 0;
			y_dir = -1;
		}
		else if(c == KEY_DOWN)
		{
			if(tail->prev->prev->prev != NULL && x_dir == 0 && y_dir == -1)
				continue;
			x_dir = 0;
			y_dir = 1;
		}
	}
}
 
/* Function: DLL_Snake_Insert(int x, int y)
 * Usage: Insert node in the snake.
 * Return: none
 */
void DLL_Snake_Insert(int x, int y)
{
	Snake_Node *temp = (Snake_Node *)malloc(sizeof(Snake_Node));
	if(temp == NULL)
		perror("malloc");
	temp->x_pos = x;
	temp->y_pos = y;
	temp->prev = head->next->prev;
	head->next->prev = temp;
	temp->next = head->next;
	head->next = temp;
}
 
/* Function: gameover(int n)
 * Usage: gameover(0) means Mission Completes; gameover(1) means crashing
 * the wall; gameover(2) means crash itself.
 * Return: none
 */
void gameover(int n)
{
	switch(n)
	{
		case 0: 
			mvaddstr(LINES / 2, COLS / 3 - 4, "Mission Completes,press any key to exit.\n");
			break;
		case 1:
			mvaddstr(LINES/2, COLS/3 - 4, "Game Over, crash the wall,press any key to exit.\n");
			break;
		case 2:
			mvaddstr(LINES/2, COLS/3 - 4, "Game Over, crash yourself,press any key to exit.\n");
			break;
		default:
			break;
	}
	refresh();
	/* delete the whole double linked list */
	DLL_Snake_Delete();
	Wrap_Up();
}
 
/* Function: DLL_Snake_Delete_Node()
 * Usage: delete a tail node, not the whole linked list
 * Return: none
 */
void DLL_Snake_Delete_Node()
{
	Snake_Node *temp;
	temp = tail->prev;
	tail->prev = tail->prev->prev;
	temp->prev->next = tail;
	free(temp);
}
 
/* Function: DLL_Snake_Delete()
 * Usage: delete the whole double linked list
 * Return: none
 */
void DLL_Snake_Delete()
{
	while(head->next != tail)
		DLL_Snake_Delete_Node();
	head->next = tail->prev = NULL;
	free(head);
	free(tail);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陌上花开缓缓归以

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

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

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

打赏作者

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

抵扣说明:

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

余额充值