查看: 1079|回复: 2

[.Net] 【参赛】控制台扫雷(不是本人写的,但很清晰)

[复制链接]

该用户从未签到

发表于 2014-6-13 12:12:37 | 显示全部楼层 |阅读模式
前段时间找到的,本来打算跟着学习写一个看看,现在发出来跟大家一群探讨一下
  1. /*
  2. * /////////////////////////////////////////////////////////////////////
  3. * Program : Console Mine Game
  4. * Author  : Arliy (ArliyCoder#gmail.com)
  5. * Date    : 2013/7/15
  6. * Resume  : 控制台扫雷游戏
  7. *
  8. * /////////////////////////////////////////////////////////////////////
  9. * Modifiy History
  10. *
  11. * Date    :
  12. * Resume  :
  13. *
  14. */
  15. using System;
  16. namespace CMinesGame
  17. {
  18.     /*
  19.      * /////////////////////////////////////////////////////////////////////
  20.      * Program : Program.cs
  21.      * Author  : Arliy (ArliyCoder#gmail.com)
  22.      * Date    : 2013/7/15     
  23.      * Resume  : 游戏主程序,命令行方式启动游戏:
  24.      *           CommandLine:ApplicationPath Width Height MineCount
  25.      *           For example:d:\Mind.exe 9 9 10
  26.      *
  27.      * /////////////////////////////////////////////////////////////////////
  28.      * Modifiy History
  29.      *
  30.      * Date    :
  31.      * Resume  :
  32.      *
  33.      */
  34.     class Program
  35.     {
  36.         static void Main(string[] args)
  37.         {
  38.             string copyright = "SimpleMine v1.0 by Arliy ArliyCoder@gmail.com";
  39.             MineGame game = null;
  40.             try
  41.             {
  42.                 game = new MineGame(copyright, int.Parse(args[0]), int.Parse(args[1]), int.Parse(args[2]));
  43.             }
  44.             catch
  45.             {
  46.                 game = new MineGame(copyright);
  47.             }
  48.             game.Run();
  49.         }
  50.     }

  51.     /*
  52.      * /////////////////////////////////////////////////////////////////////
  53.      * Program : MineGame.cs
  54.      * Author  : Arliy (ArliyCoder#gmail.com)
  55.      * Date    : 2013/7/15     
  56.      * Resume  : 游戏控制类,提供键盘操作:
  57.      *           方向键控制光标位置;
  58.      *           Z/z键扫描雷;
  59.      *           X/x键标记雷;
  60.      *           Y/y键重新游戏;
  61.      *           N/y键退出游戏;
  62.      *
  63.      * /////////////////////////////////////////////////////////////////////
  64.      * Modifiy History
  65.      *
  66.      * Date    :
  67.      * Resume  :
  68.      *
  69.      */
  70.     public class MineGame
  71.     {
  72.         #region fields

  73.         private Mine mine;//扫雷类

  74.         #endregion

  75.         #region constructors

  76.         public MineGame(string title)
  77.         {
  78.             mine = new Mine();
  79.             Console.Title = title;
  80.         }

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

  86.         #endregion

  87.         #region public functions

  88.         /// <summary>
  89.         /// 启动扫雷游戏
  90.         /// </summary>
  91.         public void Run()
  92.         {
  93.             int x, y;
  94.         Start:
  95.             x = y = 0;
  96.             mine.Render();
  97.             Console.SetCursorPosition(0, 0);
  98.             while (!mine.IsGameOver && !mine.IsSucceed())
  99.             {
  100.                 ConsoleKeyInfo key = Console.ReadKey(true);
  101.                 switch (key.Key)
  102.                 {
  103.                     case ConsoleKey.LeftArrow:
  104.                         x = x > 0 ? x - 1 : x;
  105.                         break;
  106.                     case ConsoleKey.RightArrow:
  107.                         x = x < mine.Height - 1 ? x + 1 : x;
  108.                         break;
  109.                     case ConsoleKey.UpArrow:
  110.                         y = y > 0 ? y - 1 : y;
  111.                         break;
  112.                     case ConsoleKey.DownArrow:
  113.                         y = y < mine.Width - 1 ? y + 1 : y;
  114.                         break;
  115.                     case ConsoleKey.Z:
  116.                         mine.ScanMine(y, x);
  117.                         mine.Render();
  118.                         break;
  119.                     case ConsoleKey.X:
  120.                         mine.MarkMine(y, x);
  121.                         mine.Render();
  122.                         break;
  123.                     default:
  124.                         break;
  125.                 }
  126.                 Console.SetCursorPosition(x * 2, y);
  127.             }

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

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

  136.             Console.SetCursorPosition(33, 23);
  137.             if (Console.ReadLine().ToUpper() == "Y")
  138.             {
  139.                 mine.Reset();
  140.                 goto Start;
  141.             }
  142.         }

  143.         #endregion
  144.     }

  145.     /*
  146.      * /////////////////////////////////////////////////////////////////////
  147.      * Program : Mine.cs
  148.      * Author  : Arliy (ArliyCoder#gmail.com)
  149.      * Date    : 2013/7/15     
  150.      * Resume  : 扫雷类,用二维byte类型数组表示,其中每个byte元素存储雷区区域信息:
  151.      *           高4位存储区域数据,当值为9时表示该区域为地雷;
  152.      *           低4位存储区域标记,包括空标记0000(0x00)、已扫描标记0001(0x01)与雷标记0010(0x02);
  153.      * /////////////////////////////////////////////////////////////////////
  154.      * Modifiy History
  155.      *
  156.      * Date    :
  157.      * Resume  :
  158.      *
  159.      */
  160.     public class Mine
  161.     {
  162.         #region fields

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

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

  175.         #endregion

  176.         #region properties

  177.         public int Width
  178.         {
  179.             get { return width; }
  180.         }

  181.         public int Height
  182.         {
  183.             get { return height; }
  184.         }

  185.         public bool IsGameOver
  186.         {
  187.             get { return isGameOver; }
  188.         }

  189.         #endregion

  190.         #region constructors

  191.         public Mine()
  192.         {
  193.             InitMineArea(9, 9, 10);
  194.         }

  195.         public Mine(int width, int height, int mineCount)
  196.         {
  197.             //取值范围
  198.             width = width <= 0 ? 9 : width;
  199.             width = width > 20 ? 20 : width;
  200.             height = height <= 0 ? 9 : height;
  201.             height = height > 39 ? 39 : height;
  202.             mineCount = (mineCount > width * height) ? width * height : mineCount;
  203.             InitMineArea(width, height, mineCount);
  204.         }

  205.         #endregion

  206.         #region public functions

  207.         /// <summary>
  208.         /// 在指定位置扫描雷区
  209.         /// </summary>
  210.         /// <param name="x"></param>
  211.         /// <param name="y"></param>
  212.         public void ScanMine(int x, int y)
  213.         {
  214.             //当前位置已经扫描过
  215.             if ((mines[x, y] & 0x0f) != MINE_FLAG_NULL)
  216.                 return;
  217.             //当前位置是地雷,游戏结束
  218.             if ((mines[x, y] & 0xf0) == MINE_DATA_MINE)
  219.             {
  220.                 isGameOver = true;
  221.                 return;
  222.             }
  223.             //置空
  224.             mines[x, y] = MINE_DATA_NULL;
  225.             //递归进行扫描
  226.             RecursiveScanMine(x, y);
  227.         }

  228.         /// <summary>
  229.         /// 在指定位置设置雷标记
  230.         /// </summary>
  231.         /// <param name="x"></param>
  232.         /// <param name="y"></param>
  233.         public void MarkMine(int x, int y)
  234.         {
  235.             byte data = (byte)(mines[x, y] & 0xf0);
  236.             switch ((byte)(mines[x, y] & 0x0f))
  237.             {
  238.                 case MINE_FLAG_NULL:
  239.                     if (markCount > 0)
  240.                     {
  241.                         //置雷标记
  242.                         mines[x, y] |= MINE_FLAG_MARK;
  243.                         //如果当前位置是雷,减少雷数
  244.                         mineCount = data == MINE_DATA_MINE ? mineCount - 1 : mineCount;
  245.                         //减少雷标记数量
  246.                         markCount--;
  247.                     }
  248.                     break;
  249.                 case MINE_FLAG_MARK:
  250.                     {
  251.                         //取消雷标记
  252.                         mines[x, y] ^= MINE_FLAG_MARK;
  253.                         //如果当前位置是雷,增加雷数
  254.                         mineCount = data == MINE_DATA_MINE ? mineCount + 1 : mineCount;
  255.                         //增加雷标记数量
  256.                         markCount++;
  257.                     }
  258.                     break;
  259.                 default:
  260.                     break;
  261.             }
  262.         }


复制代码


该用户从未签到

 楼主| 发表于 2014-6-13 12:13:04 | 显示全部楼层
  1. /// <summary>
  2. /// 绘制雷区
  3. /// </summary>
  4. public void Render()
  5. {
  6. Console.Clear();
  7. for (int i = 0; i < mines.GetLength(0); i++)
  8. {
  9. for (int j = 0; j < mines.GetLength(1); j++)
  10. {
  11. Console.ForegroundColor = ConsoleColor.Gray;
  12. byte data = (byte)((mines[i, j] >> 4) & 0x0f);
  13. if (isGameOver && data == 0x09)
  14. {
  15. Console.ForegroundColor = ConsoleColor.Red;
  16. Console.Write("¤");
  17. continue;
  18. }
  19. switch ((byte)(mines[i, j] & 0x0f))
  20. {
  21. case MINE_FLAG_NULL:
  22. Console.Write("■");
  23. break;
  24. case MINE_FLAG_SCAN:
  25. Console.ForegroundColor = ConsoleColor.DarkGray;
  26. if (data == MINE_DATA_NULL)
  27. Console.Write("□");
  28. else
  29. ColourNumber(data);
  30. break;
  31. case MINE_FLAG_MARK:
  32. Console.ForegroundColor = ConsoleColor.Yellow;
  33. Console.Write("♀");
  34. break;
  35. default:
  36. break;
  37. }
  38. }
  39. Console.WriteLine();
  40. }
  41. Console.ForegroundColor = ConsoleColor.Gray;
  42. for (int i = 0; i < height; i++) Console.Write("--");
  43. Console.WriteLine();
  44. Console.WriteLine(string.Format("Size:{0}*{1}", mines.GetLength(0), mines.GetLength(1)));
  45. Console.WriteLine(string.Format("Mine:{0}", initCount));
  46. Console.WriteLine(string.Format("Mark:{0}", markCount));
  47. }

  48. /// <summary>
  49. /// 是否扫雷成功
  50. /// </summary>
  51. /// <returns></returns>
  52. public bool IsSucceed()
  53. {
  54. int count = 0;
  55. for (int i = 0; i < mines.GetLength(0); i++)
  56. {
  57. for (int j = 0; j < mines.GetLength(1); j++)
  58. {
  59. if ((mines[i, j] & 0x0f) != MINE_FLAG_SCAN)
  60. count++;
  61. }
  62. }
  63. //未扫描过的雷区数量为雷数则扫雷成功,否则继续扫雷
  64. return count == initCount ? true : false;
  65. }

  66. /// <summary>
  67. /// 重置
  68. /// </summary>
  69. public void Reset()
  70. {
  71. for (int i = 0; i < mines.GetLength(0); i++)
  72. {
  73. for (int j = 0; j < mines.GetLength(1); j++)
  74. mines[i, j] = MINE_DATA_NULL;
  75. }

  76. this.mineCount = initCount;
  77. this.markCount = initCount;
  78. this.isGameOver = false;

  79. SetRandomMine(initCount);
  80. StatistikMineCount();
  81. }

  82. #endregion

  83. #region private functions

  84. /// <summary>
  85. /// 初始化雷区
  86. /// </summary>
  87. /// <param name="width">雷区宽度</param>
  88. /// <param name="height">雷区高度</param>
  89. /// <param name="mineCount">雷数</param>
  90. private void InitMineArea(int width, int height, int mineCount)
  91. {
  92. //初始化雷区
  93. mines = new byte[width, height];
  94. for (int i = 0; i < mines.GetLength(0); i++)
  95. {
  96. for (int j = 0; j < mines.GetLength(1); j++)
  97. mines[i, j] = MINE_DATA_NULL;
  98. }
  99. //随机分布雷
  100. SetRandomMine(mineCount);
  101. //统计雷区数据
  102. StatistikMineCount();

  103. this.width = width;
  104. this.height = height;
  105. this.mineCount = mineCount;
  106. this.initCount = mineCount;
  107. this.markCount = mineCount;
  108. this.isGameOver = false;
  109. }

  110. /// <summary>
  111. /// 随机分布雷
  112. /// </summary>
  113. /// <param name="minecount">雷数</param>
  114. private void SetRandomMine(int minecount)
  115. {
  116. Random random = new Random(Environment.TickCount);
  117. int x;
  118. int y;
  119. int temp = minecount;
  120. while (minecount > 0)
  121. {
  122. x = random.Next(0, mines.GetLength(0));
  123. y = random.Next(0, mines.GetLength(1));
  124. if (mines[x, y] == MINE_DATA_NULL)
  125. {
  126. mines[x, y] = MINE_DATA_MINE;
  127. minecount--;
  128. }
  129. }
  130. }

  131. /// <summary>
  132. /// 统计雷区数据
  133. /// </summary>
  134. private void StatistikMineCount()
  135. {
  136. for (int i = 0; i < mines.GetLength(0); i++)
  137. {
  138. for (int j = 0; j < mines.GetLength(1); j++)
  139. {
  140. if (mines[i, j] != MINE_DATA_MINE)
  141. {
  142. mines[i, j] = (byte)(StatistikMineCountAt(i, j) << 4);
  143. }
  144. }
  145. }
  146. }

  147. /// <summary>
  148. /// 计算指定位置周围雷数
  149. /// </summary>
  150. /// <param name="x"></param>
  151. /// <param name="y"></param>
  152. /// <returns></returns>
  153. private int StatistikMineCountAt(int x, int y)
  154. {
  155. int minecount = 0;
  156. for (int i = x - 1; i <= x + 1; i++)
  157. {
  158. if (i <= -1 || i >= mines.GetLength(0)) continue;
  159. for (int j = y - 1; j <= y + 1; j++)
  160. {
  161. if (((j <= -1) || (j >= mines.GetLength(1))) || (i == x && j == y))
  162. continue;
  163. if (mines[i, j] == MINE_DATA_MINE)
  164. {
  165. minecount++;
  166. }
  167. }
  168. }
  169. return minecount;
  170. }

  171. /// <summary>
  172. /// 递归方式扫描无雷区域
  173. /// </summary>
  174. /// <param name="x"></param>
  175. /// <param name="y"></param>
  176. private void RecursiveScanMine(int x, int y)
  177. {
  178. //边界检测
  179. if ((x < 0 || x >= mines.GetLength(0)) ||
  180. (y < 0 || y >= mines.GetLength(1)))
  181. {
  182. return;
  183. }
  184. //排除已扫描的区域或是有雷区域
  185. if (((mines[x, y] & 0x0f) != MINE_FLAG_NULL) || ((mines[x, y] & 0xf0) == MINE_DATA_MINE))
  186. {
  187. return;
  188. }
  189. if ((mines[x, y] & 0xf0) != MINE_DATA_NULL)
  190. {
  191. mines[x, y] |= MINE_FLAG_SCAN;
  192. return;
  193. }
  194. //置已扫描标记
  195. mines[x, y] |= MINE_FLAG_SCAN;
  196. //目标区域八方向递归扫描
  197. RecursiveScanMine(x - 1, y - 1);
  198. RecursiveScanMine(x - 1, y);
  199. RecursiveScanMine(x - 1, y + 1);
  200. RecursiveScanMine(x, y - 1);
  201. RecursiveScanMine(x, y + 1);
  202. RecursiveScanMine(x + 1, y - 1);
  203. RecursiveScanMine(x + 1, y);
  204. RecursiveScanMine(x + 1, y + 1);
  205. }

  206. /// <summary>
  207. /// 格式化/着色数字
  208. /// </summary>
  209. /// <param name="value"></param>
  210. private void ColourNumber(int value)
  211. {
  212. Console.ForegroundColor = MineData.ColorTable[value];
  213. Console.Write(MineData.FormatNumbers[value]);
  214. }

  215. #endregion
  216. }

  217. /*
  218. * /////////////////////////////////////////////////////////////////////
  219. * Program : MineData.cs
  220. * Author : Arliy (ArliyCoder#gmail.com)
  221. * Date : 2013/7/15
  222. * Resume : 格式化数据
  223. *
  224. * /////////////////////////////////////////////////////////////////////
  225. * Modifiy History
  226. *
  227. * Date :
  228. * Resume :
  229. *
  230. */
  231. public class MineData
  232. {
  233. public static string[] FormatNumbers = { "", "①", "②", "③", "④", "⑤", "⑥", "⑦", "⑧" };
  234. public static ConsoleColor[] ColorTable =
  235. {
  236. ConsoleColor.Gray,
  237. ConsoleColor.White,
  238. ConsoleColor.DarkGreen,
  239. ConsoleColor.Green,
  240. ConsoleColor.DarkYellow,
  241. ConsoleColor.Magenta,
  242. ConsoleColor.Blue,
  243. ConsoleColor.Cyan
  244. };
  245. }
  246. }
复制代码
  • TA的每日心情

    2015-6-25 12:42
  • 签到天数: 6 天

    [LV.2]偶尔看看I

    发表于 2014-6-13 12:35:32 | 显示全部楼层
    发张运行效果图看看
    您需要登录后才可以回帖 登录 | 注册青鸟豆号

    本版积分规则

    Copyright 1999-2019 Beijing Aptech Beida Jade Bird Information Technology Co.,Ltd

    北大青鸟IT教育 北京阿博泰克北大青鸟信息技术有限公司 版权所有

    京ICP备11045574号-3 京公网安备11010802013845号

    快速回复 返回顶部 返回列表