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

 

转载于:https://www.cnblogs.com/J2EEPLUS/archive/2011/11/10/2487980.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值