ScoreCounter 类参考¶
ScoreCounter 负责役种检测、符数计算和最终得分。
头文件¶
#include "ScoreCounter.h"
构造函数¶
ScoreCounter(
const Table* t, // 游戏桌指针
const Player* p, // 和牌玩家指针
Tile* win, // 和牌张(荣和时为荣和牌,自摸时为nullptr)
bool chankan, // 是否抢杠和
bool chanankan // 是否抢暗杠和
);
成员变量¶
基础数据¶
成员 |
类型 |
说明 |
|---|---|---|
|
|
所有和牌相关牌 |
|
|
和牌张 |
|
|
牌种列表 |
|
|
所有可能的手牌拆分 |
|
|
游戏桌指针 |
|
|
和牌玩家指针 |
检测结果¶
成员 |
类型 |
说明 |
|---|---|---|
|
|
天地和役 |
|
|
状态役(立直/一发等) |
|
|
宝牌役 |
|
|
最大番数/符数组合 |
|
|
是否有役 |
|
|
是否役满 |
|
|
几倍役满 |
|
|
清一色/字一色类型 (0-3=suit, 4=honor) |
|
|
是否门清 |
|
|
是否自摸 |
|
|
国士/国士13面 |
|
|
九莲/纯正九莲 |
役种检测方法¶
yaku_counter()¶
CounterResult yaku_counter();
主入口函数,执行完整役种检测:
手牌拆分 →
completedtiles_list特殊手型检测(天地和→国士→九莲)
对每种拆分,检测役满 → 检测普通役
状态役检测(立直/一发/海底等)
宝牌役检测
选择最大番/符组合
返回
CounterResult
get_tenhou_chihou()¶
bool get_tenhou_chihou();
检测天和(Tenhou)和地和(Chihou)。
天和:第一巡,庄家自摸,无鸣牌 → 役满 地和:第一巡,非庄家自摸,无鸣牌 → 半庄满
条件:
player->first_round == true(第一巡)player->call_groups.empty()(无鸣牌)player->oya == true(天和)或false(地和)
get_kokushi()¶
bool get_kokushi();
检测国士无双(Kokushi Musou)。
形式:
普通国士:13种幺九牌 + 任意一张幺九牌对子
十三面国士(
kokushi_13 = true):13种幺九牌各1张 + 听第14种,役满/双倍役满
get_churen()¶
bool get_churen();
检测九莲宝灯(Churen Poutou)。
形式:
普通九莲:1,1,1,2,3,4,5,6,7,8,9,9,9 + 任意一张同花色
九莲宝灯9面(
churen_pure = true):听第9张时,役满/双倍役满
get_pure_type()¶
void get_pure_type();
分析手牌,确定 mpsz_pure_type:
0, 1, 2, 3 = 万/筒/索/字
纯字一色:全为字牌(z)
get_hand_yakuman()¶
std::vector<Yaku> get_hand_yakuman(
const std::vector<string>& tile_group_string,
Wind self_wind,
Wind game_wind,
bool& yakuman
);
检测役满(非特殊手型)。支持的役满:
Yaku |
名称 |
条件 |
|---|---|---|
|
大三元 |
白/发/中三个刻子 |
|
四暗刻 |
4个刻子(单骑=双倍役满) |
|
四暗刻单骑 |
四暗刻+单面听(双倍役满) |
|
字一色 |
全为字牌 |
|
绿一色 |
仅含绿牌(2,3,4,6,8s + 发) |
|
清老头 |
仅含1/9数牌 |
|
四杠子 |
4个杠子 |
|
小四喜 |
3种风牌刻子 + 1种风牌对子 |
|
大四喜 |
4种风牌全部刻子(双倍役满) |
get_hand_yakus()¶
std::pair<vector<Yaku>, int> get_hand_yakus(
const vector<string>& tile_group_string,
Wind self_wind,
Wind game_wind,
bool menzen
);
检测普通役(非役满)。返回 {yaku列表, fu数}。
主要役种:
番数 |
役种 |
检测条件 |
|---|---|---|
1 |
Tanyao 断幺九 |
无幺九牌 |
1 |
Riichi 立直 |
已宣言立直 |
1 |
Menzentsumo 门清自摸 |
门清+自摸 |
1 |
Pinfu 平和 |
门清+顺子+非役牌对+边张/坎张 |
1 |
Ippatsu 一发 |
立直后1巡内和牌 |
1 |
Haiteiraoyue 海底摸月 |
最后一张自摸 |
1 |
Houteiraoyu 河底捞鱼 |
最后一张荣和 |
1 |
Rinshankaihou 岭上开花 |
杠后自摸 |
1 |
Chankan 抢杠 |
抢他人加杠 |
1+ |
Dora 宝牌 |
每张宝牌+1番 |
1+ |
Akadora 赤宝牌 |
每张赤5+1番 |
1 |
Uradora 里宝牌 |
立直后每张里宝牌+1番 |
2 |
Dabururiichi 两立直 |
第1巡立直 |
2 |
Sanshokudoukou 三色同刻 |
同数字m/p/s刻子 |
2 |
Toitoiho 对对和 |
全刻子 |
2 |
Sanankou 三暗刻 |
3个暗刻 |
2 |
Shousangen 小三元 |
2个三元牌刻子+1对 |
2 |
Honroutou 混老头 |
全1/9数牌+字牌 |
2 |
Chiitoitsu 七对子 |
7个对子(固定25符) |
2 |
Sankantsu 三杠子 |
3个杠子 |
3 |
Sanshokudoujun 三色同顺 |
同形状m/p/s顺子 |
3 |
Ikkitsuukan 一气通贯 |
1-4-7同花色顺子 |
3 |
Ryanpeikou 二杯口 |
两个相同顺子(门清) |
3 |
Junchantaiyaochu 纯全带幺九 |
全带幺九+门清 |
3 |
Honchantaiyaochu 混全带幺九 |
全带幺九 |
3 |
Honitsu 混一色 |
同花色+字牌(2番) |
5 |
Chinitsu 清一色 |
全同花色(5番) |
get_riichi() / get_ippatsu() / get_haitei_hotei() 等¶
void get_riichi();
void get_ippatsu();
void get_haitei_hotei();
void get_chankan();
void get_rinshan();
void get_menzentsumo();
void get_aka_dora();
void get_dora();
void get_ura_dora();
分别检测对应的状态役和宝牌役。
tile_group 字符串编码¶
手牌用字符串编码表示,用于役种检测:
格式: [数字][花色][类型][位置后缀]
类型字符 |
含义 |
|---|---|
|
刻子(3张相同) |
|
顺子(3连续) |
|
对子 |
|
杠子(4张相同) |
后缀字符 |
含义 |
|---|---|
|
副露(鸣牌) |
|
暗杠 |
|
自摸第1张 |
|
自摸第2张 |
|
自摸第3张 |
|
荣和第1张 |
|
荣和第2张 |
|
荣和第3张 |
示例:
1mK-:1万刻子(副露)1mS!:自摸123万顺子(和1万)1z:+:1字对子(暗杠)5p|:5筒杠子
CounterResult 结构¶
struct CounterResult {
vector<Yaku> yakus; // 役种列表
int score1 = 0; // 亲家支付(或荣和总支付)
int score2 = 0; // 子家支付(自摸时)
int fan = 0; // 总番数
int fu = 0; // 总符数
void calculate_score(bool oya, bool tsumo);
};
calculate_score()¶
void calculate_score(bool oya, bool tsumo);
根据番/符数计算实际得分(查标准计分表)。
得分表摘要:
番数 |
符数 |
亲家自摸 |
子家自摸 |
荣和(亲) |
荣和(子) |
|---|---|---|---|---|---|
1 |
20 |
1500 |
500 |
2000 |
2000 |
1 |
30 |
2000 |
700 |
2900 |
2900 |
2 |
20 |
3900 |
1300 |
5200 |
3900 |
3 |
40 |
7700 |
2600 |
10600 |
7100 |
4 |
40 |
11600 |
3900 |
15400 |
11600 |
5 |
— |
满贯 12000 |
8000 |
12000 |
8000 |
6-7 |
— |
跳满 18000 |
12000 |
18000 |
12000 |
8-10 |
— |
倍满 24000 |
16000 |
24000 |
16000 |
11-12 |
— |
三倍满 36000 |
24000 |
36000 |
24000 |
13+ |
— |
役满 48000 |
32000 |
48000 |
32000 |
特殊:
7对子固定25符
平和自摸固定20符(不计自摸符)
符数不满10的倍数时向上取整
计分器辅助函数¶
calculate_fan()¶
int calculate_fan(const vector<Yaku>& yakus);
计算役种列表的总番数(考虑倍役满/三倍役满/数倍役满)。
compare_yaku_fu()¶
bool compare_yaku_fu(
const pair<vector<Yaku>, int>& lhs,
const pair<vector<Yaku>, int>& rhs
);
比较两个 {役列表, 符} 对:先比番数,再比符数(用于选择最大手役)。
参考¶
Mahjong/ScoreCounter.h- 完整声明Mahjong/ScoreCounter.cpp- 完整实现docs/advanced/state_machine.md-generate_result_*系列函数的调用关系