近日,21ic论坛oufuqiang做了一个用点阵玩贪吃蛇,而这个例子非常适合新手入门算法,下面开始分享源码与原理图。不强调性能的源码就是耍流氓了,结果如下:
RAM:86.2
code:697
性能:38.4fps/Mhz@8051
源码167行的贪吃蛇
源码如下:
文字版:
#include
sbit DIN = P3^4;
sbit RCK = P3^5;
sbit SCK = P3^6; //74hc595接口
sbit k1 = P3^1;
sbit k2 = P3^0;
sbit k3 = P3^2;
sbit k4 = P3^3; //四个独立按键
unsigned char dpdat[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //显存
unsigned char she[65]; //蛇体数组,由于点阵大小为8x8,所以一个字节表示蛇的一个节点,高四位和低四位分别表示xy坐标
unsigned char fangxiang; //蛇头移动方向
bit shiwushanshuo; //食物闪烁控制位
#define shang 0
#define xia 1
#define zuo 2
#define you 3
#define k1_anxia k1==0
#define k2_anxia k2==0
#define k3_anxia k3==0
#define k4_anxia k4==0 //一些替换,省得写着写着自己逻辑乱掉
void yidongshe(unsigned char fangxiang); //移动蛇函数
void xianshishe(); //显示蛇函数
void chulishe(); //处理蛇函数
void send595(unsigned char dat) //向595发送一个字节数据
{
unsigned char i=8;
do
{
DIN=dat&0x80;
SCK=1;
SCK=0;
dat<<=1;
}while(--i);
RCK=1;
RCK=0;
}
void yanshi(unsigned int time) //一个简单的延时
{
while(--time);
}
void shechushihua() //蛇初始化,蛇长两个节点,0xff表示蛇尾,最后一个字节是食物坐标,初始向左移动
{
she[0]=0x33;she[1]=0x34;she[2]=0xff;she[64]=0x22;fangxiang=zuo;
}
void main()
{
unsigned int fps;
SCK=0;
RCK=0;
TMOD=0X01;
EA=1;
ET0=1;
TR0=1;
shechushihua();
while(1)
{
xianshishe(); //显示蛇
// yanshi(60000); //延时一下
yidongshe(fangxiang); //移动蛇
chulishe(); //处理蛇
fps++;
}
}
void t0() interrupt 1
{
code unsigned char hsm[]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //行扫数据
static unsigned char cnt; //扫描变量
static unsigned int clk5hz; //5hz时钟用变量
TH0=(65536-2500)/256;
TL0=(65536-2500)%256; //2.5ms中断周期
P0=0XFF;
send595(hsm[cnt]); //发送行扫数据
P0=~dpdat[cnt]; //送出显存数据,由于点阵是0点亮,所以数据取反后送P0
cnt++; //移向下一行
cnt=cnt&0x07; //控制变量不超过0-7
if(k1_anxia && fangxiang!=xia){fangxiang=shang;}
if(k2_anxia && fangxiang!=shang){fangxiang=xia;}
if(k3_anxia && fangxiang!=you){fangxiang=zuo;}
if(k4_anxia && fangxiang!=zuo){fangxiang=you;} //按键控制蛇头方向
clk5hz++;if(clk5hz>=40){clk5hz=0;shiwushanshuo=!shiwushanshuo;}//以5hz闪烁食物
}
void yidongshe(unsigned char fangxiang) //移动蛇
{
unsigned char i;
for(i=63;i>0;i--) //从蛇尾向蛇头遍历蛇体数据
{
if(she[i]!=0xff) //不是蛇尾
{
she[i]=she[i-1]; //后一节点复制前一节点坐标
}
else
{
continue; //是0xff表示是蛇尾数据,继续向前
}
}
if(fangxiang==shang) //向上移动.点阵左上角坐标为0,0,右下角坐标为7,7
{
she[0]=she[0]-0x10; //高四位减1
}
if(fangxiang==xia)
{
she[0]=she[0]+0x10; //高四位加1
}
if(fangxiang==zuo)
{
she[0]=(she[0]&0xf0)|(she[0]-0x01)&0x07; //低四位减1
}
if(fangxiang==you)
{
she[0]=she[0]+0x01; //低四位加1
}
she[0]=she[0]&0x77; //控制坐标范围不超过0,0-7,7
}
void xianshishe() //显示蛇,将蛇体数据映射到显存
{
unsigned char i;
for(i=0;i<8;i++)//显存为8个字节,绘制蛇之前先清除显存
{
dpdat[i]=0;
}
for(i=0;i<65;i++)//从头到尾遍历蛇体数据
{
if(she[i]!=0xff)//如果未到蛇尾
{
dpdat[she[i]>>4]|=0x80>>(she[i]&0x0f);//根据xy坐标绘制
}
else
{
break;//已到蛇尾,退出当前循环
}
}
if(shiwushanshuo){dpdat[she[64]>>4]|=0x80>>(she[64]&0x0f);}//绘制食物,蛇体最后一个字节是食物坐标
}
void chulishe()
{
unsigned char i;
bit shiwuzaisheshenshang;
if(she[0]==she[64])//蛇头坐标与食物坐标一致,说明吃到食物
{
for(i=0;i<65;i++)//遍历蛇体数据
{
if(she[i]==0xff)//如果到蛇尾
{
she[i]=she[i-1];//蛇尾复制前一节点坐标
she[i+1]=0xff;//蛇尾后移
break;
}
}
do
{
shiwuzaisheshenshang=0;//假设新生成的食物坐标不在蛇身上
she[64]=TL0&0x77;//使用TL0的值随机生成一个食物坐标
for(i=0;i<64;i++)//遍历蛇体判断新的食物是否跟蛇体重合
{
if(she[i]==she[64])//节点坐标与食物坐标相同
{
shiwuzaisheshenshang=1;//置标志位
}
}
}while(shiwuzaisheshenshang);//如果重合,再重新生成一个食物坐标
}
for(i=1;i<64;i++)//遍历蛇体
{
if(she[0]==she[i]){shechushihua();}//如果蛇头与蛇体节点重合,说明咬到自己了,重新初始化蛇
}
}
原理图如下:(请将手机翻转查看)
原文地址见底部“阅读原文”
这个经典例子可让算法有更深刻理解▼