麻将游戏软件————附带核心算法

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<int> 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<Mj> mahs, int que, SystemConfig systemConfig)
{
    //缺一门
    if (systemConfig.queyimen == 1) {
        for (Mj mj : mahs) {
            if (mj.getIsque() == true && mj.isCaisheng() == false) {
                return false;
            }
        }
    }

    list<Mj> pais = mahs;
//先剔除碰 杠的牌
    list<Mj>::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<Mj> cards, SystemConfig systemConfig)
{
    list<Mj> pais = cards;//复制一根备份
    //统计每张牌出现的次数
    unordered_map<int, int> Map;
    for (list<Mj>::iterator i = pais.begin(); i != pais.end(); ++i) {
        if (Map.find(i->getResult()) != Map.end()) {
            Map[i->getResult()]++;
        } else {
            Map[i->getResult()] = 1;
        }
    }
    //统计出现次数
    list<int> result_count;//出现的次数
    for (unordered_map<int,int>::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<int>::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<int>(pais.size()))) {
        return true;
    }
    //有4张一样的牌且没杠,其余牌都是对子 (小七对)
    if(cnt2 == 5 && cnt4 == 1){
        return  true;
    }
    //d都是四个加一对 胡牌(18罗汉)
    if (cnt2 == 1 && cnt4 * 4 == static_cast<int>(pais.size()) - 2) {
        return true;
    }

    if(systemConfig.erwubajiang == 1){
        //全部是3个相同的加一对将
        if(cnt2 == 1 && cnt3 * 3 == static_cast<int>(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<int, int>::iterator sub_enty = Map.begin();sub_enty != Map.end();sub_enty++) {//至少有一个顺子的胡牌组合
             list<Mj> suanpai = pais;//算牌(重置)
             list<Mj> tempSuanpai;
              list<Mj>::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()<<"顺子前:"<<iterator->getResult();

                      int pai = iterator->getResult();
                      int nPai1 = pai + 1;
                      int nPai2 = pai + 2;

                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai1){
                              suanpai.erase(i);
                              break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai2){
                               suanpai.erase(i);
                               break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == pai){
                             iterator = suanpai.erase(i);
                             break;
                          }
                      }
                      if(suanpai.size() > 0){
                         //qDebug()<<"顺子后:"<<iterator->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刻字前:"<<iterator->getResult();
                      int pai = iterator->getResult();
                      int cnt = 0;
                      for(list<Mj>::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刻字后:"<<iterator->getResult();
                      }
                  }else{
                      iterator++;
                  }
              }

              if (suanpai.size() == 0) {
                  qDebug()<<"胡牌将:"<<testNum;
                  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刻字前:"<<iterator->getResult();
                      int pai = iterator->getResult();
                      int cnt = 0;
                      for(list<Mj>::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刻字后:"<<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()<<"顺子前:"<<iterator->getResult();

                      int pai = iterator->getResult();
                      int nPai1 = pai + 1;
                      int nPai2 = pai + 2;

                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai1){
                              suanpai.erase(i);
                              break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai2){
                               suanpai.erase(i);
                               break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == pai){
                             iterator = suanpai.erase(i);
                             break;
                          }
                      }
                      if(suanpai.size() > 0){
                        // qDebug()<<"顺子后:"<<iterator->getResult();
                      }
                  }else{
                      iterator++;
                  }
              }

              if (suanpai.size() == 0) {
                  qDebug()<<"胡牌将:"<<testNum;
                  return true;
              }
        }
    }else{
        //全部是3个相同的加一对将
        if(cnt2 == 1 && cnt3 * 3 == static_cast<int>(pais.size()) - 2){
            return true;
        }

        for (unordered_map<int, int>::iterator sub_enty = Map.begin();sub_enty != Map.end();sub_enty++) {//至少有一个顺子的胡牌组合
             list<Mj> suanpai = pais;//算牌(重置)
             list<Mj> tempSuanpai;
              list<Mj>::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()<<"顺子前:"<<iterator->getResult();

                      int pai = iterator->getResult();
                      int nPai1 = pai + 1;
                      int nPai2 = pai + 2;

                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai1){
                              suanpai.erase(i);
                              break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai2){
                               suanpai.erase(i);
                               break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == pai){
                             iterator = suanpai.erase(i);
                             break;
                          }
                      }
                      if(suanpai.size() > 0){
                         //qDebug()<<"顺子后:"<<iterator->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刻字前:"<<iterator->getResult();
                      int pai = iterator->getResult();
                      int cnt = 0;
                      for(list<Mj>::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刻字后:"<<iterator->getResult();
                      }
                  }else{
                      iterator++;
                  }
              }

              if (suanpai.size() == 0) {
                  qDebug()<<"胡牌将:"<<testNum;
                  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刻字前:"<<iterator->getResult();
                      int pai = iterator->getResult();
                      int cnt = 0;
                      for(list<Mj>::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刻字后:"<<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()<<"顺子前:"<<iterator->getResult();

                      int pai = iterator->getResult();
                      int nPai1 = pai + 1;
                      int nPai2 = pai + 2;

                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai1){
                              suanpai.erase(i);
                              break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == nPai2){
                               suanpai.erase(i);
                               break;
                          }
                      }
                      for(list<Mj>::iterator i = suanpai.begin(); i!= suanpai.end();i++){
                          if(i->getResult() == pai){
                             iterator = suanpai.erase(i);
                             break;
                          }
                      }
                      if(suanpai.size() > 0){
                        // qDebug()<<"顺子后:"<<iterator->getResult();
                      }
                  }else{
                      iterator++;
                  }
              }

              if (suanpai.size() == 0) {
                  qDebug()<<"胡牌将:"<<testNum;
                  return true;
              }
        }
    }

    return false;
}

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

在这里插入图片描述

3 花絮

3.1 游戏

在计算排版
在这里插入图片描述
打牌状态图片测试:
在这里插入图片描述
测试选庄:
在这里插入图片描述

3.2 识别图片

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.3 调试协议

在这里插入图片描述

4 麻将源代码

地址

  • 7
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

繁星蓝雨

如果觉得文章不错可以请喝咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值