C#控制台扫雷完整源码

class Program
    {
        static void Main(string[] args)
        {
            string copyright = "SimpleMine v1.0 by Arliy ArliyCoder@gmail.com";
            MineGame game = null;
            try
            {
                game = new MineGame(copyright, int.Parse(args[0]), int.Parse(args[1]), int.Parse(args[2]));
            }
            catch
            {
                game = new MineGame(copyright);
            }
            game.Run();
        }
    }

    /*
     * /
     * Program : MineGame.cs   
     * Resume  : 游戏控制类,提供键盘操作:
     *           方向键控制光标位置;
     *           Z/z键扫描雷;
     *           X/x键标记雷;
     *           Y/y键重新游戏;
     *           N/y键退出游戏;
     * 
     * /
     * Modifiy History
     * 
     * Date    :
     * Resume  :
     * 
     */
    public class MineGame
    {
        #region fields

        private Mine mine;//扫雷类

        #endregion

        #region constructors

        public MineGame(string title)
        {
            mine = new Mine();
            Console.Title = title;
        }

        public MineGame(string title, int width, int height, int mineCount)
        {
            mine = new Mine(width, height, mineCount);
            Console.Title = title;
        }

        #endregion

        #region public functions

        /// <summary>
        /// 启动扫雷游戏
        /// </summary>
        public void Run()
        {
            int x, y;
        Start:
            x = y = 0;
            mine.Render();
            Console.SetCursorPosition(0, 0);
            while (!mine.IsGameOver && !mine.IsSucceed())
            {
                ConsoleKeyInfo key = Console.ReadKey(true);
                switch (key.Key)
                {
                    case ConsoleKey.LeftArrow:
                        x = x > 0 ? x - 1 : x;
                        break;
                    case ConsoleKey.RightArrow:
                        x = x < mine.Height - 1 ? x + 1 : x;
                        break;
                    case ConsoleKey.UpArrow:
                        y = y > 0 ? y - 1 : y;
                        break;
                    case ConsoleKey.DownArrow:
                        y = y < mine.Width - 1 ? y + 1 : y;
                        break;
                    case ConsoleKey.Z:
                        mine.ScanMine(y, x);
                        mine.Render();
                        break;
                    case ConsoleKey.X:
                        mine.MarkMine(y, x);
                        mine.Render();
                        break;
                    default:
                        break;
                }
                Console.SetCursorPosition(x * 2, y);
            }

            Console.ForegroundColor = ConsoleColor.Gray;
            Console.SetCursorPosition(30, 21);
            if (mine.IsGameOver)
                Console.WriteLine("You lose the fucking game!");
            else
                Console.WriteLine("Well done!");

            Console.SetCursorPosition(33, 22);
            Console.WriteLine("\tRetry the game? (Y/y) or (N/n)...");

            Console.SetCursorPosition(33, 23);
            if (Console.ReadLine().ToUpper() == "Y")
            {
                mine.Reset();
                goto Start;
            }
        }

        #endregion
    }

    /*
     * /
     * Program : Mine.cs   
     * Resume  : 扫雷类,用二维byte类型数组表示,其中每个byte元素存储雷区区域信息:
     *           高4位存储区域数据,当值为9时表示该区域为地雷;
     *           低4位存储区域标记,包括空标记0000(0x00)、已扫描标记0001(0x01)与雷标记0010(0x02);
     * /
     * Modifiy History
     * 
     * Date    :
     * Resume  :
     * 
     */
    public class Mine
    {
        #region fields

        private const byte MINE_FLAG_NULL = 0x00;//空标记
        private const byte MINE_FLAG_SCAN = 0x01;//已扫描标记
        private const byte MINE_FLAG_MARK = 0x02;//雷标记
        private const byte MINE_DATA_NULL = 0x00;//空值
        private const byte MINE_DATA_MINE = 0x90;//雷值

        private byte[,] mines;//雷区数据
        private bool isGameOver;//是否游戏结束
        private int initCount;//初始雷数
        private int mineCount;//当前雷数
        private int markCount;//可标记雷数
        private int width;//雷区宽度
        private int height;//雷区高度

        #endregion

        #region properties

        public int Width
        {
            get { return width; }
        }

        public int Height
        {
            get { return height; }
        }

        public bool IsGameOver
        {
            get { return isGameOver; }
        }

        #endregion

        #region constructors

        public Mine()
        {
            InitMineArea(9, 9, 10);
        }

        public Mine(int width, int height, int mineCount)
        {
            //取值范围
            width = width <= 0 ? 9 : width;
            width = width > 20 ? 20 : width;
            height = height <= 0 ? 9 : height;
            height = height > 39 ? 39 : height;
            mineCount = (mineCount > width * height) ? width * height : mineCount;
            InitMineArea(width, height, mineCount);
        }

        #endregion

        #region public functions

        /// <summary>
        /// 在指定位置扫描雷区
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void ScanMine(int x, int y)
        {
            //当前位置已经扫描过
            if ((mines[x, y] & 0x0f) != MINE_FLAG_NULL)
                return;
            //当前位置是地雷,游戏结束
            if ((mines[x, y] & 0xf0) == MINE_DATA_MINE)
            {
                isGameOver = true;
                return;
            }
            //置空
            mines[x, y] = MINE_DATA_NULL;
            //递归进行扫描
            RecursiveScanMine(x, y);
        }

        /// <summary>
        /// 在指定位置设置雷标记
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void MarkMine(int x, int y)
        {
            byte data = (byte)(mines[x, y] & 0xf0);
            switch ((byte)(mines[x, y] & 0x0f))
            {
                case MINE_FLAG_NULL:
                    if (markCount > 0)
                    {
                        //置雷标记
                        mines[x, y] |= MINE_FLAG_MARK;
                        //如果当前位置是雷,减少雷数
                        mineCount = data == MINE_DATA_MINE ? mineCount - 1 : mineCount;
                        //减少雷标记数量
                        markCount--;
                    }
                    break;
                case MINE_FLAG_MARK:
                    {
                        //取消雷标记
                        mines[x, y] ^= MINE_FLAG_MARK;
                        //如果当前位置是雷,增加雷数
                        mineCount = data == MINE_DATA_MINE ? mineCount + 1 : mineCount;
                        //增加雷标记数量
                        markCount++;
                    }
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 绘制雷区
        /// </summary>
        public void Render()
        {
            Console.Clear();
            for (int i = 0; i < mines.GetLength(0); i++)
            {
                for (int j = 0; j < mines.GetLength(1); j++)
                {
                    Console.ForegroundColor = ConsoleColor.Gray;
                    byte data = (byte)((mines[i, j] >> 4) & 0x0f);
                    if (isGameOver && data == 0x09)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.Write("¤");
                        continue;
                    }
                    switch ((byte)(mines[i, j] & 0x0f))
                    {
                        case MINE_FLAG_NULL:
                            Console.Write("■");
                            break;
                        case MINE_FLAG_SCAN:
                            Console.ForegroundColor = ConsoleColor.DarkGray;
                            if (data == MINE_DATA_NULL)
                                Console.Write("□");
                            else
                                ColourNumber(data);
                            break;
                        case MINE_FLAG_MARK:
                            Console.ForegroundColor = ConsoleColor.Yellow;
                            Console.Write("♀");
                            break;
                        default:
                            break;
                    }
                }
                Console.WriteLine();
            }
            Console.ForegroundColor = ConsoleColor.Gray;
            for (int i = 0; i < height; i++) Console.Write("--");
            Console.WriteLine();
            Console.WriteLine(string.Format("Size:{0}*{1}", mines.GetLength(0), mines.GetLength(1)));
            Console.WriteLine(string.Format("Mine:{0}", initCount));
            Console.WriteLine(string.Format("Mark:{0}", markCount));
        }

        /// <summary>
        /// 是否扫雷成功
        /// </summary>
        /// <returns></returns>
        public bool IsSucceed()
        {
            int count = 0;
            for (int i = 0; i < mines.GetLength(0); i++)
            {
                for (int j = 0; j < mines.GetLength(1); j++)
                {
                    if ((mines[i, j] & 0x0f) != MINE_FLAG_SCAN)
                        count++;
                }
            }
            //未扫描过的雷区数量为雷数则扫雷成功,否则继续扫雷
            return count == initCount ? true : false;
        }

        /// <summary>
        /// 重置
        /// </summary>
        public void Reset()
        {
            for (int i = 0; i < mines.GetLength(0); i++)
            {
                for (int j = 0; j < mines.GetLength(1); j++)
                    mines[i, j] = MINE_DATA_NULL;
            }

            this.mineCount = initCount;
            this.markCount = initCount;
            this.isGameOver = false;

            SetRandomMine(initCount);
            StatistikMineCount();
        }

        #endregion

        #region private functions

        /// <summary>
        /// 初始化雷区
        /// </summary>
        /// <param name="width">雷区宽度</param>
        /// <param name="height">雷区高度</param>
        /// <param name="mineCount">雷数</param>
        private void InitMineArea(int width, int height, int mineCount)
        {
            //初始化雷区
            mines = new byte[width, height];
            for (int i = 0; i < mines.GetLength(0); i++)
            {
                for (int j = 0; j < mines.GetLength(1); j++)
                    mines[i, j] = MINE_DATA_NULL;
            }
            //随机分布雷
            SetRandomMine(mineCount);
            //统计雷区数据
            StatistikMineCount();

            this.width = width;
            this.height = height;
            this.mineCount = mineCount;
            this.initCount = mineCount;
            this.markCount = mineCount;
            this.isGameOver = false;
        }

        /// <summary>
        /// 随机分布雷
        /// </summary>
        /// <param name="minecount">雷数</param>
        private void SetRandomMine(int minecount)
        {
            Random random = new Random(Environment.TickCount);
            int x;
            int y;
            int temp = minecount;
            while (minecount > 0)
            {
                x = random.Next(0, mines.GetLength(0));
                y = random.Next(0, mines.GetLength(1));
                if (mines[x, y] == MINE_DATA_NULL)
                {
                    mines[x, y] = MINE_DATA_MINE;
                    minecount--;
                }
            }
        }

        /// <summary>
        /// 统计雷区数据
        /// </summary>
        private void StatistikMineCount()
        {
            for (int i = 0; i < mines.GetLength(0); i++)
            {
                for (int j = 0; j < mines.GetLength(1); j++)
                {
                    if (mines[i, j] != MINE_DATA_MINE)
                    {
                        mines[i, j] = (byte)(StatistikMineCountAt(i, j) << 4);
                    }
                }
            }
        }

        /// <summary>
        /// 计算指定位置周围雷数
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        private int StatistikMineCountAt(int x, int y)
        {
            int minecount = 0;
            for (int i = x - 1; i <= x + 1; i++)
            {
                if (i <= -1 || i >= mines.GetLength(0)) continue;
                for (int j = y - 1; j <= y + 1; j++)
                {
                    if (((j <= -1) || (j >= mines.GetLength(1))) || (i == x && j == y))
                        continue;
                    if (mines[i, j] == MINE_DATA_MINE)
                    {
                        minecount++;
                    }
                }
            }
            return minecount;
        }

        /// <summary>
        /// 递归方式扫描无雷区域
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        private void RecursiveScanMine(int x, int y)
        {
            //边界检测
            if ((x < 0 || x >= mines.GetLength(0)) ||
                (y < 0 || y >= mines.GetLength(1)))
            {
                return;
            }
            //排除已扫描的区域或是有雷区域
            if (((mines[x, y] & 0x0f) != MINE_FLAG_NULL) || ((mines[x, y] & 0xf0) == MINE_DATA_MINE))
            {
                return;
            }
            if ((mines[x, y] & 0xf0) != MINE_DATA_NULL)
            {
                mines[x, y] |= MINE_FLAG_SCAN;
                return;
            }
            //置已扫描标记
            mines[x, y] |= MINE_FLAG_SCAN;
            //目标区域八方向递归扫描
            RecursiveScanMine(x - 1, y - 1);
            RecursiveScanMine(x - 1, y);
            RecursiveScanMine(x - 1, y + 1);
            RecursiveScanMine(x, y - 1);
            RecursiveScanMine(x, y + 1);
            RecursiveScanMine(x + 1, y - 1);
            RecursiveScanMine(x + 1, y);
            RecursiveScanMine(x + 1, y + 1);
        }

        /// <summary>
        /// 格式化/着色数字
        /// </summary>
        /// <param name="value"></param>
        private void ColourNumber(int value)
        {
            Console.ForegroundColor = MineData.ColorTable[value];
            Console.Write(MineData.FormatNumbers[value]);
        }

        #endregion
    }

    /*
     * /
     * Program : MineData.cs
     * Author  : Arliy (ArliyCoder#gmail.com) 
     * Date    : 2013/7/15     
     * Resume  : 格式化数据
     * 
     * /
     * Modifiy History
     * 
     * Date    :
     * Resume  :
     * 
     */
    public class MineData
    {
        public static string[] FormatNumbers = { "", "①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧" };
        public static ConsoleColor[] ColorTable =  
        {
            ConsoleColor.Gray,
            ConsoleColor.White,
            ConsoleColor.DarkGreen,
            ConsoleColor.Green,
            ConsoleColor.DarkYellow,
            ConsoleColor.Magenta,
            ConsoleColor.Blue,
            ConsoleColor.Cyan
        };
    }
}
  • 9
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LilyCoder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值