向听数就是差几张有效进章后能听牌
当听牌时,向听数为0,胡牌时向听数是-1
向听数计算的公式是
N 手牌数 属于集合{2,5,8,11,14}
P 是否有雀头是为1,否为0
G 手牌中的完整顺子或者刻子数
g 手牌中的缺一张的顺子或者缺一张的刻子数
if g = 2 and p = 0:
S = 2 * ((N - 2) / 3 - G) - g - p + 1
else:
S = 2 * ((N - 2) / 3 - G) - g - p
代码在这里可以找到
上述代码只能对14张牌的时候生效,如果要检测13张牌的时候,只需要加上一张与任何牌的距离都是无限大的牌即可。
摸牌后,遍历14张牌,去掉一张,用13张牌去检测向听数,找出能使向听数减少的牌,选择一张打出,即可在有限的回合数内胡牌
牌: ['六条', '九筒', '八万', '发', '五条', '北', '白', '北', '一条', '八筒', '七筒', '七筒', '一万']
摸到 一万
打出 一条
牌: ['一万', '一万', '八万', '五条', '六条', '七筒', '七筒', '八筒', '九筒', '北', '北', '发', '白']
摸到 八筒
打出 白
牌: ['一万', '一万', '八万', '五条', '六条', '七筒', '七筒', '八筒', '八筒', '九筒', '北', '北', '发']
摸到 发
打出 八万
牌: ['一万', '一万', '五条', '六条', '七筒', '七筒', '八筒', '八筒', '九筒', '北', '北', '发', '发']
摸到 三条
打出 六条
牌: ['一万', '一万', '三条', '五条', '七筒', '七筒', '八筒', '八筒', '九筒', '北', '北', '发', '发']
摸到 一万
打出 北
牌: ['一万', '一万', '一万', '三条', '五条', '七筒', '七筒', '八筒', '八筒', '九筒', '北', '发', '发']
摸到 六筒
听牌!['一万', '一万', '一万', '三条', '五条', '六筒', '七筒', '七筒', '八筒', '八筒', '九筒', '发', '发']
6巡听牌
混牌:就是万能牌,能当作任意牌使用.
在算法中定义:混牌与任意牌的距离都是无限大,而且一张混牌能使向听数 - 1
定义混牌
混 = [1234, 1244, 1254, 1264]
将向听数计算公式调整为
N 手牌数 属于集合{2,5,8,11,14}
P 是否有雀头是为1,否为0
G 手牌中的完整顺子或者刻子数
g 手牌中的缺一张的顺子或者缺一张的刻子数
h 手牌中的混牌数量
if g = 2 + h and p = 0:
S = 2 * ((N - 2) / 3 - G) - g - p + 1 - h
else:
S = 2 * ((N - 2) / 3 - G) - g - p - h
代码在这里可以找到
牌: ['二条', '三筒', '六筒', '九万', '五条', '中', '四万', '混', '北', '七筒', '七条', '二条', '北']
摸到 混
打出 四万
牌: ['九万', '二条', '二条', '五条', '七条', '三筒', '六筒', '七筒', '北', '北', '中', '混', '混']
摸到 二筒
打出 中
牌: ['九万', '二条', '二条', '五条', '七条', '二筒', '三筒', '六筒', '七筒', '北', '北', '混', '混']
摸到 二筒
打出 三筒
牌: ['九万', '二条', '二条', '五条', '七条', '二筒', '二筒', '六筒', '七筒', '北', '北', '混', '混']
摸到 九万
打出 二条
牌: ['九万', '九万', '二条', '五条', '七条', '二筒', '二筒', '六筒', '七筒', '北', '北', '混', '混']
摸到 九万
听牌!['九万', '九万', '九万', '五条', '七条', '二筒', '二筒', '六筒', '七筒', '北', '北', '混', '混']
5巡听牌
使用查表法实现快速判断向听数。
- 把牌编码
如手牌是 一万,二万,三万,三条,五条,八条,东风,东风 8张牌
则将其编码为 (1,1),(1,1),(1,3),(1,2),(1,3),(1,3),(2,3)
编码规则:
1张一万,一万与下一张牌二万的距离是1 -> (1,1)
1张二万,二万与下一张牌三万的距离是1 -> (1,1)
1张三万,三万与下一张牌三条的距离大于等于3 -> (1,3)
1张三条,三条与下一张牌五条的距离是2 -> (1,2)
1张五条,五条与下一张牌八条的距离大于等于3 -> (1,3)
1张八条,八条与下一张牌东风的距离大于等于3 -> (1,3)
2张东风,东风没有下一张牌 -> (2,3)
这里用3表示大于等于3的距离,也可以认为是3就是∞,将最后一张牌的距离省略,得1111131213132
把字符串用其中一个'3'分割,把左右2个字符串reverse或调整顺序不影响向听数
1111131213132
= 11111 + 3 + 2313121 = 1111132313121
= 11111312 + 3 + 231 = 111113123231
= 21311111 + 3 + 231 = 213111113231
= 21311111 + 3 + 132 = 213111113132
= 13121311111 + 3 + 2 = 1312131111132
上述6种情况可视为1种情况,这里取字典序最小的一种1111131213132
把字符串转换成int64
11 11 13 12 13 13 2
数量 1-> 00,2->01,3-> 10,4->11
距离 1-> 00 2->01 3->10
结束符 -> 11
转成int64后 0000 0000 0010 0001 0010 0010 0111
最坏情况下14张牌都不同需要 14 * 4 - 1 + 1(结束符) = 56 bits, int64足够存储
枚举所有牌型的编码一共是1292059种
使用上述算法算好这些牌型的向听数,存在hash表中即可
带混牌的情况下,需要将混牌个数 ∈ {1,2,3,4},记录下来,并将混牌本身编码成0010(1,3),查表得到向听数后再减去混牌的个数即可,这里就不再叙述混牌的查表法了。