(已更新)《WinXP经典扫雷·加强版》思路与制作(支持WinXP/Win7/Win10)
本帖最后由 klise 于 2021-12-30 12:13 编辑【前言】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
温馨提示:
1、该版本在 WinXP/Win7/Win10 都能玩,绿色软件,不用辛辛苦苦去找XP电脑,也不用辛辛苦苦装一套虚拟机。
2、如果玩家在使用过程中发现问题,我将尽力修正,因此可能发布更新版本,请各位继续关注。
3、网友反映的游戏bug已经修复,详见【游戏下载】的说明。
《WinXP》的“扫雷”游戏,是我们的集体回忆。这个小游戏既锻炼了推理能力,又练习了鼠标操作。
后来,尽管 Win7 也有扫雷游戏,但是已经找不到那种“年少”时期的感觉。而到了 Win10,干脆把这些游戏都取消了。
为了让这个经典游戏重新焕发光彩,我们对《WinXP扫雷》进行改进,称为《WinXP扫雷·加强版》,简称《JF扫雷》。
该版本可以在 WinXP/Win7/Win10 中运行。你不必辛辛苦苦去找XP的电脑,也不用辛辛苦苦装一套虚拟机。
JF是 Just Fun 的意思,所谓“世事无绝对,只有真情趣”,译成英文就是 No Worry, Just Fun ...
(注:下图可能引致密集恐惧症 ……)
【原版的缺陷】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
WinXP是2001年的产品,当时的显示器只有1024*768,《扫雷》的界面最大只能 30*24 (左右宽度30格,上下行数24行,本文全部采用这种表示方法)。
眨眼间,20年过去了,当年的同学少年,现在已经是孩子上小学了 ……
现在的电脑主流显示器是 1920*1080,显然 30*24 已经过时了……
另外,原版《扫雷》没有撤销功能,声音也难听,没有存档功能,等等 ……
因此,希望这次《WinXP扫雷·加强版》集中解决有关问题。
【准备工作】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
由于WinXP的《扫雷》、《空当接龙》都是类似的开发模式,都存在重定位的问题,因此必须用 LordPE 去除重定位,这一步请参见下帖,不再赘述:
《WinXP空当接龙》加入无限撤销和存档功能
https://www.52pojie.cn/thread-1314510-1-1.html
由于这次开发规模较大,所以把API函数全部导出,保存下来。不要少看这个步骤,后面会带来非常大的方便性。
用 OllyDbg 打开原版exe文件,右键->查找->所有模块中的名称:
然后,点击【模块地址】排序,全部复制到剪切板。
再粘贴到文件中备用:
【找到关键过程】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们知道,所有的关键过程都集中在“窗口消息处理”模块中,这是一个“大宝库”。只要找到这个模块,里面的秘密全部向你敞开。
寻找“窗口消息处理”模块的方法很多,最简单的方法是找到 RegisterClassW 函数。
这是因为,生成游戏窗口时,总是先调用 RegisterClassW (注册“窗口类”), 然后再调用 CreateWindowExW 生成窗口。
而窗口消息处理模块就在 RegisterClassW 中。
我们可以借助上面准备的“模块间调用”文件,查找字符串 RegisterClassW ,得知其地址为 010010CC :
在 OD 中找到地址 010010CC ,右键->查找参考,定位到代码处,F2断点:
运行游戏,断点停下,查看堆栈中的参数,地址是 0CFE88 :
该地址后面 4字节, 即[ 0CFE88 + 4 ]= 01001BC9 就是窗口消息过程!
【雷区的边界】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
找到了大宝藏,下面开始进行分析。
首先第一个问题,就是原版的界面(雷区)为什么这么小。我直接引用前辈们的成果,原来《扫雷》是按照“每行32格”来设计的,一共27行,即 32*27=864 字节。
为什么是32格呢?因为方便计算!因为 “行数乘以32” 就是 “行数左移5位”,就是一句 shl ecx, 5 这样子,搞定了!
游戏中,如果你选择的雷区(宽度)小于32格,也没关系,反正内存中还是按照每行32格来计算,只不过“右边界”不同而已。
应该说,“边界”的思想是神来的一笔,在判断周围布雷(包括开挖、显示数字等)都非常方便。如果不用边界,那就要判断内存(数组)越界,麻烦多了。
由于有了边界,所以雷区的尺寸要减去2,最大宽度30个(即32 减2),高度24行也是同样的道理(微软的程序员独吞了一行……)。
另外,边界还有一个重要的作用,就是“防止雷区无序扩张”,这个道理大家都懂。
【从零开始】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们看到,电脑中的元素(行、列)都是从零开始的,而不是我们习惯的 从1 开始。
为什么会这样呢?老师曾经解释过,是为了节约内存,别浪费了 ……
我们来看一个例子。快过年了,你和女朋友一起回家,你买了两张机票,座位是19和20号。
上了飞机,你问空姐座位在哪里。空姐说:“这里每一排是10个座位,19号座位就是(1,9),第1行第9个座位。”
你想了想,有道理,19除以10,商数=1,余数=9,所以就是(1,9),空姐真是美貌与智慧并重啊……
然后空姐看看你手上的20号机票,说:“20号座位就是(2,0),第2行第0个座位 ……”
你很诧异,觉得哪里不对,但是20除以10,商数=2,余数=0,所以就是(2,0),没毛病呀 ……
于是你往后一排走去,那里坐着一位大汉,络腮胡子,他对你咧嘴一笑:“我是21号,你瞅啥?”
这时,你发现那些拿着30号、40号、50号……座位的乘客,都在忙乱地找座位。
问题在哪里呢?就是因为,人类喜欢从1开始,而事实上,余数可以为0,人类就会迷惘了。
如果第一个座位从零开始,一切就迎刃而解了。你的座位(20号)变成 019=(1,9),没问题,
而络腮胡子变成 020=(2,0),就是2行0列,也没问题(注:0、1、2,也就是我们通常说的第3行)。
因此,“从零开始”是避免计算机产生 低级错误 的重要手段。
【突破雷区】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
现在我们要考虑的是,加强版要搞“多大”的雷区比较合适呢?
这里有一个天然的因素,就是显示器的大小。如果游戏窗口比屏幕还大,那显然不合适。
而主流的显示器是1920*1080,我们就以这个作为标准吧。
经测算,1920*1080允许的格子数大约是(宽度)120格,高度60行。
但是还要扣除任务栏、侧边栏等空间,所以最大雷区定为 116*56 = 6496 格,简称6500格。
【开辟内存】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
那么,只要准备6500字节就行了吗?
不是的。
前面说过,原版《扫雷》以32格作为标准,用了大量的“左移”指令,类似于 shl ecx, 5 这种汇编码(如图,3个字节)。
而 116格 是不能通过简单“左移”来计算的,必须改成乘法指令,就要打破原来的指令长度(3个字节),带来很大的麻烦。
幸好,我们知道与 116 最接近的“二次幂”是128,而128就是左移7位!
也就是说,我们在内存中定义每行128格,这样只要把所有 shl AAA,5 改成 shl AAA, 7 就行了!
至于行数,取64行,128*64=8192=8KB,也就是说,预备8K内存给雷区,足够了。
总结一下:内存预留 128*64 的雷区,但是受到屏幕尺寸的限制(视觉问题),游戏限定最大雷区是 116*56 。
于是,我们给exe加上一个新区段,大小8KB,新的雷区数据全部搬迁到这里。
【代码扩容】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
接下来,要修改原版exe中所有关于雷区尺寸的代码,把“宽度”32格扩展为128格,”高度“也要相应扩展。
这个工作比较繁琐,但是不难,因为代码特征容易找。
原版exe的雷区数据位于 01005340,在 OD 中查找所有引用该地址的代码:
然后出来很多地址,现在要做的就是逐个地方进行修改。
如上图,这“一处”要改4个地方:
(1) 左移5位(乘以32),改成左移7位(乘以128)
(2) 把 01005340 改成新区段(8KB那个)的首地址
(3) 这一句是按照每行32字节(0x20)递增,改成 add edx, 0x80 (按照128字节递增)
(4) 这一句比较隐蔽,它的用意是首地址 01005340 就上 0x20 组成,也就是雷区01行的首地址,要改成 [ 新区段+128字节 ] 的地址。
下图是改动后的情况,第(1)(2)两句最简单,第(4)句我给01行加了标号,直接替换。第(3)句最麻烦,因为原句是3字节,改成add edx, 0x80 是6字节的指令,打破了长度,必须跳转补丁。
【午饭时间】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
上述过程不难,但是非常繁琐,要改N处,每一处有M句,就是要改 N*M 句,凡是 add AAA,0x80 的都要改成跳转。
还有一个最麻烦的事,就是必须所有地方全部改完,才能测试。因为只要有一处没做好,运行结果就一定是错的(雷区残缺),
而最要命的是,你还不知道哪一句漏掉了 …… 这就要从头全部检查一遍。
因此,这个工作是专门花一个下午来进行的,而且还要做如下准备工作:
1、斋戒
2、沐浴
3、焚香
4、关门
…… 好了,终于进入了屏息静气,天人合一的境界 ……
现在,没有任何外物可以打扰我的心神 ……除了外卖 ……
【乔布雷师】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
经过一个下午的奋战,到了凌晨零时十分,终于搞定了所有“代码扩容”,可以正常开局(布雷)了。
开局布雷是一个标准的随机数产生过程。这里要说一下我们熟悉的《空当接龙》。
大家知道,WinXP的《空当接龙》有100万局,每局都不同。但是那个exe只有几十KB,几万个字节,那么这100万局扑克牌是储存在哪里呢?
就算一局只要1个字节,那也要100万字节呀!这都要1MB呀,怎么几十KB就能搞定呢?
原来,这里涉及到电脑“随机数”的原理。简单来说,牌局是随机的,但是实际上,牌局是确定的。
就好像你问女朋友,中午吃什么?她说“随便”,其实根本不能随便。
随机数是一个迭代过程,类似于这样:
也就是
以上是 VC 的随机数生成过程,上面这些 r1r2r3 就是随机数。我们看到,只要有了 r0 ,就能计算 r1,然后计算 r2……
这里只有 r0 是“必须给定”的,它不是根据其它数值计算得到的。这个 r0 称为“随机种子”。
《空当接龙》就是利用这个原理,把牌局编号(比如 202021) 作为r0 ,由此得到 r1r2r3…… 这就是发牌顺序。
因此,《空当接龙》根本不用储存任何牌局。
现在回到《经典扫雷》,它也是利用(上述一模一样的)随机数原理,来埋设地雷(布雷)。只要你指定一个r0 ,它后面的布雷就是完全一样的。
看上去是一本正经的布雷师,实际上是假装随机的!所以它是“乔布雷师”。
【1亿小目标】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
明白了上述原理,我们就能像《空当接龙》那样,使用“牌局编号”(还是称为“关卡编号”吧)作为特定的“随机种子”,产生特定的雷区。
《 JF扫雷》采用8位数字作为随机种子,因此可以产生 9999 9999 个雷区,也就是“1亿小目标”。
每一局开始后,在窗口标题上会显示当前“关卡编号”,可以通过“选择游戏”功能,输入关卡编号,重现任何一关。
同时,也可以实现“重新开始”当前关卡的功能,因为就是一个关卡编号。
(Win7的官方扫雷也实现了“重新开始”功能)
【 调用默契】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
由于屏幕大了,地雷多了,原版的两个液晶显示(999秒 和 999雷)显然不够用了,要把它们改成 9999秒 和 9999个雷。
这个改动不难,调整一下显示位置(坐标),然后把数值循环 4次 显示即可。
当然,我们是调用原版的功能来显示的,总不会自己重新写一套 LED 函数。
既然调用原函数,就涉及到寄存器的问题。对于CPU的8个寄存器,编译器是怎样安排的呢?
1、寄存器 eax/ecx/edx 是“易失”的,也就是在函数过程中会随意使用,不会保存、恢复其数值。函数返回后,这3个寄存器的内容是无法预测的。
因此,如有需要,你必须自己保存、恢复。
2、如果函数有返回值,那么通常就用 eax 返回。
比如 eax 是 0或1,就是返回 真/假,也可以是数值、或者地址(指针)。
3、寄存器 ebx/ebp/esi/edi 是保管的,函数过程会保存它们的数值,在返回时恢复它们的数值。
这些寄存器你就不用费心保管了,函数返回后,保证毫发无损,完璧归赵。
4、堆栈 esp 通常是平衡的,不用费心,但是如果你在call 后面看见add esp, 0x8 之类,那就是必须手工平衡,照抄即可。
通常 VC 申请/释放 内存时,要手工平衡堆栈( add esp, 0x4 )。
以上这些“调用默契”是非常重要的。比如一个函数包含 1000 句代码,但其实编译器是首先生成 N个小“代码片”,每个“代码片”就是5句、10句的样子,再把这些“代码片”组装成 1000句 的。
比如,做个加减乘除,用eax/ecx/edx 足够了,这几个寄存器也不用保存恢复,是不是简便很多?
【找对象】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这里的对象,是指高级语言的“面向对象”。
在《空档接龙》《扫雷》这些小游戏中,是用不上“面向对象”的。不过,由于在“吾爱”发帖的机会不是很多,这里简单讲解一下。
对于通常的函数调用,我们是熟悉的,比如 sum(a, b),就是:
push b
push a
call <sum>
那么,如果是“对象方法”,比如 往箱子 box 里放苹果,也就是 box.sum(a,b) ,在汇编语言里是怎么样的呢?
以前我们总是觉得“面向对象”是很深奥的东西,但是在汇编的世界里,却是很单纯的。
对于汇编语言来说,对象就是一个地址,指向一个“结构”,仅此而已。
比如box.sum(a,b),用 VC 编译后,生成的汇编就是这样的:
push b
push a
mov ecx, ebp ; 注意这一句!ebp=box指针
call <sum>
注意:用VC编译器生成的“对象”,就是通过 ecx 传递到函数中的,而不是 push 到堆栈的。
比如本例中,ebp指向box对象(ebp是保管变量,可靠呀),调用 sum 之前,先复制到 ecx 。
在<sum>过程中会认为 ecx 就是对象指针,这是调用约定!
我们假设 box 对象具有4个属性:
{
长, //00~03字节
宽, //04~07字节
高, //08~0B字节
苹果数量 //0C~0F字节
}
那么 box.apple 就是第 0xC 字节
在 <sum>过程中是这样的:
mov eax, ; 取 a
add eax, ; eax=a+b
mov ,eax ; 苹果数量写入box.apple
retn 0x8
我们可以理解为:<sum>是 box的方法,它不但做运算,而且还改写属性(苹果数量),用高级语言类似于:
void box.sum(a,b)
{
box.apple=a+b;
}
这就是“面向对象”在汇编语言中的具体实现。
现在,无论是日常应用,还是大型游戏,VC 都占据主流了。了解这个规则,是有现实意义的。
【开辟根据地】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
我们知道,WinXP《扫雷》在玩家第一次点击时,会刻意保证不会爆雷。
到了 Win7,第一次点击会出现一块空地,称为“根据地”。
《 JF扫雷》也实现了这个功能,下面说一下实现原理。
如下图,玩家(随机)点击(1)处,程序首先以(1)作为中心点,在该点周围 3x3 的范围内的地雷,全部移到别处。
这样,就产生一个至少 3x3 的空地,也就是(2),红色小方框。
但是实际上,这个“空地”可以紧邻其它空格,这是当初布雷的时候形成的,与玩家开局的点击无关。
所有这些紧邻的空格互相连通,就形成一片“根据地”,也就是(3),红色大方框。
“开辟根据地”必须打钩开启“安全模式”,下面说明。
【安全模式】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
随着雷区的扩大,玩家投入的时间成倍增加,踩雷的机会也会大增。
尤其是一时手误,那更无辜,玩了半小时的游戏直接 Over 了。
因此,《 JF扫雷》提供了安全模式。每次运行exe后,自动默认打钩。
在安全模式下,每一局开局后第一次点击,会自动开辟根据地。
而在游戏过程中,每一局提供3次金钟罩,就是3次“爆雷纠错机会”。
重复:是“每一局”都有3次机会。同一局 重新开始,也重新获得3次机会。
当玩家踩雷后,游戏会提示你使用纠错机会,当然也要扣减一次。
如果3次机会都用完了,那就 ……
有的网友希望实现“撤销功能”,其实就是纠错机会。
【善意的谎言】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
随着开发的推进,我们需要不断修改exe的内容,包括菜单、快捷键等。
比如《 JF扫雷》加入了“功能”子菜单,通过exescope等工具很容易实现。但是,不知不觉的,这个exe的体积也在悄悄增大了。
然后再用 OD 打开,你会发现,哇烤,那些辛辛苦苦做的 断点、注释、地址、标签、补丁 …… 通通的不见啦??
进去 OD/udd 目录一看,原来是 udd 文件被清空了!是谁干的?!
原来,这是 OD的自动机制。它在udd文件中记录了exe文件的信息,包括体积。
一旦发现体积变了,OD 就认为是另一个 exe,原来的调试信息(想当然地)对不上了,于是干脆清空 udd 文件,重新开始。
遇到这种情况,首先一定(一定)尽快把 bak 文件拷贝出来,这是原来 udd 的备份,称为 “旧udd” 。
(注:自从几年前发生过一次之后,我就养成了主动备份 udd 的习惯,写个 bat 文件就行,每半天关机之前备份一次)
现在,请你用 HexEdit 之类编辑器,打开 “旧 udd” 文件,开头不远处有个 Size 字样,后面就是文件体积。
当然,这里是旧的文件大小,把它改成新的体积,这样 udd 就能继续使用了。
这是用来骗过 OD 的善意谎言。
其实,尽管exe体积变了,但是各个区段的“基址”通常都没变,那些 断点、注释、地址、标签、补丁 基本上都能用,
【播放音效】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
原版扫雷的声音比较坑,打开之后,逐秒播放,而且音量大,巨难听。
所以,绝大多数玩家都会关掉声音功能。
《 JF扫雷》重新改进了声音功能:
1、 取消了逐秒播放,以免打扰玩家
2、 仅在开局、踩雷、结束(胜局、败局)播放声音
3、 内置两套音效,也就是开局两种音效、爆雷两种音效、胜局两种音效、败局两种音效
两套音效随机播放,以免过于单调。
声音文件以“资源”方式内置于DLL中,这也是《WinXP空当接龙》加入无限撤销和存档功能 中的观点:引入DLL,受益无穷。
【难度级别】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
随着游戏画面的扩大,从原始的 30*24 发展到 6500 格,原版单纯的“三级制”显得太粗疏了。
这个问题花费了很多时间去考量,在整个开发过程中,也经过多次修订。最终我们敲定了一个思路:
1、界面宽度从(近似)30~120,以30格递增。这样构成4个级别,称为:初级、中级、高级、超级
2、界面高度(行数)是以宽度乘以 0.618,这样界面的长宽比例接近黄金分割,视觉上比较舒适
3、每个级别(例如中级)内部又分为三种难度、、,三种难度的长宽都一样,区别在于地雷数量不同
中级 60*36:300
中级 60*36:350
中级 60*36:400
这3种难度都是 60*36,即宽度(从左到右)是60个格子,高度(从上到下)是36行,共 60*36=2160 个格子。
而它们的区别就是地雷数量(即冒号后面的数字),分别是 300、350、400 个地雷。同样的界面大小(格子数目),地雷越多,难度越大。
【难度测试 】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在游戏主菜单可以看到,各种难度的地雷数目相差只是几十个(50个左右)。
这是经过实践测试的,虽然只是几十个之差,但是难度的提高很显著。
这是因为,地雷密度增大后,开局的“根据地”会变小,导致开局不利。
而玩到后面,推理也越来越难。有时候甚至无法推导,要靠“盲猜”。
这里要感谢我的贤妻,她花费了很多时间进行测试,尤其是上述难度级别曾经多次调整(修订)。
通常,女性的逻辑思维都不强,但奇怪的是,她玩《空当接龙》、《扫雷》却是好手。
如果她噼里啪啦一顿鼠标,然后跑去厨房继续做饭,那么这种难度一定很低。
如果她聚精会神玩了很久,厨房还飘来焦糊的味道,那说明这一关真的很难,不是一般的难。
由于她在几个著名的购物节里,专心进行测试(我故意安排的),终于确定了各个难度级别。
整个测试下来,我想对大家说一句心底话:没事别碰“超级关”!
【其它功能 】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
【练习模式】—— 该功能会揭晓(标出)当前关卡中所有地雷,以供练习思考。当然也就不算成绩。
【游戏秘籍】—— 原版扫雷中,可以使用 XYZZY 秘籍。该功能予以保留(不变),详情可以网搜。
【保存游戏/读取存档】—— 可以保存当前盘面,以后读档 继续玩,不必从头开始。
存档功能有以下实用意义:
1、由于游戏界面大幅扩充,玩一次所需的时间很长,加入存档功能可以提供便利。
2、有些关卡玩到后来,确实只能盲猜,可以利用 存档/读档 功能,合法避雷。
3、在《 JF扫雷》开发过程中,需要对一些特定(布雷)情况进行测试,存档功能可以“重现”游戏局面,非常有用。
【附录:Win7原版扫雷 】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
这次顺便研究了《Win7原版扫雷》在 Win10 运行的问题。
虽然在网上可以找到相关的方法,但是由于使用了 Win7x64 的《扫雷》版本,这是x64的文件,不能用 OllyDbg 调试。
因此,现在从 Win7 32位 中提取了《扫雷》,供大家研究。
但是,这个32位的扫雷用 OD 打开后,其执行地址是变化的,每次打开都不同,这就给调试带来麻烦,连个断点都记不住。
为此,对原版 MineSweeper.exe 清除重定位,基址就固定下来了:
现在可以正常用 OD 调试了。破解后的文件可以正常在 Win10 运行。
在附录中,包含了上述(过渡及成品)文件,参见目录中的说明。有兴趣的朋友可以自己动手进行破解。
【下载地址 】
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
以下是作品下载地址,请仔细阅读目录的《使用说明》。
如有问题,欢迎反馈,将尽快修复并更新。谢谢大家!
更新说明
自从《JF扫雷》发布后,有网友反映,按下<Shift+左键>点击数字时(相当于“左右双键”同时按下),安全模式失效。
本次更新修复了这个问题。如果你习惯使用<Shift+左键>操作,请下载这个更新版本。
感谢大家的支持!
【2021-01-03】《JF扫雷》更新版:
蓝奏下载:
https://wwi.lanzouw.com/iizp3jzjdij
--------------------------------------------------------------------------------
《 JF扫雷》首发版(有bug):
蓝奏下载:
https://wwi.lanzouj.com/i9bIhjqpawh
(已破解·支持Win10):
https://wwi.lanzouj.com/i3BOJjqpmqd
扫了这么多年,一次自定义巨型图都没有过。。。
不仅仅因为自己经常性眼疾手残
更是因为一次次的二选一会让你耗光所有运气
会让你觉得过这么大的图压根就不可能了
作为一个资深扫雷爱好者,真心要感谢楼主和你的安全模式。
有没有那种打包成exe的……
我还挺想玩的,但不是大神,楼主的教程实在是看不懂。 作者大佬先解决一下空当接龙丢牌bug 超大杯吗?火钳 坐等楼主成品 评分先献上!闲暇之余爱玩扫雷 之前在吾爱下过一个完美支持WIN8的 太简单了 就喜欢这种密集难度的 大兄弟链接呢? 链接呢? 屌爆了。。这么一片吓死了 绝对的高手啊 喜欢数学才会去玩吧!!! 持续关注,期待下一步的进展{:1_927:}