1. 程式人生 > >鬥地主-比較牌大小演算法

鬥地主-比較牌大小演算法

先將牌轉化字串,牌和字元的對照如下
//牌和程式碼中字元的對應
//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 <string>
#include <string.h>
#include <iostream>
#include <algorithm>

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;
}