【任务】利用混沌随机数实现贪吃蛇游戏。
【解析】
【分析】
(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