扫雷与编程
Ⅰ C语言如何编程实现扫雷使用WIN-TC或Microsoft Visual C++
我以前写过 很简单。
定义一个2维的数组,然后用rand() 随机布雷,然后计算没有雷的上面的数字。 有雷的定义为-1,没有雷的上面可能是0~8。
算法很简单,剩下的就是绘制界面了。总体不难,为何不自己试试?
Ⅱ 如何用C语言编程 扫雷!~
C语言模拟扫雷的代码如下:
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
int map[9][9] = {0};
int result[9][9] = {0};
int mine[10][2];
bool Check(int i)
{
int j;
for(j=0;j<i;j++)
if(mine[j][0] == mine[i][0] && mine[j][1] == mine[i][0]) return true;
return false;
}
int MineNum(int x,int y) //这个函数计算坐标(x,y)周围地雷的数目
{
int sum = 0;
int i,j;
if(x-1>=0 && x+1<=8 && y-1>=0 && y+1<=8)
{//中间位置
for(i=x-1;i<=x+1;i++)
for(j=y-1;j<=y+1;j++) sum += map[i][j];
return (sum-map[x][y])/9;
}
if(x==0 && y==0) return (map[0][1]+map[1][0]+map[1][1])/9; //左上角
if(x==0 && y==8) return (map[0][7]+map[1][7]+map[1][8])/9; //右上角
if(x==8 && y==0) return (map[7][0]+map[7][1]+map[8][1])/9; //左下角
if(x==8 && y==8) return (map[7][7]+map[7][8]+map[8][7])/9; //右上角
if(x==0)
{//上边界
for(i=x;i<=x+1;i++)
for(j=y-1;j<=y+1;j++) sum += map[i][j];
return (sum-map[x][y])/9;
}
if(x==8)
{//下边界
for(i=x-1;i<=x;i++)
for(j=y-1;j<=y+1;j++) sum += map[i][j];
return (sum-map[x][y])/9;
}
if(y==0)
{//左边界
for(i=x-1;i<=x+1;i++)
for(j=y;j<=y+1;j++) sum += map[i][j];
return (sum-map[x][y])/9;
}
if(y==8)
{//右边界
for(i=x-1;i<=x+1;i++)
for(j=y-1;j<=y;j++) sum += map[i][j];
return (sum-map[x][y])/9;
}
}
void main()
{
int i,j,x,y;
srand((int)time(0));
for(i=0;i<10;i++)
{
do{
mine[i][0] = rand()%9;
mine[i][1] = rand()%9;
}while(Check(i));
printf("%d\t%d\n",mine[i][0],mine[i][1]);
}
//标识地雷
for(i=0;i<10;i++) map[mine[i][0]][mine[i][1]] = 9;
//计算地雷的数目
for(i=0;i<9;i++)
{
for(j=0;j<9;j++)
{
if(map[i][j] == 9) result[i][j] = 9;
else result[i][j] = MineNum(i,j);
printf("%d ",result[i][j]);
}
printf("\n");
}
}
Ⅲ 关于扫雷程序设计
可以实现:
(1) 定义一个雷区结构体,存放当前雷区有无雷,周边有几个雷区有雷,用户标识有雷标志;
踩开标志;
(2) 定义一个二维 雷区 数组,描述 雷场;
(3) 定义二个变量,保存当前 排雷的 区域(行,列);其它变量(计时,计分,计雷数等)根据需要定义;
(4) 初始化,生成雷场;雷区显示方式为未排雷;
(5) 循环
显示雷场;
扫描用户输入(用KBHIT);
如果是光标键,改变当前排雷区域;如果是回车键,设定当前雷场踩开标志;(无雷->踩开同时周边无雷区域一并踩开,有雷->结束);如果是空格, 标识有雷或取消标识;
如果未排开雷区数等于总雷数,游戏结束,显示用户成绩;
(6)根据用户选择,到(4)重新开始 或退出程序。
如果用图形界面,初学者可以VB,想一步到位就用VC;装个Visual Studio 6 或 2010 就行。
Ⅳ 关于编程,扫雷的算法问题,求教~~~
点下去空白自动出现可以根据递归来算,找每个格子周围是否有空白,有就递归。。。
Ⅳ 扫雷编程
事实上Win的原版扫雷是点击第一次之后再随机布置的.而且按合理性来说理应如此.但是不排除其他的扫雷游戏会一开始就确定局势.
Ⅵ c程序编程扫雷
希望对你有帮助!
#include <graphics.h>
#include <stdlib.h>
#include <dos.h>
#define LEFTPRESS 0xff01
#define LEFTCLICK 0xff10
#define LEFTDRAG 0xff19
#define MOUSEMOVE 0xff08
int num[10][10];/*范围*/
int p[10][10];/*统计雷的数组*/
int loop;/*重新来的标志*/
int again=0;/*是否重来的变量*/
int scorenum;/*一开始统计有几个雷*/
char score[3];/*输出一共有几个地雷*/
int Keystate;
int MouseExist;
int MouseButton;
int MouseX;
int MouseY;
/*鼠标光标形状定义*/
typedef struct
{
unsigned int shape[32];
char hotx;
char hoty;
}SHAPE;
/*箭头型*/
SHAPE ARROW={
{
0x3fff,0x1fff,0x0fff,0x07ff,
0x03ff,0x01ff,0x00ff,0x007f,
0x003f,0x00ff,0x01ff,0x10ff,
0x30ff,0xf87f,0xf87f,0xfc3f,
0x0000,0x7c00,0x6000,0x7000,
0x7800,0x7c00,0x7e00,0x7f00,
0x7f80,0x7e00,0x7c00,0x4600,
0x0600,0x0300,0x0300,0x0180
},
0,0,
};
/*鼠标光标显示*/
void MouseOn()
{
_AX=0x01;
geninterrupt(0x33);
}
/*鼠标光标掩示*/
void MouseOff()/*鼠标光标隐藏*/
{
_AX=0x02;
geninterrupt(0x33);
}
void MouseSetXY(int x,int y)/*设置当前位置*/
{
_CX=x;
_DX=y;
_AX=0x04;
geninterrupt(0x33);
}
int LeftPress()/*左键按下*/
{
_AX=0x03;
geninterrupt(0x33);
return(_BX&1);
}
void MouseGetXY()/*得到当前位置*/
{
_AX=0x03;
geninterrupt(0x33);
MouseX=_CX;
MouseY=_DX;
}
begain()/*游戏开始画面*/
{
int i,j;
loop: cleardevice();
MouseOn();
MouseSetXY(180,30);
MouseX=180;
MouseY=30;
scorenum=0;
setfillstyle(SOLID_FILL,7);
bar(190,60,390,290);
setfillstyle(SOLID_FILL,8);
for(i=100;i<300;i+=20)/*画格子*/
for(j=200;j<400;j+=20)
bar(j-8,i+8,j+8,i-8);
setcolor(7);
setfillstyle(SOLID_FILL,YELLOW);/*画脸*/
fillellipse(290,75,10,10);
setcolor(YELLOW);
setfillstyle(SOLID_FILL,0);
fillellipse(285,75,2,2);
fillellipse(295,75,2,2);
setcolor(0);
bar(287,80,293,81);
randomize();
for(i=0;i<10;i++)
for(j=0;j<10;j++)
{
num[i][j]=random(7)+10;/*用10代表地雷算了*/
if(num[i][j]==10)
scorenum++;
}
sprintf(score,"%d",scorenum);
setcolor(1);
settextstyle(0,0,2);
outtextxy(210,70,score);
scorenum=100-scorenum;/*为了后面判断胜利*/
}
gameove()/*游戏结束画面*/
{
int i,j;
setcolor(0);
for(i=0;i<10;i++)
for(j=0;j<10;j++)
if(num[i][j]==10)/*是地雷的就显示出来*/
{
setfillstyle(SOLID_FILL,RED);
bar(200+j*20-8,100+i*20-8,200+j*20+8,100+i*20+8);
setfillstyle(SOLID_FILL,0);
fillellipse(200+j*20,100+i*20,7,7);
}
}
int tongji(int i,int j)/*计算有几个雷*/
{
int x=0;/*10代表地雷*/
if(i==0&&j==0)
{
if(num[0][1]==10)
x++;
if(num[1][0]==10)
x++;
if(num[1][1]==10)
x++;
}
else if(i==0&&j==9)
{
if(num[0][8]==10)
x++;
if(num[1][9]==10)
x++;
if(num[1][8]==10)
x++;
}
else if(i==9&&j==0)
{
if(num[8][0]==10)
x++;
if(num[9][1]==10)
x++;
if(num[8][1]==10)
x++;
}
else if(i==9&&j==9)
{
if(num[9][8]==10)
x++;
if(num[8][9]==10)
x++;
if(num[8][8]==10)
x++;
}
else if(j==0)
{
if(num[i][j+1]==10)
x++;
if(num[i+1][j]==10)
x++;
if(num[i-1][j]==10)
x++;
if(num[i-1][j+1]==10)
x++;
if(num[i+1][j+1]==10)
x++;
}
else if(j==9)
{
if(num[i][j-1]==10)
x++;
if(num[i+1][j]==10)
x++;
if(num[i-1][j]==10)
x++;
if(num[i-1][j-1]==10)
x++;
if(num[i+1][j-1]==10)
x++;
}
else if(i==0)
{
if(num[i+1][j]==10)
x++;
if(num[i][j-1]==10)
x++;
if(num[i][j+1]==10)
x++;
if(num[i+1][j-1]==10)
x++;
if(num[i+1][j+1]==10)
x++;
}
else if(i==9)
{
if(num[i-1][j]==10)
x++;
if(num[i][j-1]==10)
x++;
if(num[i][j+1]==10)
x++;
if(num[i-1][j-1]==10)
x++;
if(num[i-1][j+1]==10)
x++;
}
else
{
if(num[i-1][j]==10)
x++;
if(num[i-1][j+1]==10)
x++;
if(num[i][j+1]==10)
x++;
if(num[i+1][j+1]==10)
x++;
if(num[i+1][j]==10)
x++;
if(num[i+1][j-1]==10)
x++;
if(num[i][j-1]==10)
x++;
if(num[i-1][j-1]==10)
x++;
}
return(x);
}
funcheck(int i,int j)/*开始找无雷*/
{
scorenum--;
if(p[i][j]==0&&num[i][j]!=10)
{
setfillstyle(SOLID_FILL,7);/*显示无雷区*/
bar(200+j*20-7,100+i*20-7,200+j*20+7,100+i*20+7);
num[i][j]=-1;
}
else if(p[i][j]!=0)
{
sprintf(score,"%d",p[i][j]);/*输出雷数*/
setcolor(RED);
outtextxy(195+j*20,95+i*20,score);
num[i][j]=-1;
return ;
}
if(i!=0&&num[i-1][j]!=-1&&num[i-1][j]!=10)/*第归开始*/
funcheck(i-1,j);
if(i!=0&&j!=9&&num[i-1][j+1]!=-1&&num[i-1][j+1]!=10)
funcheck(i-1,j+1);
if(j!=9&&num[i][j+1]!=-1&&num[i][j+1]!=10)
funcheck(i,j+1);
if(j!=9&&i!=9&&num[i+1][j+1]!=-1&&num[i+1][j+1]!=10)
funcheck(i+1,j+1);
if(i!=9&&num[i+1][j]!=-1&&num[i+1][j]!=10)
funcheck(i+1,j);
if(i!=9&&j!=0&&num[i+1][j-1]!=-1&&num[i+1][j-1]!=10)
funcheck(i+1,j-1);
if(j!=0&&num[i][j-1]!=-1&&num[i][j-1]!=10)
funcheck(i,j-1);
if(i!=0&&j!=0&&num[i-1][j-1]!=-1&&num[i-1][j-1]!=10)
funcheck(i-1,j-1);
}
playgame()/*游戏过程*/
{int i,j,numx;
for(i=0;i<10;i++)
for(j=0;j<10;j++)
p[i][j]=tongji(i,j);/*把标记有几个雷的数字都存放起来*/
while(!kbhit())
{
if(LeftPress())/*左键盘按下*/
{
MouseGetXY();
if(MouseX>280&&MouseX<300&&MouseY>65&&MouseY<85)/*重新来*/
{
MouseOff();
again=1;
break;
}
if(MouseX>190&&MouseX<390&&MouseY>90&&MouseY<290)/*是否在游戏范围内*/
{
j=(MouseX-190)/20;/*x坐标*/
i=(MouseY-90)/20;/*y坐标*/
if(num[i][j]!=-1)
{
if(num[i][j]==10)/*中雷*/
{
MouseOff();
gameove();/*失败*/
break;
}
else/*非中雷*/
{
MouseOff();
numx=tongji(i,j);
if(numx==0)/*周围没地雷*/
funcheck(i,j);/*开始找无雷*/
else/*有地雷*/
{
sprintf(score,"%d",numx);/*输出雷数*/
setcolor(RED);
outtextxy(195+j*20,95+i*20,score);
scorenum--;
}
MouseOn();
num[i][j]=-1;
if(scorenum<1)/*胜利了*/
{
setcolor(11);
settextstyle(0,0,2);
outtextxy(230,30,"YOU WIN!");
break;
}
}
}
}
}
}
}
main()
{int gd=DETECT,gr;
registerbgidriver(EGAVGA_driver);
initgraph(&gd,&gr,"c:\\tc");
loop: begain();
playgame();/*具体游戏*/
if(again)/*游戏中重新开始*/
{
again=0;
goto loop;
}
MouseOn();
while(!kbhit())/*重新来*/
{
if(LeftPress())
{
MouseGetXY();/*失败后重新来*/
if(MouseX>280&&MouseX<300&&MouseY>65&&MouseY<85)
goto loop;
}
}
MouseOff();
closegraph();
}
本文来自: 中科软件园(www.4oa.com) 详细出处参考:http://www.4oa.com/Article/html/6/31/446/2005/15615.html
Ⅶ 扫雷的VB编程
Private Sub Form_Load()Init_FormEnd Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)Dim x1 As Integer, y1 As Integerx1 = Fix((x - x0) / a): y1 = Fix((y - y0) / a)If (x - x0) > ((Col_Num + 1) * a) Or (y - y0) > ((Col_Num + 1) * a) Then Exit SubIf x < x0 Or y < y0 Then Exit SubIf x < x0 + x1 * a + 2 Or _x > x0 + x1 * a + a - 4 Or _y < y0 + y1 * a + 2 Or _y > y0 + y1 * a + a - 4 _Then Exit SubIf Button = 1 ThenIf Map(x1, y1) = 0 ThenCall fan(x1, y1)ElseIf Map(x1, y1) = 1 ThenCall loseEnd IfElseIf Button = 2 ThenCall draw_flg(x1, y1)End IfDim n As Integern = 0Dim i As Integer, j As IntegerFor i = 0 To Col_NumFor j = 0 To Row_NumIf Map(i, j) = -2 Then n = n + 1Next jNext iIf n = (Col_Num + 1) * (Row_Num + 1) - Ant_Num ThenBeepCurrentX = (Col_Num / 2) * a + x0CurrentY = (Row_Num / 2) * a + y0Call sub1a = Form1.FontSizeForm1.FontSize = 80'Form1.ForeColor = vbBlackPrint "you win"Form1.FontSize = aEnd IfEnd Sub
Sub fan(x As Integer, y As Integer)Dim i As Integer, j As IntegerDim n As IntegerFor i = -1 To 1For j = -1 To 1If j * i = 0 And Map(x + i, y + j) = 0 ThenMap(x + i, y + j) = -2n = Counts(x + i, y + j)Form1.Line (x0 + (i + x) * a + 2, y0 + (j + y) * a + 2)-Step(a - 4, a - 4), Form1.BackColor, BF
If n <> 0 ThenCurrentX = (x + i) * a + 2 + x0CurrentY = (y + j) * a + 2 + y0Select Case nCase Is = 1Form1.ForeColor = vbWhiteCase Is = 2Form1.ForeColor = vbYellowCase Is > 2Form1.ForeColor = vbRedEnd SelectPrint nElseIf n = 0 Then
Call fan(x + i, y + j)End IfEnd IfNext jNext iEnd Sub
Function Counts(x As Integer, y As Integer) As IntegerDim i As Integer, j As IntegerFor i = -1 To 1For j = -1 To 1If Map(x + i, y + j) = 1 Then Counts = Counts + 1NextNextEnd FunctionSub lose()Dim i As Integer, j As IntegerFor i = 0 To Row_NumFor j = 0 To Col_NumIf Map(j, i) = 1 ThenForm1.FillColor = vbBlackForm1.FillStyle = 0Form1.Circle (x0 + j * a + a / 2, y0 + i * a + a / 2), a / 3, vbBlack, , , 0.8Form1.Line (x0 + j * a, y0 + i * a)-Step(a, a), vbWhiteForm1.Line (x0 + j * a + a, y0 + i * a)-Step(-a, a), vbWhite
ElseIf Map(j, i) = 0 ThenForm1.Line (x0 + j * a + 2, y0 + i * a + 2)-Step(a - 4, a - 4), Form1.BackColor, BFCurrentX = j * a + x0CurrentY = i * a + y0Print Counts(j, i)End IfNext j
Next iBeepa = Form1.FontSizeForm1.FontSize = 80'Form1.ForeColor = vbBlackPrint "you lose"Form1.FontSize = aEnd SubSub draw_flg(x As Integer, y As Integer)CurrentX = x * a + x0 + 2CurrentY = y * a + y0 + 2Print "?"End Sub
Public Sub Init_Form()
Form1.ClsForm1.ScaleMode = 3Form1.Width = 8000Form1.Height = 6000Form1.BackColor = vbGreenForm1.AutoRedraw = Trueform1.caption="一个简单扫雷游戏 "Col_Num = 10 '获取列数Row_Num = 10 '获取行数a = 20 '单元宽(高)度Ant_Num = 40 '雷的数量ReDim Map(-1 To Col_Num + 1, -1 To Row_Num + 1)Dim i As Integer, j As IntegerFor i = -1 To Row_Num + 1
For j = -1 To Col_Num + 1Form1.Line (x0 + j * a, y0 + i * a)-Step(a, a), 0, BForm1.Line (x0 + j * a + 2, y0 + i * a + 2)-Step(a - 4, a - 4), vbRed, BFMap(j, i) = 0 '初始化位置标记为空格0If i = -1 Or i = Row_Num + 1 Or j = -1 Or j = Row_Num + 1 ThenForm1.Line (x0 + j * a + 1, y0 + i * a + 1)-Step(a - 2, a - 2), RGB(100, 120, 100), BF '画四周墙体Map(j, i) = -1 '四周位置标记为墙体:-1End IfNext j
Next iDim x As Integer, y As IntegerFor i = 1 To Ant_Num1000Randomizex = Rnd * Col_Numy = Rnd * Row_NumDoEventsIf Map(x, y) <> 0 Then GoTo 1000Map(x, y) = 1NextEnd Sub
Sub sub1()
Dim i As Integer, j As IntegerFor i = 0 To Row_NumFor j = 0 To Col_NumIf Map(j, i) = 1 ThenForm1.FillColor = vbBlackForm1.FillStyle = 0Form1.Circle (x0 + j * a + a / 2, y0 + i * a + a / 2), a / 3, vbBlack, , , 0.8ElseIf Map(j, i) = 0 ThenForm1.Line (x0 + j * a + 2, y0 + i * a + 2)-Step(a - 4, a - 4), Form1.BackColor, BFCurrentX = j * a + x0CurrentY = i * a + y0Print Counts(j, i)End IfNext j
Next iEnd Sub
Ⅷ 用c++builder编程扫雷程序流程是什么应该怎么开始呢
发一个人家的程序思想:
扫雷程序思想讲解
在我大二的时候就编写了一个扫雷程序,现在也有很多
源程序下载,我不知道他们的算法是怎么样的,但我想我的
算法应是最清晰和简单的。下面就来讲解我的扫雷程序思想。
首先我们在雷区上随机地放上雷,没有雷的地方被点击
后就会显示一个数字表示它周围有几个雷,这是怎么实现的
呢?我们可以把整个雷区看成一个二维数组a[i,j],如雷区:
11 12 13 14 15 16 17 18
21 22 23 24 25 26 27 28
31 32 33 34 35 36 37 38
41 42 43 44 45 46 47 48
51 52 53 54 55 56 57 58
我要知道a[34]周围有几个雷,就只有去检测
a[23],a[24],a[25]
a[33], a[35]
a[43],a[44],a[45]
这8个雷区是否放上了雷,仔细观察它们成在数学关系。
抽象出来就是:a[i,j]的雷的个数就是由
a[i-1,j-1],a[i-1,j],a[i-1,j+1]
a[ i ,j-1], a[ i ,j+1]
a[i+1,j-1],a[i+1,j],a[i+1,j+1]
(如果超出边界再加以判断)
这样的8个雷区决定的。
扫雷程序还会自动展开已确定没有雷的雷区。如果
a[3,4]周围雷数为1,a[2,3]已被标示为地雷,那么
a[24],a[25],a[33],a[35],a[43],a[44],a[45]
将被展开,一直波及到不可确定的雷区。这也是实现的
关键。我们可以把数组的元素设定为一个类对象,它们
所属的类
Ⅸ 用VB编程实现扫雷的思路
'一个简单扫雷游戏
Option Explicit
Dim Map() As Integer
Dim Row_Num, Col_Num As Integer '范围,一个正方形的边长
Dim Ant_Num As Long '白蚁数量
Const x0 = 30 '方框左上角坐标
Const y0 = 30
Const 小快宽度 = 9
Dim a As Integer '各个小块的边长
Private Sub Command1_Click()
'重设按钮
Init_Form
End Sub
Private Sub Form_Load()
Init_Form
End Sub
Private Sub Form_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single)
Dim x1 As Integer, y1 As Integer
x1 = Fix((x - x0) / a): y1 = Fix((y - y0) / a)
If (x - x0) > ((Col_Num + 1) * a) Or (y - y0) > ((Col_Num + 1) * a) Then Exit Sub
If x < x0 Or y < y0 Then Exit Sub
If x < x0 + x1 * a + 2 Or _
x > x0 + x1 * a + a - 4 Or _
y < y0 + y1 * a + 2 Or _
y > y0 + y1 * a + a - 4 _
Then Exit Sub
If Button = 1 Then
If Map(x1, y1) = 0 Then
Call fan(x1, y1)
ElseIf Map(x1, y1) = 1 Then
Call lose
End If
ElseIf Button = 2 Then
Call draw_flg(x1, y1)
End If
Dim n As Integer
n = 0
Dim i As Integer, j As Integer
For i = 0 To Col_Num
For j = 0 To Row_Num
If Map(i, j) = -2 Then n = n + 1
Next j
Next i
If n = (Col_Num + 1) * (Row_Num + 1) - Ant_Num Then
Beep
CurrentX = (Col_Num / 2) * a + x0
CurrentY = (Row_Num / 2) * a + y0
Call sub1
a = Form1.FontSize
Form1.FontSize = 80
'Form1.ForeColor = vbBlack
Print "you win"
Form1.FontSize = a
End If
End Sub
Sub fan(x As Integer, y As Integer)
Dim i As Integer, j As Integer
Dim n As Integer
For i = -1 To 1
For j = -1 To 1
If j * i = 0 And Map(x + i, y + j) = 0 Then
Map(x + i, y + j) = -2
n = Counts(x + i, y + j)
Form1.Line (x0 + (i + x) * a + 2, y0 + (j + y) * a + 2)-Step(a - 4, a - 4), Form1.BackColor, BF
If n <> 0 Then
CurrentX = (x + i) * a + 2 + x0
CurrentY = (y + j) * a + 2 + y0
Select Case n
Case Is = 1
Form1.ForeColor = vbWhite
Case Is = 2
Form1.ForeColor = vbYellow
Case Is > 2
Form1.ForeColor = vbRed
End Select
Print n
ElseIf n = 0 Then
Call fan(x + i, y + j)
End If
End If
Next j
Next i
End Sub
Function Counts(x As Integer, y As Integer) As Integer
Dim i As Integer, j As Integer
For i = -1 To 1
For j = -1 To 1
If Map(x + i, y + j) = 1 Then Counts = Counts + 1
Next
Next
End Function
Sub lose()
Dim i As Integer, j As Integer
For i = 0 To Row_Num
For j = 0 To Col_Num
If Map(j, i) = 1 Then
Form1.FillColor = vbBlack
Form1.FillStyle = 0
Form1.Circle (x0 + j * a + a / 2, y0 + i * a + a / 2), a / 3, vbBlack, , , 0.8
Form1.Line (x0 + j * a, y0 + i * a)-Step(a, a), vbWhite
Form1.Line (x0 + j * a + a, y0 + i * a)-Step(-a, a), vbWhite
ElseIf Map(j, i) = 0 Then
Form1.Line (x0 + j * a + 2, y0 + i * a + 2)-Step(a - 4, a - 4), Form1.BackColor, BF
CurrentX = j * a + x0
CurrentY = i * a + y0
Print Counts(j, i)
End If
Next j
Next i
Beep
a = Form1.FontSize
Form1.FontSize = 80
'Form1.ForeColor = vbBlack
Print "you lose"
Form1.FontSize = a
End Sub
Sub draw_flg(x As Integer, y As Integer)
CurrentX = x * a + x0 + 2
CurrentY = y * a + y0 + 2
Print "?"
End Sub
Public Sub Init_Form()
Form1.Cls
Form1.ScaleMode = 3
Form1.Width = 8000
Form1.Height = 6000
Form1.BackColor = vbGreen
Form1.AutoRedraw = True
Form1.Caption = "一个简单扫雷游戏 作者 zfc"
Col_Num = 10 '获取列数
Row_Num = 10 '获取行数
a = 20 '单元宽(高)度
Ant_Num = 40 '雷的数量
ReDim Map(-1 To Col_Num + 1, -1 To Row_Num + 1)
Dim i As Integer, j As Integer
For i = -1 To Row_Num + 1
For j = -1 To Col_Num + 1
Form1.Line (x0 + j * a, y0 + i * a)-Step(a, a), 0, B
Form1.Line (x0 + j * a + 2, y0 + i * a + 2)-Step(a - 4, a - 4), vbRed, BF
Map(j, i) = 0 '初始化位置标记为空格0
If i = -1 Or i = Row_Num + 1 Or j = -1 Or j = Row_Num + 1 Then
Form1.Line (x0 + j * a + 1, y0 + i * a + 1)-Step(a - 2, a - 2), RGB(100, 120, 100), BF '画四周墙体
Map(j, i) = -1 '四周位置标记为墙体:-1
End If
Next j
Next i
Dim x As Integer, y As Integer
For i = 1 To Ant_Num
1000
Randomize
x = Rnd * Col_Num
y = Rnd * Row_Num
DoEvents
If Map(x, y) <> 0 Then GoTo 1000
Map(x, y) = 1
Next
End Sub
Sub sub1()
Dim i As Integer, j As Integer
For i = 0 To Row_Num
For j = 0 To Col_Num
If Map(j, i) = 1 Then
Form1.FillColor = vbBlack
Form1.FillStyle = 0
Form1.Circle (x0 + j * a + a / 2, y0 + i * a + a / 2), a / 3, vbBlack, , , 0.8
ElseIf Map(j, i) = 0 Then
Form1.Line (x0 + j * a + 2, y0 + i * a + 2)-Step(a - 4, a - 4), Form1.BackColor, BF
CurrentX = j * a + x0
CurrentY = i * a + y0
Print Counts(j, i)
End If
Next j
Next i
End Sub
Ⅹ 如何用C++写扫雷
用VC++编写扫雷游戏
用VC++编写扫雷游戏
王洪亚
本文从分析windows扫雷游戏的功能特点开始,应用面向对象的可视化编程语言visual c++给出了个功能模块的具体实现方法,并提供了编写小游戏程序的一般方法和visual c++的一些使用技巧。
首先分析扫雷的最基本功能。
点击鼠标左键于未知区域,如果未知区域有雷,游戏停止,显示所有的地雷。如果没雷,则显示周围雷数,如果周围没雷,则再查看周围八个区域是否有雷直到有雷为止并显示,这其实是一个递归过程。
点击鼠标右键于未知区域,则将其置为有雷而不管是否真的有雷。可选择初、中、高三级并可自定义雷数和区域大小。
雷区上部左侧显示总雷数减被标明有雷区域的数目。
雷区上部中间位置显示一按钮用于开局和显示鼠标动作的结果。
雷区上部右侧显示扫雷的时间。
将雷全部扫清后,则显示一对话框将你的姓名记入排行榜。以时间排序。
为完成上述功能,应用visual c++的具体技术细节如下:
1. 应用appwizard创建基于sdi的应用程序cbombapp,去除打印和状态条支持,在资源编辑器中修改菜单和相应的加速键,使其与windows扫雷游戏一致。具体为开局(id-game-begin)、初级(id-game-junior)、中级(id-game-middle)、高级(id-game-senior)、自定义(id-game-custom)、颜色(id-game-color)、英雄榜(id-game-sort)、退出(id-game-exit)、帮助(id-help)。
2. 在资源编辑器中对应于雷区的每个小区域的13个属性。用画笔或其他绘图工具绘制出相对应的13个10乘10的16色小位图,三个对应于小人表情的20乘20的16色小位图,供更换颜色时使用的一套与前16个对应的单色位图,显示时间和雷数的0~9十个数字位图(底色为黑色)。
定制customer对话框,内含三个静态文本控件和三个编辑控件,三个编辑控件分别对应成员m_irownum,m_icolumnnum,m_ibombnum。该对话框用于定制雷数,行列数,其相应的mfc类为ccustomer。定制sort对话框,内含九个静态文本控件,其中六个显示排行榜的姓名和时间,其对应的mfc类为csort。定制input对话框,内含一个静态文本控件和一个编辑控件,编辑控件用于在游戏成功结束时输入姓名,其对应的mfc类为cinput。
3. 定义类bomb,封装每颗雷的相关属性。
class bomb
{
public:
int isbomb;//决定初始时是否是雷
bool issel; //判断区域是否被处理过且周围有雷
bool isdone;//判断递归时是否被处理过
int num; //周围雷数
bool findbomb; //排雷者认为是雷时置一(但是不一定真是雷)
} ;
4. 重载cmainframe中precreatewindow,并设置相应属性,使其窗体大小固定,这样就固定了显示区域的大小为初始10乘10个雷和外加雷区上部的控制区域,部分代码如下。
cs.style=ws_overlapped|ws_sysmenu| ws_border|ws_minimizebox;
cs.cy = 10*15+6;
cs.cx = 10*15+60; //6和60分别是横纵的附加值,用于边框、菜单、标题条、控制区域。
5. 游戏的主要工作就是呈现不断变换的图形或动画,并按用户的输入交互进行显示,而windows文档-----视窗构架中的视窗的功能正是接受用户输入并负责显示,因此由cview类来完成扫雷的大部分工作。在cbombview中定义下列成员变量记录相关操作的结果或对象的状态。
bomb m_bomb[30][30]; //最大的地雷区域
cstring m_currenttime; //用于记录并显示扫雷时间
ctime m_begintime;//记录游戏开始时的时间
bool m_timerbegin;//定时器是否开启
int m_ibomnum;//雷的数目
int m_irow;//雷的行数
int m_icolumn;//雷的列数
int m_ibombfound;//指示被认为是雷的数目
cbitmapbutton m_bitbutton;//控制区的位图按钮
int m_currentlevel;//指示当前游戏的级别
bool m_biscolor;//指示当前是彩色还是单色
cbitmap m_bmbomb[12];//用于存放12个小位图
int m_igameover;//游戏未结束置0,已清除所有的雷置1,被炸死置2。
重载cbombview中oncreate函数创建位图按钮,该位图按钮的两幅位图对应了正常、排雷正确两种状态,当要显示被炸死的状态时应动态销毁该按钮,并重新创建一位图对应正常和被炸死两种状态,将该位图按钮的id号定为id_game_begin,这样一来当点击按钮时便可重新开始游戏,部分代码如下。
crect rcclient;
getclientrect(&rcclient);
crect rect(rcclient.cx/2-8,10,rcclient.cx/2+8,20);
m_button.create("new",bs_defpushbutton|ws_visible|
bs_ownerdraw,rect,this,id_game_begin);
m_button.loadbitmaps(idb_face1, idb_face2);
显示时间的功能相对比较简单,在响应第一个wm_lbuttomdown消息时开启定时器,并记录游戏开始的时间,在wm_time消息响应函数ontimer中获得当前时间,减去游戏开始时的时间,在显示时间的客户区域显示得到的时间差(用数字位图),当游戏结束时(排完全部雷或被炸死)关闭定时器,停止显示。
wm_lbuttomdown消息响应函数onlbuttomdown是处理用户输入的主要执行者,函数首先判断点中位置是否是雷,是则关闭定时器,销毁原位图按钮,创建一对应正常和被炸死两种状态的新位图按钮,并调用setstate将其设置为pushdown(小人哭的状态),将m_bgameover,置为true标志游戏结束,否则先调用setstate 设置位图按钮为pushdown (小人笑的状态),并在onlbuttomup中设置位图按钮为正常状态,然后调用caculate函数记下周围雷的数目,最后调用invalidate使客户区无效,迫使ondraw函数重绘客户区域,在调用invalidate时不应重画背景,避免闪烁,这样就完成了在雷区按下左键的响应动作。
wm_rbuttomdown消息响应函数onlbuttomdown将被认为有雷位置的m_ibombnum.findbomb置一,减少左上角的雷记数,然后判断是否真正全部排完了雷,是则结束游戏弹出input对话框,让扫雷的人输入姓名,在响应idok通知码时将其写入注册表,没有全部排完则使客户区无效,迫使ondraw函数重绘客户区域完成在雷区按下右键的动作。
ondraw函数在每次点击左键或右键时都会被调用重雷区和控制区域,因为点击情况的复杂性和雷属性的多元化导致ondraw函数需要精心设计。
函数caculate计算某个雷周围的雷数,根据前面的分析知道,计算某个雷周围的雷数本身就是一个递归过程,在编制时应注意递归的边界条件,稍不注意会陷入无穷递归而耗尽了系统的资源。
6. 菜单命令的响应是游戏交互的另一个重要方式,下面的九个命令响应函数分别与九个菜单项相对应,用以完成用户的更新和设置命令。
ongamebegin完成初始时间清零,随机布雷,依据颜色指示装载12幅小位图,使雷区无效调用ondraw重绘等工作。其中随机布雷就是多次调用rand(),根据其返回值决定m_bomb[i][j].isbomb的值。
ongamecustom首先弹出ccustomer对话框,在用户输入设置后响应idok通知码时将用户输入的雷数、行列数分别赋给cview的数据成员m_ibombnum、m_irow、m_icolumn,得到框架窗口的指针,用其调用movewindow将窗口调至所需大小,销毁原位置的位图按钮,并在x轴坐标为新窗口宽1/2减8处,y轴坐标为新窗口顶部加30的位置创建一新按钮。最后调用ongamebegin重新开始游戏。
ongamejunior、ongamemiddle、ongamesenior三个函数与ongamecustom类似,只不过将分别赋给cview的数据成员m_ibombnum、m_irow、m_icolumn以固定的值,其大小可由编程者自定,笔者定为junior(20,8,8,)、middle(40,13,13)、senior(99,20,25)。
ongamecolor函数销毁原位图按钮,根据重新装载位图的标志m_iscolor来创建新的位图按钮,将装载12幅单色位图的标志取反,调用ongamebegin重新开始游戏。
ongamesort函数根据当前游戏级别从注册表中读出排名并弹出sort对话框显示结果。到现在为止,一个自己编制的扫雷游戏就基本完成了,将数百行代码编译一下,找出小错误,最后build一遍,run一下,好了,可爱的扫雷游戏就出现在你的面前了。怎么样,自己的劳动成果并不比microsoft的差吧,而且你还可以把小位图画成各种样子,当然你自己要认得出才行了。