libsaki/form/tile_count.h定义了一个类TileCountTileCountT37的一个多集(multiset),记录每种牌有几张。 TileCount有很多用途,可用于表示手牌,也可以用于表示牌山。 不过牌河是表示不了的,因为TileCount不记录牌之间的先后顺序。


构造函数

Prototype Explanation
TileCount() 一个空集
TileCount(AkadoraCount) 包含136张牌的集合,赤牌数可定
TileCount(std::initializer_list) 从已有数据创建


计数、添加、删除

通过ct(T34)ct(const T37&)可查看某种牌在集合里有几张。 两者的区别见下面的例子:

// 创建一个集合,里面有一张0p, 一张5p
TileCount count({ T37(Suit::P, 0), T37(Suit::P, 5) });

T34 p(Suit::P, 5);
T37 p5(Suit::P, 5);
T37 p0(Suit::P, 0);

int i1 = count.ct(p);  // i1 == 2
int i2 = count.ct(p5); // i2 == 1
int i3 = count.ct(p0); // i3 == 1

通过inc(const T37 &t, int delta)方法可修改集合中一种牌的个数。 delta为正数即为添加,为负数即为去除。 注意inc的参数只能是T37,不能是T34 ——虽然查个数时可以概括,但增删时必须清楚地表明增删的到底是赤牌还是黑牌。


向听数计算

前文提到,TileCount可用于表示手牌。 当TileCount表示手牌时,可以通过成员方法计算向听数。

Libsaki 中我们用 step 一词代表向听数。 TileCount中有一系列关于向听数计算的方法:

方法 用途
step4(int barkCt) 指定副露数,求四面子向听数
step7() 假设门前清,求七对子向听数
step13() 假设门前清,求国士向听数
step(int barkCt) min(step4, step7, step13)
step7Gb() 国标七对子向听数,允许四归一
stepGb(int barkCt) min(step4, step7Gb, step13)

Libsaki 内部我们用 bark 一词统称吃、碰、大明杠、暗杠、加杠。 (本应该叫 call,但容易和 function call 弄混)

向听数为 0 代表形式听牌或纯空听,向听数为 -1 代表和牌。

四面子形的向听数计算采用的是暴力搜索算法,耗时为毫秒级。


有效牌计算

代码内部通过effA表示一类有效牌(降低向听数), 用effB表示二类有效牌(改良), 用effC表示三类有效牌(改良增多)。

hasEffA系列方法判断某张牌是否为当前手牌的一类有效牌。 effA可以列举出所有的一类有效牌。 后面的4, 7, 13等后缀意义与step系列相同。


其它方法

TileCount里的其它方法都不是很常用,不必一一了解。