斗地主-比较牌大小算法

先将牌转化字符串,牌和字符的对照如下
//牌和代码中字符的对应
//3:3, 4:4, 5:5, 6:6, 7:7, 8:8, 9:9, a:10, b:J, c:Q, d:K, e:A, f:2, g:王

看代码:

//.h头文件

#ifndef CHECKPOKER_H
#define CHECKPOKER_H
#pragma once
#include 
#include 
#include 
#include 

using namespace std;

//需要连续多少才合法
const int needNum[5] = { 16, 1, 1, 1, 1 };
//最多能带多少牌
const int mostTake[5] = { 0, 0, 0, 2, 2 };

//牌和代码中字符的对应
//3:3, 4:4,5:5,6:6,7:7,8:8,9:9,a:10,b:J, c:Q, d:K, e:A, f:2, g:王

//牌的类型
enum pokerType {
    illegal = 0,     //非法
    single = 1,      //单牌, 顺子
    couple = 2,      //对子, 连对
    three = 3,       //三带一,三带一对, 飞机
    four = 4,        //四带一,四带二
    bomb = 5,        //炸弹
    rocket = 6,      //火箭
};

//检测牌类型函数返回的结果
class checkResult {
public:
    char maxChar;   //用于比较大小的字符
    pokerType pType;//牌的类型
    checkResult(pokerType _pType = illegal, char _maxChar = '3') {
        this->maxChar = _maxChar;
        this->pType = _pType;
    }
};

class checkPoker {
public:
    checkPoker();
    virtual ~checkPoker();

    //从有序的字符串中查找数量为num的字符
    static void findCharByNumber(char *retStr, std::string &srcStr, int num);
    //检测字符串中的字符是否连续
    static bool checkCharIsConnect(const char *str);
    //检测牌的类型
    static checkResult checkType(std::string &pokerList);
    //判断牌的大小
    static bool pokerCmp(std::string &a, std::string &b);
};

#endif
//.cpp源文件
#include "checkPoker.h"

checkPoker::checkPoker() {
}


checkPoker::~checkPoker() {
}


//从有序的字符串中查找数量为num的字符
void checkPoker::findCharByNumber(char *retStr, std::string &srcStr, int num) {
    int retNum = 0;
    int maxNumber = 1;
    for (int i = 0; i < srcStr.size(); i++) {
        if (0 < i && srcStr[i - 1] == srcStr[i]) {
            maxNumber++;
        } else {
            maxNumber = 1;
        }
        if (maxNumber == num) {
            retStr[retNum++] = srcStr[i];
        }
    }
    retStr[retNum] = 0;
}

//检测字符串中的字符是否连续
bool  checkPoker::checkCharIsConnect(const char *str) {
    int len = strlen(str);
    for (int i = 1; i < len; i++) {
        if ('9' == str[i - 1] && 'a' == str[i]) {
            //特殊情况
            continue;
        }
        if (str[i - 1] != (str[i] - 1)) {
            return false;
        }
    }
    return true;
}

//检测牌的类型
checkResult checkPoker::checkType(std::string &pokerList) {
    checkResult ret;
    int pokerNum = pokerList.size();
    if (0 == pokerNum) {
        ret = checkResult(pokerType::illegal);
        return ret;
    }
    //判断王炸
    if (2 == pokerNum && strcmp("gg", pokerList.c_str()) == 0) {
        ret = checkResult(pokerType::rocket, 'g');
        return ret;
    }
    //将字符串排序
    sort(pokerList.begin(), pokerList.end());
    //依次判断是否是包含相同的4个,3个,2个, 1个牌
    char retStr[15];
    for (int i = 4; i > 0; i--) {
        findCharByNumber(retStr, pokerList, i);
        //有多少个数大于i的牌
        int connectNum = strlen(retStr);
        if (0 == connectNum) {
            //没有结果
            continue;
        }
        if (false == checkCharIsConnect(retStr)) {
            //不连续的不合法
            continue;
        }
        if (connectNum * mostTake[i] < pokerNum - connectNum * i) {
            //带的牌太多了
            continue;
        }
        /////////////下面判读细节
        if (4 == i) {
            //如果只有4个牌那么就是炸弹
            ret = checkResult((4 == pokerNum) ? pokerType::bomb : pokerType::four, retStr[connectNum - 1]);
            return ret;
        } else if (3 == i) {
            int lastPokerNum = pokerNum - connectNum * i;
            if (0 != lastPokerNum && lastPokerNum != connectNum && lastPokerNum != (connectNum << 1)) {
                //3只能带1个或者1对
                continue;
            } else if (0 == lastPokerNum || lastPokerNum == connectNum) {
                //三带一或者不带的情况
                ret = checkResult(pokerType::three, retStr[connectNum - 1]);
                return ret;
            } else {
                char tmpChar[15];
                findCharByNumber(tmpChar, pokerList, 2);
                if (strlen(tmpChar) == (connectNum << 1)) {
                    //三带一对的情况
                    ret = checkResult(pokerType::three, retStr[connectNum - 1]);
                    return ret;
                }
                //有单牌,不合法
                continue;
            }
        } else if (2 == i) {
            if (1 == connectNum || 3 <= connectNum) {
                //一对,或者三连对以上
                ret = checkResult(pokerType::couple, retStr[connectNum - 1]);
                return ret;
            }
        } else if (1 == i) {
            if (1 == connectNum || 5 <= connectNum) {
                //单牌或者顺子
                ret = checkResult(pokerType::single, retStr[connectNum - 1]);
                return ret;
            }
        }
    }
    ret = checkResult(pokerType::illegal);
    return ret;
}

//判断牌的大小
bool checkPoker::pokerCmp(std::string &a, std::string &b) {
    int alen = a.size();
    int blen = b.size();
    checkResult aRet = checkType(a);
    checkResult bRet = checkType(b);
    if (pokerType::rocket == aRet.pType || pokerType::rocket == bRet.pType) {
        //有火箭
        return pokerType::rocket == aRet.pType;
    } else if (pokerType::bomb == aRet.pType && pokerType::bomb == bRet.pType) {
        //都是炸弹
        return bRet.maxChar < aRet.maxChar;
    } else if (pokerType::bomb == aRet.pType || pokerType::bomb == bRet.pType) {
        //有一个有炸弹
        return pokerType::bomb == aRet.pType;
    }
    if (0 == b.length()) {
        return pokerType::illegal != aRet.pType;
    }
    if (alen != blen) {
        //牌数量不相等
        return false;
    }
    if (aRet.pType == bRet.pType) {
        //类型相同
        return bRet.maxChar < aRet.maxChar;
    }
    return false;
}

你可能感兴趣的:(基础算法)