原创

《明星三缺一》麻将牌存储和表示

本文字数:

2457

,大约阅读2分钟

明星三缺一是一个古老的单机麻将游戏,没事干的时候可以简单的消遣一下。但是发现,对于我这种不会玩的人来说,还是有点难度,而且总是给人家 “点炮”,总是输。没办法,想着看看电脑的牌,让自己玩的时候小心一点。

拿出工具,自己操刀,试着搞一下!其实也没有太多的思路怎么搞,后来想那就直接先找找游戏中的积分,搜到积分以后就在积分的附近随便看看内存中的数据,有没有什么特征,然后我竟然运气很好的看到了牌的存储。

麻将牌在内存中的表示是这样的:

万:0x00~0x08

筒:0x10~0x18

条:0x20~0x28

白:0x34

中:0x36

东南西北:0x30 0x31 0x32 0x33

牌在内存中是一个 WORD 数组结构,我就有些奇怪,既然牌的值都是 BYTE 表示的,那么在内存中存储不用 BYTE 节省点空间呢?要么省事用 DWORD 也可以啊,竟然用个不伦不类的 WORD。管他呢,先把牌从内存中读出来再说。获取牌的时候可以很顺利的把牌的数组通过程序读取出来。

可以看到程序已经把每个人的牌都读取出来,但当有 “吃、碰、杠” 的时候,读牌程序会报错。然后继续看了一下内存,原来有 ”吃、碰、杠“ 的时候,数组会填充 FF,而我定义的数组没有 FF 下标,就报错了。下图是正常的麻将牌的内存。

下图是有 “吃、碰、杠” 时内存的情况。

可以看到,前六个字节被填充成了 FF,因此只要我的程序读到 FF 的时候,直接读取下一个 WORD 就可以了。

那么,我看来还要找到 “吃、碰、杠” 的牌,开始以为 “吃、碰、杠” 的牌会在另外一个数组中存放,但是在上面的图中发现,其实和手中的牌在一个数组中。数组开始位置被填充了 FF,在数组的最后存放了 “吃、碰、杠” 的牌。通过观察发现,对于牌值为什么用 WORD 进行存储恍然大悟。常规的手牌中,低字节存储牌的值,高字节填充为 00。对于 “吃、碰、杠” 的存储,低字节也存储的牌,高字节则存储一个 “类型”,这个 “类型” 用来说明当前牌它是 “吃、碰、杠” 的类型值。经过分析,它的存储是这样的。

碰的类型值为 1,杠的类型值为 2,暗杠的类型值为 3,这种表示感觉比较好理解,因为无论是 “碰” 和 “杠” 牌面的值都是一样的。而 “吃” 的话是三张牌,三张牌怎么用一个 WORD 进行存储呢?经过自己 “吃” 了好几次以后,发现有三种情况,总结如下:

我吃了一个吃 6 筒,形成的牌是 456 筒,内存中存储的 WORD 是 13 20,13 是 4 筒,20 是吃的类型;

我吃了一个 8 条,形成的牌是 789 条,内存中存储的 WORD 是 26 10,26 是 7 条,10 是吃的类型;

我吃了一个 1 万,形成的牌是 123 万,内存中存储的 WORD 是 00 00,00 是 1 万,00 是吃的类型;

看到上面的情况,其实已经可以自问自答了。“吃” 了一个六筒,那么存储的时候是 13 20,13 是四筒,20 是什么呢?然后 “吃” 了一个八条,存储的是 26 10,26 是七条,10 是什么呢?再然后 “吃” 了一个一万,存储的是 00 00,00 是一万,00 又是什么呢?

其实它的 WORD 中的存储的内容中,低字节用来存储 “吃” 牌的第一张牌,高字节存储的是 “吃” 牌的位置,00 表示吃牌的是第一张,那么 00 00 表示 “吃” 的就是一万;26 10 表示 “吃” 的八条,13 20 表示 “吃” 的是四筒。继续改改代码,运行结果如下:

用 WORD 来进行存储,的确也是节省空间,因为在 ”吃、碰、杠“ 时存储牌只占用了一个 WORD。而且手牌和 ”吃、碰、杠“ 可以用一个数组进行存储。再者,为什么用牌的值用 十六进制 进行存储呢?这个其实也是有道理的,出牌时会判断牌是否是三张(或者是两张)连续的顺子。正常情况下,比如是万子,可以是 七万、八万 和 九万,那么值就是 6、7 和 8,然后筒子如果有 一筒、二筒 和 三筒,如果用 十进制 表示,那么就是 10、11 和 12,在判断值的时候,就会考虑 8 和 10 的问题,那么就要考虑 万 和 筒 的边界问题。如果用 十六进制表示 0x08 和 0x10 之间就不是连续的了。那么,你可能会说,8 和 10 也不是连续的啊,但是在实际出牌时,两张牌之间相隔一张牌,它就有可能会称为一个三张牌的顺子,那么我们出牌时也会考虑留下这两张牌,想着把它们凑成三张的情况。

虽然电脑的牌是读出来了,但是还是赢不了!算了,不玩了,放弃吧!

信息安全
Win32/64
安全工具开发
C/C++
二进制
加密与解密
逆向分析
  • 作者:Netor0x86(联系作者)
  • 发表时间:2023-03-27 07:30
  • 版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)
  • 公众号转载:请在文末添加作者公众号二维码
  • 评论