[荐]Linux C编程连载(6)- “混沌”贪吃蛇

 【任务】利用混沌随机数实现贪吃蛇游戏。

【解析】

【分析】

(1) 采用Lorenz 混沌映射                                           

       根据混沌时间序列的非周期性,改变迭代次数则会产生伪随机的运算结果。将时间(微秒) 向正的方向平移j(j>0),作为Lorenz映射的迭代因子,则迭代次数的范围为[j,j+1000],则混沌方程最少进行j次迭代,最多进行j+1000次迭代。将迭代的序列进行映射处理与本地时间组合,则可以形成随机且唯一的序列码。该序列码可以作为贪吃蛇食物的种子。

(2) 贪吃蛇实现

       贪吃蛇是双链表的典型操作。初始化的贪吃蛇为一个具有3个节点的双链表,包括head,tail和temp节点。

游戏开始后,首先在贪吃蛇头结点之后插入一个新节点,如果贪吃蛇没有吃到食物,就删除掉尾节点之前的一个节点。这样只要在相当短的时间内进行(如20ms),利用人眼的视觉暂留,就会显示出贪吃蛇移动的效果。如果贪吃蛇吃到了食物,就不删除新插入的节点,并显示这个节点的内容(蛇身)。贪吃蛇实现效果如图1所示:

图1 贪吃蛇实现效果

 

chaos.h

#ifndef __CHAOS_H__
#define __CHAOS_H__

extern void chaos_lorenz(char *result);

#endif

chaos.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <sys/time.h>
#include "chaos.h"

void chaos_lorenz(char *result)
{
	int i;
	int j=20;

	float x[2],y[2],z[2];
	float a=10,b=8/3,c=28;
	float t=0.01;

	struct timeval tv;
	struct timezone tz;
	gettimeofday (&tv , &tz);

	x[0]=0.1;
	y[0]=0.1;
	z[0]=0.1;

	for(i=0;i<tv.tv_usec%1000+j;i++)
	{
		x[1]=x[0]+t*(a*(y[0]-x[0]));
		y[1]=y[0]+t*(c*x[0]-y[0]-x[0]*z[0]);
		z[1]=z[0]+t*(x[0]*y[0]-b*z[0]);

		x[0]=x[1];
		y[0]=y[1];
		z[0]=z[1];
	}
	
	sprintf(result,"%6.4f&%6.4f&%6.4f",x[0],y[0],z[0]);
	//printf("%s\n",result);
}

list.h

#ifndef __LIST_H__
#define __LIST_H__

#ifdef __cplusplus
extern "C"{
#endif

typedef enum _dListRet
{
	DLIST_RET_OK,
	DLIST_RET_OOM,
	DLIST_RET_PARAMS,
	DLIST_RET_STOP,
	DLIST_RET_FAIL
}dListRet;

struct direct
{
	int cx;
	int cy;
};

struct _node
{
	int cx;
	int cy;
	struct _node *prev;
	struct _node *next;
};

typedef struct _node node;

struct _dList
{
	node *head;
	node *tail;
};
typedef struct _dList dList;


extern dList* list_create(void);
extern dListRet add_node_after_head(dList *thiz, int x, int y);
extern dListRet delete_node_before_tail(dList *thiz);
extern dListRet delete_list(dList *thiz);

#ifdef __cplusplus
}
#endif

#endif

list.c

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

dList* list_create(void)
{
	dList *thiz =(dList *)malloc(sizeof(dList));
	node *temp = (node *)malloc(sizeof(node));

	thiz->head =(node *)malloc(sizeof(node));
	thiz->tail =(node *)malloc(sizeof(node));

	if(temp != NULL)
	{
		temp->cx = 5;
		temp->cy = 10;
	}

	if(thiz != NULL && temp != NULL)
	{
		thiz->head->prev = thiz->tail->next = NULL;
		thiz->head->next = temp;
		thiz->tail->prev = temp;
		temp->prev = thiz->head;
		temp->next = thiz->tail;
	}
	return thiz;
}

dListRet add_node_after_head(dList *thiz, int x, int y)
{
	node *temp = (node *)malloc(sizeof(node));

	if(temp != NULL)
	{
		temp->cx = x;
		temp->cy = y;
		
		
		temp->prev = thiz->head;
		temp->next = thiz->head->next;
		temp->next->prev = temp;
		thiz->head->next = temp;
		

		/*2
		temp->prev = thiz->head;
		temp->next = thiz->head->next;
		thiz->head->next = temp;
		thiz->head->next->next->prev = temp;
		*/

		/*3
		thiz->head->next->prev =temp;
		temp->prev = thiz->head;
		temp->next = thiz->head->next;//此前发布的博文此处有误,修改时间2011-11-18
		thiz->head->next = temp;
		*/
	}

	return DLIST_RET_OK;
}

dListRet delete_node_before_tail(dList *thiz)
{
	node *temp = thiz->tail->prev;
        node *btemp = temp->prev;
	btemp->next = thiz->tail;
	thiz->tail->prev = btemp;
	free(temp);
	return DLIST_RET_OK;
}

dListRet delete_list(dList *thiz)
{
	while(thiz->head->next != thiz->tail)
	{
		delete_node_before_tail(thiz);
	}
	free(thiz->head);
	free(thiz->tail);
	free(thiz);
	return DLIST_RET_OK;
}


snake.c

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <signal.h>
#include <sys/time.h>
#include <time.h>
#include <assert.h>
#include <math.h>
#include "list.h"
#include "chaos.h"

#define NUM 60

void init_screen();
int setTicker(long n_msec);
void food_gen();
void init_game();
void show();
void getDir();
void over(int i);

int hour,minute,second;
int tTime,length,level;
struct direct dir,food;
dList *list;

int main(void)
{
	init_game();
	signal(SIGALRM, show);
    	getDir();
	endwin();
	return 0;
}

void init_screen()
{
	initscr();
	cbreak(); 
	//nonl(); 
	noecho();
	curs_set(0);
	//intrflush(stdscr,FALSE); 
	keypad(stdscr,TRUE); 
	//refresh();
}

void food_gen()
{
	char *result;
	float x,y,z;
	int m,n,k;
	time_t now;
	now = time(0);
	struct tm *tnow = localtime(&now);

	result=(char *)malloc(100);
	if(!result)
	{
		fprintf(stderr, "malloc failed!\n");
	}
	chaos_lorenz(result);
	sscanf(result,"%f&%f&%f",&x,&y,&z);
	free(result);

	m=((int)(fabs(x)*1000))&0xffff;		
	n=((int)(fabs(y)*1000))&0xffff;
	k=((int)(fabs(z)*1000))&0xffff;
	
	int htime = tnow->tm_year+tnow->tm_mon+1+tnow->tm_mday;
	int ltime = tnow->tm_hour+tnow->tm_min+tnow->tm_sec;
	food.cx = (m+ltime%1000+htime%1000) % COLS;
    	food.cy = (n+ltime%1000+htime%1000) % (LINES-2) + 2;
}

void init_game()
{
	init_screen();
	hour = minute = second = 0;
	tTime = 0;
	length = 1;
	level = 0;
	dir.cx = 1;
	dir.cy = 0;
	food_gen();
	/*
	srand(time(0));
	food.cx = rand() % COLS;
    	food.cy = rand() % (LINES-2) + 2;
	*/
	list=list_create();
	setTicker(20);
}

int setTicker(long n_msec)
{
	struct itimerval new_timerset;
	long n_sec;
	long n_usec;
	n_sec = n_msec/1000;
	n_usec = (n_msec%1000)*1000L;
	new_timerset.it_interval.tv_sec = n_sec;
	new_timerset.it_interval.tv_usec = n_usec;
	n_msec = 1;
	n_sec = n_msec/1000;
	n_usec = (n_msec%1000)*1000L;
	new_timerset.it_value.tv_sec = n_sec;
	new_timerset.it_value.tv_usec = n_usec;
	return setitimer(ITIMER_REAL,&new_timerset,NULL);
}

void showInformation()
{
	int i;
	tTime++;
	if(tTime >= 1000000)
		tTime = 0;
	if(1 != tTime % 50)	//50*20ms=1000ms
		return;
	
	//清屏并显示分隔符
	move(0, 0);
	for(i=0;i<COLS;i++)
		addstr(" ");

	move(1, 0);
	for(i=0;i<COLS;i++)
		addstr("-");

	//显示时间
	move(0, 3); 
	printw("time: %d:%d:%d %c", hour, minute, second);
		second++;

	if(second >= NUM)
	{
		second = 0;
		minute++;
	}
	if(minute >= NUM)
	{
		minute = 0;
		hour++;
	}
	//显示长度,等级
	move(0, COLS/2-5);
	printw("length: %d", length);
	move(0, COLS-10);
	level = length / 3 + 1;
	printw("level: %d", level);
}

void showSnake()
{
	if(1 != tTime % (30-level))
		return;
	//判断蛇的长度有没有改变
	bool lenChange = false;
	//显示食物
	move(food.cy, food.cx);
	printw("{1}quot;);
	//如果蛇碰到墙,则游戏结束
	if((COLS-1==list->head->next->cx && 1==dir.cx) 
	|| (0==list->head->next->cx && -1==dir.cx)
	|| (LINES-1==list->head->next->cy && 1==dir.cy)
	|| (2==list->head->next->cy && -1==dir.cy))
	{
		over(1);
		return;
	}

	//如果蛇头砬到自己的身体,则游戏结束
	if('*' == mvinch(list->head->next->cy+dir.cy, list->head->next->cx+dir.cx) )
	{
		over(2);
		return;
	}

	assert(add_node_after_head(list,list->head->next->cx+dir.cx,list->head->next->cy+dir.cy)==DLIST_RET_OK);
	//蛇吃了一个“食物”
	if(list->head->next->cx==food.cx && list->head->next->cy==food.cy)
	{
		lenChange = true;
		length++;
		//恭喜你,通关了
		if(length >= 50)
		{
			over(3);
			return;
		}
		//重新设置食物的位置
		food_gen();
		/*
		food.cx = rand() % COLS;
		food.cy = rand() % (LINES-2) + 2;
		*/
	}
	if(!lenChange)
	{
		move(list->tail->prev->cy, list->tail->prev->cx);
		printw(" ");
		assert(delete_node_before_tail(list)==DLIST_RET_OK);
	}

	move(list->head->next->cy, list->head->next->cx);
	printw("*");
}

void show()
{
	signal(SIGALRM, show);
	showInformation();
	showSnake();
	refresh();
};

void getDir()
{
	int ch;
	while(1)
	{
		ch=getch();	
		switch(ch)
		{
			case KEY_LEFT:
				dir.cx = -1;
            			dir.cy = 0;
				break;
			case KEY_UP:
				dir.cx = 0;
            			dir.cy = -1;
				break;
			case KEY_RIGHT:
				dir.cx = 1;
            			dir.cy = 0;
				break;
			case KEY_DOWN:
				dir.cx = 0;
            			dir.cy = 1;
				break;
			case 27:
				setTicker(0);                //关闭计时器
				delete_list(list);
				endwin();
				exit(0);
			default:;
		}

		setTicker(20);
	}
}

void over(int i)
{
	int j;
	//separator
	move(LINES-2, 0);
	for(j=0;j<COLS;j++)
		addstr("-");
	
	//Exit information
	move(LINES-3, 0);
	for(j=0;j<COLS;j++)
		addstr(" ");
	move(LINES-3,0);
	switch(i)
	{
		case 1:
			addstr("Crash the wall! Game over.");
			break;
		case 2:
			addstr("Crash itself! Game over");
			break;
		case 3:
			addstr("Mission Complete!");
			break;
		default:;
	}
	setTicker(0);                //关闭计时器
	delete_list(list);           //释放链表的空间
	
	//Tips
	move(LINES-1, 0);
	for(j=0;j<COLS;j++)
	addstr(" ");
	move(LINES-1, 0);
	addstr("Tips : Please enter any key to quit.");
	getch();
	endwin();
	exit(1);
}

Makefile

test:snake.c list.c chaos.c
	gcc -g snake.c list.c chaos.c -o snake -lcurses
clean:
	rm snake
distclean:
	rm snake *~

 

【链接】Qt写的贪吃蛇,代码暂不公开。

【特点】食物的颜色和位置按混沌运算规律改变。


【参考】

1 http://blog.csdn.net/tandesir/article/details/6917393

2 http://topic.csdn.net/u/20101001/01/2280b2dd-1446-439d-b1f8-cdd9db1fd615.html

【备注】

list.c 注释掉的代码有误,已修改。2011-11-18


 转载请表明出处,欢迎转载!

http://blog.csdn.net/tandesir/article/details/6954910

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值