分享一个Winform扫雷的小程序(面向初学者所以用了中文变量名不喜勿喷)

zmidl 2017-06-03 01:37:53
加精
源代码如下:

using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;

namespace 扫雷
{
public partial class Form1 : Form
{
/// <summary>
/// 我们自己定义一个雷的方格按钮控件 继承自Button按钮
/// </summary>
public class 雷方格 : Button
{
// 在原来的基础上添加三个变量
// 当前方格所在的横坐标
public int 横坐标 { get; set; }

// 当前方格所在的纵坐标
public int 纵坐标 { get; set; }

// 当前方格显示的内容信息 有无雷 雷的个数等等
public string 内容信息 { get; set; }

// 标记此雷有没有被判过
public bool 是否判定过 { get; set; }
}

private const int 雷数量 = 36;
private const int 字体大小 = 7;
private const int 矩阵边界 = 10;
private const int 矩阵行数 = 12;
private const int 矩阵列数 = 9;
private const int 矩阵间隙 = 2;
private const int 方格宽度 = 30;
private 雷方格[,] 方格矩阵数组;
private FontFamily 字体样式 = FontFamily.Families[0];


public Form1()
{
InitializeComponent();
this.矩阵布局();
this.随机布雷();
this.注册点击事件();
}

/// <summary>
/// 把方格矩阵布局到窗体的方法函数
/// </summary>
private void 矩阵布局()
{
// 矩阵数组初始化一个新的对象 列乘以行的一个矩阵
this.方格矩阵数组 = new 雷方格[矩阵列数, 矩阵行数];

// 循环添加每一行 每一行的列数自然取决于列的个数
for (int 行 = 0; 行 < 矩阵行数; 行++)
{
// 同理循环添加每一列
for (int 列 = 0; 列 < 矩阵列数; 列++)
{
// 初始化一个新的方格
雷方格 方格 = new 雷方格();

// 指定该方格的宽度和高度
方格.Width = 方格.Height = 方格宽度;

// 设置方格上显示的信息的字体样式
方格.Font = new Font(this.字体样式, 字体大小, FontStyle.Bold);

// 字体的颜色
方格.ForeColor = Color.FromArgb(0x9A, 0xCD, 0x32);

// 设置方格的位置
方格.Location = new Point(矩阵边界 + ((方格宽度 + 矩阵间隙) * 列), +矩阵边界 + ((方格宽度 + 矩阵间隙) * 行));

// 指定方格的横坐标
方格.横坐标 = 列;

// 指定方格的纵坐标
方格.纵坐标 = 行;

// 指定方格显示的内容信息 暂且为什么都不显示为空
方格.内容信息 = string.Empty;

// 把初始化后的方格对象放入数组内
this.方格矩阵数组[列, 行] = 方格;

// 最终把这些方格全部放到窗体上
this.Controls.Add(方格);
}
}

// 设置窗体宽度 可以更具自己的情况来计算和放偏移量
this.Width = 矩阵边界 * 3 + (方格宽度 + 矩阵间隙) * 矩阵列数 + 矩阵间隙 * 2;

// 设置窗体高度
this.Height = SystemInformation.CaptionHeight + 矩阵边界 * 3 + (方格宽度 + 矩阵间隙) * 矩阵行数 + 矩阵间隙 * 2;

}

/// <summary>
/// 矩阵布雷方法
/// </summary>
private void 随机布雷()
{
// 新声明一个随机对象
System.Random 随机 = new System.Random();

// 新建一个临时变量“雷数量临时变量”取值与 之前定义的“雷数量”
int 雷数量临时变量 = 雷数量;

// 开始循环随机布雷 只要这个临时变量大于0 也就是还有雷需要布
while (雷数量临时变量 > 0)
{
// 随机生成一个行数 从0到行数的上限
int 随机行 = 随机.Next(矩阵行数);

// 同理生成一个随机列数
int 随机列 = 随机.Next(矩阵列数);

// 然后再判断是否有重复 如果内容是空的 则表示没有随机过这个坐标
if (this.方格矩阵数组[随机列, 随机行].内容信息 == string.Empty)
{
// 就给个 这个标记表示 当前这个方格为雷
this.方格矩阵数组[随机列, 随机行].内容信息 = "雷";

// 测试代码
//this.方格矩阵数组[随机列, 随机行].Text = "雷";

// 成功随机一个雷后 临时变量减去一个
雷数量临时变量 -= 1;
}
}
}

private void 方格点击事件(object sender, System.EventArgs e)
{
// 测试代码
雷方格 当前方格 = (雷方格)sender;
//MessageBox.Show(当前方格.横坐标.ToString()+"--"+ 当前方格.纵坐标.ToString());

this.踩雷与扫雷(当前方格.横坐标, 当前方格.纵坐标);

}

private void 注册点击事件()
{
// 遍历窗体下所有方格
foreach (雷方格 方格 in this.Controls)
{
// 每个方格注册一个点击事件
方格.Click += 方格点击事件;
}
}

/// <summary>
/// 判定当前点击的方格是否是雷
/// </summary>
/// <param name="横坐标"></param>
/// <param name="纵坐标"></param>
/// <returns></returns>
private bool 是否是雷(int 横坐标, int 纵坐标)
{
// 申明一个判定结果假设不是雷
bool 判定结果 = false;

// 坐标范围限制,不能是负数 也不能超过矩阵的行数和列数的上限
if (横坐标 >= 0 && 横坐标 < 矩阵列数 && 纵坐标 >= 0 && 纵坐标 < 矩阵行数)
{
// 如果指定的方格没有判定过的才可以判定
if (this.方格矩阵数组[横坐标,纵坐标].是否判定过 == false)
{
// 如果是随机布局的雷
if (this.方格矩阵数组[横坐标, 纵坐标].内容信息 == "雷")
{
// 那么返回是雷
判定结果 = true;
}
}
}
// 最后返回这个结果
return 判定结果;
}

/// <summary>
/// 把周围的雷全部收集起来放入一个列表里
/// </summary>
/// <param name="横坐标"></param>
/// <param name="纵坐标"></param>
/// <returns></returns>
private List<雷方格> 收集周围雷群(int 横坐标, int 纵坐标)
{
// 申明一个放群雷的列表 满打满算有8个
List<雷方格> 群雷列表 = new List<雷方格>(8);

// 如果点击的方格不是最左边
if (横坐标 > 0)
{
// 如果点击的方格不是最上边的方格
if (纵坐标 > 0)
{
// 那么左上角是有方格的 又如果这个方格没有判定过
if (this.方格矩阵数组[横坐标 - 1, 纵坐标 - 1].是否判定过 == false)
{
// 则把这个方格放入列表里
群雷列表.Add(this.方格矩阵数组[横坐标 - 1, 纵坐标 - 1]);
}
}
// 如果点击的方格不是最下面的方格
if (纵坐标 + 1 < 矩阵行数)
{
// 并且左下方是有方格的 又如果这个方格没有判定过的话
if (this.方格矩阵数组[横坐标 - 1, 纵坐标 +1].是否判定过 == false)
{
// 这个左下方的方格就放入列表里
群雷列表.Add(this.方格矩阵数组[横坐标 - 1, 纵坐标 + 1]);
}
}
// 点击的方格不是最左边的话 左边还有一个方格 并且没有判定过的话
if (this.方格矩阵数组[横坐标 - 1, 纵坐标 ].是否判定过 == false)
{
// 把左边这个方格放入列表里
群雷列表.Add(this.方格矩阵数组[横坐标 - 1, 纵坐标]);
}
}

// 点击的方格+1小于列数的话说明点击的方格是最右边的左边一个方格
if (横坐标 + 1 < 矩阵列数)
{
// 再如果不是最上边的那个的话
if (纵坐标 > 0)
{
// 那么右上角是有方格的 这个方格没有判定过的话
if (this.方格矩阵数组[横坐标 + 1, 纵坐标 - 1].是否判定过 == false)
{
// 把这个方格放入列表
群雷列表.Add(this.方格矩阵数组[横坐标 + 1, 纵坐标 - 1]);
}
}
// 再如果点击的这个方格是最下面的上面一个的话
if (纵坐标 + 1 < 矩阵行数)
{
// 那么点击的方格的右下方是有方格的 这个方格没有判定过的话
if (this.方格矩阵数组[横坐标 + 1, 纵坐标 + 1].是否判定过 == false)
{
// 把这个方格放入列表里
群雷列表.Add(this.方格矩阵数组[横坐标 + 1, 纵坐标 + 1]);
}
}
// 右边一定是有方格的 这个方格没有判定过的话
if (this.方格矩阵数组[横坐标 + 1, 纵坐标].是否判定过 == false)
{
// 把这个方格放入列表里
群雷列表.Add(this.方格矩阵数组[横坐标 + 1, 纵坐标]);
}
}

// 左右两边的都计算过了 剩下上面和下面的了
// 如果点击的不是最上面的方格 上面方是有方格的
if (纵坐标 > 0)
{
// 如果上方的方格没有判定过
if (this.方格矩阵数组[横坐标 , 纵坐标 - 1].是否判定过 == false)
{
// 把上方的方格放入列表里
群雷列表.Add(this.方格矩阵数组[横坐标 , 纵坐标 - 1]);
}
}

// 同样的判定是否是最下面的上面一个方格
if (纵坐标 + 1 < 矩阵行数)
{
// 如果下面有方格且没有判定过
if (this.方格矩阵数组[横坐标, 纵坐标 + 1].是否判定过 == false)
{
// 把这个方格放入列表里
群雷列表.Add(this.方格矩阵数组[横坐标, 纵坐标 + 1]);
}
}
// 最终方法得到这个周围雷群的列表集合
return 群雷列表;
}

/// <summary>
/// 扫雷游戏的核心代码-踩雷与扫雷
/// </summary>
/// <param name="横坐标"></param>
/// <param name="纵坐标"></param>
private void 踩雷与扫雷(int 横坐标, int 纵坐标)
{
// 首先需要创建一个缓存列表用来把所有需要递归
// 遍历的雷方格通通塞到这个缓存列表里慢慢消化
List<雷方格> 缓存列表 = new List<雷方格>();

// 当前这个也不列外先放进来
缓存列表.Add(this.方格矩阵数组[横坐标, 纵坐标]);

// 开始循环遍历,退出的条件当然是没有可以循环的
// 方格了也就是说列表成员=0了就没有了可以退出了
while (缓存列表.Count > 0)
{
// 我们总是从列表的第一个方格开始判定起,程序里第0个就是第一个
// 我的先得到第一个方格的横坐标的值
int 当前横坐标 = 缓存列表[0].横坐标;

// 以及纵坐标的值
int 当前纵坐标 = 缓存列表[0].纵坐标;

// 声明一个雷数计数变量 一开始假设没有雷
int 周围雷数 = 0;

// 这里就用到了之前写的辅助方法 判定当前坐标下的方格是不是雷 如果是
if (this.是否是雷(当前横坐标, 当前纵坐标) == true)
{
// 把列表清除掉 工作结束了。
缓存列表.Clear();

// 弹出框 展示噩耗。
MessageBox.Show("你小子踩到雷啦。哇咔咔。。。");
}
else
{
// 如果不是雷 那么就开始 周围一圈一个个判定是不是雷 是的话 计数变量就加1
if (this.是否是雷(当前横坐标 - 1, 当前纵坐标) == true) 周围雷数++;
// 以下是周围八个方向的方格是否雷的判定 省略。。。
if (this.是否是雷(当前横坐标 - 1, 当前纵坐标 - 1) == true) 周围雷数++;
if (this.是否是雷(当前横坐标, 当前纵坐标 - 1) == true) 周围雷数++;
if (this.是否是雷(当前横坐标 + 1, 当前纵坐标 - 1) == true) 周围雷数++;
if (this.是否是雷(当前横坐标 + 1, 当前纵坐标) == true) 周围雷数++;
if (this.是否是雷(当前横坐标 + 1, 当前纵坐标 + 1) == true) 周围雷数++;
if (this.是否是雷(当前横坐标, 当前纵坐标 + 1) == true) 周围雷数++;
if (this.是否是雷(当前横坐标 - 1, 当前纵坐标 + 1) == true) 周围雷数++;

// 判定过了的话,那么把“是否判定过”的标帜置成true;
缓存列表[0].是否判定过 = true;

// 不管当前是不是雷踩过了就设置背景颜色为暗灰色来区别对待
缓存列表[0].BackColor = SystemColors.ScrollBar;

// 如果雷数是0的话收集周围的雷群
if (周围雷数 == 0)
{
// 把之前写的收集雷的方法带进去,方法返回的是雷方格的集合
// 所以缓存列表用的是AddRange方法-即添加范围
缓存列表.AddRange(this.收集周围雷群(当前横坐标, 当前纵坐标));
}
// 如果周围有雷
else
{
// 那么当前点击的方格也就是踩的雷显示周围雷的数量
// 记住“周围雷数”是int 整型变量要.ToString()转成字符串类型
this.方格矩阵数组[当前横坐标, 当前纵坐标].Text = 周围雷数.ToString();

// 为了把周围雷数看清楚点我们把雷数量的字体用深色显示出来
this.方格矩阵数组[当前横坐标, 当前纵坐标].ForeColor = SystemColors.WindowText;
}
// 处理完一个当前踩的雷后 把它从缓存里移除
缓存列表.RemoveAt(0);
}
}
}
}
}

...全文
7075 42 打赏 收藏 转发到动态 举报
写回复
用AI写文章
42 条回复
切换为时间正序
请发表友善的回复…
发表回复
zmidl 2017-07-30
  • 打赏
  • 举报
回复
为了给开火车教程助阵,自己顶一下。
liuguangnan 2017-07-13
  • 打赏
  • 举报
回复
很好的帖子,支持一下支持
  • 打赏
  • 举报
回复
厉害厉害
zs1678940727 2017-07-13
  • 打赏
  • 举报
回复
中文与源码相结合,不错呦~
fenaoy 2017-07-13
  • 打赏
  • 举报
回复
挺好的
  • 打赏
  • 举报
回复
很好的帖子,支持一下支持
秋的红果实 2017-07-09
  • 打赏
  • 举报
回复
感谢分享,中文倒是觉得有点不习惯
a376179526 2017-07-09
  • 打赏
  • 举报
回复
不错,下下来看看
FreshBird1 2017-07-02
  • 打赏
  • 举报
回复
谢谢分享,菜鸟还是需要多关照
jlqwer.com 2017-06-30
  • 打赏
  • 举报
回复
学习一下,谢谢分享!
  • 打赏
  • 举报
回复
qq_36219845 2017-06-24
  • 打赏
  • 举报
回复
6666666
OneCoderr 2017-06-19
  • 打赏
  • 举报
回复
第一次见中文变量,不过感觉到很好阅读啊。 大家都是用什么? 英文? 全拼? 简拼?
ARX7500 2017-06-18
  • 打赏
  • 举报
回复
这个需要编辑窗体么?
  • 打赏
  • 举报
回复
你这个“每个方法名或者重要点的地方就会中文写个注释”说法偷换概念啊。 我是说用大量英文名,然后英文名旁边只有一个中文名对照,是这个意思。 而比如说 lz 的代码
方格.纵坐标 = 行;
旁边还写了一个中文注释
//  指定方格的纵坐标
这是他自己要写这个中文注释,并不是对号入座的我说的“中译英+英译中==重复翻译”的书写方式。 并不是说凡是自己认为重点的地方旁边都要写个中文注释就是我说的那个意思,这样说是在歪曲我的话。
  • 打赏
  • 举报
回复
引用 29 楼 happy4944 的回复:
[quote=引用 25 楼 sp1234 的回复:] [quote=引用 22 楼 chen_767 的回复:] 第一次看的中文变量的代码
中文变量本身没有什么。反而是,我看到有的变量是英文的,然后再每一个英文变量旁边都注释上中文名字,这才是折腾哪。[/quote] 说的就是我,每个方法名或者重要点的地方就会中文写个注释。要求都是英文,我又怕过段时间就不知道那些方法表示什么意思,只能注释[/quote] 那为啥不用汉语拼音?
踏遍天涯路 2017-06-15
  • 打赏
  • 举报
回复
中文变量,怪怪滴
zmidl 2017-06-12
  • 打赏
  • 举报
回复
引用 32 楼 only_endure 的回复:
还要扫码下载啊。
扫码后进入公众号里面有超详细图文教程,劳动果实啊,万望支持下。
pkuzhx 2017-06-10
  • 打赏
  • 举报
回复
第一次见中文变量代码,666666
iiweixiao 2017-06-10
  • 打赏
  • 举报
回复
写的真详细,给你点赞
加载更多回复(22)

110,499

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧