欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C#实现内置音乐播放功能的新型扫雷游戏

程序员文章站 2024-03-19 16:47:46
...

程序视频展示链接

http://v.youku.com/v_show/id_XNDA2ODQwODYwNA==.html?spm=a2h3j.8428770.3416059.1

程序描述及代码展示

1、扫雷游戏设计的内容主要包含在两个大类上,即程序代码中的Game类和Square类。Game类表示一局扫雷游戏,其中包含游戏数据,游戏等级,雷区数,布雷方法等等。Square类表示游戏中的一个小方格,小方格中可能埋有地雷。Game类来实现一个游戏实例,Square类则代表一个游戏实例中的元素。用二维数组来保存游戏界面的信息,定义一个二维数组public static Square[,] gameData,游戏界面的宽度和高度即二维数组的第一维和第二维的长度。

2、扫雷游戏设计要求共有四个方面:

 能够实现游戏中雷区和非雷区的分布,且能够在第一次点击时不踩中雷。

 能够实现计时功能,即一局游戏结束时,能给出用户进行这局游戏所花费的时间。

 能实现标记计数功能,即每次鼠标右击方格时,在方格中画一个小旗标记时,主界面中相应的雷数也要减1,而再次点击质疑时,主界面中雷数又要相应的加1。

 当游戏正在进行时,如果用户做任何终止本次游戏的行为,则程序应该能够弹出提示框,询问用户是否继续进行正在进行的游戏,根据用户的选择,执行相应的操作。

2、扫雷程序设计流程:

C#实现内置音乐播放功能的新型扫雷游戏

#主窗口程序

using System;
using System.Windows.Forms;
using System.Media;
namespace SweepingMine
{
    public partial class FormMain : Form
    {
        public Game game1;
        public static int SquareColor;
        public static FormMain fm1 = null;
        public static DateTime beginTime;
        public GameLevel formmerLevel = GameLevel.Beginner;
        public GameLevel nowLevel = GameLevel.Beginner;
        SetSize size = new SetSize();
        public FormMain()
        {
            InitializeComponent();
            fm1 = this;
        }
        /// <summary>
        /// 游戏开局
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 开局NF2ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (userControl12.gameLevel == GameLevel.Customize)
            {
                timer1.Enabled = false;
                this.textBox1.Text = "0";
                textBox2.Text = Properties.Settings.Default.MinesCount.ToString();
                userControl12.NewGameC(userControl12.logicalSize, userControl12.MineCount);
            }
            else
            {
                timer1.Enabled = false;
                this.textBox1.Text = "0";
                userControl12.NewGameL(userControl12.gameLevel);
                switch (userControl12.gameLevel)
                {
                    case GameLevel.Beginner:
                        textBox2.Text = "10";
                        break;
                    case GameLevel.Intermediate:
                        textBox2.Text = "40";
                        break;
                    case GameLevel.Expert:
                        textBox2.Text = "99";
                        break;
                }
            }
        }
        /// <summary>
        /// 游戏等级初级
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 初级BToolStripMenuItem_Click(object sender, EventArgs e)
        {
            nowLevel = GameLevel.Beginner;
            if (timer1.Enabled != false)
            {
                FormTips ft = new FormTips();
                ft.Show();
            }
            else
            {
                userControl12.gameLevel = formmerLevel = GameLevel.Beginner;
                size.GetGameLevel(userControl12.gameLevel);
            }
        }
        /// <summary>
        /// 游戏等级中级
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 中级IToolStripMenuItem_Click(object sender, EventArgs e)
        {
            nowLevel = GameLevel.Intermediate;
            if (timer1.Enabled != false)
            {
                FormTips ft = new FormTips();
                ft.Show();
            }
            else
            {
                userControl12.gameLevel = formmerLevel = GameLevel.Intermediate;
                size.GetGameLevel(userControl12.gameLevel);
            }
        }
        /// <summary>
        /// 游戏等级高级
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 高级EToolStripMenuItem_Click(object sender, EventArgs e)
        {
            nowLevel = GameLevel.Expert;
            if (timer1.Enabled != false)
            {
                FormTips ft = new FormTips();
                ft.Show();
            }
            else
            {
                userControl12.gameLevel = formmerLevel = GameLevel.Expert;
                size.GetGameLevel(userControl12.gameLevel);
            }
        }
        /// <summary>
        /// 自定义游戏设置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 自定义CToolStripMenuItem_Click(object sender, EventArgs e)
        {
            nowLevel = GameLevel.Customize;
            if (timer1.Enabled != false)
            {
                FormCustomize f = new FormCustomize();
                if (f.ShowDialog() == DialogResult.OK)
                {
                    FormTips ft = new FormTips();
                    ft.Show();
                }
            }
            else
            {
                userControl12.gameLevel = formmerLevel = GameLevel.Customize;
                FormCustomize f = new FormCustomize();
                if (f.ShowDialog() != DialogResult.OK)
                    return;
                size.GetGameLevel(userControl12.gameLevel);
            }
        }
        private void 银色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SquareColor = 0;
            userControl12.game.Draw();
        }
        private void 蓝色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SquareColor = 1;
            userControl12.game.Draw();
        }
        private void 粉色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SquareColor = 2;
            userControl12.game.Draw();
        }
        private void 紫色ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SquareColor = 3;
            userControl12.game.Draw();
        }
        /// <summary>
        /// 窗体初始化加载内容设置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_Load(object sender, EventArgs e)
        {
            textBox1.Text = "0";
            textBox2.Text = "10";
            formmerLevel = GameLevel.Beginner;
        }
        /// <summary>
        /// 游戏计时功能
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void timer1_Tick(object sender, EventArgs e)
        {
            try
            {
                this.textBox1.Text = (((int)DateTime.Now.Subtract(beginTime).TotalSeconds) + 1).ToString();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        /// <summary>
        /// 帮助信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 帮助ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("哈哈哈,我就不告诉你怎么玩!!!");
        }
        /// <summary>
        /// 退出游戏系统
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 退出XToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }
        /// <summary>
        /// 播放在线音乐
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 在线播放ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormMusic fmusic_ = new FormMusic();
            fmusic_.Show();
        }
        /// <summary>
        /// 播放本地音乐
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 本地ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FileDialog open = new OpenFileDialog();
            open.Filter = "*.mp3|*.mp3";
            open.Title = "打开文件";
            if (open.ShowDialog() == DialogResult.OK)
            {
                axWindowsMediaPlayer1.URL = open.FileName;
                axWindowsMediaPlayer1.Ctlcontrols.play();//播放文件
            }
        }
        /// <summary>
        /// 暂停音乐
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 暂停ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            axWindowsMediaPlayer1.Ctlcontrols.pause();//暂停
            FormMusic.fmusic.Close();
        }
        /// <summary>
        /// 显示游戏信息内容
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void 游戏信息MToolStripMenuItem_Click(object sender, EventArgs e)
        {
            FormMessage fms = new FormMessage();
            fms.Show();
        }
        /// <summary>
        /// 中止游戏提示
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (textBox1.Text != "0" && timer1.Enabled != false)
            {
                if (MessageBox.Show("游戏正在进行,你确定要退出游戏吗?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
                {
                    SaveSweepMineInfo ss = new SaveSweepMineInfo();
                    ss.SaveInformation(textBox1.Text, DateTime.Now.ToString("yyyy-M-d"), "-1", userControl12.gameLevel);
                    Environment.Exit(0);
                }
                else
                {
                    e.Cancel = true;
                }
            }
            else
            {
                Environment.Exit(0);
            }
        }
    }
}

#Square类

using System;
using System.Drawing;
using System.Runtime.Serialization;
namespace SweepingMine
{
    /// <summary>
    /// 表示游戏中一个方块区, 在类声明中使用sealed可防止其它类继承此类
    /// </summary>
    public sealed class Square
    {
        /// <summary>
        /// 方块区状态
        /// </summary>
        public enum SquareStatus
        {
            /// <summary>
            /// 闲置
            /// </summary>
            Idle,
            /// <summary>
            /// 已打开
            /// </summary>
            Opened,
            /// <summary>
            /// 已标记
            /// </summary>
            Marked,
            /// <summary>
            /// 已质疑
            /// </summary>
            Queried,
            /// <summary>
            /// 游戏结束
            /// </summary>
            GameOver,
            /// <summary>
            /// 标记失误(仅在游戏结束时用于绘制)
            /// </summary>
            MarkMissed
        }
        private static readonly Font Font = new Font(new FontFamily("Arial"), SquareSize / 1.5f, FontStyle.Bold);
        public const int SquareSize = 25;
        private readonly Point location;
        private readonly bool minedS;
        private readonly int minesAroundS;
        private SquareStatus status;
        private bool isBombPoint;
        //仅用于调试时在对象查看器中显示对象摘要
#if DEBUG
        public override string ToString()
        {
            return string.Format("[{0},{1}]是否雷区:{2},周围雷数:{3},状态:{4}", location.X, location.Y, minedS, minesAroundS, status);
        }
#endif
        /// <summary>
        /// 是否为雷区
        /// </summary>
        public bool Mined
        {
            get { return minedS; }
        }
        /// <summary>
        /// 状态
        /// </summary>
        public SquareStatus Status
        {
            get { return status; }
        }
        /// <summary>
        /// 周围雷数
        /// </summary>
        public int MinesAround
        {
            get { return minesAroundS; }
        }
        /// <summary>
        /// 逻辑坐标(对应二维数组索引)
        /// </summary>
        public Point Location
        {
            get { return location; }
        }
        /// <summary>
        /// 初始化一个方块区
        /// </summary>
        /// <param name="loc">位置</param>
        /// <param name="mined">是否为雷区</param>
        /// <param name="minesAround">周围雷区数</param>
        public Square(Point loc, bool mined, int minesAround)
        {
            location = loc;
            minedS = mined;
            minesAroundS = minesAround;
            status = SquareStatus.Idle;
            isBombPoint = false;
        }
        /// <summary>
        /// 左键单击
        /// </summary>
        /// <returns>是否踩到雷</returns>
        public bool LeftClick()
        {
            switch (status)
            {
                case SquareStatus.Idle:
                case SquareStatus.Queried:
                    status = SquareStatus.Opened;
                return minedS;  
                case SquareStatus.Opened:
                case SquareStatus.Marked:
                case SquareStatus.GameOver:
                    return false;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// 右键单击
        /// </summary>
        public void RightClick()
        {
            switch (status)
            {
                case SquareStatus.Idle:
                    {
                        status = SquareStatus.Marked;
                        FormMain.fm1.textBox2.Text = ((int.Parse(FormMain.fm1.textBox2.Text.ToString()) - 1).ToString());
                        break;
                    }
                case SquareStatus.Opened:
                case SquareStatus.GameOver:
                    break;
                case SquareStatus.Marked:
                    {
                        status = SquareStatus.Queried;
                        FormMain.fm1.textBox2.Text = (int.Parse(FormMain.fm1.textBox2.Text.ToString()) + 1).ToString();
                        break;
                    }
                case SquareStatus.Queried:
                    {
                        status = SquareStatus.Idle;
                        break;
                    }
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// 绘制
        /// </summary>
        /// <param name="g">图面</param>
        public void Draw(Graphics g)
        {
            Rectangle rect = new Rectangle(location.X * SquareSize, location.Y * SquareSize, SquareSize, SquareSize);

            switch (status)
            {
                case SquareStatus.Idle:
                    DrawIdleBackground(g, rect);
                    break;
                case SquareStatus.Marked:
                    {
                        DrawIdleBackground(g, rect);
                        Point[] flagTriangle =
                    {
                        new Point(rect.X + SquareSize / 2, rect.Y + 1), 
                        new Point(rect.X + SquareSize / 2, rect.Y + SquareSize / 2 + 1), 
                        new Point(rect.X + SquareSize / 4 - 1, rect.Y + SquareSize / 4)
                    };
                        Point[] flagBaseTriangle =
                    {
                        new Point(rect.X + SquareSize / 2, rect.Y +  SquareSize / 2),
                        new Point(rect.X + SquareSize / 4 - 3, rect.Y +  SquareSize - 3), 
                        new Point(rect.X + SquareSize / 4 * 3,  rect.Y + SquareSize - 3)
                    };
                        g.FillPolygon(Brushes.Red, flagTriangle);
                        g.FillPolygon(Brushes.Black, flagBaseTriangle);
                        break;
                    }
                case SquareStatus.Queried:
                    {
                        DrawIdleBackground(g, rect);
                        SizeF querySize = g.MeasureString("?", Font);
                        g.DrawString("?", Font, Brushes.Black, rect.X + SquareSize / 2 - querySize.Width / 2 - 1, rect.Y + SquareSize / 2 - querySize.Height / 2);
                        break;
                    }
                case SquareStatus.Opened:
                    {
                        g.FillRectangle(Brushes.Silver, rect);
                        g.DrawRectangle(new Pen(Color.Gray, 2f), rect);
                        if (minesAroundS > 0)
                        {
                            string numStr = minesAroundS.ToString();
                            SizeF numSize = g.MeasureString(numStr, Font);
                            g.DrawString(numStr, Font, GetNumberBrush(), rect.X + SquareSize / 2 - numSize.Width / 2 - 1, rect.Y + SquareSize / 2 - numSize.Height / 2);
                        }
                        break;
                    }
                case SquareStatus.GameOver:
                    {
                        if (!minedS) break;
                        g.FillRectangle(isBombPoint ? Brushes.Red : Brushes.Silver, rect);
                        g.DrawRectangle(new Pen(Color.Gray, 2f), rect);
                        g.FillEllipse(Brushes.Black, new Rectangle(rect.X + 2, rect.Y + 2, rect.Width - 2 * 2, rect.Height - 2 * 2));
                        break;
                    }
                case SquareStatus.MarkMissed:
                    {
                        g.FillRectangle(Brushes.Silver, rect);
                        g.DrawRectangle(new Pen(Color.Gray, 2f), rect);
                        g.FillEllipse(Brushes.Black, new Rectangle(rect.X + 2, rect.Y + 2, rect.Width - 2 * 2, rect.Height - 2 * 2));
                        g.DrawLine(Pens.Red, rect.X, rect.Y, rect.Right, rect.Bottom);//左上到右下
                        g.DrawLine(Pens.Red, rect.Right, rect.Y, rect.X, rect.Bottom);//右上到左下
                        break;
                    }
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// 游戏结束
        /// </summary>
        /// <param name="bombPt">爆炸点</param>
        public void GameOver(Point bombPt)
        {
            status = SquareStatus.GameOver;
            isBombPoint = bombPt == location;
        }
        /// <summary>
        /// 指定标记失误
        /// </summary>
        public void IndicateMarkMissed()
        {
            status = SquareStatus.MarkMissed;
        }
        /// <summary>
        /// 获取附近雷数数字颜色画刷
        /// </summary>
        /// <returns>画刷</returns>
        private Brush GetNumberBrush()
        {
            switch (minesAroundS)
            {
                case 1:
                    return Brushes.Blue;
                case 2:
                    return Brushes.Green;
                case 3:
                    return Brushes.Red;
                case 4:
                    return Brushes.Navy;
                case 5:
                    return Brushes.Maroon;
                case 6:
                    return Brushes.Teal;
                case 7:
                    return Brushes.Black;
                case 8:
                    return Brushes.Gray;
            }
            return null;
        }
        /// <summary>
        /// 绘制闲置时的背景图
        /// </summary>
        /// <param name="g">图面</param>
        /// <param name="rect">矩形</param>
        private static void DrawIdleBackground(Graphics g, Rectangle rect)
        {
            switch (FormMain.SquareColor)
            {
                case 0:
                    g.FillRectangle(Brushes.Silver, new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 4, rect.Height - 4));
                    break;
                case 1:
                    g.FillRectangle(Brushes.Green, new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 4, rect.Height - 4));
                    break;
                case 2:
                    g.FillRectangle(Brushes.Pink, new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 4, rect.Height - 4));
                    break;
                case 3:
                    g.FillRectangle(Brushes.Purple, new Rectangle(rect.X + 1, rect.Y + 1, rect.Width - 4, rect.Height - 4));
                    break;
            }
            g.DrawLine(new Pen(Color.White, 2f), rect.X, rect.Y, rect.Right - 2, rect.Y);
            g.DrawLine(new Pen(Color.White, 2f), rect.X, rect.Y, rect.X, rect.Bottom - 2);
            g.DrawLine(new Pen(Color.Gray, 2f), rect.Right - 2, rect.Y, rect.Right - 2, rect.Bottom - 1);
            g.DrawLine(new Pen(Color.Gray, 2f), rect.X, rect.Bottom - 2, rect.Right - 1, rect.Bottom - 2);
        }
    }
}

#Game类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
namespace SweepingMine
{
    public sealed class Game
    {
        public static Square[,] _gameData;
        private readonly GameLevel _level;
        private readonly int _minesCount;
        private readonly Size _gameFieldOffset;
        private readonly Graphics _wndGraphics;
        private readonly Bitmap buffer;
        private readonly Graphics _bufferGraphics;
        private static readonly Random Rnd = new Random();
        public bool _gameStarted;
        public bool _gameStoped;
        public const int
            MaxWidth = 30,
            MaxHeight = 24,
            MinWidth = 9,
            MinHeight = 9,
            MinMinesCount = 10;
        /// <summary>
        /// 从预设等级初始化游戏
        /// </summary>
        /// <param name="level">预设等级</param>
        /// <param name="g">图面</param>
        /// <param name="gameFieldOffset">游戏区偏移</param>
        public Game(GameLevel level, Graphics g, Size gameFieldOffset)
        {
            _level = level;
            _gameFieldOffset = gameFieldOffset;
            _wndGraphics = g;
            switch (level)
            {
                case GameLevel.Beginner:
                    _gameData = new Square[9, 9];
                    _minesCount = 10;
                    break;
                case GameLevel.Intermediate:
                    _gameData = new Square[16, 16];
                    _minesCount = 40;
                    break;
                case GameLevel.Expert:
                    _gameData = new Square[30, 16];
                    _minesCount = 99;
                    break;
                case GameLevel.Customize:
                    break;
                default:
                    throw new ArgumentOutOfRangeException("level", level, null);
            }
            buffer = new Bitmap(_gameData.GetLength(0) * Square.SquareSize, _gameData.GetLength(1) * Square.SquareSize);
            _bufferGraphics = Graphics.FromImage(buffer);
        }
        /// <summary>
        /// 创建自定义游戏实例
        /// </summary>
        /// <param name="gameSize">游戏宽高</param>
        /// <param name="minesCount">雷数</param>
        /// <param name="g">图面</param>
        /// <param name="gameFieldOffset">游戏区偏移</param>
        /// <exception cref="ArgumentOutOfRangeException">游戏尺寸或雷数非法</exception>
        public Game(Size gameSize, int minesCount, Graphics g, Size gameFieldOffset)
        {
            _level = GameLevel.Customize;
            _gameFieldOffset = gameFieldOffset;
            _wndGraphics = g;

            if (gameSize.Width > MaxWidth)
                gameSize.Width = MaxWidth;
            else if (gameSize.Width < MinWidth)
                gameSize.Width = MinWidth;
            if (gameSize.Height > MaxHeight)
                gameSize.Height = MaxHeight;
            else if (gameSize.Height < MinHeight)
                gameSize.Height = MinHeight;

            if (minesCount < MinMinesCount)
                minesCount = MinMinesCount;
            else if (minesCount > (gameSize.Width - 1) * (gameSize.Height - 1))
                minesCount = (gameSize.Width - 1) * (gameSize.Height - 1);
            _gameData = new Square[gameSize.Width, gameSize.Height];
            _minesCount = minesCount;
            buffer = new Bitmap(_gameData.GetLength(0) * Square.SquareSize, _gameData.GetLength(1) * Square.SquareSize);
            _bufferGraphics = Graphics.FromImage(buffer);
        }
        /// <summary>
        /// 开始游戏
        /// </summary>
        public void Start()
        {
            //假设所有方块区均非雷区
            for (int i = 0; i < _gameData.GetLength(0); i++)
                for (int j = 0; j < _gameData.GetLength(1); j++)
                    _gameData[i, j] = new Square(new Point(i, j), false, 0);
        }
        /// <summary>
        /// 获取游戏区像素尺寸,即雷区的尺寸
        /// </summary>
        /// <returns></returns>
        public Size GetGamePixcelSize()
        {
            return new Size(_gameData.GetLength(0) * Square.SquareSize, _gameData.GetLength(1) * Square.SquareSize);
        }

        /// <summary>
        /// 左键单击
        /// </summary>
        /// <param name="pixelPt">鼠标单击像素点</param>
        /// <returns>
        /// 0:空白处
        /// 1:获胜
        /// -1:游戏结束
        /// </returns>
        public int LeftClick(Point pixelPt)
        {
            if (_gameStoped) return 0;
            Point gameFieldpt = new Point(pixelPt.X - _gameFieldOffset.Width, pixelPt.Y - _gameFieldOffset.Height);
            Point logicalPt = new Point(gameFieldpt.X / Square.SquareSize, gameFieldpt.Y / Square.SquareSize);

            if (!_gameStarted)
            {
                FormMain.beginTime = DateTime.Now;
                FormMain.fm1.timer1.Enabled = true;
                Mine(logicalPt);
            }
            if (!_gameData[logicalPt.X, logicalPt.Y].LeftClick())
            {
                if ((_gameData[logicalPt.X, logicalPt.Y].MinesAround == 0) && _gameData[logicalPt.X, logicalPt.Y].Status!=Square.SquareStatus.Marked)
                    AutoOpenAround(logicalPt);

                for (int i = 0; i < _gameData.GetLength(0); i++)
                {
                    for (int j = 0; j < _gameData.GetLength(1); j++)
                    {
                        if (_gameData[i, j].Mined)
                            continue;
                        if (_gameData[i, j].Status == Square.SquareStatus.Opened)
                            continue;
                        return 0;
                    }
                }
                return 1;
            }
            for (int i = 0; i < _gameData.GetLength(0); i++)
                for (int j = 0; j < _gameData.GetLength(1); j++)
                    if (_gameData[i, j].Mined)
                        _gameData[i, j].GameOver(logicalPt);
                    else
                        if (_gameData[i, j].Status == Square.SquareStatus.Marked)
                            _gameData[i, j].IndicateMarkMissed();
            return -1;
        }
        /// <summary>
        /// 右键单击
        /// </summary>
        /// <param name="pixelPt">鼠标单击像素点</param>
        public void RightClick(Point pixelPt)
        {
            if (_gameStoped) return;
            Point pt = new Point(pixelPt.X - _gameFieldOffset.Width, pixelPt.Y - _gameFieldOffset.Height);
            _gameData[pt.X / Square.SquareSize, pt.Y / Square.SquareSize].RightClick();
        }
        /// <summary>
        /// 结束游戏
        /// </summary>
        public void Stop()
        {
            _gameStoped = true;
        }
        /// <summary>
        /// 绘制一帧
        /// </summary>
        public void Draw()
        {
            for (int i = 0; i < _gameData.GetLength(0); i++)
                for (int j = 0; j < _gameData.GetLength(1); j++)
                    _gameData[i, j].Draw(_bufferGraphics);

            _wndGraphics.DrawImage(buffer, new Point(_gameFieldOffset.Width, _gameFieldOffset.Height));
        }
        /// <summary>
        /// 布雷
        /// </summary>
        /// <param name="startPt">首次单击点</param>
        private void Mine(Point startPt)
        {
            Size area = new Size(_gameData.GetLength(0), _gameData.GetLength(1));
            List<Point> excluded = new List<Point> { startPt }; 
            for (int i = 0; i < _minesCount; i++)
            {
                Point pt = GetRandomPoint(area, excluded);
                _gameData[pt.X, pt.Y] = new Square(pt, true, 0);
                excluded.Add(pt);
            }
            for (int i = 0; i < _gameData.GetLength(0); i++)
                for (int j = 0; j < _gameData.GetLength(1); j++)
                    if (!_gameData[i, j].Mined)
                    {
                        int minesAround = EnumSquaresAround(new Point(i, j)).Cast<Square>().Count(square => square.Mined);//周围雷数

                        _gameData[i, j] = new Square(new Point(i, j), false, minesAround);
                    }
            _gameStarted = true;
        }
        /// <summary>
        /// 自动打开周围非雷区方块(递归)
        /// </summary>
        /// <param name="squarePt">原方块逻辑坐标</param>
        private void AutoOpenAround(Point squarePt)
        {
            foreach (Square square in EnumSquaresAround(squarePt))
            {
                if (square.Mined || square.Status == Square.SquareStatus.Marked || square.Status == Square.SquareStatus.Opened)
                    continue;
                square.LeftClick();
                if (square.MinesAround == 0)
                    AutoOpenAround(square.Location);
            }
        }
        /// <summary>
        /// 枚举某一方块的周围所有方块区
        /// </summary>
        /// <param name="squarePt">原方块区</param>
        /// <returns>枚举数</returns>
        private IEnumerable EnumSquaresAround(Point squarePt)
        {
            int i = squarePt.X, j = squarePt.Y;
            for (int x = i - 1; x <= i + 1; ++x)
            {
                if (x < 0 || x >= _gameData.GetLength(0))
                    continue;
                for (int y = j - 1; y <= j + 1; ++y)
                {
                    if (y < 0 || y >= _gameData.GetLength(1))
                        continue;
                    if (x == squarePt.X && y == squarePt.Y)
                        continue;
                    yield return _gameData[x, y];
                }
            }
        }
        /// <summary>
        /// 获取指定区域内的一个不在排除项列表中的随机点
        /// </summary>
        /// <param name="areaSize">区域大小,指定了随机点坐标的范围</param>
        /// <param name="excluded">排除项</param>
        /// <returns>随机点</returns>
        /// <exception cref="ArgumentNullException">排除项为空</exception>
        private static Point GetRandomPoint(Size areaSize, List<Point> excluded)
        {
            if (excluded == null)
                throw new ArgumentNullException("excluded");
            int x, y;
            do
            {
                x = Rnd.Next(0, areaSize.Width);
                y = Rnd.Next(0, areaSize.Height);
            } while (excluded.Any(pt => pt.X == x && pt.Y == y));
            return new Point(x, y);
        }
    }
}