c#扫雷游戏
一、C#实现扫雷
1、在form中
BombClass bombClass = new BombClass();
/*布雷按钮事件*/
private void initBombBtn_Click(object sender, EventArgs e)
{
bombClass.InitBombData();
bombClass.winHandle = bombPanel.Handle;
bombPanel.Width = bombClass.Width;
bombPanel.Height = bombClass.Height;
bombClass.BombDraw(); //使用方法一画雷盘
//bombClass.DispBomb(); //使用方法二画雷盘
}
/*雷盘的鼠标点击事件:方法一 */
private void bombPanel_MouseClick(object sender, MouseEventArgs e)
{
//获取鼠标点击时的位置
int row = e.Y / (bombClass.CellSize + 1);
int column = e.X / (bombClass.CellSize + 1);
//如果已经点击过了
if (bombClass.BombDataFlag[row, column] == 1)
return;
//可以显示标志
bombClass.BombDataFlag[row, column] = 1;
//如果踩到的方格是数字
if (bombClass.BombData[row, column] > 0)
{
;
}
else if (bombClass.BombData[row, column] == BombClass.BombInt)
{
bombClass.ShowAllBomb();
MessageBox.Show("踩到地雷了!");
return;
}
else if (bombClass.BombData[row, column] == 0)
{
//bombClass.NullDepthFindFirst(row, column);//深度优先搜索
bombClass.NullWidthFindFirst(row, column); //广度优先搜索
}
if (bombClass.CheckFinishFirst())
{
MessageBox.Show("成功!");
bombClass.ShowAllBomb();
}
else
bombClass.BombDraw();
}
/*扫雷panel重绘事件*/
private void bombPanel_Paint(object sender, PaintEventArgs e)
{
if (bombClass.BombStartFlag)
{
if (bombClass.winHandle == null)
bombClass.winHandle = bombPanel.Handle;
bombClass.BombDraw();
}
}
2、扫雷类
public class BombClass
{
#region 参数
/*扫雷是否开始标志*/
public bool BombStartFlag = false;
/*坐标点数据结构*/
public struct point
{
public int row;
public int column;
};
/*雷数*/
public int BombCount;
/*雷数组*/
public int[,] BombData;
/*是否点击的标志*/
public int[,] BombDataFlag;
/*棋子大小*/
public int CellSize = 30;
/*表示地雷的数字*/
public const int BombInt = -2;
public System.IntPtr winHandle;
public int Width;
public int Height;
#endregion
/*初始化雷数组(点击布雷按钮之后才用)*/
public void InitBombData()
{
BombStartFlag = true;
BombCount = 10;
BombData = new int[BombCount, BombCount];
BombDataFlag = new int[BombCount, BombCount]; //是否点击了的标志数组
List<point> bombs = RadomBomb(BombCount);
SetBomb(bombs);
Width = (CellSize + 1) * BombCount + 1;
Height = (CellSize + 1) * BombCount + 1;
}
/*随机数生成雷的位置*/
protected List<point> RadomBomb(int BombCount)
{
List<point> bombs = new List<point>();
for (int i = 0; i < BombCount; i++)
{
Random rad = new Random();
int row = rad.Next(0, BombCount - 1); //行号
int column = rad.Next(0, BombCount - 1); //列号
bool checkFlag = false;
for (int j = 0; j < bombs.Count; j++)
{
if (row == ((point)bombs[j]).row && column == ((point)bombs[j]).column)
{
checkFlag = true;//找到一个相同位置的点
break;
}
}
if (checkFlag)
{
i--; //退一位
continue;
}
else
{
point newPoint = new point() { row = row, column = column };
bombs.Add(newPoint);
}
}
return bombs;
}
/*布雷(以雷为中心访问四周)*/
protected void SetBomb(List<point> bombs)
{
for (int i = 0; i < bombs.Count; i++)
{
point onePoint = bombs[i];
//用-2表示地雷 -1表示已经遍历过的空
BombData[onePoint.row, onePoint.column] = BombInt;
int[] locationRound = GetRoundLocation(onePoint.row, onePoint.column);
for (int j = 0; j < 8; j++)
{
if (locationRound[j * 2] == -1)
break;
else if (BombData[locationRound[j * 2], locationRound[j * 2 + 1]] != BombInt)
BombData[locationRound[j * 2], locationRound[j * 2 + 1]]++;
}
}
}
/*获取四周合法的坐标并返回*/
public int[] GetRoundLocation(int row, int column)
{
//不合法的用-1代替
int[] locationRound = new int[16];
for (int j = 0; j < 16; j++)
{
locationRound[j] = -1;
}
int i = 0;
//左上
if (row - 1 >= 0 && column - 1 >= 0)
{
locationRound[i++] = row - 1;
locationRound[i++] = column - 1;
}
//上
if (row - 1 >= 0)
{
locationRound[i++] = row - 1;
locationRound[i++] = column;
}
//右上
if (row - 1 >= 0 && column + 1 < BombCount)
{
locationRound[i++] = row - 1;
locationRound[i++] = column + 1;
}
//左
if (column - 1 >= 0)
{
locationRound[i++] = row;
locationRound[i++] = column - 1;
}
//右
if (column + 1 < BombCount)
{
locationRound[i++] = row;
locationRound[i++] = column + 1;
}
//左下
if (row + 1 < BombCount && column - 1 >= 0)
{
locationRound[i++] = row + 1;
locationRound[i++] = column - 1;
}
//下
if (row + 1 < BombCount)
{
locationRound[i++] = row + 1;
locationRound[i++] = column;
}
//右下
if (row + 1 < BombCount && column + 1 < BombCount)
{
locationRound[i++] = row + 1;
locationRound[i++] = column + 1;
}
return locationRound;
}
/*使用画图方法:画雷盘一 */
public void BombDraw()
{
Image myImage = new Bitmap(Width, Height);
Graphics g = Graphics.FromImage(myImage);
//画线(正方形的)
for (int i = 0; i <= BombCount; i++)
{
g.DrawLine(new Pen(Color.Black), (CellSize + 1) * i, 0,
(CellSize + 1) * i, Height);
g.DrawLine(new Pen(Color.Black), 0, (CellSize + 1) * i,
Width, (CellSize + 1) * i);
}
//画方格及数字
for (int i = 0; i < BombCount; i++)
{
for (int j = 0; j < BombCount; j++)
{
SolidBrush brush = new SolidBrush(Color.Gold); //默认金色背景画刷
FontFamily fontFamily = new FontFamily("Arial");
Font font = new Font(fontFamily, 16, FontStyle.Regular, GraphicsUnit.Pixel);
string strTemp = ""; //默认需要写的字
//如果已经点击过了,需要处理显示行为
if (BombDataFlag[i, j] == 1)
{
//如果点击到的是大于0的数字
if (BombData[i, j] > 0)
{
brush = new SolidBrush(Color.White);
strTemp = BombData[i, j].ToString();
}
//如果点击到的是空
else if (BombData[i, j] == 0 || BombData[i, j] == -1)
{
brush = new SolidBrush(Color.White);
}
//如果点击到的是地雷
else if (BombData[i, j] == -2)
{
strTemp = "*";
}
}
g.FillRectangle(brush, (CellSize + 1) * j + 1
, (CellSize + 1) * i + 1, CellSize, CellSize);
g.DrawString(strTemp, font, new SolidBrush(Color.Black),
(CellSize + 1) * j + 8, (CellSize + 1) * i + 8);
}
}
Graphics gg = Graphics.FromHwnd(winHandle);
//Graphics gg = bombPanel.CreateGraphics();
gg.DrawImage(myImage, 0, 0);
}
/*踩到空时处理方法(深度优先搜索):方法一*/
public void NullDepthFindFirst(int row, int column)
{
//遍历到空,置为-1
BombData[row, column] = -1;
//获取周围8个坐标位置(有时候四周并不具有8个位置,用-1表示不合法的位置)
int[] eightLocation = GetRoundLocation(row, column);
for (int i = 0; i < 8; i++)
{
//如果要访问的坐标位置不存在
if (eightLocation[i * 2] == -1)
break;
else
{
BombDataFlag[eightLocation[i * 2], eightLocation[i * 2 + 1]] = 1;
if (BombData[eightLocation[i * 2], eightLocation[i * 2 + 1]] == 0)
{
//递归调用
NullDepthFindFirst(eightLocation[i * 2], eightLocation[i * 2 + 1]);
}
}
}
}
/*踩到空时处理方法(广度优先搜索):方法一*/
public void NullWidthFindFirst(int row, int column)
{
BombData[row, column] = -1;
BombDataFlag[row,column] = 1; //可以显示标志
//存放为空的方格坐标的队列
int[] waitCheck = new int[BombCount * BombCount * 2];
for (int k = 0; k < waitCheck.Length; k++)
{
waitCheck[k] = -1;
}
waitCheck[0] = row;
waitCheck[1] = column;
int frontCount = 0; //队头
int backCount = frontCount + 2; //队尾
//队头不等于队尾
while (frontCount != backCount)
{
//置为已经访问过
BombData[waitCheck[frontCount], waitCheck[frontCount + 1]] = -1;
//得到周围8个方位的坐标
int[] eightLocation = GetRoundLocation(waitCheck[frontCount], waitCheck[frontCount + 1]);
//遍历8个方位的坐标,选择可以加入候选队列的坐标
for (int i = 0; i < 8; i++)
{
if (eightLocation[i * 2] == -1)
break;
else
{
BombDataFlag[eightLocation[i * 2], eightLocation[i * 2 + 1]] = 1; //可以显示标志
if (BombData[eightLocation[i * 2], eightLocation[i * 2 + 1]] == 0)
{
BombData[eightLocation[i * 2], eightLocation[i * 2 + 1]] = -1;
//加入候选队列
waitCheck[backCount++] = eightLocation[i * 2];
waitCheck[backCount++] = eightLocation[i * 2 + 1];
}
}
}
frontCount += 2; //队列指针移动
}
}
/*检查扫雷是否完成:方法一*/
public bool CheckFinishFirst()
{
int leftCount = 0; //剩余雷数
for (int i = 0; i < BombCount; i++)
{
bool flag = false;
for (int j = 0; j < BombCount; j++)
{
if (BombDataFlag[i, j] == 0)
{
//未点击且是雷
if (BombData[i, j] == BombInt)
leftCount++;
//为点击且不是雷,直接退出所有循环
else
{
flag = true;
break;
}
}
}
if (flag)
break;
}
if (leftCount == BombCount)
{
return true;
}
else
return false;
}
/*踩到雷时显示所有:方法一*/
public void ShowAllBomb()
{
for (int i = 0; i < BombCount; i++)
{
for (int j = 0; j < BombCount; j++)
{
BombDataFlag[i, j] = 1;
}
}
BombDraw();
}
}
浙公网安备 33010602011771号