导入
可能已经注意到了,前一篇的所有 Tile 类型都是指针
这是因为打麻将时一共只有136张牌,所以各种牌山、牌河、手牌、副露都可以用指针指向那原来的136张牌,也可以提高效率
正题
首先写出这些量的指向关系,其中:
- 只有牌常量才是 Tile 类型,其他都是指针
- 直线表示包含有相同指针,箭头表示指针指向
- 牌河、手牌、副露都来自于牌山,所以一定被真包含于(⊂)牌山;由于副露可能是吃、碰、杠他人打出(牌河)的牌,所以副露和牌河有交集
由于其他都是指针,所以 Tile 类主要针对于牌常量(const_card)编写,可以写成以下的代码:
因为 const_card 作为唯一的非指针对象,并不需要改变他的值,所以 card 的值用 const 类型
class Tile
{
public:
const _int_ card; //存放牌信息
Tile(_int_ _card) : card{ _card } {} //构造
operator _int_() const { return card; } //直接返回牌的值
};
然后要决定不同的牌分别怎么表示,为了计算方便,我实行了如下设定:
character | card |
---|---|
一萬 ~ 九萬 | 0 ~ 8 |
一筒 ~ 九筒 | 16 ~ 24 |
一索 ~ 九索 | 32 ~ 40 |
東 | 48 |
南 | 56 |
西 | 64 |
北 | 72 |
白 | 80 |
發 | 88 |
中 | 96 |
可以发现幺九牌都是 8 的倍数,这样做有如下好处:
- 判断幺九牌(%8)和数牌字牌(/8)很方便
- 判断牌与牌之间关系很方便(相减分辨两张牌是否相同或连续)
- 判断是否是五万、筒、索方便
然后便可以着手写 const_card,由于牌数是确定的,所以可以用 array 类型
array<Tile,136> const_card //牌常量
{
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
16,16,16,16, 17,17,17,17, 18,18,18,18, 19,19,19,19, 20,20,20,20, 21,21,21,21, 22,22,22,22, 23,23,23,23, 24,24,24,24,
32,32,32,32, 33,33,33,33, 34,34,34,34, 35,35,35,35, 36,36,36,36, 37,37,37,37, 38,38,38,38, 39,39,39,39, 40,40,40,40,
48,48,48,48, 56,56,56,56, 64,64,64,64, 72,72,72,72, 80,80,80,80, 88,88,88,88, 96,96,96,96
};
然后要考虑的是如何给牌山赋值(随机)
暂时先用简单的时间作为随机数种子:
首先将牌山整齐地对应牌常量,然后创建一个随机的数组 arr[136],在用冒泡法排序 arr[136] 同时,打乱牌山以达到随机牌山的目的
explicit Maj_system(_wind_ _wind) :wind{ _wind } //(场风)开局
{
srand((unsigned)time(nullptr)); //设置时间随机数种子
for (_int_ i{ 0 }; i < 136; ++i) //牌山初始化
shan[i] = &const_card[i];
_int_ arr[136]; //随机数组
for (_int_ i{ 0 }; i < 136; ++i) //随机牌山
arr[i] = rand() % 32767 + 1; //赋随机值
for (_ull_ i{ 0 }; i < 135; ++i) //排序
for (_ull_ j{ 0 }; j < 135 - i; ++j) //防止出现警告,这里用 unsigned long long 类型
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
swap(shan[j], shan[j + 1]);
}
...
...
...
}
以上,关于 Tile 大体就介绍完毕了,这时(大概)就可以顺利运行该程序了233
规则参考
[1] 日麻百科
[2] 资深麻友
[3] 雀魂麻将
[4] 雀姬麻将
原创文章,转载请标明出处,如有谬误欢迎各位指正
欢迎交流麻将算法,QQ:2639914082