扫地雷源代码Keil编写
扫地雷的源代码分为两部分,一部分是与硬件相关的,如屏的驱动,打印图片,设置前景色,清除屏幕…..;二,扫地雷的实现,主要是计算方法。如读者需要移值,只需要第二部分的程序稍加改动。
#define _GAME_DRV_H_
#include <DP8051XP.H>
#include "..\public\TypeDef.h"
#include "..\public\Key.h"
#include <..\public\uigameapi.h>
///为了调试,其调用了字库,屏的底层驱动
void gShowHexAscii(XWORD xwX,XWORD xwY,PXBYTE pxData,XWORD xLen) large
{
*(PXWORD)(GAME_SWAP_RAM_ADDR +0) = xwX;
*(PXWORD)(GAME_SWAP_RAM_ADDR +2) = xwY;
*(PXDWORD)(GAME_SWAP_RAM_ADDR+4) = (XDWORD)pxData;
*(PXWORD)(GAME_SWAP_RAM_ADDR +8) = (XDWORD)xLen;
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 0;
Run_Game_Api();
}
//打印图片子程序,bx,by为屏的坐标输入,wId为资源ID号
void gResShowPic(XWORD bx,XWORD by,XWORD wId) large
{
*(PXWORD)(GAME_SWAP_RAM_ADDR +0) = bx;
*(PXWORD)(GAME_SWAP_RAM_ADDR +2) = by;
*(PXWORD)(GAME_SWAP_RAM_ADDR +4) = wId;
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 1;
Run_Game_Api();
}
//设置前景色
void gSetPenColor(XWORD xwPenColor) large
{
*(PXWORD)(GAME_SWAP_RAM_ADDR +0) = xwPenColor;
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 2;
Run_Game_Api();
}
//设置背景色
void gSetBackgdColor(XWORD xwGgColor) large
{
*(PXWORD)(GAME_SWAP_RAM_ADDR +0) = xwGgColor;
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 3;
Run_Game_Api();
}
//清屏
void gClearScreen(XWORD wColStart, XWORD wRowStart, XWORD wWidth, XWORD wHeight) large
{
*(PXWORD)(GAME_SWAP_RAM_ADDR +0) = wColStart;
*(PXWORD)(GAME_SWAP_RAM_ADDR +2) = wRowStart;
*(PXWORD)(GAME_SWAP_RAM_ADDR +4) = wWidth;
*(PXWORD)(GAME_SWAP_RAM_ADDR +6) = wHeight;
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 4;
Run_Game_Api();
}
//延时,等待
void gap_sleep(XWORD xwDelayTime) large
{
*(PXWORD)(GAME_SWAP_RAM_ADDR +0) = xwDelayTime;
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 5;
Run_Game_Api();
}
//获取系统消息,如时间,按键消息
XBYTE gap_get_message() large
{
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 6;
Run_Game_Api();
return *(PXBYTE)(GAME_SWAP_RAM_ADDR +0);
}
//设置时钟频率
void gSetGameSpeed(XBYTE xbType) large
{
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 7;
*(PXBYTE)(GAME_SWAP_RAM_ADDR +0) = xbType;
Run_Game_Api();
}
//获得一个随机数
XBYTE gGetRandVar(void) large
{
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 8;
Run_Game_Api();
return *(PXWORD)(GAME_SWAP_RAM_ADDR +0);
}
XDWORD gGetGameRomFileMaxSector(void) large
{
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 9;
Run_Game_Api();
return *(PXDWORD)(GAME_SWAP_RAM_ADDR +0);
}
void gfsReadOnePage(XDWORD PagePos,PXBYTE pxbTarget) large
{
*(PXBYTE)(GAME_SWAP_RAM_ADDR +12) = 10;
*(PXDWORD)(GAME_SWAP_RAM_ADDR +0) = PagePos;
*(PXDWORD)(GAME_SWAP_RAM_ADDR+4) = (XDWORD)pxbTarget;
Run_Game_Api();
}
下面的程序为计算方法,我所用到的硬件是三代苹果(五个按键实现);对于下面的变量我全面申明为large,xdata的主要原因是我的系统造成的。我把游戏写为两个工程;一个工程我们可以理解为主程序,主要的功能是与硬件打交道的,如按键,定时器,关机,电池检测,屏的驱动;另一个工程为游戏的具体实现,与硬件与关的。两个工程的代码区域不一样的,xdata的区域也不一样。但是由于keil的编译系统,在工程1里面已经把data,idata占用了,如果工程2里面的变量用到data,idata的话,两个工程的变量会重叠,当定时中断时,未知的因素会发生。我这样设计的的好处是,外部的游戏可以做为文件拷入内存,而工程1无须改动。
#include <DP8051XP.H>
#include "..\public\TypeDef.h"
#include "..\public\Key.h"
#include <..\public\uigameapi.h>
#include <SokuTek.h>
void Timer0(void) interrupt 1 using 2
{
}
#define MINE_MAX_X 17
#define MINE_MAX_Y 11
#define MINE_FLAG 9
#define MINE_START_X 3
#define MINE_START_Y 26
#define MINE_BMP_WIDTH 9
#define MINE_BMP_HEIGHT 9
#define MN_LAUGH_FACE_X 72
#define MN_LAUGH_FACE_Y 4
#define MN_MINE_NUM MINE_MAX_X + MINE_MAX_Y
#define INT16U XWORD
#define ResShowPic gResShowPic
INT16U MN_Mine[MINE_MAX_X*MINE_MAX_Y];
INT16U MN_Turn[MINE_MAX_X*MINE_MAX_Y];
INT16U MN_Mark[MINE_MAX_X*MINE_MAX_Y];
INT16U MN_TmpSchBlackMine[MINE_MAX_Y][MINE_MAX_X];
INT16U MN_MarkNum;
INT16U MN_RandSeed;
INT16U MN_RandOffset;
INT16U MN_RandMaxvalue;
INT16U MN_curx;
INT16U MN_cury;
INT16U MN_Random() large;
void MN_IniMineMap() large;
void MN_TurnBack(INT16U xx, INT16U yy) large;
INT16U MN_Edge_Stack(INT16U xx, INT16U yy) large;
void MN_Edge(INT16U xx, INT16U yy) large;
void MN_FailGame() large;
INT16U MN_LButton(INT16U xx, INT16U yy) large;
INT16U MN_RButton(INT16U xx,INT16U yy) large;
INT16U MN_ChkSuccess() large;
void RestoreCurMine() large;
void ShowMinesMap() large;
void ShowIniGameBckMap() large;
void iniMineGame() large;
void MarkCurMine() large;
void MN_New_Edge(INT16U xx, INT16U yy) large;
extern rand();
INT16U MN_Random() large
{
INT16U x,y;
MN_RandSeed = MN_RandSeed*109 + 57;
x = MN_RandSeed + MN_RandOffset;
y = x & MN_RandMaxvalue;
return y;
}
void MN_IniMineMap() large
{
INT16U x, y,i;
for(y = 0;y <MINE_MAX_Y;y++)
for(x = 0;x <MINE_MAX_X;x++)
{
MN_Mine[y * MINE_MAX_X + x] = 0;
MN_Turn[y * MINE_MAX_X + x] = 0;
MN_Mark[y * MINE_MAX_X + x] = 0;
}
for(i = 0;i <MN_MINE_NUM;i++)
{
x = MN_Random();
while (MN_Mine[x] || (x > =MINE_MAX_X*MINE_MAX_Y - 1))
{
x = MN_Random();
}
MN_Mine[x] = MINE_FLAG;
}
for (y=0;y <MINE_MAX_Y;y++)
for (x=0;x <MINE_MAX_X;x++)
{
i=0;
if (MN_Mine[y*MINE_MAX_X +x]!=MINE_FLAG)
{
if ((MN_Mine[y*MINE_MAX_X +x-1]==MINE_FLAG)&&(x> =1)) i++;
if ((MN_Mine[y*MINE_MAX_X +x+1]==MINE_FLAG)&&((x+1) <MINE_MAX_X)) i++;
if ((MN_Mine[(y-1)*MINE_MAX_X +x]==MINE_FLAG)&&(y> =1)) i++;
if ((MN_Mine[(y+1)*MINE_MAX_X +x]==MINE_FLAG)&&((y+1) <MINE_MAX_Y)) i++;
if ((MN_Mine[(y-1)*MINE_MAX_X +x-1]==MINE_FLAG)&&(x> =1)&&(y> =1)) i++;
if ((MN_Mine[(y-1)*MINE_MAX_X +x+1]==MINE_FLAG)&&((x+1) <MINE_MAX_X)&&(y> =1)) i++;
if ((MN_Mine[(y+1)*MINE_MAX_X +x+1]==MINE_FLAG)&&((x+1) <MINE_MAX_X)&&((y+1) <MINE_MAX_Y)) i++;
if ((MN_Mine[(y+1)*MINE_MAX_X +x-1]==MINE_FLAG)&&(x> =1)&&((y+1) <MINE_MAX_Y)) i++;
MN_Mine[y*MINE_MAX_X +x]=i;
}
}
}
void MN_TurnBack(INT16U xx, INT16U yy) large
{
if(!MN_Turn[yy*MINE_MAX_X+xx])
MN_Turn[yy*MINE_MAX_X+xx] = 2 + MN_Mine[yy*MINE_MAX_X+xx];
}
INT16U MN_Edge_Stack(INT16U xx, INT16U yy) large
{
INT16U ZZ;
if ( (xx&0x8000) || (xx> MINE_MAX_X -1)) return 0;
if ( (yy&0x8000) || (yy> MINE_MAX_Y -1)) return 0;
ZZ=MN_Turn[yy*MINE_MAX_X+xx];
if (ZZ) return 0 ;
MN_TurnBack(xx,yy);
if (MN_Mine[yy*MINE_MAX_X+xx] == 0) return 1;
return 0;
}
void MN_Edge(INT16U xx, INT16U yy) large
{
MN_New_Edge(xx,yy);
}
///以前的程序是递归调用,我进行了修改,原因是如果递归的深度过于深的话,堆栈会溢出。我重新改写了程序
void MN_New_Edge(INT16U xx, INT16U yy) large
{
INT16U i,j,tmpcnt;
for(i = 0;i <MINE_MAX_Y;i++)
for(j = 0;j <MINE_MAX_X;j++)
MN_TmpSchBlackMine[i][j] = 0;
MN_TmpSchBlackMine[yy][xx]= 1;
while(1)
{
tmpcnt = 0;
for(j = 0;j <MINE_MAX_Y;j++)
for(i = 0;i <MINE_MAX_X;i++)
if (MN_TmpSchBlackMine[j][i] == 1)
{
MN_Edge_Stack(i,j);
if (MN_Edge_Stack(i-1,j)) MN_TmpSchBlackMine[j][i-1] = 1;
if (MN_Edge_Stack(i,j-1)) MN_TmpSchBlackMine[j-1][i] = 1;
if (MN_Edge_Stack(i+1,j)) MN_TmpSchBlackMine[j][i+1] = 1;
if (MN_Edge_Stack(i,j+1)) MN_TmpSchBlackMine[j+1][i] = 1;
MN_TmpSchBlackMine[j][i] = 0;
tmpcnt = 1;
}
if (tmpcnt==0) break;
}
}
void MN_FailGame() large
{
INT16U x;
for(x = 0;x <MINE_MAX_X*MINE_MAX_Y;x++)
if( MN_Mine[x]==MINE_FLAG) MN_Turn[x]= 2 + MINE_FLAG;
}
INT16U MN_LButton(INT16U xx, INT16U yy) large
{
if ( (xx <MINE_MAX_X) && (yy <MINE_MAX_Y))
{
if ( (MN_Mine[yy*MINE_MAX_X + xx] == MINE_FLAG) &&(MN_Turn[yy*MINE_MAX_X + xx]==0) )
{
MN_FailGame();
MN_Turn[yy*MINE_MAX_X + xx]= 2 + MINE_FLAG + 2;
return 0;
}
if (MN_Mine[yy*MINE_MAX_X + xx] == 0)
{
MN_Edge(xx,yy);
}
else
MN_TurnBack(xx,yy);
return 1;
}
return 2;
}
INT16U MN_RButton(INT16U xx,INT16U yy) large
{
INT16U x;
if((MN_Turn[yy*MINE_MAX_X+xx] <2))
{
x = 0;
if(MN_Turn[yy*MINE_MAX_X+xx]==0) {MN_Turn[yy*MINE_MAX_X+xx] = 1; x = MINE_FLAG; }
else if(MN_Turn[yy*MINE_MAX_X+xx]==1) MN_Turn[yy*MINE_MAX_X+xx] = 0;
MN_Mark[yy*MINE_MAX_X+xx] = x;
MN_MarkNum=0;
for(x = 0;x <MINE_MAX_X*MINE_MAX_Y;x++)
if (MN_Mark[x]==MINE_FLAG) MN_MarkNum++;
return 1;
}
return 2;
}
INT16U MN_ChkSuccess() large
{
INT16U x,y;
y = 0;
for(x = 0;x <MINE_MAX_X*MINE_MAX_Y;x++)
if(MN_Turn[x] <2) y++;
if (y == MN_MINE_NUM)
{
for(x = 0;x <MINE_MAX_X*MINE_MAX_Y;x++)
if(MN_Turn[x]==0) MN_Turn[x]=1;
return 1;
}
return 0;
}
void RestoreCurMine() large
{
ResShowPic(MINE_START_X+MINE_BMP_WIDTH*MN_curx,
MINE_START_Y+ MINE_BMP_HEIGHT* MN_cury,
MN_Turn[MINE_MAX_X*MN_cury+MN_curx]+p_RGMINE00);
}
void MarkCurMine() large
{
ResShowPic(MINE_START_X+MINE_BMP_WIDTH*MN_curx,
MINE_START_Y+ MINE_BMP_HEIGHT* MN_cury,
MN_Turn[MINE_MAX_X*MN_cury+MN_curx]+p_RGMINE20);
}
void ShowMinesMap() large
{
XWORD i,j;
for(i=0;i <MINE_MAX_Y;i++)
for(j = 0;j <MINE_MAX_X;j++)
{
ResShowPic(MINE_START_X+MINE_BMP_WIDTH*j,
MINE_START_Y+ MINE_BMP_HEIGHT* i,
MN_Turn[MINE_MAX_X*i+j]+p_RGMINE00);
}
}
void ShowIniGameBckMap() large
{
ResShowPic(0,0,p_RGMINEBLKGRND);
ResShowPic(MN_LAUGH_FACE_X,MN_LAUGH_FACE_Y,p_RGMINE14);
ShowMinesMap();
MarkCurMine();
}
void iniMineGame() large
{
EA = 0;
MN_curx = 0;
MN_cury = 0;
MN_RandSeed = gGetRandVar();
MN_RandOffset = gGetRandVar();
MN_RandMaxvalue = 255;
MN_IniMineMap();
ShowIniGameBckMap();
EA = 1;
}
void main() large
{
XBYTE xbKey;
XBYTE SkipKeyRunFlag;
iniMineGame();
SkipKeyRunFlag = 0;
while(1)
{
xbKey = gap_get_message();
if (xbKey!=AP_KEY_NULL)
{
switch(xbKey)
{
case AP_KEY_VOLUP | AP_KEY_UP:
if(SkipKeyRunFlag==1)
{
SkipKeyRunFlag = 0;
break;
}
RestoreCurMine();
MN_cury++;
if (MN_cury == MINE_MAX_Y) MN_cury=0;
MarkCurMine();
break;
case AP_KEY_POWER | AP_KEY_UP:
if(MN_LButton(MN_curx,MN_cury)==0)
{ // failure
ShowMinesMap();
ResShowPic(MN_LAUGH_FACE_X,MN_LAUGH_FACE_Y,p_RGMINE15);
iniMineGame();
}
else if(MN_ChkSuccess())
{ //success
ShowMinesMap();
ResShowPic(MN_LAUGH_FACE_X,MN_LAUGH_FACE_Y,p_RGMINE16);
iniMineGame();
}
else
{
ShowMinesMap();
MarkCurMine();
}
break;
case AP_KEY_VOLUP |AP_KEY_LONG:
SkipKeyRunFlag = 1;
MN_RButton(MN_curx,MN_cury);
if(MN_ChkSuccess())
{
ShowMinesMap();
ResShowPic(MN_LAUGH_FACE_X,MN_LAUGH_FACE_Y,p_RGMINE16);
iniMineGame();
} //sucess
else
{
ShowMinesMap();
MarkCurMine();
}
break;
case AP_KEY_RIGHT:
case AP_KEY_RIGHT | AP_KEY_HOLD:
RestoreCurMine();
MN_curx++;
if (MN_curx == MINE_MAX_X) MN_curx=0;
MarkCurMine();
break;
case AP_KEY_LEFT:
case AP_KEY_LEFT | AP_KEY_HOLD:
RestoreCurMine();
if (MN_curx==0) MN_curx= MINE_MAX_X;
MN_curx --;
MarkCurMine();
break;
case AP_KEY_FUNC |AP_KEY_UP:
RestoreCurMine();
if (MN_cury==0) MN_cury= MINE_MAX_Y;
MN_cury --;
MarkCurMine();
break;
default:
break;
}
}
}
}
我把整个工程及图片资源放于: ;有兴趣的朋友可以去下载
发表时间:2008年6月14日16:49:20