无聊写了个扫雷小游戏,输入非雷坐标(x,y),清除掉非雷的区域,剩下地雷。算法很简单的,关键是空白区域的处理,即如果输入的坐标四周不存在雷,则连通的空白区域自动清除。这个模型与计算机图形学中的区域填充相当类似。填充算法一般有扫描线填充,种子填充等等。在这里借鉴种子填充算法。实现如下:输入一个点,从左右两个方向遍历改点所处的水平线,遇到雷终止,得到一个x的区间,扫描该线的上方和下方的水平线,如果在该区间内发现有空白点,则以该点为种子,递归调用。
附上代码。代码有点烂,程序还有小bug。不过大致的算法就是那么回事吧。小问题懒得改了。
// play.cpp : Defines the entry point for the console application. // /* 如果认为(x,y)不是雷,输入坐标(x,y)清除,不可以标记雷。可以实现,只是操作起来会比较麻烦 本程序的坐标系: |------>y | | | | ∨ x '.':为清除的点;'*'地雷;空白(四周没有雷)用空格代替。 */ #include "stdafx.h" #include <time.h> #include <stdlib.h> #include <iostream> using namespace std; bool g_Llimet = false; bool g_Rlimet = false; int top_line = 0; int bottom_line = 0; struct coor { int x; int y; }; struct mask { int x; int y; bool isshow;//是否展示 bool isblank;//是否空白区域的点 }; int xx,yy; int recursion = 0; mask masks[500]; char mines[100][100]; #define DEFAULT_X 16 #define DEFAULT_Y 30 #define DEFAULT_MINESNUMBER 100 int COORDINATE_X = DEFAULT_X; int COORDINATE_Y = DEFAULT_Y; int MINE_NUMBER = DEFAULT_MINESNUMBER; void initialization() { for(int a = 0;a<COORDINATE_X;a++) { for(int b = 0;b<COORDINATE_Y;b++) { mines[a][b] = '.'; masks[a*COORDINATE_Y+b].x = a; masks[a*COORDINATE_Y+b].y = b; masks[a*COORDINATE_Y+b].isshow = false; masks[a*COORDINATE_Y+b].isblank = false; } } srand(time(NULL)); int cc=MINE_NUMBER,aa[1000],bb[1000],ii=0,jj=0; while(cc--)//生成随机地雷坐标 { aa[++ii]=rand()%(0-COORDINATE_X); bb[++jj]=rand()%(0-COORDINATE_Y); mines[aa[ii]][bb[jj]] = '*'; //masks[aa[ii]*y + bb[jj]].isshow = true; } } void SetMinesShow() { for(int cc = 0;cc<500;cc++) { masks[cc].isshow = true; } } void FreshScrean() { system("CLS"); //printf(" "); for(int c = 0;c<=COORDINATE_Y;c++) { printf("%3d",c); } printf("\n"); printf("\n"); for(int i = 0;i<COORDINATE_X;i++) { printf("%3d",i+1); for(int j = 0;j<COORDINATE_Y;j++) { if(masks[i*COORDINATE_Y+j].isshow == true) { printf("%3c",mines[i][j]); } // else if(mines[i][j] == '*') // { // printf("%3c",'*'); // // } else { printf("%3c",'.'); } } printf("\n"); printf("\n"); } } int CheckSingle(int x,int y,bool needcharge) { bool bFind = false; int count = 0; coor coor_xy[9] = {{x-1,y-1},{x-1,y},{x-1,y+1}, {x,y-1},{x,y},{x,y+1}, {x+1,y-1},{x+1,y},{x+1,y+1} }; for (int i = 0;i<9;i++)//取雷个数 { if( coor_xy[i].x >=0 && coor_xy[i].x<COORDINATE_X && coor_xy[i].y >=0 && coor_xy[i].y<COORDINATE_Y && mines[coor_xy[i].x][coor_xy[i].y] == '*') { count ++; bFind = true; if(needcharge) { if(i == 3)g_Llimet = true; if(i == 5)g_Rlimet = true; } } } if((!bFind) && needcharge)//没有发现边上有雷,则该点是空白点,周围的点都该展示出来 { for (int j = 0;j<9;j++) { if( coor_xy[j].x >=0 && coor_xy[j].x<COORDINATE_X && coor_xy[j].y >=0 && coor_xy[j].y<COORDINATE_Y && mines[coor_xy[j].x][coor_xy[j].y] != '*') { masks[coor_xy[j].x*COORDINATE_Y+coor_xy[j].y].isshow = true; masks[coor_xy[j].x*COORDINATE_Y+coor_xy[j].y].isblank = true; } } } return count; } int ccc = 0; void CheckLogic(int coor_x,int coor_y) { int realCoor_x = coor_x -1; int realCoor_y = coor_y -1; int imin = realCoor_y; int imax = realCoor_y; int icount = 0; char num[2] = {'0'}; // -- new test. if(coor_x ==xx && coor_y == yy && mines[realCoor_x][realCoor_y] != '*' )//选择的点无论如何展示出来 { //加上!= ‘*’的条件是递归可能会扫到该点,导致是雷也展示 masks[realCoor_x*COORDINATE_Y+realCoor_y].isshow = true; } --以下两个while遍历一行,一个往左,一个往右。 while('0'==num[0] && realCoor_y - icount >=0) { sprintf(num,"%d",CheckSingle(realCoor_x,realCoor_y-icount,true)); if('0'!=num[0] ) { icount ++; if(mines[realCoor_x][realCoor_y-icount+1] != '*' && (mines[realCoor_x][realCoor_y-icount+1] <'0' || mines[realCoor_x][realCoor_y-icount+1] >'8')) mines[realCoor_x][realCoor_y-icount+1] = num[0]; if(g_Llimet) { imin --; } if( icount == 0 || g_Llimet || mines[realCoor_x][realCoor_y-icount+1] != '*') { masks[realCoor_x*COORDINATE_Y+(realCoor_y-icount)+1].isshow = true; } break; } else { if(mines[realCoor_x][realCoor_y-icount] != '*' && mines[realCoor_x][realCoor_y-icount] == '.') mines[realCoor_x][realCoor_y-icount] = ' '; imin --; icount ++; } } if(imin <0)imin=0; int temmp =icount; g_Llimet = false; icount = 1; num[0] = '0'; while(('0'==num[0]) && temmp >=1 && realCoor_y+icount<=COORDINATE_Y) { sprintf(num,"%d",CheckSingle(realCoor_x,realCoor_y+icount,true)); if('0'!=num[0] ) { if(mines[realCoor_x][realCoor_y+icount] != '*' && (mines[realCoor_x][realCoor_y+icount] <'0' || mines[realCoor_x][realCoor_y+icount] >'8')) mines[realCoor_x][realCoor_y+icount] = num[0]; if(!g_Rlimet) { imax ++; } if( g_Rlimet && mines[realCoor_x][realCoor_y+icount] != '*') { masks[realCoor_x*COORDINATE_Y+(realCoor_y+icount)].isshow = true; } icount ++; break; } else { if(mines[realCoor_x][realCoor_y+icount] != '*' && mines[realCoor_x][realCoor_y+icount] == '.') mines[realCoor_x][realCoor_y+icount] = ' '; imax ++; icount ++; } } if(imax>COORDINATE_Y)imax = COORDINATE_Y; g_Rlimet = false; temmp =icount; icount = 0; // 以下递归调用处理空白区域,借鉴种子填充算法。 /*分上下遍历所有行,如果发现有空白的点,以该点为种子,递归遍历 */ for(int t = imin; t<= imax+1;t++ ) { //往上 if(realCoor_x-1>=0 && realCoor_x-1<xx-1 /*&&temmp>2*/ && masks[(realCoor_x-1-1)*COORDINATE_Y+t].isshow == false) { sprintf(num,"%d",CheckSingle(realCoor_x-1,t,false)); if( masks[(realCoor_x-1)*COORDINATE_Y+t].isblank == true)CheckLogic(realCoor_x,t+1); } //往下 if( realCoor_x+1<=COORDINATE_X-1 && realCoor_x+1>xx-1 /*&&temmp>2*/ && masks[(realCoor_x+1+1)*COORDINATE_Y+t].isshow == false) { sprintf(num,"%d",CheckSingle(realCoor_x+1,t,false)); if( masks[(realCoor_x+1)*COORDINATE_Y+t].isblank == true)CheckLogic(realCoor_x+1+1,t+1); } } recursion ++; return; // } void init() { int len = 0,weidth = 0; int iParam = 0; cout<<"Please select : [1] Start game;[2] Setting"<<endl; cin>>iParam; switch(iParam) { case 1: { initialization(); FreshScrean(); break; } case 2: { cout<<"Please input Length:"<<endl; cin>>COORDINATE_X; cout<<"Please input weidth:"<<endl; cin>>COORDINATE_Y; cout<<"Please input mine's number:"<<endl; cin>>MINE_NUMBER; initialization(); FreshScrean(); break; } default: { initialization(); FreshScrean(); break; } } } int main(int argc, char* argv[]) { init(); while(true) { cout<<"Please input coordinate (x,y).recursion's time:"<<recursion<<endl; recursion = 0; scanf("%d,%d",&xx,&yy); if(xx>COORDINATE_X || xx<0 || yy>COORDINATE_Y || yy<0) { printf("coordinate error! Please input again!\n"); continue; } if(mines[xx-1][yy-1] == '*') { SetMinesShow(); FreshScrean(); printf("\n"); printf("You got a mine,asshole!\n"); printf("Please select : [1] Play again;[2] quit.\n"); int iParam = 0; scanf("%d",&iParam); if(iParam == 1) { init(); continue; } else exit(0); } CheckLogic(xx,yy); FreshScrean(); } return 0; } <span style="FONT-SIZE: 10pt" dir="ltr"></span>
运行效果如下: