📄 ptgame.c
字号:
#include "COMM.H"
//拼图游戏代码
//支持 3*3 4*4 5*5三个等级,要继续添加也是比较容易的
//基本只要修改图片编号Cur_Table的大小,PT_Size的大小就可以了
//不过要注意不要超出数据类型的范围
//正点原子@SCUT
//2009/05/30
//V1.2
//存储在sram里面的 图片起始地址(在SD卡上) 列表
u32 *Pic_Addr=(u32*)iclip;//注意 0:表示预览图片的地址 1~n,表示1~n块图片的地址
u8 Cur_Table[26];//图片编号存储列表 5*5时大小为25+1=26
u8 Xscal; //倍乘数
//这四个变量需要保存到EEPROM里面
u8 PT_Size=3; //拼图游戏的难度级别 3、4两个值
u8 PT_New=0; //是否已经在玩?1,没有在玩,必须更新。0,已经在玩,但是未完成,可以不更新。
u16 PT_Step=0;//拼图所用步骤
u16 PT_Time=0;//拼图所用时间
const u8 *PTGmenu_F1[1]={"拼图游戏"};//第1级父目录目录
const u8 *PTGmenu_S1[4]={"继续","新游戏","最佳排行","游戏设置"};//第1级子目录
const u8 *PTGmenu_S2[3]={"简单","一般","困难"}; //第2级子目录 设置
#define PT_BASIC 1 //基本信息
#define PT_TABLE 2 //图表信息
//保存当前游戏信息
//地址区间:412~443
void Save_PTG_Info(u8 type)
{
u8 i;
if(type==PT_BASIC)//保存基本信息
{
FM24C16_WriteOneByte(412,PT_Size);//保存图片大小
FM24C16_WriteOneByte(413,PT_New); //保存是否已经在玩
//保存当前所用步骤
FM24C16_WriteLenByte(414,PT_Step,2);
//保存当前所用时间
FM24C16_WriteLenByte(416,PT_Time,2);
}else if(type==PT_TABLE)//保存图标信息
{
for(i=0;i<26;i++)FM24C16_WriteOneByte(418+i,Cur_Table[i]);//保存当前图表信息
}
}
//读取当前游戏信息
//地址区间:412~443
void Read_PTG_Info(u8 type)
{
u8 i;
if(type==PT_BASIC)//读取基本信息
{
PT_Size=FM24C16_ReadOneByte(412);//读取图片大小
PT_New=FM24C16_ReadOneByte(413); //读取是否已经在玩
//读取当前所用步骤
PT_Step=FM24C16_ReadLenByte(414,2);
//读取当前所用时间
PT_Time=FM24C16_ReadLenByte(416,2);
}else if(type==PT_TABLE)//保存图标信息
{
for(i=0;i<26;i++)Cur_Table[i]=FM24C16_ReadOneByte(418+i);//读取当前图表信息
}
}
//保存最佳值
//level:等级 0~2
// step:步数
// time:用时
//地址区间:444~ 455
void Save_PTG_Best(u8 level,u16 step,u16 time)
{
//保存当前所用步数
FM24C16_WriteLenByte(444+level*4,step,2);
//保存当前所用时间
FM24C16_WriteLenByte(446+level*4,time,2);
}
//读取最佳值
//level:等级 0~2 == 3 4 5
// step:步数
// time:用时
//地址区间:444~ 455
void Read_PTG_Best(u8 level,u16 *step,u16 *time)
{
//读取当前所用步骤
*step=FM24C16_ReadLenByte(444+level*4,2);
//读取当前所用时间
*time=FM24C16_ReadLenByte(446+level*4,2);
}
//对指定列表,得到图片起始坐标点
//这个函数与LCD显示有关
//table:固定区域值 0~PT_Size*PT_Size
//xpos :x坐标值
//ypos :y坐标值
//CHECK OK 09/05/30
void Get_Ps_Addr(u8 table,u8 *xpos,u8 *ypos)
{
u8 x,y;
for(y=0;y<PT_Size;y++)
{
for(x=0;x<PT_Size;x++)
{
if(table==y*PT_Size+x)
{
*xpos=Xscal*x+5;
*ypos=Xscal*y+5;
return;
}
}
}
if(table==PT_Size*PT_Size)//第PT_Size*PT_Size格的起始地址
{
*xpos=Xscal*(PT_Size-1)+5;
*ypos=Xscal*PT_Size+5;
}
}
/////////////////////////////////////////////////////////////////////
//检查拼图游戏获胜的算法
//返回值:0,没成功;1,成功了
//支持从3*3~15*15的棋盘大小
//CHECK OK 09/05/30
u8 PT_Win_Chk(void)
{
u8 t;
u8 size;
size=PT_Size*PT_Size;
for(t=0;t<size;t++){if(Cur_Table[t]!=t)break;}
if(t==size)return 1;
return 0;
}
//初始化(生成随机位置)
//带检测拼图能否完成的算法
//CHECK OK 09/05/30
void PT_Map_Init(void)
{
u8 size;
u8 i,t,a, b;
u8 d=1;
signed char w,h;
size=PT_Size*PT_Size;
srand(RTC->CNTL);//得到种子
for(i=0;i<size;i++)Cur_Table[i]=i;
Cur_Table[size]=size-1; //最后一个图片,必须放在原位,否则游戏无法完成
// 初始化(生成随机位置)
i=0;
while(i++<size||d==0)// 交换至少单位数量次
{
do
{
a = rand()%(size);
b = rand()%(size);
}while(a==b);
t=Cur_Table[a];
Cur_Table[a]=Cur_Table[b];
Cur_Table[b]=t;
// 计算距离,必须要模为1有解
if(Cur_Table[a]==(size-1)|| Cur_Table[b]==(size-1))
{
w=a%PT_Size-b%PT_Size+1;
h=a/PT_Size-b/PT_Size;
w=w<0?-w:w;
h=h<0?-h:h;
d=(d+w+h)%2;
}else d=!d;
}
for(i=0;i<size;i++)
{
if(Cur_Table[i]==size-1){Cur_Table[i]=size;break;}
}
}
//装载游戏图片
//支持从3*3~15*15的棋盘大小
//CHECK OK 09/05/30
void Load_Game_PIC(void)
{
FileInfoStruct TempPic;//部分图片的临时存放空间
u8 t;
u8 temp;
u8 tempx,tempy;
u8 size;
size=PT_Size*PT_Size;
TempPic.F_StartCluster=Pic_Addr[0];//加载预览图片
TempPic.F_Type=T_BMP;//指定为BMP图片
AI_LoadPicFile(&TempPic,3,242,79,318);//装载预览图片
//加载
for(t=0;t<size+1;t++)
{
temp=Cur_Table[t];
Get_Ps_Addr(t,&tempx,&tempy);
if(temp==size)//空格所在区域,填充灰色
{
TFT_Fill(tempx,tempy,tempx+Xscal-2,tempy+Xscal-2,LGRAY);
}else
{
TempPic.F_StartCluster=Pic_Addr[temp+1];//图片地址
AI_LoadPicFile(&TempPic,tempx,tempy,tempx+Xscal-1,tempy+Xscal-1);
}
}
}
//sour:按键所按的固定编号
//dest:空格所在的固定编号
//空格一定是在dest区里面
//CHECK OK 09/05/30
void Move_Pic(u8 sour,u8 dest)
{
FileInfoStruct PicPart;//部分图片的临时存放空间
u8 pic_real_addr;
u8 tempx,tempy;
pic_real_addr=Cur_Table[sour]+1;//得到图片的编号地址
PicPart.F_StartCluster=Pic_Addr[pic_real_addr];
PicPart.F_Type=T_BMP;//指定为BMP图片
//清空sour区的图片,就是把空格移到这个区
Get_Ps_Addr(sour,&tempx,&tempy);//得到源坐标
TFT_Fill(tempx,tempy,tempx+Xscal-2,tempy+Xscal-2,LGRAY);
//把sour区的图片部分显示到dest区
Get_Ps_Addr(dest,&tempx,&tempy);//得到目标坐标
AI_LoadPicFile(&PicPart,tempx,tempy,tempx+Xscal-1,tempy+Xscal-1);
Cur_Table[dest]=Cur_Table[sour];//把sour区的图片编号赋给dest区
Cur_Table[sour]=PT_Size*PT_Size;//空格在sour区了,调换完成
}
//返回值:PT_Size*PT_Size+1,不需要移动
//0~PT_Size*PT_Size 需要移动,与key交换
//拼图游戏的核心算法
//支持从3*3~15*15的棋盘大小
//CHECK OK 09/05/30
u8 Need_Move(u8 key)
{
u8 temp;
u8 size;
u8 i;
size=PT_Size*PT_Size;
if(Cur_Table[key]==size)return size+1;//点中了空格,不移动
else
{
///////////////////////////////////判断是不是需要减PT_Size
if(key>=PT_Size)//判断减PT_Size(3,4,5...)
{
if(key==size)temp=size-1;//按中了最后一个 9,对于这个按键,-1相当于其他按键-size
else temp=key-PT_Size;
if(Cur_Table[temp]==size)return temp;//空格与此次按键值相邻,返回空格所在地址
}
///////////////////////////////////判断是不是需要加PT_Size
if(key<(size-PT_Size))//判断加PT_Size
{
temp=key+PT_Size;
if(Cur_Table[temp]==size)return temp;//空格与此次按键值相邻,返回空格所在地址
}
///////////////////////////////////判断是不是需要减1
for(i=0;i<PT_Size;i++)//边际处理,3:0,3,6;4:0,4,8,12;5:0,5,10,15,20....这些数值不需要减1
{
if(key==PT_Size*i)break;
}
if(i==PT_Size)//需要减1的
{
temp=key-1;
if(Cur_Table[temp]==size)return temp;//空格与此次按键值相邻,返回空格所在地址
}
///////////////////////////////////判断是不是需要加1
for(i=0;i<PT_Size;i++)//边际处理
{
if((key+1)==PT_Size*i)break;
}
if(i==PT_Size)//需要加1的
{
temp=key+1;//判断+1
if(temp==(size+1))return size+1;//不需要移动
if(Cur_Table[temp]==size)return temp;//空格与此次按键值相邻,返回空格所在地址
}
return size+1;//不需要移动
}
}
/////////////////////////////////////////////////////////////////////
//拼图游戏的按键值获取函数
//返回按键值
//CHECK OK 09/05/30
u8 PTGame_Key_To_Num(void)
{
u8 t,ytemp;
if(Is_In_Area(100,300,133,316))return 0XFF;//选择了退出按键,退出模式
for(t=0;t<PT_Size;t++)//返回常规按键
{
for(ytemp=0;ytemp<PT_Size;ytemp++)
if(Is_In_Area(5+Xscal*t,5+Xscal*ytemp,5+Xscal*(t+1),5+Xscal*(ytemp+1)))return t+ytemp*PT_Size+1;
}
if(PT_Size==3&&Is_In_Area(159,236,236,313))return 10;
else if(PT_Size==4&&Is_In_Area(179,237,237,314))return 17;
else if(PT_Size==5&&Is_In_Area(188,234,234,280))return 26;
return 0;//按键无效
}
//显示数据
//显示步骤和时间
//CHECK OK 09/05/30
void PTGame_Show_Msg(void)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -