C#实现扫雷源码

闲来无事,做动手做了个扫雷小游戏供新手学习,扫雷小游戏中主要功能有两个

一个是布雷某个坐标雷区周围的地雷数量,一个是递归空白并显示地雷数量
其他的细节自己注意就没问题了,本程序只是用来学习,其他的bug不做探讨

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DoMine
{
    //by 速分享 http://sulianqi.cn
    public partial class Main : Form
    {
        public Main()
        {
            InitializeComponent();
        }
        
        private void Main_Load(object sender, EventArgs e)
        {
            LoadGame();
        }
        void btnMine_Click(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            DoClickMine(btn);
        }
        private void btnReStart_Click(object sender, EventArgs e)
        {
            Reload();
        }
        int mi = 0;
        private void timer1_Tick(object sender, EventArgs e)
        {
            mi++;
            lbltime.Text = mi.ToString();
        }
        List<Mine> mines = new List<Mine>();//地雷集合

       
        /// <summary>
        /// 初始化游戏界面
        /// 1.根据设定的地图行列及地雷个数生成随机地雷集合
        /// 2.遍历生成地图,同时判断标示地图上的地雷,地雷个数
        /// </summary>
        public void LoadGame()
        {
            int x = Convert.ToInt16(cbX.Text);//行坐标
            int y = Convert.ToInt16(cbY.Text);//纵坐标
            int mine_count = Convert.ToInt16(cbMinecount.Text);//地雷个数
            mines = new List<Mine>();
            mines = CreateMines(x, y, mine_count);//生成随机地雷集合

            int btnx = plMines.Location.X + 5;
            int btny = 5;
            for (int i = 0; i < x; i++)
            {
                for (int j = 0; j < y; j++)
                {
                    Button btn = CreateButton(btnx, btny);
                    btn.Tag = j + "," + i;
                    plMines.Controls.Add(btn);
                    btnx += 40;
                }
                btnx = plMines.Location.X + 5;
                btny += 40;
                Application.DoEvents();
            }
        }
        /// <summary>
        /// 重新开始游戏
        /// </summary>
        public void Reload()
        {
            this.ClientSize = new System.Drawing.Size(Convert.ToInt16(cbY.Text) * 39 + 35, Convert.ToInt16(cbX.Text) * 40 + 60);
            plMines.Controls.Clear();
            plMines.Enabled = true;
            mi = 0;
            LoadGame();
        }
        //创建地雷按钮
        public Button CreateButton(int x, int y)
        {
            Button btnMine = new Button();
            btnMine.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
            btnMine.Location = new System.Drawing.Point(x, y);
            btnMine.Size = new System.Drawing.Size(38, 38);
            btnMine.BackColor = Color.Transparent;
            btnMine.Click += new EventHandler(btnMine_Click);
            btnMine.MouseUp += new MouseEventHandler(btnMine_MouseUp);
            return btnMine;
        }
        //地雷鼠标右键
        void btnMine_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button.ToString().ToUpper() == "RIGHT")
            {
                Button btn = (Button)sender;
                if (btn.Text == "")
                {
                    btn.Text = "★";
                    btn.BackColor = Color.YellowGreen;
                }
                else if (btn.Text == "★")
                {
                    btn.Text = "?";
                    btn.BackColor = Color.Salmon;
                }
                else if (btn.Text == "?")
                {
                    btn.Text = "";
                    btn.BackColor = Color.Transparent;
                }
                IsSuccess();
            }
        }

        /// <summary>
        /// 地雷点击事件,要处理是否点到地雷,
        /// 没点到地雷要把点到的坐标周边的地雷个数显示,
        /// 没地雷的空白区要去掉
        /// </summary>
        /// <param name="curbtn">点击的地雷按钮</param>
        public void DoClickMine(Button curbtn)
        {
            if (curbtn.Text == "★") return;

            if (!timer1.Enabled)
            {
                timer1.Enabled = true;
            }
            int mx = Convert.ToInt16(curbtn.Tag.ToString().Split(',')[0]);
            int my = Convert.ToInt16(curbtn.Tag.ToString().Split(',')[1]);
            Mine m = new Mine(mx, my);
            int countm = GetMinecount(m);


            if (IsMine(m))
            {
                timer1.Enabled = false;//点到炸弹停止计时
                plMines.Enabled = false;//点到炸弹禁用面板

                foreach (Control c in plMines.Controls)
                {
                    if (c is Button)
                    {
                        int mxc = Convert.ToInt16(c.Tag.ToString().Split(',')[0]);
                        int myc = Convert.ToInt16(c.Tag.ToString().Split(',')[1]);
                        Mine mc = new Mine(mxc, myc);
                        if (IsMine(mc))
                        {
                            c.BackColor = Color.Green;
                        }
                    }
                }
                curbtn.Text = countm.ToString() == "-1" ? "" : countm.ToString();
                curbtn.BackColor = Color.Red;
                timer1.Enabled = false;
                DialogResult result = MessageBox.Show(this, "就这么挂了,敢不敢再来一次!", "失败", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk);
                if (result == DialogResult.Yes)
                {
                    Reload();
                }
            }
            else
            {
                if (countm == 0)
                {
                    Removem(m);
                }
                else
                {
                    curbtn.Text = countm.ToString();
                }
                IsSuccess();
            }
        }
        //是否完成游戏
        public void IsSuccess()
        {
            bool Success = false;
            int mcount = 0;
            foreach (Control item in plMines.Controls)
            {
                if (item is Button)
                {
                    if (item.Text == "" || item.Text == "?")
                    {
                        Success = false;
                        break;
                    }
                    if (item.Text == "★")
                    {
                        mcount++;
                    }
                }
            }
            int mine_count = Convert.ToInt16(cbMinecount.Text);//地雷个数
            if (mcount == mine_count)
            {
                Success = true;
            }

            if (Success)
            {
                timer1.Enabled = false;
                DialogResult result = MessageBox.Show(this, "好厉害,你赢了,是否再来一次!", "成功", MessageBoxButtons.YesNo, MessageBoxIcon.Asterisk);
                if (result == DialogResult.Yes)
                {
                    Reload();
                }
            }
        }
        //扫雷点击递归去空白
        public void Removem(Mine m)
        {
            int x = Convert.ToInt16(cbX.Text);//行坐标
            int y = Convert.ToInt16(cbY.Text);//纵坐标

            List<Mine> listResult = new List<Mine>();
            List<Mine> list = new List<Mine>();
            list.Add(m);

            while (list.Count > 0)
            {
                m = list[0];
                if (!CheckMine(listResult, m))
                {
                    listResult.Add(m);
                    Removebtn(m);
                }
                list.Remove(m);

                if (m.X >= 0 & m.X < x && m.Y >= 0 && m.Y < y && GetMinecount(m) == 0)
                {
                    Mine left = new Mine(m.X, m.Y - 1);
                    if (left.Y > -1 && !CheckMine(listResult, left) && GetMinecount(left) == 0) list.Add(left);

                    Mine right = new Mine(m.X, m.Y + 1);
                    if (right.Y < y && !CheckMine(listResult, right) && GetMinecount(right) == 0) list.Add(right);

                    Mine up = new Mine(m.X - 1, m.Y);
                    if (up.X > -1 && !CheckMine(listResult, up) && GetMinecount(up) == 0) list.Add(up);

                    Mine down = new Mine(m.X + 1, m.Y);
                    if (down.X < x && !CheckMine(listResult, down) && GetMinecount(down) == 0) list.Add(down);
                }
                Application.DoEvents();
            }
        }
        //移除空白按钮并显示边界地雷数量
        public void Removebtn(Mine m)
        {
            int x = Convert.ToInt16(cbX.Text);//行坐标
            int y = Convert.ToInt16(cbY.Text);//纵坐标

            Mine up = new Mine(m.X, m.Y - 1);
            Mine down = new Mine(m.X, m.Y + 1);
            Mine left = new Mine(m.X - 1, m.Y);
            Mine right = new Mine(m.X + 1, m.Y);
            if (up.Y > -1)
            {
                Button btnup = GetBtnBytag(up);
                int c = GetMinecount(up);
                btnup.Text = c == 0 ? "" : c.ToString();
            }
            if (down.Y < y)
            {
                Button btndown = GetBtnBytag(down);
                int c = GetMinecount(down);
                btndown.Text = c == 0 ? "" : c.ToString();
            }
            if (left.X > -1)
            {
                Button btnleft = GetBtnBytag(left);
                int c = GetMinecount(left);
                btnleft.Text = c == 0 ? "" : c.ToString();
            }
            if (right.X < x)
            {
                Button btnright = GetBtnBytag(right);
                int c = GetMinecount(right);
                btnright.Text = c == 0 ? "" : c.ToString();
            }
            plMines.Controls.Remove(GetBtnBytag(m));
        }
        //根据tag找按钮
        public Button GetBtnBytag(Mine m)
        {
            Button b = new Button();
            foreach (Control item in plMines.Controls)
            {
                if (item is Button)
                {
                    string tag = item.Tag.ToString();

                    if (tag == m.X + "," + m.Y)
                    {
                        b = (Button)item;
                        break;
                    }
                }
            }
            return b;
        }
        /// <summary>
        /// 四面八方探测地雷个数
        /// </summary>
        /// <param name="m">地雷对象</param>
        /// <returns></returns>
        public int GetMinecount(Mine m)
        {
            int c = 0;
            if (IsMine(m)) return -1;

            Mine up = new Mine(m.X, m.Y - 1);
            Mine down = new Mine(m.X, m.Y + 1);
            Mine left = new Mine(m.X - 1, m.Y);
            Mine right = new Mine(m.X + 1, m.Y);
            Mine lup = new Mine(m.X - 1, m.Y - 1);
            Mine ldown = new Mine(m.X - 1, m.Y + 1);
            Mine rup = new Mine(m.X + 1, m.Y - 1);
            Mine rdown = new Mine(m.X + 1, m.Y + 1);
            if (IsMine(up)) c++;
            if (IsMine(down)) c++;
            if (IsMine(left)) c++;
            if (IsMine(right)) c++;
            if (IsMine(lup)) c++;
            if (IsMine(ldown)) c++;
            if (IsMine(rdown)) c++;
            return c;
        }
        /// <summary>
        /// 探测是否是地雷
        /// </summary>
        /// <param name="m">地雷对象</param>
        /// <returns></returns>
        public bool IsMine(Mine m)
        {
            bool b = false;
            foreach (Mine item in mines)
            {
                if (m.X == item.X && m.Y == item.Y)
                {
                    b = true;
                    break;
                }
            }
            return b;
        }
        /// <summary>
        /// 探测是否存在集合中
        /// </summary>
        /// <param name="m">地雷对象</param>
        /// <returns></returns>
        public bool CheckMine(List<Mine> list, Mine m)
        {
            bool b = false;
            foreach (Mine item in list)
            {
                if (m.X == item.X && m.Y == item.Y)
                {
                    b = true;
                    break;
                }
            }
            return b;
        }
        /// <summary>
        /// 制造地雷
        /// </summary>
        /// <param name="x">地图行数</param>
        /// <param name="y">地图列数</param>
        /// <param name="mine_count">地雷个数</param>
        /// <returns>返回地雷集合</returns>
        public List<Mine> CreateMines(int x, int y, int mine_count)
        {
            List<Mine> mines = new List<Mine>();//地雷集合

            for (int i = 0; i < mine_count; i++)
            {
                int mine_x = new Random(GetRandomSeed()).Next(x);//随机地雷x坐标
                int mine_y = new Random(GetRandomSeed()).Next(y);//随机地雷y坐标
                Mine m = new Mine(mine_x, mine_y);
                //如果包含这个地雷坐标则添加,否则i--再生成一次
                if (!mines.Contains(m))
                    mines.Add(m);
                else
                    i--;
            }
            return mines;
        }
        //生成随机种子
        public int GetRandomSeed()
        {
            byte[] bytes = new byte[4];
            System.Security.Cryptography.RNGCryptoServiceProvider rng = new System.Security.Cryptography.RNGCryptoServiceProvider();
            rng.GetBytes(bytes);
            return BitConverter.ToInt32(bytes, 0);
        }
        //地雷类
        public class Mine
        {
            public Mine(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }
            public int X { get; set; }
            public int Y { get; set; }
        }

    }
}

 扫雷源码