一、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(); } }