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

    }
posted on 2011-06-10 17:06  windfree  阅读(1311)  评论(1编辑  收藏  举报