文章目录

0 背景1 软件图片1.1 设置1.2 游戏界面1.3 识别界面

2 核心算法2.1 牌类2.2 胡牌2.3 其他(明杠、暗杠、抢杠胡)

3 花絮3.1 游戏3.2 识别图片3.3 调试协议

4 麻将源代码

0 背景

因为项目需要,于是使用Qt编写了一个麻将软件。但是后面由于种种原因,软件被弃用了【当时就写了一个月,还是刚学完Qt写的,写的比较粗糙😂】,于是现在把项目开源,供大家参考交流、学习。

1 软件图片

1.1 设置

感觉这应该是市面上玩法最多的设置了,不过由于时间原因只实现了一小部分的功能,

1.2 游戏界面

抓庄 选庄,抽牌,【右上角显示庄家】打牌过程,

1.3 识别界面

2 核心算法

2.1 牌类

牌类

class Mj;

class Mj {

// friend HuPaiKit;

public:

bool isHu() const{return hu;}

void setHu(bool hu) {this->hu = hu;}

bool isLast() const {return last;}

void setLast(bool last) {this->last = last;}

// ImageView getHupai_imageView() {return hupai_imageView;}

///缺一门(有用)

bool getIsque() const {return isque;}

void setIsque(bool isque) {this->isque = isque;}

//void setHupai_imageView(ImageView hupai_imageView) {this->hupai_imageView = hupai_imageView;}

///吃碰杠胡(有用)

int getPaizhuangtai() const {return paizhuangtai;}

void setPaizhuangtai(int paizhuangtai) {this->paizhuangtai = paizhuangtai;}

int getYuce_direction() {return yuce_direction;}

void setYuce_direction(int yuce_direction) {this->yuce_direction = yuce_direction;}

int getNapai_direction() {return napai_direction;}

void setNapai_direction(int napai_direction) {this->napai_direction = napai_direction;}

bool getSimo() {return simo;}

void setSimo(bool simo) {this->simo = simo;}

int getChupai_direction() {return chupai_direction;}

void setChupai_direction(int chupai_direction) {this->chupai_direction = chupai_direction;}

//Node getOther() {return other;}

//void setOther(Node other) {this->other = other;}

//ImageView getWeina_imageView() {return weina_imageView;}

//void setWeina_imageView(ImageView weina_imageView) {this->weina_imageView = weina_imageView;}

//MjControlInterface getYina_imageView() {return yina_imageView;}

//void setYina_imageView(MjControlInterface yina_imageView) {this->yina_imageView = yina_imageView;}

//MjControlInterface getYuce_imageView() {return yuce_imageView;}

//void setYuce_imageView(MjControlInterface yuce_imageView) {this->yuce_imageView = yuce_imageView;}

//ImageView getYichu_imageView() {return yichu_imageView;}

//void setYichu_imageView(ImageView yichu_imageView) {this->yichu_imageView = yichu_imageView;}

int getResult() const{return result;}

void setResult(int result) {this->result = result;}

//牌id(有用)

int getId() const {return id;}

void setId(int id) {this->id = id;}

int getSerial_number() {return serial_number;}

void setSerial_number(int serial_number) {this->serial_number = serial_number;}

int getMahjong_number() {return mahjong_number;}

void setMahjong_number(int mahjong_number) {this->mahjong_number = mahjong_number;}

int getDirection() {return direction;}

void setDirection(int direction) {this->direction = direction;}

int getZhuo_id() {return zhuo_id;}

void setZhuo_id(int zhuo_id) {this->zhuo_id = zhuo_id;}

bool isMaima() {return maima;}

void setMaima(bool maima) {this->maima = maima;}

std::string getZhiBiaoZHi() {return std::to_string(result) + "_" + std::to_string(yuanpai) ; }

///自写

bool isCaisheng() const{ return caisheng;}

bool operator==(const Mj mj) const {

if(this->result == mj.getResult()){

return true;

}else{

return false;

}

}

Mj& operator=(const Mj &mj) {

if(&mj != this){//自我赋值判断

result = mj.getResult();

paizhuangtai = mj.getPaizhuangtai();

id = mj.getId();

hu = mj.isHu() ;

last = mj.isLast();

isque = mj.getIsque();

}

return *this;

}

private:

int id;//id

int serial_number;//设备序列号 桌号

int mahjong_number;//第几张牌

int zhuo_id = 0;//局id

int direction;//设备方向

int napai_direction = -1;//拿牌方向

int yuce_direction = -1;//预测方向

int chupai_direction = -1;//出牌方向

std::string add_time;//时间

int result = -1;

int paizhuangtai = 0;//牌的状态 0:正常 1:碰 2:明杠 3:暗杠 4:吃的牌 5:胡牌

bool isque = false;//缺一门

bool simo = false;//是否已拿

bool maima = false;//买马

bool last = false;//最后摸的

bool hu = false;//胡的

public:

bool caisheng = false;//财神

int caisheng_dipai = 0;//财神所抵的牌

bool kedi_caisheng = false;//可抵财神

int yuanpai = 0;//抵财神或花牌的原牌

bool kedi_huapai = false;//可抵花牌

bool huapai_yuce = false;//预测花牌 杠后预测的牌

//private ImageView weina_imageView;

//private MjControlInterface yina_imageView;

//private MjControlInterface yuce_imageView;

//private ImageView yichu_imageView;

//private ImageView hupai_imageView;

//private Node other;

};

class Config;

class SystemConfig{

friend Config;

public:

//规则参数

int mapaicengshu=2;//码牌层数

int mapaifangshi=0;//码牌方式 0:摆两层 1:摆三层 2:单张(栋)在后 3:逐层码牌 4:136三层 5:144三层 6:摆四层(头+尾=六栋)

int wanjiapaishu=13;//玩家牌数

QString tiaopai="隔跳";//跳牌

int meishouzhangshu=4;//每手张数

int yucepai = 10;//预测牌

int wanjiarenshu=4;//玩家人数

int huanshoupai=0;//换手牌

int guoshanchediaohuan=0;//过山车调换牌

int zhuapaihouxuanzhuang=0;//抓牌后选庄

int sanceng_liangdongsizhang=0;//三层,两栋四张(抓牌)

int errenzhuaerfangweipai=0;//二人抓二方位牌

int qutouzhang=0;//去头张

int xianzhuan8houzhuan4=0;//先抓8后抓4

int meijuchongxuanquefang=0;//每局重选缺方

int disancengzuowanjiapai=0;//第三层做玩家牌

int meijushetiaopai=0;//每局设挑牌

int bugoudongyizhiweibu=0;//不够栋移至尾部

int _20zhangzhuangjiaxianzhuangsanzhangzaizhuayizhang=0;//20张庄家先抓3张再抓1张

int butiaopaizhangjialianxu14xian13=0;//不跳牌,庄家连续14,闲13

int zhuapai123=0;//抓牌123

int zhuapai321=0;//抓牌321

int pingna=0;//平拿

int niezhuanimo=0;//逆抓逆摸

int nanbeihuhuandongdexiajiashibei=0;//南北互换,东的下家是北

int zijiazuosandunyousandun=0;//自家左3墩右3墩

int sicengsandun=0;//四层3墩

int qishourenyiliangdong=0;//起手任意两栋

int renyiandongnapai=0;//任意按栋拿牌

//花牌

std::string gangfa="轮到自由杠(手动杠花)";//杠法

int zixuanhuapai=0;//自选花牌(非花牌当花)

int anhuiganghua=0;//安徽杠花(首轮)

int shoupaibuxianshihuapai=0;//手牌不显示花牌

int yucepaibuxianshihuapai=0;//预测牌不显示花牌

int anqingmajiangdahua=0;//安庆麻将打花

int huapaikepang_foushanmajiang=0;//花牌可碰(佛山麻将)

int huapaidaiticaishengpai_foushanmajiang=0;//花牌代替财神牌(佛山麻将140)

std::string ganghua="顺杠牌";//杠花

//扣牌

int diyishou=0;//第一手

int diershou=0;//第二手

int disanshou=0;//第三手

int zuihouyizhang=0;//最后一张

int zixuankoupai=1;//自选扣牌

//其它

int jiemianbuju=0;//界面布局

// double[] zidingyibeijingyanse={0,0,0};//自定义背景颜色

int shengyingtishi=0;//声音提示

int chupaixianshi=0;//出牌显示 0:出牌顺序 1;花色

int zidongjietu=0;//自动截图

int mimabaohu=0;//密码保护

int jianpancaozuomoshi=0;//键盘操作模式

int zhuomianbuxuanzhuan=0;//桌面牌不旋转

//打牌

int pongpai = 1;//碰牌(yong)

int chipai = 0;//吃牌(yong)

int baoliupai = 0;//保留手上的牌

int danzhangkechi = 0;//单张可吃

int chisanfangpai = 0;//吃三方牌

int gangshouzhongpai = 1;//杠手中牌(yong)

int fengpaizipaisanzhangkegang = 0;//风牌字牌三张可杠

int angang = 1;//暗杠(yong)

int minggang = 1;//明杠(yong)

int danzhangkegang = 0;//单张可杠

std::list danzhangkegang_pai;//单张可杠的牌

int koupai=0;//扣牌(右击)

int dongnanxibeikechikegang=0;//东南西北可吃可杠

int zipaifengkai=0;//字牌分开(西南北,中发白)

int renyisangedanzhangzipai=0;//任意三个单张字牌

int leqing=0;//乐清(红中当花)

int dongnanxibeizhongfabaigang=0;//东南西北(中发白)杠

int dongnanxibeizhongfabaigangqingdao=0;//东南西北(中发白)杠(青岛)

int dongnanxibeizhongfabaishunzi=0;//东南西北(中发白)顺子

int pangjiang=0;//碰将

int yaojiyitongdangfengpai=0;//幺鸡一筒当风牌(甘肃)

int rengyijiu=0;//扔一九(甘肃)

int yaojiyitongdangzipai=0;//幺鸡一筒当字牌(甘肃)

int yaojiyitongdangzipaifengpai=0;//幺鸡一筒当字牌风牌(甘肃)

int wugezipaigang=0;//五个字牌杠(三个风牌两个箭牌,补两个)

int yaojiugangsangebubusigebuyige=0;//幺九杠(三个不补,四个补一个)

int yaojiugang=0;//幺九杠

int yaojiugangshengyangbusangehuosige=0;//幺九杠(沈阳补三个或四个)

int zhucengnapai=0;//逐层拿牌

int niezhuapai=0;//逆抓牌

int yingchuanbufeng=0;//银川补风

std::string gangpaishunxu="顺杠牌";//杠牌顺序

//胡牌

int zhixianzimo=0;//只限自摸

int qiangganghu=1;//抢杠胡

int erwubajiang=0;//二五八将

int queyimen =0;//缺一门

int xueliuchenghe=0;//血流成河

int hupaikepang=0;//胡牌可碰

int hupaikegang=0;//胡牌可杠

int fangpaoxiajia=0;//放炮下家

int yipaoduoxiang=1;//一炮多响

int hupaikemo=0;//胡牌可摸

int buchibupangdapaitishi=0;//不吃不碰打牌提示

int lanpai=0;//烂牌

int xiaoqidui=1;//小七对

int bixuyou19zipaifengpairenyiyizhang=0;//19字牌风牌任意一张

int pengpaihuozhezhongfabaidui=0;//碰牌或者中发白对

//财神

int zixuancaisheng=0;//自选财神

int houcaisheng=0;//后财神

int shunmocaisheng=0;//顺摸财神

int renyicaisheng=0;//任意财神

int shengjicaisheng=0;//升级财神

int shuangcaisheng=0;//双财神

int shangcaisheng_combox=0;//双财神

int zhongjianpaizuohua=0;//中间牌做花

int shengjicaishengshihuapaijixu=0;//升级财神是花牌继续升

int daiticaishengpai=0;//代替财神牌

int daiticaishengpai_combox=0;//代替财神牌

int daitipaibaoliuyuanpaizuoyong=0;//代替牌保留原牌作用

int caishenganzhengchangpaichanyuchangpanggang=0;//财神按正常牌参与吃碰杠

int andaitipaixianshi=0;//按代替牌显示

int budaiticaishengzipai=0;//不代替财神字牌

int buhuahoumocaisheng=0;//补花后摸财神

int caishengcanyuchipanggang=0;//财神参与吃碰杠(起飞)

int caishengkedangang=0;//财神可单杠

int jiaohuanpai=0;//交换牌(与拿牌位置倒数第三栋第一张)

int fankaidcaishengpaidanghua=0;//翻开的财神牌当花

int fankaidcaishengpaifangzuihouweizhi=0;//翻开的财神牌放在最后位置

int fankaishihuapaijixufan=0;//翻开是花牌继续翻

int caishenganzhengchangpaicanyuchengpanggang=0;//财神按正常牌参与吃碰杠

int zhuapaihouxuancaisheng=0;//抓牌后选财神

int zipaifengpaifenkaishengji=0;//字牌风牌分开升级

int fankaidepaibuzuocaisheng=0;//翻开的牌不做财神

//int

//快捷方式

std::string huoqushuju;//获取数据

std::string guopai;//过牌

std::string xunhuanguopai;//循环过牌

std::string guodong;//过栋

std::string kanchupai;//看出牌

std::string mopai="空格键";//摸牌

std::string chipai_kjj;//吃牌

std::string gangpai;//杠牌

std::string pangpai_kjj;//碰牌

std::string chexiao="z";//撤销

std::string chongxuanzhuang;//重选庄

std::string shubiaoyouji="撤销";//鼠标右击

int leqingmajiang=0;//乐清麻将

int guangxi152=0;//广西152

int xianmajiang=0;//仙麻将

int yuhuanwahua=0;//玉环挖花

int wenchengmajiang=0;//文城麻将

int wenlingmajiang=0;//温岭麻将

int xianmaimahoudingzhuang=0;//先买马后定庄

};

class MjConfig {

public:

int getId() {return id;}

void setId(int id) {this->id = id;}

int getNumber() { return number;}

void setNumber(int number) {this->number = number;}

std::string getName() {return name;}

void setName(std::string name) {this->name = name;}

std::string getUrl() {return url;}

void setUrl(std::string url) {this->url = url;}

private:

int id;

int number;

std::string name;

std::string url;

};

2.2 胡牌

思想:先移除顺子,再移除刻子,最后判断将。

//正式版

bool UIMainWindows::HuPaiPanDin(std::list mahs, int que, SystemConfig systemConfig)

{

//缺一门

if (systemConfig.queyimen == 1) {

for (Mj mj : mahs) {

if (mj.getIsque() == true && mj.isCaisheng() == false) {

return false;

}

}

}

list pais = mahs;

//先剔除碰 杠的牌

list::iterator iterator = pais.begin();

while (iterator != pais.end()) {

if (iterator->getPaizhuangtai() == 1 || iterator->getPaizhuangtai() == 2 || iterator->getPaizhuangtai() == 3 || iterator->getPaizhuangtai() == 4) {

iterator = pais.erase(iterator);

}else{

iterator++;

}

}

if (pais.size() % 3 != 2) {

return false;

}

//qDebug()<<"HuPaiPanDin 1";

bool kehu = hupaipanduan(pais, systemConfig);

//qDebug()<<"HuPaiPanDin 2";

return kehu;

}

bool UIMainWindows::hupaipanduan(std::list cards, SystemConfig systemConfig)

{

list pais = cards;//复制一根备份

//统计每张牌出现的次数

unordered_map Map;

for (list::iterator i = pais.begin(); i != pais.end(); ++i) {

if (Map.find(i->getResult()) != Map.end()) {

Map[i->getResult()]++;

} else {

Map[i->getResult()] = 1;

}

}

//统计出现次数

list result_count;//出现的次数

for (unordered_map::const_iterator i = Map.begin(); i != Map.end(); ++i) {

result_count.push_back(i->second);

}

int cnt1 = 0, cnt2 = 0, cnt3 = 0, cnt4 = 0;//出现1,2,3,4次

for (list::iterator i = result_count.begin(); i != result_count.end(); ++i) {

if (*i == 1) {//出现一次的

cnt1++;

}

if (*i == 2) {//出现两次的

cnt2++;

}

if (*i == 3) {//出现三次的

cnt3++;

}

if (*i == 4) {//出现四次的

cnt4++;

}

}

//所有的牌全部都能组成2个 胡牌

if (cnt2 * 2 == systemConfig.wanjiapaishu + 1) {//小七对

return true;

}

//只有两张牌

if (pais.size() == 2) {//刚好凑成将

return pais.begin()->getResult() == (++pais.begin())->getResult();

}

//有至少两个4张一样的牌,其余牌都是对子 胡牌(龙七对)

if (cnt4 > 1 && (cnt2 * 2 + cnt4 * 4 == static_cast(pais.size()))) {

return true;

}

//有4张一样的牌且没杠,其余牌都是对子 (小七对)

if(cnt2 == 5 && cnt4 == 1){

return true;

}

//d都是四个加一对 胡牌(18罗汉)

if (cnt2 == 1 && cnt4 * 4 == static_cast(pais.size()) - 2) {

return true;

}

if(systemConfig.erwubajiang == 1){

//全部是3个相同的加一对将

if(cnt2 == 1 && cnt3 * 3 == static_cast(pais.size()) - 2){

for(auto i:Map){

if(i.second == 2){

if(i.first % 10 == 2 || i.first % 10 == 5 || i.first % 10 == 8){

return true;

}

}

}

}

for (unordered_map::iterator sub_enty = Map.begin();sub_enty != Map.end();sub_enty++) {//至少有一个顺子的胡牌组合

list suanpai = pais;//算牌(重置)

list tempSuanpai;

list::iterator iterator = suanpai.begin();

int jiangCnt = 0;

int testNum = sub_enty->first;//用于调试

while(iterator != suanpai.end()){

if(iterator->getResult() == sub_enty->first && jiangCnt < 2 && (sub_enty->first % 10 == 2 || sub_enty->first % 10 == 5 || sub_enty->first % 10 == 8)){

iterator = suanpai.erase(iterator);

jiangCnt++;

}else{

iterator++;

}

}

if(suanpai.size() % 3 != 0){//剩下的不是3的倍数

continue;

}

//排序

suanpai.sort(ComparatorMjResult2);

tempSuanpai = suanpai;

//先移除顺子再移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

//移除顺子

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(isSequence(suanpai,iterator->getResult()) == true){

//qDebug()<<"顺子前:"<getResult();

int pai = iterator->getResult();

int nPai1 = pai + 1;

int nPai2 = pai + 2;

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai1){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai2){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == pai){

iterator = suanpai.erase(i);

break;

}

}

if(suanpai.size() > 0){

//qDebug()<<"顺子后:"<getResult();

}

}else{

iterator++;

}

}

// if(testNum == 1){

// qDebug()<<"调试";

// }

//移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(iterator->getResult() != sub_enty->first && isTriplet(suanpai, iterator->getResult()) == true){//删除刻字

//qDebug()<<"iterator刻字前:"<getResult();

int pai = iterator->getResult();

int cnt = 0;

for(list::iterator i = suanpai.begin();i != suanpai.end();){

if(pai == i->getResult()){

i = suanpai.erase(i);

cnt++;

}else{

i++;

}

if(cnt == 3){

break;

}

}

if(suanpai.size() > 0){

iterator = suanpai.begin();

//qDebug()<<"iterator刻字后:"<getResult();

}

}else{

iterator++;

}

}

if (suanpai.size() == 0) {

qDebug()<<"胡牌将:"<

return true;

}

// if(testNum == 7){

// qDebug()<<"调试";

// }

suanpai = tempSuanpai;//有一对刻字,其余的都是顺子(刻字被拆未顺子)

iterator = suanpai.begin();

//移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

int getTriplet = 0;

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(getTriplet != 0){break;}

if(iterator->getResult() != sub_enty->first && isTriplet(suanpai, iterator->getResult()) == true){//删除刻字

//qDebug()<<"iterator刻字前:"<getResult();

int pai = iterator->getResult();

int cnt = 0;

for(list::iterator i = suanpai.begin();i != suanpai.end();){

if(pai == i->getResult()){

i = suanpai.erase(i);

cnt++;

getTriplet++;

}else{

i++;

}

if(cnt == 3){

break;

}

}

if(suanpai.size() > 0){

iterator = suanpai.begin();

// qDebug()<<"iterator刻字后:"<getResult();

}

}else{

iterator++;

}

}

//先移除顺子再移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

//移除顺子

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(isSequence(suanpai,iterator->getResult()) == true){

//qDebug()<<"顺子前:"<getResult();

int pai = iterator->getResult();

int nPai1 = pai + 1;

int nPai2 = pai + 2;

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai1){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai2){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == pai){

iterator = suanpai.erase(i);

break;

}

}

if(suanpai.size() > 0){

// qDebug()<<"顺子后:"<getResult();

}

}else{

iterator++;

}

}

if (suanpai.size() == 0) {

qDebug()<<"胡牌将:"<

return true;

}

}

}else{

//全部是3个相同的加一对将

if(cnt2 == 1 && cnt3 * 3 == static_cast(pais.size()) - 2){

return true;

}

for (unordered_map::iterator sub_enty = Map.begin();sub_enty != Map.end();sub_enty++) {//至少有一个顺子的胡牌组合

list suanpai = pais;//算牌(重置)

list tempSuanpai;

list::iterator iterator = suanpai.begin();

int jiangCnt = 0;

int testNum = sub_enty->first;//用于调试

while(iterator != suanpai.end()){

if(iterator->getResult() == sub_enty->first && jiangCnt < 2){

iterator = suanpai.erase(iterator);

jiangCnt++;

}else{

iterator++;

}

}

if(suanpai.size() % 3 != 0){//剩下的不是3的倍数

continue;

}

//排序

suanpai.sort(ComparatorMjResult2);

tempSuanpai = suanpai;

//先移除顺子再移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

//移除顺子

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(isSequence(suanpai,iterator->getResult()) == true){

//qDebug()<<"顺子前:"<getResult();

int pai = iterator->getResult();

int nPai1 = pai + 1;

int nPai2 = pai + 2;

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai1){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai2){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == pai){

iterator = suanpai.erase(i);

break;

}

}

if(suanpai.size() > 0){

//qDebug()<<"顺子后:"<getResult();

}

}else{

iterator++;

}

}

// if(testNum == 1){

// qDebug()<<"调试";

// }

//移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(iterator->getResult() != sub_enty->first && isTriplet(suanpai, iterator->getResult()) == true){//删除刻字

//qDebug()<<"iterator刻字前:"<getResult();

int pai = iterator->getResult();

int cnt = 0;

for(list::iterator i = suanpai.begin();i != suanpai.end();){

if(pai == i->getResult()){

i = suanpai.erase(i);

cnt++;

}else{

i++;

}

if(cnt == 3){

break;

}

}

if(suanpai.size() > 0){

iterator = suanpai.begin();

// qDebug()<<"iterator刻字后:"<getResult();

}

}else{

iterator++;

}

}

if (suanpai.size() == 0) {

qDebug()<<"胡牌将:"<

return true;

}

// if(testNum == 7){

// qDebug()<<"调试";

// }

suanpai = tempSuanpai;//有一对刻字,其余的都是顺子(刻字被拆未顺子)

iterator = suanpai.begin();

//移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

int getTriplet = 0;

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(getTriplet != 0){break;}

if(iterator->getResult() != sub_enty->first && isTriplet(suanpai, iterator->getResult()) == true){//删除刻字

qDebug()<<"iterator刻字前:"<getResult();

int pai = iterator->getResult();

int cnt = 0;

for(list::iterator i = suanpai.begin();i != suanpai.end();){

if(pai == i->getResult()){

i = suanpai.erase(i);

cnt++;

getTriplet++;

}else{

i++;

}

if(cnt == 3){

break;

}

}

if(suanpai.size() > 0){

iterator = suanpai.begin();

//qDebug()<<"iterator刻字后:"<getResult();

}

}else{

iterator++;

}

}

//先移除顺子再移除刻字

if(suanpai.size() > 0){

iterator = suanpai.begin();

}

//移除顺子

while(suanpai.size() > 0 && iterator != suanpai.end()){

if(isSequence(suanpai,iterator->getResult()) == true){

// qDebug()<<"顺子前:"<getResult();

int pai = iterator->getResult();

int nPai1 = pai + 1;

int nPai2 = pai + 2;

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai1){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == nPai2){

suanpai.erase(i);

break;

}

}

for(list::iterator i = suanpai.begin(); i!= suanpai.end();i++){

if(i->getResult() == pai){

iterator = suanpai.erase(i);

break;

}

}

if(suanpai.size() > 0){

// qDebug()<<"顺子后:"<getResult();

}

}else{

iterator++;

}

}

if (suanpai.size() == 0) {

qDebug()<<"胡牌将:"<

return true;

}

}

}

return false;

}

2.3 其他(明杠、暗杠、抢杠胡)

3 花絮

3.1 游戏

在计算排版 打牌状态图片测试: 测试选庄:

3.2 识别图片

3.3 调试协议

4 麻将源代码

地址

2025-10-26 11:39:05