扫地雷的源代码分为两部分,一部分是与硬件相关的,如屏的驱动,打印图片,设置前景色,清除屏幕…..;二,扫地雷的实现,主要是计算方法。如读者需要移值,只需要第二部分的程序稍加改动。
#define _GAME_DRV_H_ #include <DP8051XP.H> #include "..publicTypeDef.h" #include "..publicKey.h" #include <..publicuigameapi.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 "..publicTypeDef.h" #include "..publicKey.h" #include <..publicuigameapi.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[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] == 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] = 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] = 1; MN_TmpSchBlackMine[j] = 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; } } } }
我把整个工程及图片资源放于: http://www.sokutek.com/document.asp;有兴趣的朋友可以去下载
|
|