鬥地主-比較牌大小演算法
阿新 • • 發佈:2019-01-23
先將牌轉化字串,牌和字元的對照如下
//牌和程式碼中字元的對應
//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;
}