├── PJ.cpp ├── PJ.h ├── README.md ├── cardsList.ini ├── cfg.cpp ├── cfg.h ├── funcC.cpp ├── funcC.h ├── pb2Json.cpp ├── pb2Json.h ├── s13s.CMD_S_GameStart.txt ├── s13s.Message.proto ├── s13s.PlayerItem.txt ├── s13s.cpp ├── s13s.h ├── weights.cpp ├── weights.h ├── zjh.cpp ├── zjh.h └── 十三水手牌测试结果.txt /PJ.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #include 6 | #include 7 | #include "math.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "PJ.h" 19 | 20 | namespace QZPJ { 21 | 22 | //一副牌九(32张) 23 | uint8_t s_CardListData[MaxCardTotal] = 24 | { 25 | 0x66,0x66,0x11,0x11,0x44,0x44,0x13,0x13, 26 | 0x55,0x55,0x33,0x33,0x22,0x22,0x56,0x56, 27 | 0x46,0x46,0x16,0x16,0x15,0x15,0x45,0x36, 28 | 0x35,0x26,0x34,0x25,0x14,0x32,0x24,0x12, 29 | }; 30 | 31 | //牌九信息 [TIAN] = {0x66, "TIAN"} 32 | struct CardInfo_t { 33 | uint8_t iType; 34 | std::string name; 35 | }s_cardInfo_tbl[CARDMAX] = { 36 | { 0x66, "TIAN" },//天牌 37 | { 0x11, "DI" },//地牌 38 | { 0x44, "REN" },//人牌 39 | { 0x13, "ER" },//鹅牌 40 | { 0x55, "MEI" },//梅牌 41 | { 0x33, "CH3" },//长三 42 | { 0x22, "BD" },//板凳 43 | { 0x56, "FT" },//斧头 44 | { 0x46, "HT10" },//红头十 45 | { 0x16, "GJ7" },//高脚七 46 | { 0x15, "LL6" },//零霖六 47 | { 0x45, "Z945" },//杂九(45型) 48 | { 0x36, "Z936" },//杂九(36型) 49 | { 0x35, "Z835" },//杂八(35型) 50 | { 0x26, "Z826" },//杂八(26型) 51 | { 0x34, "Z734" },//杂七(34型) 52 | { 0x25, "Z725" },//杂七(25型) 53 | { 0x14, "Z514" },//杂五(14型) 54 | { 0x32, "Z532" },//杂五(32型) 55 | { 0x24, "C24" },//二四 56 | { 0x12, "CD3" },//丁三 57 | }; 58 | 59 | //构造函数 60 | CGameLogic::CGameLogic() 61 | { 62 | index_ = 0; 63 | memset(cardsData_, 0, sizeof(uint8_t)*MaxCardTotal); 64 | } 65 | 66 | //析构函数 67 | CGameLogic::~CGameLogic() 68 | { 69 | 70 | } 71 | 72 | //初始化扑克牌数据 73 | void CGameLogic::InitCards() 74 | { 75 | //printf("--- *** 初始化一副牌九...\n"); 76 | memcpy(cardsData_, s_CardListData, sizeof(uint8_t)*MaxCardTotal); 77 | } 78 | 79 | //debug打印 80 | void CGameLogic::DebugListCards() { 81 | for (int i = 0; i < MaxCardTotal; ++i) { 82 | printf("%02X %s %d\n", cardsData_[i], StringCardTypeByCard(cardsData_[i]).c_str(), GetCardValue(cardsData_[i])); 83 | } 84 | } 85 | 86 | //剩余牌数 87 | int8_t CGameLogic::Remaining() { 88 | return int8_t(MaxCardTotal - index_); 89 | } 90 | 91 | //洗牌 92 | void CGameLogic::ShuffleCards() 93 | { 94 | //printf("-- *** 洗牌...\n"); 95 | for (int k = 0; k < 5; ++k) { 96 | for (int i = 0; i < MaxCardTotal; ++i) { 97 | int j = rand() % MaxCardTotal; 98 | swap(cardsData_[i], cardsData_[j]); 99 | } 100 | } 101 | index_ = 0; 102 | } 103 | 104 | //发牌,生成n张玩家手牌 105 | void CGameLogic::DealCards(int8_t n, uint8_t *cards) 106 | { 107 | //printf("-- *** %d张余牌,发牌 ...\n", Remaining()); 108 | if (cards == NULL) { 109 | return; 110 | } 111 | if (n > Remaining()) { 112 | return; 113 | } 114 | int k = 0; 115 | for (int i = index_; i < index_ + n; ++i) { 116 | cards[k++] = cardsData_[i]; 117 | } 118 | index_ += n; 119 | } 120 | 121 | //0x66->PAITIAN 122 | CardType CGameLogic::CardTypeByCard(uint8_t card) 123 | { 124 | CardType cardtype = CNIL; 125 | switch (card) { 126 | case 0x66: cardtype = TIAN; break; 127 | case 0x11: cardtype = DI; break; 128 | case 0x44: cardtype = REN; break; 129 | case 0x13: cardtype = ER; break; 130 | case 0x55: cardtype = MEI; break; 131 | case 0x33: cardtype = CH3; break; 132 | case 0x22: cardtype = BD; break; 133 | case 0x56: cardtype = FT; break; 134 | case 0x46: cardtype = HT10; break; 135 | case 0x16: cardtype = GJ7; break; 136 | case 0x15: cardtype = LL6; break; 137 | case 0x45: cardtype = Z945; break; 138 | case 0x36: cardtype = Z936; break; 139 | case 0x35: cardtype = Z835; break; 140 | case 0x26: cardtype = Z826; break; 141 | case 0x34: cardtype = Z734; break; 142 | case 0x25: cardtype = Z725; break; 143 | case 0x14: cardtype = Z514; break; 144 | case 0x32: cardtype = Z532; break; 145 | case 0x24: cardtype = C24; break; 146 | case 0x12: cardtype = CD3; break; 147 | } 148 | return cardtype; 149 | } 150 | 151 | //卡牌类型字符串 0x66->"TIAN" 152 | std::string CGameLogic::StringCardTypeByCard(uint8_t card) { 153 | std::string cardtype = "CNIL"; 154 | switch (card) 155 | { 156 | case 0x66: cardtype = "TIAN"; break; 157 | case 0x11: cardtype = "DI"; break; 158 | case 0x44: cardtype = "REN"; break; 159 | case 0x13: cardtype = "ER"; break; 160 | case 0x55: cardtype = "MEI"; break; 161 | case 0x33: cardtype = "CH3"; break; 162 | case 0x22: cardtype = "BD"; break; 163 | case 0x56: cardtype = "FT"; break; 164 | case 0x46: cardtype = "HT10"; break; 165 | case 0x16: cardtype = "GJ7"; break; 166 | case 0x15: cardtype = "LL6"; break; 167 | case 0x45: cardtype = "Z945"; break; 168 | case 0x36: cardtype = "Z936"; break; 169 | case 0x35: cardtype = "Z835"; break; 170 | case 0x26: cardtype = "Z826"; break; 171 | case 0x34: cardtype = "Z734"; break; 172 | case 0x25: cardtype = "Z725"; break; 173 | case 0x14: cardtype = "Z514"; break; 174 | case 0x32: cardtype = "Z532"; break; 175 | case 0x24: cardtype = "C24"; break; 176 | case 0x12: cardtype = "CD3"; break; 177 | } 178 | return cardtype; 179 | } 180 | 181 | //对牌类型字符串 182 | std::string CGameLogic::StringPairType(PairType pairType) 183 | { 184 | std::string spairtype = "PNIL"; 185 | switch (pairType) 186 | { 187 | /////////// 特殊牌型 188 | case PNIL: spairtype = "PNIL"; break; //无 189 | case PZZUN: spairtype = "PZZUN"; break; //至尊 190 | case PTIAN: spairtype = "PTIAN"; break; //双天 191 | case PDI: spairtype = "PDI"; break; //双地 192 | case PREN: spairtype = "PREN"; break; //双人 193 | case PER: spairtype = "PER"; break; //双鹅 194 | case PMEI: spairtype = "PMEI"; break; //双梅 195 | case PCH3: spairtype = "PCH3"; break; //双长三 196 | case PBD: spairtype = "PBD"; break; //双板凳 197 | case PFT: spairtype = "PFT"; break; //双斧头 198 | case PHT10: spairtype = "PHT10"; break; //双红头 199 | case PGJ7: spairtype = "PGJ7"; break; //双高脚 200 | case PLL6: spairtype = "PLL6"; break; //双零霖 201 | case PZ9: spairtype = "PZ9"; break; //杂九 202 | case PZ8: spairtype = "PZ8"; break; //杂八 203 | case PZ7: spairtype = "PZ7"; break; //杂七 204 | case PZ5: spairtype = "PZ5"; break; //杂五 205 | case PTW: spairtype = "PTW"; break; //天王 206 | case PDW: spairtype = "PDW"; break; //地王 207 | case PTG: spairtype = "PTG"; break; //天杠 208 | case PDG: spairtype = "PDG"; break; //地杠 209 | case PTG9: spairtype = "PTG9"; break; //天高九 210 | case PDG9: spairtype = "PDG9"; break; //地高九 211 | /////////// 普通牌点 212 | case PPT9: spairtype = "PPT9"; break; //九点 213 | case PPT8: spairtype = "PPT8"; break; //八点 214 | case PPT7: spairtype = "PPT7"; break; //七点 215 | case PPT6: spairtype = "PPT6"; break; //六点 216 | case PPT5: spairtype = "PPT5"; break; //五点 217 | case PPT4: spairtype = "PPT4"; break; //四点 218 | case PPT3: spairtype = "PPT3"; break; //三点 219 | case PPT2: spairtype = "PPT2"; break; //二点 220 | case PPT1: spairtype = "PPT1"; break; //一点 221 | case PPT0: spairtype = "PPT0"; break; //零点 222 | } 223 | return spairtype; 224 | } 225 | 226 | //TIAN->"TIAN" 227 | std::string CGameLogic::StringCardType(CardType cardType) 228 | { 229 | return s_cardInfo_tbl[cardType].name; 230 | } 231 | 232 | //TIAN->0x66 233 | uint8_t CGameLogic::CardByCardType(CardType cardType) 234 | { 235 | return s_cardInfo_tbl[cardType].iType; 236 | } 237 | 238 | //单牌比较 0-相等 >0-card1大 <0-cards1小 239 | int CGameLogic::CompareCard(uint8_t card1, uint8_t card2) 240 | { 241 | //单牌大小 242 | //天牌 > 地牌 > 人牌 > 鹅牌 > 梅牌 > 长三 > 243 | //板凳 > 斧头 > 红头十 > 高脚七 > 零霖六 > 杂九 = 244 | //杂九 > 杂八 = 杂八 > 杂七 = 杂七 > 杂五 = 245 | //杂五 > 二四 = 丁三 246 | CardType t1 = CardTypeByCard(card1); 247 | CardType t2 = CardTypeByCard(card2); 248 | if (t1 == t2) { 249 | return 0; //card1==card2 250 | } 251 | int d = std::abs(t1 - t2); 252 | if (d == 1) {//相邻 253 | int m = std::max(t1, t2); 254 | if (m == Z936 || m == Z826 || m == Z725 || m == Z532 || m == CD3) 255 | return 0; //card1==card2 256 | } 257 | return t2 - t1; 258 | } 259 | 260 | //单牌大小 261 | static bool compareByCardType(uint8_t card1, uint8_t card2) { 262 | int t1 = CGameLogic::CardTypeByCard(card1); 263 | int t2 = CGameLogic::CardTypeByCard(card2); 264 | return t2 > t1; 265 | } 266 | 267 | //手牌由大到小排序 268 | void CGameLogic::SortCards(uint8_t *cards, int n) 269 | { 270 | std::sort(cards, cards + n, compareByCardType); 271 | } 272 | 273 | //玩家手牌类型,对牌类型 274 | PairType CGameLogic::JudgePairType(uint8_t *cards) { 275 | PairType t = PNIL; 276 | //手牌由大到小排序 277 | //SortCards(cards, MAX_PLAYER_CARD); 278 | uint8_t t1 = CardTypeByCard(cards[0]); 279 | uint8_t t2 = CardTypeByCard(cards[1]); 280 | if (t1 == C24 && t2 == CD3) 281 | t = PZZUN; //至尊 282 | else if (t1 == TIAN && t2 == TIAN) 283 | t = PTIAN; //双天 284 | else if (t1 == DI && t2 == DI) 285 | t = PDI; //双地 286 | else if (t1 == REN && t2 == REN) 287 | t = PREN; //双人 288 | else if (t1 == ER && t2 == ER) 289 | t = PER; //双鹅 290 | else if (t1 == MEI && t2 == MEI) 291 | t = PMEI; //双梅 292 | else if (t1 == CH3 && t2 == CH3) 293 | t = PCH3; //双长三 294 | else if (t1 == BD && t2 == BD) 295 | t = PBD; //双板凳 296 | else if (t1 == FT && t2 == FT) 297 | t = PFT; //双斧头 298 | else if (t1 == HT10 && t2 == HT10) 299 | t = PHT10; //双红头 300 | else if (t1 == GJ7 && t2 == GJ7) 301 | t = PGJ7; //双高脚 302 | else if (t1 == LL6 && t2 == LL6) 303 | t = PLL6; //双零霖 304 | else if (t1 == Z945 && t2 == Z936) 305 | t = PZ9; //杂九 306 | else if (t1 == Z835 && t2 == Z826) 307 | t = PZ8; //杂八 308 | else if (t1 == Z734 && t2 == Z725) 309 | t = PZ7; //杂七 310 | else if (t1 == Z514 && t2 == Z532) 311 | t = PZ5; //杂五 312 | else if (t1 == TIAN && (t2 == Z945 || t2 == Z936)) 313 | t = PTW; //天王 314 | else if (t1 == DI && (t2 == Z945 || t2 == Z936)) 315 | t = PDW; //地王 316 | else if (t1 == TIAN && (t2 == REN || t2 == Z835 || t2 == Z826)) 317 | t = PTG; //天杠 318 | else if (t1 == DI && (t2 == REN || t2 == Z835 || t2 == Z826)) 319 | t = PDG; //地杠 320 | else if (t1 == TIAN && t2 == Z725) 321 | t = PTG9; //天高九 322 | else if (t1 == DI && t2 == GJ7) 323 | t = PDG9; //地高九 324 | return t; 325 | } 326 | 327 | //玩家手牌点数 328 | int CGameLogic::CalcCardsPoints(uint8_t *cards) 329 | { 330 | //手牌由大到小排序 331 | //SortCards(cards, MAX_COUNT); 332 | return (GetCardValue(cards[0]) + GetCardValue(cards[1])) % 10; 333 | } 334 | 335 | //9->PPT9 336 | PairType CGameLogic::PairTypeByPoint(int point) 337 | { 338 | PairType pairtype = PNIL; 339 | switch (point) 340 | { 341 | case 9: pairtype = PPT9; break; 342 | case 8: pairtype = PPT8; break; 343 | case 7: pairtype = PPT7; break; 344 | case 6: pairtype = PPT6; break; 345 | case 5: pairtype = PPT5; break; 346 | case 4: pairtype = PPT4; break; 347 | case 3: pairtype = PPT3; break; 348 | case 2: pairtype = PPT2; break; 349 | case 1: pairtype = PPT1; break; 350 | case 0: pairtype = PPT0; break; 351 | } 352 | return pairtype; 353 | } 354 | 355 | //单牌点数(牌值) 356 | int CGameLogic::GetCardValue(uint8_t card) { 357 | return (card & 0x0F) + ((card >> 4) & 0x0F); 358 | } 359 | 360 | //玩家比牌(闲家与庄家比牌) 0-和局 >0-cards1赢 <0-cards2赢 361 | int CGameLogic::CompareHandCards(uint8_t *cards1, uint8_t *cards2) 362 | { 363 | //手牌由大到小排序 364 | //SortCards(cards1, MAX_COUNT); 365 | //SortCards(cards2, MAX_COUNT); 366 | //判断玩家手牌类型 367 | PairType pairType1 = JudgePairType(cards1); 368 | PairType pairType2 = JudgePairType(cards2); 369 | //有对牌且牌型不同 370 | if (pairType1 != pairType2) { 371 | if (pairType1 == PNIL) { 372 | return -1; 373 | } 374 | if (pairType2 == PNIL) { 375 | return 1; 376 | } 377 | return pairType2 - pairType1; 378 | } 379 | //pairType1 == pairType2 != nil 有对牌且牌型相同 380 | if (pairType1 != PNIL) { 381 | return 0;//和局 382 | } 383 | //pairType1 == pairType2 == nil 无对牌,两牌点数和取个位数来进行比牌 384 | int pt1 = CalcCardsPoints(cards1); 385 | int pt2 = CalcCardsPoints(cards2); 386 | //点数不同 387 | if (pt1 != pt2) { 388 | return pt1 - pt2; 389 | } 390 | //点数相同,比较单牌最大牌大小 391 | int result = CompareCard(cards1[0], cards2[0]); 392 | if (result != 0) { 393 | return result; 394 | } 395 | //result == 0 单牌最大牌大小相同,比较单牌最小牌大小 396 | result = CompareCard(cards1[1], cards2[1]); 397 | if (result != 0) { 398 | return result; 399 | } 400 | //result == 0 单牌最小牌大小相同 401 | return 0;//和局 402 | } 403 | 404 | //确定牌型 405 | PairType CGameLogic::GetHandCardsType(uint8_t *cards) 406 | { 407 | PairType pairType = JudgePairType(cards); 408 | if (pairType != PNIL) { 409 | return pairType;//特殊牌型 410 | } 411 | pairType = PairTypeByPoint(CalcCardsPoints(cards)); 412 | return pairType;//普通牌点 413 | } 414 | }; -------------------------------------------------------------------------------- /PJ.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #ifndef GAME_LOGIC_PJ_H 6 | #define GAME_LOGIC_PJ_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef isZero 21 | #define isZero(a) ((a>-0.000001) && (a<0.000001)) 22 | #endif//isZero 23 | 24 | #define MAX_CARD_TOTAL QZPJ::MaxCardTotal //牌总个数 25 | #define GAME_PLAYER QZPJ::MaxPlayer //最多4人局 26 | #define MAX_COUNT QZPJ::MaxCount //每人2张牌 27 | #define MAX_ROUND QZPJ::MaxRound //最大局数 28 | 29 | //抢庄牌九 30 | namespace QZPJ { 31 | 32 | const int MaxCardTotal = 32; //牌总个数 33 | const int MaxPlayer = 4; //最多4人局 34 | const int MaxCount = 2; //每人2张牌 35 | const int MaxRound = 2; //最大局数 36 | 37 | //单牌类型:从大到小 38 | //天牌 > 地牌 > 人牌 > 鹅牌 > 梅牌 > 长三 > 39 | //板凳 > 斧头 > 红头十 > 高脚七 > 零霖六 > 杂九 = 40 | //杂九 > 杂八 = 杂八 > 杂七 = 杂七 > 杂五 = 41 | //杂五 > 二四 = 丁三 42 | enum CardType { 43 | CNIL = -1, //无 44 | TIAN, //天牌 45 | DI, //地牌 46 | REN, //人牌 47 | ER, //鹅牌 48 | MEI, //梅牌 49 | CH3, //长三 50 | BD, //板凳 51 | FT, //斧头 52 | HT10, //红头十 53 | GJ7, //高脚七 54 | LL6, //零霖六 55 | Z945, //杂九(45型) 56 | Z936, //杂九(36型) 57 | Z835, //杂八(35型) 58 | Z826, //杂八(26型) 59 | Z734, //杂七(34型) 60 | Z725, //杂七(25型) 61 | Z514, //杂五(14型) 62 | Z532, //杂五(32型) 63 | C24, //二四 64 | CD3, //丁三 65 | CARDMAX, 66 | }; 67 | 68 | //对牌类型:从大到小 69 | //至尊 > 双天 > 双地 > 双人 > 双鹅 > 70 | //双梅 > 双长三 > 双板凳 > 双斧头 > 双红头 > 71 | //双高脚 > 双零霖 > 杂九 > 杂八 > 杂七 > 72 | //杂五 > 天王 > 地王 > 天杠 > 地杠 > 73 | //天高九 > 地高九 74 | enum PairType { 75 | PNIL = -1, //无 76 | /////////// 特殊牌型 77 | PZZUN, //至尊 78 | PTIAN, //双天 79 | PDI, //双地 80 | PREN, //双人 81 | PER, //双鹅 82 | PMEI, //双梅 83 | PCH3, //双长三 84 | PBD, //双板凳 85 | PFT, //双斧头 86 | PHT10, //双红头 87 | PGJ7, //双高脚 88 | PLL6, //双零霖 89 | PZ9, //杂九 90 | PZ8, //杂八 91 | PZ7, //杂七 92 | PZ5, //杂五 93 | PTW, //天王 94 | PDW, //地王 95 | PTG, //天杠 96 | PDG, //地杠 97 | PTG9, //天高九 98 | PDG9, //地高九 99 | /////////// 普通牌点 100 | PPT9, //九点 101 | PPT8, //八点 102 | PPT7, //七点 103 | PPT6, //六点 104 | PPT5, //五点 105 | PPT4, //四点 106 | PPT3, //三点 107 | PPT2, //二点 108 | PPT1, //一点 109 | PPT0, //零点 110 | }; 111 | 112 | //游戏逻辑类 113 | class CGameLogic 114 | { 115 | public: 116 | //构造函数 117 | CGameLogic(); 118 | //析构函数 119 | virtual ~CGameLogic(); 120 | public: 121 | //初始化扑克牌数据 122 | void InitCards(); 123 | //debug打印 124 | void DebugListCards(); 125 | //剩余牌数 126 | int8_t Remaining(); 127 | //洗牌 128 | void ShuffleCards(); 129 | //发牌,生成n张玩家手牌 130 | void DealCards(int8_t n, uint8_t *cards); 131 | public: 132 | //0x66->PAITIAN 133 | static CardType CardTypeByCard(uint8_t card); 134 | //卡牌类型字符串 0x66->"TIAN" 135 | static std::string StringCardTypeByCard(uint8_t card); 136 | public: 137 | //对牌类型字符串 138 | static std::string StringPairType(PairType pairType); 139 | //TIAN->"TIAN" 140 | static std::string StringCardType(CardType cardType); 141 | //TIAN->0x66 142 | static uint8_t CardByCardType(CardType cardType); 143 | //单牌比较 0-相等 >0-card1大 <0-cards1小 144 | static int CompareCard(uint8_t card1, uint8_t card2); 145 | //手牌由大到小排序 146 | static void SortCards(uint8_t *cards, int n); 147 | //玩家手牌类型,对牌类型 148 | static PairType JudgePairType(uint8_t *cards); 149 | //玩家手牌点数 150 | static int CalcCardsPoints(uint8_t *cards); 151 | //9->PPT9 152 | static PairType PairTypeByPoint(int point); 153 | //单牌点数(牌值) 154 | static int GetCardValue(uint8_t card); 155 | public: 156 | //确定牌型 157 | static PairType GetHandCardsType(uint8_t *cards); 158 | //玩家比牌(闲家与庄家比牌) 0-和局 >0-cards1赢 <0-cards2赢 159 | static int CompareHandCards(uint8_t *cards1, uint8_t *cards2); 160 | private: 161 | int8_t index_; 162 | uint8_t cardsData_[MaxCardTotal]; 163 | }; 164 | }; 165 | 166 | #endif 167 | 168 | 169 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QPAlgorithm 2 | 3 | C++ 棋牌算法封装,牌九,扎金花,十三水... 4 | cfg 文件读取 5 | funcC 组合函数类 6 | pb2Json protobuf/json格式转换 7 | weights 按权重计算随机概率 8 | 9 | PJ 牌九算法 10 | s13s 十三水算法,也是最复杂的一个 11 | zjh 炸金花算法实现 12 | 13 | 十三水算法接口说明: 14 | //枚举牌型测试 15 | static void TestEnumCards(int size); 16 | 17 | //枚举牌型测试 18 | //filename char const* 文件读取手牌 cardsList.ini 19 | static void TestEnumCards(char const* filename); 20 | 21 | //玩家发牌测试 22 | static void TestPlayerCards(); 23 | 24 | //开始游戏测试 25 | static void TestProtoCards(); 26 | 27 | //手动摆牌测试 28 | static void TestManualCards(); 29 | 30 | //确定牌型/比牌测试 31 | //先让每个玩家确定手牌三墩牌型,手动摆牌或者从枚举几组中任选一组作为手牌牌型与其他玩家比牌, 32 | //再玩家之间两两比牌,头敦与头敦比,中墩与中墩比,尾墩与尾墩比,并计算输赢积分(输赢多少水,统计打枪/全垒打) 33 | static void TestCompareCards(); 34 | 35 | //手牌牌型分析(特殊牌型判断/枚举三墩组合),算法入口 ///////// 36 | //src uint8_t const* 一副手牌(13张) 37 | //n int 最大枚举多少组墩(头墩&中墩&尾墩加起来为一组) 38 | //chairID int 玩家座椅ID 39 | //hand handinfo_t& 保存手牌信息 40 | static int AnalyseHandCards(uint8_t const* src, int len, int n, handinfo_t& hand); 41 | 42 | //单墩牌型判断(3/5张牌) 43 | //dt DunTy 指定为第几墩 44 | //src uint8_t const* 一墩5张或3张的牌 45 | static HandTy GetDunCardHandTy(DunTy dt, uint8_t const* src, int len); 46 | 47 | //牌型相同的src与dst比大小,牌数相同 48 | //src uint8_t const* 单墩牌(3/5张) 49 | //dst uint8_t const* 单墩牌(3/5张) 50 | //clr bool 是否比花色 51 | //ty HandTy 比较的两单墩牌的普通牌型 52 | static int CompareCards(uint8_t const* src, uint8_t const* dst, int n, bool clr, HandTy ty); 53 | 54 | //按照尾墩5张/中墩5张/头敦3张依次抽取枚举普通牌型 55 | //src uint8_t const* 手牌余牌(13/8/3),初始13张,按5/5/3依次抽,余牌依次为13/8/3 56 | //n int 抽取n张(5/5/3) 第一次抽5张余8张,第二次抽5张余3张,第三次取余下3张抽完 57 | //classify classify_t& 存放分类信息(所有重复四张/三张/二张/散牌/余牌) 58 | //enumList EnumTree& 存放枚举墩牌型列表数据 dt DunTy 指定为第几墩 59 | static void EnumCards(uint8_t const* src, int len, 60 | int n, classify_t& classify, EnumTree& enumList, DunTy dt); 61 | 62 | //返回组墩后剩余牌/散牌 63 | //src uint8_t const* 一副手牌13张 64 | //duns dundata_t const* 一组墩(头/中/尾墩) 65 | //cpy uint8_t *cpy 组墩后剩余牌 cpylen int& 余牌数量 66 | static void GetLeftCards(uint8_t const* src, int len, 67 | dundata_t const* duns, uint8_t *cpy, int& cpylen); 68 | 69 | -------------------------------------------------------------------------------- /cardsList.ini: -------------------------------------------------------------------------------- 1 | ;;方块(♦) 梅花(♣) 红心(♥) 黑桃(♠) 2 | ;;1->文件读取手牌 0->随机生成13张牌 3 | 1 4 | ;;默认最多枚举多少组墩,开元或德胜是三组 5 | 5 6 | ;;一条青龙 7 | ;;♠A ♠2 ♠3 ♠4 ♠5 ♠6 ♠7 ♠8 ♠9 ♠10 ♠J ♠Q ♠K 8 | ;;一条龙 9 | ;;♥A ♣2 ♣3 ♦4 ♦5 ♣6 ♠7 ♣8 ♣9 ♥10 ♣J ♠Q ♥K 10 | ;;十二皇族 11 | ;;♠A ♥A ♠K ♥K ♣K ♦K ♠Q ♥Q ♣Q ♦Q ♥J ♣J ♦J 12 | ;;三同花顺 13 | ;;♠A ♠2 ♠3 ♥6 ♥7 ♥8 ♥9 ♥10 ♣2 ♣3 ♣4 ♣5 ♣6 14 | ;;三分天下 15 | ;;♠A ♥A ♣A ♦A ♠10 ♥10 ♣10 ♦10 ♠6 ♥6 ♣6 ♦6 ♦Q 16 | ;;全大 17 | ;;♠A ♣A ♠K ♥K ♣K ♥Q ♣Q ♥J ♠10 ♣9 ♦9 ♣8 ♦8 18 | ;;全小 19 | ;;♠2 ♥2 ♣2 ♣3 ♦3 ♠4 ♥4 ♠5 ♣5 ♥6 ♣6 ♣7 ♥8 20 | ;;凑一色 21 | ;;♥2 ♥5 ♥8 ♥7 ♦9 ♦4 ♥J ♦3 ♦5 ♦6 ♦8 ♦Q ♥K 22 | ;;双怪冲三 23 | ;;♠A ♥A ♣A ♠K ♥K ♣K ♥4 ♣4 ♥7 ♣7 ♥3 ♣3 ♦5 24 | ;;四套三条 25 | ;;♠2 ♥2 ♣2 ♥4 ♣4 ♦4 ♠8 ♥8 ♦8 ♠K ♣K ♦K ♦10 26 | ;;五对三条 27 | ;;♠9 ♥9 ♥8 ♣8 ♠K ♥K ♥5 ♦5 ♠Q ♦Q ♠7 ♣7 ♦7 28 | ;;六对半 29 | ;;♠9 ♥9 ♥8 ♣8 ♠K ♥K ♥5 ♦5 ♠Q ♦Q ♠7 ♣7 ♥J 30 | ;;三顺子 31 | ;;♠2 ♣3 ♥4 ♣7 ♣8 ♠9 ♥10 ♥J ♥2 ♥3 ♣4 ♣5 ♠6 32 | ;;三同花 33 | ;;♥2 ♥5 ♥8 ♠Q ♠K ♠9 ♠3 ♠6 ♦3 ♦5 ♦8 ♦10 ♦Q -------------------------------------------------------------------------------- /cfg.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #include 6 | #include 7 | #include "math.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "cfg.h" 19 | 20 | //按行读取文件 21 | void readFile(char const* filename, std::vector& lines, char const* skip) { 22 | #if 1 23 | { 24 | FILE* fp = fopen(filename, "r"); 25 | if (fp == NULL) { 26 | return; 27 | } 28 | char line[512] = { 0 }; 29 | while (!feof(fp)) { 30 | if (NULL != fgets(line, 512, fp)) { 31 | int len = strlen(line); 32 | if (line[len - 1] == '\r' || 33 | (line[len - 2] != '\r' && line[len - 1] == '\n')) { 34 | //去掉\r或\n结尾 35 | line[len - 1] = '\0'; 36 | --len; 37 | } 38 | else if (line[len - 2] == '\r' && line[len - 1] == '\n') { 39 | //0 == strcmp(&line[len-2], "\r\n") 40 | //去掉\r\n结尾 41 | line[len - 2] = '\0'; 42 | line[len - 1] = '\0'; 43 | len -= 2; 44 | } 45 | //printf(line); 46 | if (line[0] != '\0') { 47 | if (len >= strlen(skip) && 0 == strncmp(line, skip, strlen(skip))) { 48 | } 49 | else { 50 | lines.push_back(line); 51 | } 52 | } 53 | } 54 | } 55 | //printf("--- *** fgets:%d\n", lines.size()); 56 | //for (std::vector::iterator it = lines.begin(); 57 | // it != lines.end(); ++it) { 58 | // printf("%s\n", it->c_str()); 59 | //} 60 | fclose(fp); 61 | } 62 | #else 63 | { 64 | lines.clear(); 65 | std::fstream fs(filename); 66 | std::string line; 67 | while (getline(fs, line)) { 68 | int len = line.size(); 69 | if (line[len - 1] == '\r' || 70 | (line[len - 2] != '\r' && line[len - 1] == '\n')) { 71 | //去掉\r或\n结尾 72 | line[len - 1] = '\0'; 73 | --len; 74 | } 75 | else if (line[len - 2] == '\r' && line[len - 1] == '\n') { 76 | //去掉\r\n结尾 77 | line[len - 2] = '\0'; 78 | line[len - 1] = '\0'; 79 | len -= 2; 80 | } 81 | //printf(line.c_str()); 82 | if (line[0] != '\0') { 83 | if (len >= strlen(skip) && 84 | 0 == strncmp(&line.front(), skip, strlen(skip))) { 85 | } 86 | else { 87 | lines.push_back(line); 88 | } 89 | } 90 | } 91 | //printf("--- *** getline:%d\n", lines.size()); 92 | //for (std::vector::iterator it = lines.begin(); 93 | // it != lines.end(); ++it) { 94 | // printf("%s\n", it->c_str()); 95 | //} 96 | } 97 | #endif 98 | } -------------------------------------------------------------------------------- /cfg.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #ifndef CFG_H 6 | #define CFG_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | //按行读取文件 19 | void readFile(char const* filename, std::vector& lines, char const* skip); 20 | 21 | #endif 22 | 23 | 24 | -------------------------------------------------------------------------------- /funcC.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #include 6 | #include 7 | #include "math.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "funcC.h" 19 | 20 | //求组合C(n,k) 21 | CFuncC::CFuncC() :c(0) { 22 | } 23 | 24 | //深度遍历实现找规律 25 | int CFuncC::Depth() { 26 | //深度优先遍历,由浅到深,广度遍历,由里向外 27 | printf("\n------------\n"); 28 | int c = 0; 29 | int e[6] = { 0 }; 30 | e[0] = 4; 31 | for (int i = 4; i > 0; --i) { 32 | e[1] = i;//深度为1 33 | for (int j = 4; j > 0; --j) { 34 | e[2] = j;//深度为2 35 | for (int k = 4; k > 0; --k) { 36 | e[3] = k;//深度为3 37 | for (int x = 4; x > 0; --x) { 38 | e[4] = x;//深度为4 39 | //for (int y = 4; y > 0; --y) { 40 | // e[5] = y;//深度为5 41 | //for (int z = 4; z > 0; --z) { 42 | //e[6] = z;//深度为6 43 | ++c; 44 | for (int m = 1; m <= e[0]; ++m) { 45 | printf("%d", e[m]); 46 | } 47 | printf(" "); 48 | //} 49 | //} 50 | } 51 | } 52 | } 53 | } 54 | printf("\nc = %d\n\n", c); 55 | return c; 56 | } 57 | 58 | //求组合C(n,k),返回数组集合 59 | //arr((i0),...) = F(C(n,1)) 60 | //arr((i0,i1),...) = F(C(n,2)) 61 | //arr((i0,i1,i2),...) = F(C(n,3)) 62 | //arr((i0,i1,...ik),...) = F(C(n,k)) 63 | int CFuncC::FuncC(int n, int k, std::vector>& vec) { 64 | c = 0; 65 | e[0] = k; 66 | vec.clear(); 67 | return StaC(n, k, vec); 68 | } 69 | 70 | //求组合C(n,1)*C(n,1)...*C(n,1) 71 | //f(k)=C(n,1) 72 | //Muti(k)=f(1)*f(2)...*f(k) 73 | //n int 访问广度 74 | //k int 访问深度 75 | //深度优先遍历,由浅到深,广度遍历,由里向外 76 | int CFuncC::DepthVisit(int n, int k) { 77 | c = 0; 78 | e[0] = k; 79 | return DepthC(n, k); 80 | } 81 | 82 | //递归求组合C(n,k) 83 | //n int 访问广度 84 | //k int 访问深度 85 | //深度优先遍历,由浅到深,广度遍历,由里向外 86 | int CFuncC::StaC(int n, int k, std::vector>& vec) { 87 | for (int i = n; i >= k; --i) { 88 | assert(k > 0); 89 | e[k] = i; 90 | if (k > 1) { 91 | //递归C(i-1,k-1) 92 | StaC(i - 1, k - 1, vec); 93 | } 94 | else { 95 | ++c; 96 | for (int j = e[0]; j > 0; --j) { 97 | //printf("%d", e[j]); 98 | v.push_back(e[j] - 1); 99 | } 100 | //printf(","); 101 | vec.push_back(v); 102 | v.clear(); 103 | } 104 | } 105 | //返回组合数 106 | return c; 107 | } 108 | 109 | //递归求组合C(n,1)*C(n,1)...*C(n,1) 110 | //f(k)=C(n,1) 111 | //Muti(k)=f(1)*f(2)...*f(k) 112 | //n int 访问广度 113 | //k int 访问深度 114 | //深度优先遍历,由浅到深,广度遍历,由里向外 115 | int CFuncC::DepthC(int n, int k) { 116 | for (int i = n; i > 0; --i) { 117 | assert(k > 0); 118 | e[k] = i; 119 | if (k > 1) { 120 | //递归C(n,k-1) 121 | DepthC(n, k - 1); 122 | } 123 | else { 124 | ++c; 125 | for (int j = e[0]; j > 0; --j) { 126 | printf("%d", e[j]); 127 | } 128 | printf(" "); 129 | } 130 | } 131 | //返回组合数 132 | return c; 133 | } 134 | 135 | void CFuncC::Print(std::vector>& vec) { 136 | for (std::vector>::iterator it = vec.begin(); 137 | it != vec.end(); ++it) { 138 | for (std::vector::iterator ir = it->begin(); 139 | ir != it->end(); ++ir) { 140 | printf("%d", *ir); 141 | } 142 | printf(" "); 143 | } 144 | printf("\n"); 145 | } 146 | 147 | void CFuncC::Test() { 148 | CFuncC C; 149 | std::vector> vec; 150 | while (1) { 151 | int n, k; 152 | std::cin >> n >> k; 153 | int c = C.FuncC(n, k, vec); 154 | printf("\n%d\n", c); 155 | //CFuncC::Print(vec); 156 | } 157 | } 158 | 159 | void CFuncC::Test1() { 160 | int c0 = CFuncC::Depth(); 161 | CFuncC C; 162 | int c = C.DepthVisit(4, 4); 163 | printf("\nc0=%d c=%d\n\n", c0, c); 164 | } -------------------------------------------------------------------------------- /funcC.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #ifndef FUNC_C_H 6 | #define FUNC_C_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | //求组合C(n,k) 19 | class CFuncC { 20 | public: 21 | static void Print(std::vector>& vec); 22 | static void Test(); 23 | static void Test1(); 24 | public: 25 | CFuncC(); 26 | //深度遍历实现找规律 27 | static int Depth(); 28 | //求组合C(n,k),返回数组集合 29 | //arr((i0),...) = F(C(n,1)) 30 | //arr((i0,i1),...) = F(C(n,2)) 31 | //arr((i0,i1,i2),...) = F(C(n,3)) 32 | //arr((i0,i1,...ik),...) = F(C(n,k)) 33 | int FuncC(int n, int k, std::vector>& vec); 34 | //求组合C(n,1)*C(n,1)...*C(n,1) 35 | //f(k)=C(n,1) 36 | //Muti(k)=f(1)*f(2)...*f(k) 37 | //n int 访问广度 38 | //k int 访问深度 39 | //深度优先遍历,由浅到深,广度遍历,由里向外 40 | int DepthVisit(int n, int k); 41 | private: 42 | //递归求组合C(n,k) 43 | //f(k)=C(n,1) 44 | //Muti(k)=f(1)*f(2)...*f(k) 45 | //n int 访问广度 46 | //k int 访问深度 47 | //深度优先遍历,由浅到深,广度遍历,由里向外 48 | int StaC(int n, int k, std::vector>& vec); 49 | //递归求组合C(n,1)*C(n,1)...*C(n,1) 50 | //n int 访问广度 51 | //k int 访问深度 52 | //深度优先遍历,由浅到深,广度遍历,由里向外 53 | int DepthC(int n, int k); 54 | private: 55 | int c; 56 | static int const KDEPTH = 13; 57 | int e[KDEPTH + 1]; 58 | std::vector v; 59 | }; 60 | 61 | #endif 62 | 63 | 64 | -------------------------------------------------------------------------------- /pb2Json.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | 6 | #include "pb2Json.h" 7 | 8 | namespace PB2JSON { 9 | 10 | void Pb2Json::PbMsg2JsonStr(ProtobufMessage const& src, std::string& dst, bool enum2str) { 11 | Json::Value value; 12 | PbMsg2Json(src, value, enum2str); 13 | Json::FastWriter writer; 14 | dst = writer.write(value); 15 | } 16 | 17 | bool Pb2Json::JsonStr2PbMsg(std::string const& src, ProtobufMessage& dst, bool str2enum) { 18 | Json::Value value; 19 | Json::Reader reader(Json::Features::strictMode()); 20 | if (!reader.parse(src, value)) { 21 | printf("parse json string is fail,str=%s\n", src.c_str()); 22 | return false; 23 | } 24 | if (!Json2PbMsg(value, dst, str2enum)) { 25 | printf("pb convert error"); 26 | return false; 27 | } 28 | return true; 29 | } 30 | 31 | bool Pb2Json::Json2PbMsg(Json::Value const& src, ProtobufMessage& dst, bool str2enum) { 32 | ProtobufDescriptor const* descriptor = dst.GetDescriptor(); 33 | ProtobufReflection const* reflection = dst.GetReflection(); 34 | if (NULL == descriptor || NULL == reflection) { 35 | return false; 36 | } 37 | int32_t count = descriptor->field_count(); 38 | for (int32_t i = 0; i < count; ++i) { 39 | ProtobufFieldDescriptor const* field = descriptor->field(i); 40 | if (NULL == field) { 41 | continue; 42 | } 43 | if (!src.isMember(field->name())) { 44 | continue; 45 | } 46 | Json::Value const& value = src[field->name()]; 47 | if (field->is_repeated()) { 48 | if (!value.isArray()) { 49 | printf("pb error"); 50 | return false; 51 | } 52 | else { 53 | Json2RepeatedMessage(value, dst, field, reflection, str2enum); 54 | continue; 55 | } 56 | } 57 | switch (field->type()) { 58 | case ProtobufFieldDescriptor::TYPE_BOOL: { 59 | if (value.isBool()) { 60 | reflection->SetBool(&dst, field, value.asBool()); 61 | } 62 | else if (value.isInt()) { 63 | reflection->SetBool(&dst, field, value.isInt()); 64 | } 65 | else if (value.isString()) { 66 | if (value.asString() == "true") { 67 | reflection->SetBool(&dst, field, true); 68 | } 69 | else if (value.asString() == "false") { 70 | reflection->SetBool(&dst, field, false); 71 | } 72 | } 73 | break; 74 | } 75 | case ProtobufFieldDescriptor::TYPE_INT32: 76 | case ProtobufFieldDescriptor::TYPE_SINT32: 77 | case ProtobufFieldDescriptor::TYPE_SFIXED32: { 78 | if (value.isInt()) { 79 | reflection->SetInt32(&dst, field, value.asInt()); 80 | } 81 | break; 82 | } 83 | case ProtobufFieldDescriptor::TYPE_UINT32: 84 | case ProtobufFieldDescriptor::TYPE_FIXED32: { 85 | if (value.isUInt()) { 86 | reflection->SetUInt32(&dst, field, value.asUInt()); 87 | } 88 | break; 89 | } 90 | case ProtobufFieldDescriptor::TYPE_INT64: 91 | case ProtobufFieldDescriptor::TYPE_SINT64: 92 | case ProtobufFieldDescriptor::TYPE_SFIXED64: { 93 | if (value.isInt()) { 94 | reflection->SetInt64(&dst, field, value.asInt64()); 95 | } 96 | break; 97 | } 98 | case ProtobufFieldDescriptor::TYPE_UINT64: 99 | case ProtobufFieldDescriptor::TYPE_FIXED64: { 100 | if (value.isUInt()) { 101 | reflection->SetUInt64(&dst, field, value.asUInt64()); 102 | } 103 | break; 104 | } 105 | case ProtobufFieldDescriptor::TYPE_FLOAT: { 106 | if (value.isDouble()) { 107 | reflection->SetFloat(&dst, field, value.asFloat()); 108 | } 109 | break; 110 | } 111 | case ProtobufFieldDescriptor::TYPE_DOUBLE: { 112 | if (value.isDouble()) { 113 | reflection->SetDouble(&dst, field, value.asDouble()); 114 | } 115 | break; 116 | } 117 | case ProtobufFieldDescriptor::TYPE_STRING: 118 | case ProtobufFieldDescriptor::TYPE_BYTES: { 119 | if (value.isString()) { 120 | reflection->SetString(&dst, field, value.asString()); 121 | } 122 | break; 123 | } 124 | case ProtobufFieldDescriptor::TYPE_MESSAGE: { 125 | if (value.isObject()) { 126 | Json2PbMsg(value, *reflection->MutableMessage(&dst, field)); 127 | } 128 | break; 129 | } 130 | } 131 | } 132 | return true; 133 | } 134 | 135 | void Pb2Json::PbMsg2Json( 136 | ProtobufMessage const& src, Json::Value& dst, bool enum2str) { 137 | ProtobufDescriptor const* descriptor = src.GetDescriptor(); 138 | ProtobufReflection const* reflection = src.GetReflection(); 139 | if (NULL == descriptor || NULL == descriptor) { 140 | return; 141 | } 142 | int32_t count = descriptor->field_count(); 143 | for (int32_t i = 0; i < count; ++i) { 144 | ProtobufFieldDescriptor const* field = descriptor->field(i); 145 | if (field->is_repeated()) { 146 | if (reflection->FieldSize(src, field) > 0) { 147 | RepeatedMessage2Json(src, field, reflection, dst[field->name()], enum2str); 148 | } 149 | continue; 150 | } 151 | if (!reflection->HasField(src, field)) { 152 | continue; 153 | } 154 | switch (field->type()) { 155 | case ProtobufFieldDescriptor::TYPE_MESSAGE: { 156 | ProtobufMessage const& tMsg = reflection->GetMessage(src, field); 157 | if (0 != tMsg.ByteSize()) { 158 | PbMsg2Json(tMsg, dst[field->name()]); 159 | } 160 | break; 161 | } 162 | case ProtobufFieldDescriptor::TYPE_BOOL: 163 | dst[field->name()] = reflection->GetBool(src, field) ? true : false; 164 | break; 165 | case ProtobufFieldDescriptor::TYPE_ENUM: { 166 | ::google::protobuf::EnumValueDescriptor const* enum_value_desc = reflection->GetEnum(src, field); 167 | if (enum2str) { 168 | dst[field->name()] = enum_value_desc->name(); 169 | } 170 | else { 171 | dst[field->name()] = enum_value_desc->number(); 172 | } 173 | break; 174 | } 175 | case ProtobufFieldDescriptor::TYPE_INT32: 176 | case ProtobufFieldDescriptor::TYPE_SINT32: 177 | case ProtobufFieldDescriptor::TYPE_SFIXED32: 178 | dst[field->name()] = Json::Int(reflection->GetInt32(src, field)); 179 | break; 180 | case ProtobufFieldDescriptor::TYPE_UINT32: 181 | case ProtobufFieldDescriptor::TYPE_FIXED32: 182 | dst[field->name()] = Json::UInt(reflection->GetUInt32(src, field)); 183 | break; 184 | 185 | case ProtobufFieldDescriptor::TYPE_INT64: 186 | case ProtobufFieldDescriptor::TYPE_SINT64: 187 | case ProtobufFieldDescriptor::TYPE_SFIXED64: 188 | dst[field->name()] = Json::Int64(reflection->GetInt64(src, field)); 189 | break; 190 | case ProtobufFieldDescriptor::TYPE_UINT64: 191 | case ProtobufFieldDescriptor::TYPE_FIXED64: 192 | dst[field->name()] = Json::UInt64(reflection->GetUInt64(src, field)); 193 | break; 194 | case ProtobufFieldDescriptor::TYPE_FLOAT: 195 | dst[field->name()] = reflection->GetFloat(src, field); 196 | break; 197 | case ProtobufFieldDescriptor::TYPE_STRING: 198 | case ProtobufFieldDescriptor::TYPE_BYTES: 199 | dst[field->name()] = reflection->GetString(src, field); 200 | break; 201 | } 202 | } 203 | } 204 | 205 | bool Pb2Json::Json2RepeatedMessage( 206 | Json::Value const& json, ProtobufMessage& message, 207 | ProtobufFieldDescriptor const* field, 208 | ProtobufReflection const* reflection, 209 | bool str2enum) { 210 | int32_t count = json.size(); 211 | for (int32_t j = 0; j < count; ++j) { 212 | switch (field->type()) { 213 | case ProtobufFieldDescriptor::TYPE_BOOL: { 214 | if (json.isBool()) { 215 | reflection->AddBool(&message, field, json[j].asBool()); 216 | } 217 | else if (json[j].isInt()) { 218 | reflection->AddBool(&message, field, json[j].asInt()); 219 | } 220 | else if (json[j].isString()) { 221 | if (json[j].asString() == "true") { 222 | reflection->AddBool(&message, field, true); 223 | } 224 | else if (json[j].asString() == "false") { 225 | reflection->AddBool(&message, field, false); 226 | } 227 | } 228 | break; 229 | } 230 | case ProtobufFieldDescriptor::TYPE_ENUM: { 231 | ::google::protobuf::EnumDescriptor const* pedesc = field->enum_type(); 232 | ::google::protobuf::EnumValueDescriptor const* pevdesc = NULL; 233 | if (str2enum) { 234 | pevdesc = pedesc->FindValueByName(json[j].asString()); 235 | } 236 | else { 237 | pevdesc = pedesc->FindValueByNumber(json[j].asInt()); 238 | } 239 | if (NULL != pevdesc) { 240 | reflection->AddEnum(&message, field, pevdesc); 241 | } 242 | break; 243 | } 244 | case ProtobufFieldDescriptor::TYPE_INT32: 245 | case ProtobufFieldDescriptor::TYPE_SINT32: 246 | case ProtobufFieldDescriptor::TYPE_SFIXED32: { 247 | if (json[j].isInt()) { 248 | reflection->AddInt32(&message, field, json[j].asInt()); 249 | } 250 | } break; 251 | case ProtobufFieldDescriptor::TYPE_UINT32: 252 | case ProtobufFieldDescriptor::TYPE_FIXED32: { 253 | if (json[j].isUInt()) { 254 | reflection->AddUInt32(&message, field, json[j].asUInt()); 255 | } 256 | } break; 257 | case ProtobufFieldDescriptor::TYPE_INT64: 258 | case ProtobufFieldDescriptor::TYPE_SINT64: 259 | case ProtobufFieldDescriptor::TYPE_SFIXED64: { 260 | if (json[j].isInt()) { 261 | reflection->AddInt64(&message, field, json[j].asInt64()); 262 | } 263 | } break; 264 | case ProtobufFieldDescriptor::TYPE_UINT64: 265 | case ProtobufFieldDescriptor::TYPE_FIXED64: { 266 | if (json[j].isUInt()) { 267 | reflection->AddUInt64(&message, field, json[j].asUInt64()); 268 | } 269 | } break; 270 | case ProtobufFieldDescriptor::TYPE_FLOAT: { 271 | if (json[j].isDouble()) { 272 | reflection->AddFloat(&message, field, json[j].asFloat()); 273 | } 274 | } break; 275 | case ProtobufFieldDescriptor::TYPE_DOUBLE: { 276 | if (json[j].isDouble()) { 277 | reflection->AddDouble(&message, field, json[j].asDouble()); 278 | } 279 | } break; 280 | case ProtobufFieldDescriptor::TYPE_MESSAGE: { 281 | if (json[j].isObject()) { 282 | Json2PbMsg(json[j], *reflection->AddMessage(&message, field)); 283 | } 284 | } break; 285 | case ProtobufFieldDescriptor::TYPE_STRING: 286 | case ProtobufFieldDescriptor::TYPE_BYTES: { 287 | if (json[j].isString()) { 288 | reflection->AddString(&message, field, json[j].asString()); 289 | } 290 | } break; 291 | } 292 | } 293 | return true; 294 | } 295 | 296 | void Pb2Json::RepeatedMessage2Json(ProtobufMessage const& message, 297 | ProtobufFieldDescriptor const* field, 298 | ProtobufReflection const* reflection, 299 | Json::Value& json, bool enum2str) 300 | { 301 | if (NULL == field || NULL == reflection) { 302 | PbMsg2Json(message, json); 303 | } 304 | for (int32_t i = 0; i < reflection->FieldSize(message, field); ++i) { 305 | Json::Value tJson; 306 | switch (field->type()) { 307 | case ProtobufFieldDescriptor::TYPE_MESSAGE: { 308 | ProtobufMessage const& tMsg = reflection->GetRepeatedMessage(message, field, i); 309 | if (0 != tMsg.ByteSize()) { 310 | PbMsg2Json(tMsg, tJson); 311 | } 312 | break; 313 | } 314 | case ProtobufFieldDescriptor::TYPE_BOOL: 315 | tJson[field->name()] = reflection->GetRepeatedBool(message, field, i) ? true : false; 316 | break; 317 | case ProtobufFieldDescriptor::TYPE_ENUM: { 318 | const ::google::protobuf::EnumValueDescriptor* enum_value_desc = reflection->GetRepeatedEnum(message, field, i); 319 | if (enum2str) { 320 | tJson = enum_value_desc->name(); 321 | } 322 | else { 323 | tJson = enum_value_desc->number(); 324 | } 325 | break; 326 | } 327 | case ProtobufFieldDescriptor::TYPE_INT32: 328 | case ProtobufFieldDescriptor::TYPE_SINT32: 329 | case ProtobufFieldDescriptor::TYPE_SFIXED32: 330 | tJson[field->name()] = reflection->GetRepeatedInt32(message, field, i); 331 | break; 332 | case ProtobufFieldDescriptor::TYPE_UINT32: 333 | case ProtobufFieldDescriptor::TYPE_FIXED32: 334 | tJson[field->name()] = reflection->GetRepeatedUInt32(message, field, i); 335 | break; 336 | case ProtobufFieldDescriptor::TYPE_INT64: 337 | case ProtobufFieldDescriptor::TYPE_SINT64: 338 | case ProtobufFieldDescriptor::TYPE_SFIXED64: 339 | tJson[field->name()] = (Json::Int64)reflection->GetRepeatedInt64(message, field, i); 340 | break; 341 | case ProtobufFieldDescriptor::TYPE_UINT64: 342 | case ProtobufFieldDescriptor::TYPE_FIXED64: 343 | tJson[field->name()] = Json::UInt64(reflection->GetRepeatedUInt64(message, field, i)); 344 | break; 345 | case ProtobufFieldDescriptor::TYPE_FLOAT: 346 | tJson[field->name()] = reflection->GetRepeatedFloat(message, field, i); 347 | break; 348 | case ProtobufFieldDescriptor::TYPE_STRING: 349 | case ProtobufFieldDescriptor::TYPE_BYTES: 350 | tJson[field->name()] = reflection->GetRepeatedString(message, field, i); 351 | break; 352 | } 353 | json.append(tJson); 354 | } 355 | } 356 | }; -------------------------------------------------------------------------------- /pb2Json.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #ifndef PROTOBUF2JSON_H 6 | #define PROTOBUF2JSON_H 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | //protobuf与json之间转换 13 | namespace PB2JSON { 14 | class Pb2Json { 15 | public: 16 | typedef ::google::protobuf::Message ProtobufMessage; 17 | typedef ::google::protobuf::Reflection ProtobufReflection; 18 | typedef ::google::protobuf::FieldDescriptor ProtobufFieldDescriptor; 19 | typedef ::google::protobuf::Descriptor ProtobufDescriptor; 20 | public: 21 | static void PbMsg2JsonStr(ProtobufMessage const& src, std::string& dst, bool enum2str = false); 22 | static bool JsonStr2PbMsg(std::string const& src, ProtobufMessage& dst, bool str2enum = false); 23 | static bool Json2PbMsg(Json::Value const& src, ProtobufMessage& dst, bool str2enum = false); 24 | static void PbMsg2Json(ProtobufMessage const& src, Json::Value& dst, bool enum2str = false); 25 | private: 26 | static bool Json2RepeatedMessage( 27 | Json::Value const& json, ProtobufMessage& message, 28 | ProtobufFieldDescriptor const* field, 29 | ProtobufReflection const* reflection, 30 | bool str2enum = false); 31 | static void RepeatedMessage2Json( 32 | ProtobufMessage const& message, 33 | ProtobufFieldDescriptor const* field, 34 | ProtobufReflection const* reflection, 35 | Json::Value& json, bool enum2str); 36 | }; 37 | }; 38 | 39 | #endif -------------------------------------------------------------------------------- /s13s.CMD_S_GameStart.txt: -------------------------------------------------------------------------------- 1 | { 2 | "handCards": { 3 | "cards": "!\u0012D5&'GH*:L=M", 4 | "groups": [ 5 | { 6 | "duns": [ 7 | { 8 | "c": 3, 9 | "cards": "!&'", 10 | "id": 0, 11 | "ty": 2 12 | }, 13 | { 14 | "c": 2, 15 | "cards": ":*", 16 | "id": 1, 17 | "ty": 3 18 | }, 19 | { 20 | "c": 5, 21 | "cards": "DGHLM", 22 | "id": 2, 23 | "ty": 7 24 | } 25 | ], 26 | "specialTy": 0, 27 | "start": 2 28 | }, 29 | { 30 | "duns": [ 31 | { 32 | "c": 3, 33 | "cards": "!'*", 34 | "id": 0, 35 | "ty": 2 36 | }, 37 | { 38 | "c": 2, 39 | "cards": "M=", 40 | "id": 1, 41 | "ty": 3 42 | }, 43 | { 44 | "c": 5, 45 | "cards": "D5&GH", 46 | "id": 2, 47 | "ty": 6 48 | } 49 | ], 50 | "specialTy": 0, 51 | "start": 2 52 | }, 53 | { 54 | "duns": [ 55 | { 56 | "c": 2, 57 | "cards": ":*", 58 | "id": 0, 59 | "ty": 3 60 | }, 61 | { 62 | "c": 2, 63 | "cards": "M=", 64 | "id": 1, 65 | "ty": 3 66 | }, 67 | { 68 | "c": 5, 69 | "cards": "D5&'H", 70 | "id": 2, 71 | "ty": 6 72 | } 73 | ], 74 | "specialTy": 0, 75 | "start": 2 76 | } 77 | ], 78 | "specialTy": 0 79 | } 80 | } -------------------------------------------------------------------------------- /s13s.Message.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto2"; 2 | package s13s; 3 | 4 | enum SUBID 5 | { 6 | //客户端命令结构 7 | SUB_C_MANUALCARDS = 1; // 手动摆牌 CMD_C_ManualCards 8 | SUB_C_MAKESUREDUNHANDTY = 2; // 确定三墩牌型 CMD_C_MakesureDunHandTy 9 | } 10 | 11 | //////////////////////////////////////////////////////////////////////////////// 12 | //牌数据 13 | message CardData 14 | { 15 | required bytes cards = 1; 16 | } 17 | //////////////////////////////////////////////////////////////////////////////// 18 | //单墩数据 19 | message DunData 20 | { 21 | required int32 id = 1; //标记0-头/1-中/2-尾 22 | required int32 ty = 2; //墩对应普通牌型 23 | required int32 c = 3; //墩对应牌数c(3/5/5) 24 | required bytes cards = 4; //墩牌数据(头敦3张牌/中墩和尾墩各5张牌) 25 | } 26 | //////////////////////////////////////////////////////////////////////////////// 27 | //一组墩(含头墩/中墩/尾墩) 28 | message GroupDunData 29 | { 30 | required int32 start = 1; //从哪墩开始的 31 | required int32 specialTy = 2; //总体对应特殊牌型 32 | repeated DunData duns = 3; //[0]头敦(3)/[1]中墩(5)/[2]尾墩(5) 33 | } 34 | //////////////////////////////////////////////////////////////////////////////// 35 | //手牌数据 36 | message HandCards 37 | { 38 | required bytes cards = 1; //一副13张手牌 39 | required int32 specialTy = 2; //标记手牌特殊牌型 40 | repeated GroupDunData groups = 3; //枚举几组最优墩(开元或得胜是给了3组,这里给了5组) 41 | } 42 | //////////////////////////////////////////////////////////////////////////////// 43 | //枚举牌型 44 | message EnumCards 45 | { 46 | repeated bytes v123sc = 1; //所有同花色五张/三张连续牌(五张/三张同花顺) 47 | repeated bytes v40 = 2; //所有铁支(四张) 48 | repeated bytes v32 = 3; //所有葫芦(一组三条加上一组对子) 49 | repeated bytes vsc = 4; //所有同花五张/三张非连续牌(五张/三张同花) 50 | repeated bytes v123 = 5; //所有非同花五张/三张连续牌(五张/三张顺子) 51 | repeated bytes v30 = 6; //所有三条(三张) 52 | repeated bytes v22 = 7; //所有两对(两个对子) 53 | repeated bytes v20 = 8; //所有对子(一对) 54 | } 55 | //////////////////////////////////////////////////////////////////////////////// 56 | //比牌对方 57 | message ComparePlayer 58 | { 59 | required int32 chairId = 1; //座椅ID 60 | required GroupDunData group = 2; //选择一组墩(含头墩/中墩/尾墩) 61 | } 62 | //////////////////////////////////////////////////////////////////////////////// 63 | //单墩比输赢 64 | message CompareItem 65 | { 66 | required int32 winLost = 1; //输赢 -1输/0和/1赢 67 | optional int32 score = 2; //赢分+/和分0/输分- 68 | optional int32 ty = 3; //单墩牌型 69 | optional int32 peerTy = 4; //对方单墩牌型 70 | } 71 | //////////////////////////////////////////////////////////////////////////////// 72 | //三墩比输赢 73 | message CompareResult 74 | { 75 | repeated CompareItem items = 1; //items[DunMax] 76 | optional int32 shoot = 2; //-1被打枪/0不打枪/1打枪 77 | optional int32 score = 3; //三墩不考虑打枪总输赢 赢分+/和分0/输分- 78 | } 79 | //////////////////////////////////////////////////////////////////////////////// 80 | //桌椅玩家 81 | message PlayerItem 82 | { 83 | required int32 chairId = 1; //座椅ID 84 | repeated ComparePlayer peers = 2;//比牌对方 85 | repeated CompareResult results = 3;//比牌结果 86 | optional int32 allshoot = 4;//是否全垒打 -1被全垒打/0无全垒打/1全垒打 87 | optional int32 deltascore = 5;//玩家两两比牌总输赢 赢分+/和分0/输分- 包括打枪/全垒打 88 | } 89 | //////////////////////////////////////////////////////////////////////////////// 90 | //游戏开始 91 | message CMD_S_GameStart 92 | { 93 | required HandCards handCards = 1; //手牌数据 94 | }; 95 | //////////////////////////////////////////////////////////////////////////////// 96 | //手动摆牌 97 | message CMD_S_ManualCards 98 | { 99 | optional EnumCards enums = 1; //枚举牌型 100 | optional int32 dt = 2; //客户端选择了哪一墩,标记0-头/1-中/2-尾 101 | optional int32 ty = 3; //墩对应牌型 102 | optional bytes cpy = 4; //剩余牌 103 | } 104 | //////////////////////////////////////////////////////////////////////////////// 105 | //手动摆牌 106 | message CMD_C_ManualCards 107 | { 108 | optional int32 dt = 1; //客户端选择了哪一墩,标记0-头/1-中/2-尾 109 | optional bytes cards = 2; //客户端选择了哪些牌,作为一墩,后端用余牌再计算枚举 110 | } 111 | //////////////////////////////////////////////////////////////////////////////// 112 | //确定牌型,所有玩家都确定牌型后比牌 113 | message CMD_C_MakesureDunHandTy 114 | { 115 | required int32 groupindex = 1; //>=0从枚举的几组墩中选择一组,-1手动摆牌确认 116 | } -------------------------------------------------------------------------------- /s13s.PlayerItem.txt: -------------------------------------------------------------------------------- 1 | --- *** {"s13s.PlayerItem": 2 | {"chairId":0,"deltascore":-12,"peers":[{"chairId":3,"group":{"duns":[{"c":3,"cards":"!1A","id":0,"ty":5},{"c":5,"cards":"\"\u001BL-M","id":1,"ty":3},{"c":5,"cards":"#3\u00156\u0019","id":2,"ty":3}],"specialTy":0,"start":0}},{"chairId":2,"group":{"duns":[{"c":3,"cards":"\u0013(*","id":0,"ty":2},{"c":5,"cards":"'\u0017,\u001C\u0012","id":1,"ty":4},{"c":5,"cards":"4579;","id":2,"ty":7}],"specialTy":0,"start":0}},{"chairId":1,"group":{"duns":[{"c":3,"cards":"B<\u001D","id":0,"ty":2},{"c":5,"cards":"C\u0018HI:","id":1,"ty":3},{"c":5,"cards":"$E\u0016&F","id":2,"ty":5}],"specialTy":0,"start":0}}],"results":[{"items":[{"peerTy":5,"score":-3,"ty":3,"winLost":-1},{"peerTy":3,"score":-1,"ty":3,"winLost":-1},{"peerTy":3,"score":-1,"ty":2,"winLost":-1}],"score":-5,"shoot":-1},{"items":[{"peerTy":2,"score":1,"ty":3,"winLost":1},{"peerTy":4,"score":-1,"ty":3,"winLost":-1},{"peerTy":7,"score":-1,"ty":2,"winLost":-1}],"score":-1,"shoot":0},{"items":[{"peerTy":2,"score":1,"ty":3,"winLost":1},{"peerTy":3,"score":-1,"ty":3,"winLost":-1},{"peerTy":5,"score":-1,"ty":2,"winLost":-1}],"score":-1,"shoot":0}]} 3 | } 4 | 5 | 6 | --- *** {"s13s.PlayerItem": 7 | {"chairId":1,"deltascore":-8,"peers":[{"chairId":3,"group":{"duns":[{"c":3,"cards":"!1A","id":0,"ty":5},{"c":5,"cards":"\"\u001BL-M","id":1,"ty":3},{"c":5,"cards":"#3\u00156\u0019","id":2,"ty":3}],"specialTy":0,"start":0}},{"chairId":2,"group":{"duns":[{"c":3,"cards":"\u0013(*","id":0,"ty":2},{"c":5,"cards":"'\u0017,\u001C\u0012","id":1,"ty":4},{"c":5,"cards":"4579;","id":2,"ty":7}],"specialTy":0,"start":0}},{"chairId":0,"group":{"duns":[{"c":3,"cards":"+K=","id":0,"ty":3},{"c":5,"cards":"\u00112\u0014DJ","id":1,"ty":3},{"c":5,"cards":"%G8)\u001A","id":2,"ty":2}],"specialTy":0,"start":0}}],"results":[{"items":[{"peerTy":5,"score":-3,"ty":2,"winLost":-1},{"peerTy":3,"score":-1,"ty":3,"winLost":-1},{"peerTy":3,"score":1,"ty":5,"winLost":1}],"score":-3,"shoot":0},{"items":[{"peerTy":2,"score":-1,"ty":2,"winLost":-1},{"peerTy":4,"score":-1,"ty":3,"winLost":-1},{"peerTy":7,"score":-1,"ty":5,"winLost":-1}],"score":-3,"shoot":-1},{"items":[{"peerTy":3,"score":-1,"ty":2,"winLost":-1},{"peerTy":3,"score":1,"ty":3,"winLost":1},{"peerTy":2,"score":1,"ty":5,"winLost":1}],"score":1,"shoot":0}]} 8 | } 9 | 10 | 11 | --- *** {"s13s.PlayerItem": 12 | {"chairId":2,"deltascore":6,"peers":[{"chairId":3,"group":{"duns":[{"c":3,"cards":"!1A","id":0,"ty":5},{"c":5,"cards":"\"\u001BL-M","id":1,"ty":3},{"c":5,"cards":"#3\u00156\u0019","id":2,"ty":3}],"specialTy":0,"start":0}},{"chairId":1,"group":{"duns":[{"c":3,"cards":"B<\u001D","id":0,"ty":2},{"c":5,"cards":"C\u0018HI:","id":1,"ty":3},{"c":5,"cards":"$E\u0016&F","id":2,"ty":5}],"specialTy":0,"start":0}},{"chairId":0,"group":{"duns":[{"c":3,"cards":"+K=","id":0,"ty":3},{"c":5,"cards":"\u00112\u0014DJ","id":1,"ty":3},{"c":5,"cards":"%G8)\u001A","id":2,"ty":2}],"specialTy":0,"start":0}}],"results":[{"items":[{"peerTy":5,"score":-3,"ty":2,"winLost":-1},{"peerTy":3,"score":1,"ty":4,"winLost":1},{"peerTy":3,"score":1,"ty":7,"winLost":1}],"score":-1,"shoot":0},{"items":[{"peerTy":2,"score":1,"ty":2,"winLost":1},{"peerTy":3,"score":1,"ty":4,"winLost":1},{"peerTy":5,"score":1,"ty":7,"winLost":1}],"score":3,"shoot":1},{"items":[{"peerTy":3,"score":-1,"ty":2,"winLost":-1},{"peerTy":3,"score":1,"ty":4,"winLost":1},{"peerTy":2,"score":1,"ty":7,"winLost":1}],"score":1,"shoot":0}]} 13 | } 14 | 15 | 16 | --- *** {"s13s.PlayerItem": 17 | {"chairId":3,"deltascore":14,"peers":[{"chairId":2,"group":{"duns":[{"c":3,"cards":"\u0013(*","id":0,"ty":2},{"c":5,"cards":"'\u0017,\u001C\u0012","id":1,"ty":4},{"c":5,"cards":"4579;","id":2,"ty":7}],"specialTy":0,"start":0}},{"chairId":1,"group":{"duns":[{"c":3,"cards":"B<\u001D","id":0,"ty":2},{"c":5,"cards":"C\u0018HI:","id":1,"ty":3},{"c":5,"cards":"$E\u0016&F","id":2,"ty":5}],"specialTy":0,"start":0}},{"chairId":0,"group":{"duns":[{"c":3,"cards":"+K=","id":0,"ty":3},{"c":5,"cards":"\u00112\u0014DJ","id":1,"ty":3},{"c":5,"cards":"%G8)\u001A","id":2,"ty":2}],"specialTy":0,"start":0}}],"results":[{"items":[{"peerTy":2,"score":3,"ty":5,"winLost":1},{"peerTy":4,"score":-1,"ty":3,"winLost":-1},{"peerTy":7,"score":-1,"ty":3,"winLost":-1}],"score":1,"shoot":0},{"items":[{"peerTy":2,"score":3,"ty":5,"winLost":1},{"peerTy":3,"score":1,"ty":3,"winLost":1},{"peerTy":5,"score":-1,"ty":3,"winLost":-1}],"score":3,"shoot":0},{"items":[{"peerTy":3,"score":3,"ty":5,"winLost":1},{"peerTy":3,"score":1,"ty":3,"winLost":1},{"peerTy":2,"score":1,"ty":3,"winLost":1}],"score":5,"shoot":1}]} 18 | } 19 | 20 | 21 | json格式在线view工具:http://www.bejson.com/jsonviewernew/ 22 | { 23 | "s13s.PlayerItem": { 24 | "chairId": 0, 25 | "deltascore": -12, 26 | "peers": [ 27 | { 28 | "chairId": 3, 29 | "group": { 30 | "duns": [ 31 | { 32 | "c": 3, 33 | "cards": "!1A", 34 | "id": 0, 35 | "ty": 5 36 | }, 37 | { 38 | "c": 5, 39 | "cards": "\"\u001BL-M", 40 | "id": 1, 41 | "ty": 3 42 | }, 43 | { 44 | "c": 5, 45 | "cards": "#3\u00156\u0019", 46 | "id": 2, 47 | "ty": 3 48 | } 49 | ], 50 | "specialTy": 0, 51 | "start": 0 52 | } 53 | }, 54 | { 55 | "chairId": 2, 56 | "group": { 57 | "duns": [ 58 | { 59 | "c": 3, 60 | "cards": "\u0013(*", 61 | "id": 0, 62 | "ty": 2 63 | }, 64 | { 65 | "c": 5, 66 | "cards": "'\u0017,\u001C\u0012", 67 | "id": 1, 68 | "ty": 4 69 | }, 70 | { 71 | "c": 5, 72 | "cards": "4579;", 73 | "id": 2, 74 | "ty": 7 75 | } 76 | ], 77 | "specialTy": 0, 78 | "start": 0 79 | } 80 | }, 81 | { 82 | "chairId": 1, 83 | "group": { 84 | "duns": [ 85 | { 86 | "c": 3, 87 | "cards": "B<\u001D", 88 | "id": 0, 89 | "ty": 2 90 | }, 91 | { 92 | "c": 5, 93 | "cards": "C\u0018HI:", 94 | "id": 1, 95 | "ty": 3 96 | }, 97 | { 98 | "c": 5, 99 | "cards": "$E\u0016&F", 100 | "id": 2, 101 | "ty": 5 102 | } 103 | ], 104 | "specialTy": 0, 105 | "start": 0 106 | } 107 | } 108 | ], 109 | "results": [ 110 | { 111 | "items": [ 112 | { 113 | "peerTy": 5, 114 | "score": -3, 115 | "ty": 3, 116 | "winLost": -1 117 | }, 118 | { 119 | "peerTy": 3, 120 | "score": -1, 121 | "ty": 3, 122 | "winLost": -1 123 | }, 124 | { 125 | "peerTy": 3, 126 | "score": -1, 127 | "ty": 2, 128 | "winLost": -1 129 | } 130 | ], 131 | "score": -5, 132 | "shoot": -1 133 | }, 134 | { 135 | "items": [ 136 | { 137 | "peerTy": 2, 138 | "score": 1, 139 | "ty": 3, 140 | "winLost": 1 141 | }, 142 | { 143 | "peerTy": 4, 144 | "score": -1, 145 | "ty": 3, 146 | "winLost": -1 147 | }, 148 | { 149 | "peerTy": 7, 150 | "score": -1, 151 | "ty": 2, 152 | "winLost": -1 153 | } 154 | ], 155 | "score": -1, 156 | "shoot": 0 157 | }, 158 | { 159 | "items": [ 160 | { 161 | "peerTy": 2, 162 | "score": 1, 163 | "ty": 3, 164 | "winLost": 1 165 | }, 166 | { 167 | "peerTy": 3, 168 | "score": -1, 169 | "ty": 3, 170 | "winLost": -1 171 | }, 172 | { 173 | "peerTy": 5, 174 | "score": -1, 175 | "ty": 2, 176 | "winLost": -1 177 | } 178 | ], 179 | "score": -1, 180 | "shoot": 0 181 | } 182 | ] 183 | } 184 | } -------------------------------------------------------------------------------- /s13s.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #ifndef GAME_LOGIC_S13S_H 6 | #define GAME_LOGIC_S13S_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef isZero 21 | #define isZero(a) ((a>-0.000001) && (a<0.000001)) 22 | #endif//isZero 23 | 24 | #define MAX_CARD_TOTAL S13S::MaxCardTotal //牌总个数 25 | #define GAME_PLAYER S13S::MaxPlayer //最多4人局 26 | #define MIN_GAME_PLAYER S13S::MinPlayer //至少2人局 27 | #define MAX_COUNT S13S::MaxCount //每人13张牌 28 | #define MAX_ROUND S13S::MaxRound //最大局数 29 | 30 | //十三水 31 | namespace S13S { 32 | const int MaxCardTotal = 52; //牌总个数,除去大小王,52张牌 33 | const int MaxPlayer = 4; //最多4人局 34 | const int MinPlayer = 2; //至少2人局 35 | const int MaxCount = 13; //每人13张牌 36 | const int MaxRound = 1; //最大局数 37 | 38 | //牌值:A<2<3<4<5<6<7<8<9<10红>梅>方 41 | // 42 | //普通牌型 43 | //同花顺>铁支>葫芦>同花>顺子>三条>两对>对子>乌龙 44 | // 45 | //特殊牌型 46 | //至尊青龙>一条龙>十二皇族>三同花顺>三分天下>全大>全小>凑一色>双怪冲三>四套三条>五对三条>六对半>三顺子>三同花 47 | //至尊青龙>一条龙>十二皇族>三同花顺>三套炸弹>全大>全小>凑一色> >四套冲三>五对冲三>六对半>三同花>三顺子 48 | // 49 | //手牌类型:从小到大 50 | enum HandTy { 51 | ////// 普通牌型 52 | TyNil, 53 | TyAllBase, //所有普通牌型 54 | Tysp, //散牌(乌龙):一墩牌不组成任何牌型 55 | Ty20, //对子(一对):除了两张值相同的牌外没有其它牌型 56 | Ty22, //两对:两个对子加上一张单牌 57 | Ty30, //三条:除了三张值相同的牌外没有其它牌型 58 | Ty123, //顺子:花色不同的连续五张牌(A2345仅小于10JQKA) 59 | Tysc, //同花:花色相同的五张牌,非顺子 60 | Ty32, //葫芦:一组三条加上一组对子 61 | Ty40, //铁支:除了四张值相同的牌外没有其它牌型 62 | Ty123sc, //同花顺:花色相同的连续五张牌(A2345仅小于10JQKA) 63 | ////// 特殊牌型 64 | TyThreesc, //三同花:三墩均是同一花色的牌型 65 | TyThree123, //三顺子:三墩均是顺子的牌型 66 | TySix20, //六对半:六个对子加上一张单张的牌型 67 | TyFive2030, //五对三条(五对冲三):五个对子加上一个三条 68 | TyFour30, //四套三条(四套冲三):四个三条加上一张单张的牌型 69 | TyTwo3220, //双怪冲三:二对葫芦加上一个对子加上一张单张的牌型 70 | TyAllOneColor, //凑一色:全是红牌(方块/红心)或黑牌(黑桃/梅花)的牌型 71 | TyAllSmall, //全小:全是2至8的牌型 72 | TyAllBig, //全大:全是8至A的牌型 73 | TyThree40, //三分天下(三套炸弹):三副炸弹(四张值相同)加上一张单张的牌型 74 | TyThree123sc, //三同花顺:三墩均是同花顺的牌型 75 | Ty12Royal, //十二皇族:十三张全是J,Q,K,A的牌型 76 | TyOneDragon, //一条龙(十三水):A到K的牌型,非同花,A2345678910JQK 77 | TyZZQDragon, //至尊青龙:同花A到K的牌型,A2345678910JQK 78 | }; 79 | 80 | //花色:黑>红>梅>方 81 | enum CardColor { 82 | Diamond = 0x10, //方块(♦) 83 | Club = 0x20, //梅花(♣) 84 | Heart = 0x30, //红心(♥) 85 | Spade = 0x40, //黑桃(♠) 86 | }; 87 | 88 | //牌值:A<2<3<4<5<6<7<8<9<10A,2,,,K,0 牌点对应占位->0,2,,,K,A 116 | int const MaxSZ = K + 1; 117 | int const MaxEnumSZ = 1500; 118 | 119 | //游戏逻辑类 120 | class CGameLogic 121 | { 122 | public: 123 | CGameLogic(); 124 | virtual ~CGameLogic(); 125 | public: 126 | //初始化扑克牌数据 127 | void InitCards(); 128 | //debug打印 129 | void DebugListCards(); 130 | //剩余牌数 131 | int8_t Remaining(); 132 | //洗牌 133 | void ShuffleCards(); 134 | //发牌,生成n张玩家手牌 135 | void DealCards(int8_t n, uint8_t *cards); 136 | public: 137 | //花色:黑>红>梅>方 138 | static uint8_t GetCardColor(uint8_t card); 139 | //牌值:A<2<3<4<5<6<7<8<9<10按牌点 true->按牌值 147 | //ascend bool false->降序排列(即从大到小排列) true->升序排列(即从小到大排列) 148 | //clrAscend bool false->花色降序(即黑桃到方块) true->花色升序(即从方块到黑桃) 149 | static void SortCards(uint8_t *cards, int n, bool byValue, bool ascend, bool clrAscend); 150 | //手牌排序(默认按牌点降序排列),先比花色,再比牌值/点数 151 | //clrAscend bool false->花色降序(即黑桃到方块) true->花色升序(即从方块到黑桃) 152 | //byValue bool false->按牌点 true->按牌值 153 | //ascend bool false->降序排列(即从大到小排列) true->升序排列(即从小到大排列) 154 | static void SortCardsColor(uint8_t *cards, int n, bool clrAscend, bool byValue, bool ascend); 155 | //牌值字符串 156 | static std::string StringCardValue(uint8_t value); 157 | //花色字符串 158 | static std::string StringCardColor(uint8_t color); 159 | //单牌字符串 160 | static std::string StringCard(uint8_t card); 161 | //牌型字符串 162 | static std::string StringHandTy(HandTy ty); 163 | //打印n张牌 164 | static void PrintCardList(uint8_t const* cards, int n, bool hide = true); 165 | //获取牌有效列数 166 | //cards uint8_t const* 相同牌值n张牌(n<=4) 167 | //n uint8_t 黑/红/梅/方4张牌 168 | static uint8_t get_card_c(uint8_t const* cards, int n); 169 | //返回指定花色牌列号 170 | //cards uint8_t const* 相同牌值n张牌(n<=4) 171 | //n uint8_t 黑/红/梅/方4张牌 172 | //clr CardColor 指定花色 173 | static uint8_t get_card_colorcol(uint8_t const* cards, int n, CardColor clr); 174 | private: 175 | //拆分字符串"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 176 | static void CardsBy(std::string const& strcards, std::vector& vec); 177 | //字串构造牌"♦A"->0x01 178 | static uint8_t MakeCardBy(std::string const& name); 179 | //生成n张牌<-"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 180 | static void MakeCardList(std::vector const& vec, uint8_t *cards, int size); 181 | public: 182 | //生成n张牌<-"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 183 | static int MakeCardList(std::string const& strcards, uint8_t *cards, int size); 184 | private: 185 | int8_t index_; 186 | uint8_t cardsData_[MaxCardTotal]; 187 | public: 188 | ////////////////////////////////////////////////////////////// 189 | //EnumTree 枚举一墩牌型的所有可能,多叉树结构 190 | class EnumTree { 191 | public: 192 | //枚举牌,枚举一墩牌,5/3张 193 | typedef std::vector CardData; 194 | //枚举项,pair<牌型,一墩牌> 195 | typedef std::pair EnumItem; 196 | //树节点,pair<枚举项,子枚举项列表> 197 | typedef std::pair TreeNode; 198 | //树节点,pair<树节点指针,对应树枚举项> 199 | typedef std::pair TraverseTreeNode; 200 | public: 201 | EnumTree() { 202 | Reset(); 203 | parent_ = NULL; 204 | parentcursor_ = -1; 205 | } 206 | ~EnumTree() { 207 | Reset(); 208 | } 209 | //初始化牌墩 210 | void Init(DunTy dt); 211 | void Reset(); 212 | //释放new内存 213 | void Release(); 214 | //重置游标 215 | void ResetCursor(); 216 | //返回下一个游标 217 | bool GetNextCursor(int& cursor); 218 | //打印指定枚举牌型 219 | void PrintEnumCards(bool reverse/* = false*/, HandTy ty/* = TyAllBase*/); 220 | //打印指定枚举牌型 221 | void PrintEnumCards(std::string const& name, HandTy ty, std::vector> const& src, bool reverse); 222 | //打印游标处枚举牌型 223 | void PrintCursorEnumCards(); 224 | //打印游标处枚举牌型 225 | void PrintCursorEnumCards(std::string const& name, HandTy ty, std::vector const& src); 226 | //返回游标处枚举牌型 227 | EnumItem const* GetCursorItem(int cursor); 228 | //返回游标处枚举牌型对应余牌枚举子项列表指针 229 | EnumTree*& GetCursorChild(int cursor); 230 | //返回下一个枚举牌型(从大到小返回) 231 | bool GetNextEnumItem(uint8_t const* src, int len, 232 | CardData const*& dst, HandTy& ty, 233 | int& cursor, uint8_t *cpy, int& cpylen); 234 | public: 235 | //所有同花色五张/三张连续牌(五张/三张同花顺) 236 | std::vector v123sc; 237 | //所有铁支(四张) 238 | std::vector v40; 239 | //所有葫芦(一组三条加上一组对子) 240 | std::vector v32; 241 | //所有同花五张/三张非连续牌(五张/三张同花) 242 | std::vector vsc; 243 | //所有非同花五张/三张连续牌(五张/三张顺子) 244 | std::vector v123; 245 | //所有三条(三张) 246 | std::vector v30; 247 | //所有两对(两个对子) 248 | std::vector v22; 249 | //所有对子(一对) 250 | std::vector v20; 251 | //散牌/乌龙(头敦中指向Ty123sc/Ty123/Tysc中的一个) 252 | std::vector const* vsp; 253 | public: 254 | //标识头/中/尾墩 255 | DunTy dt_; 256 | //遍历游标 257 | int c, cursor_; 258 | //父亲节点 259 | EnumTree* parent_; 260 | //对应父节点游标位置 261 | int parentcursor_; 262 | //pair<枚举项牌型,对应余牌枚举子项列表>,多叉树结构 263 | TreeNode tree[MaxEnumSZ]; 264 | }; 265 | public: 266 | ////////////////////////////////////////////////////////////// 267 | //classify_t 分类牌型 268 | struct classify_t { 269 | int c4, c3, c2; 270 | //所有重复四张牌型 271 | static int const size4 = 3; 272 | uint8_t dst4[size4][4]; 273 | //所有重复三张牌型 274 | static int const size3 = 4; 275 | uint8_t dst3[size3][4]; 276 | //所有重复二张牌型 277 | static int const size2 = 6; 278 | uint8_t dst2[size2][4]; 279 | //去重后的余牌/散牌 280 | uint8_t cpy[MaxSZ]; 281 | int cpylen; 282 | void PrintCardList(); 283 | }; 284 | ////////////////////////////////////////////////////////////// 285 | //dundata_t 单墩数据 286 | struct dundata_t { 287 | dundata_t() :dt_(DunNil), ty_({ TyNil }), c(0), cards({ 0 }) { 288 | } 289 | void assign(DunTy dt, HandTy ty, uint8_t const* src, int len) { 290 | assert(len > 0); 291 | assert(dt > DunNil && dt < DunMax); 292 | assert(len <= ((dt == DunFirst) ? 3 : 5)); 293 | assert(dt_ == DunNil && ty_ == TyNil && c == 0); 294 | dt_ = dt; ty_ = ty; c = len; 295 | memcpy(cards, src, len); 296 | } 297 | void Reset() { 298 | dt_ = DunNil; 299 | ty_ = TyNil; 300 | c = 0; 301 | memset(cards, 0, sizeof(uint8_t) * 5); 302 | } 303 | int needC() { 304 | switch (dt_) 305 | { 306 | case DunFirst: return 3 - c; 307 | case DunSecond: 308 | case DunLast: return 5 - c; 309 | } 310 | return 0; 311 | } 312 | void append(uint8_t const* src, int len) { 313 | assert(len > 0); 314 | assert(dt_ > DunNil && dt_ < DunMax); 315 | assert(c + len == ((dt_ == DunFirst) ? 3 : 5)); 316 | memcpy(&cards[c], src, len); 317 | c += len; 318 | } 319 | inline int GetC() const { return c; } 320 | //标记0-头/1-中/2-尾 321 | DunTy dt_; 322 | //墩对应普通牌型 323 | HandTy ty_; 324 | //墩对应牌数c(3/5/5) 325 | uint8_t c; 326 | //墩牌数据(头敦3/中墩5/尾墩5) 327 | uint8_t cards[5]; 328 | }; 329 | ////////////////////////////////////////////////////////////// 330 | //groupdun_t 一组墩(头墩&中墩&尾墩) 331 | class groupdun_t { 332 | public: 333 | groupdun_t() :specialTy(TyNil), start(DunNil) { 334 | //memset(duns, 0, sizeof(dundata_t)*DunMax); 335 | for (int i = DunFirst; i <= DunLast; ++i) { 336 | duns[i].Reset(); 337 | } 338 | } 339 | groupdun_t(groupdun_t const& ref) { 340 | copy(ref); 341 | } 342 | groupdun_t& operator=(groupdun_t const& ref) { 343 | return copy(ref); 344 | } 345 | groupdun_t& copy(groupdun_t const& ref) { 346 | start = ref.start; 347 | specialTy = ref.specialTy; 348 | memcpy(duns, ref.duns, sizeof(dundata_t)*DunMax); 349 | return *this; 350 | } 351 | void Reset() { 352 | start = DunNil; 353 | specialTy = TyNil; 354 | //memset(duns, 0, sizeof(dundata_t)*DunMax); 355 | for (int i = DunFirst; i <= DunLast; ++i) { 356 | duns[i].Reset(); 357 | } 358 | } 359 | void assign(DunTy dt, HandTy ty, uint8_t const* src, int len) { 360 | assert(dt != DunNil); 361 | if (start == DunNil || dt < start) { 362 | start = dt; 363 | } 364 | duns[(int)(dt)].assign(dt, ty, src, len); 365 | } 366 | int needC(DunTy dt) { 367 | return duns[(int)(dt)].needC(); 368 | } 369 | void append(DunTy dt, uint8_t const* src, int len) { 370 | duns[(int)(dt)].append(src, len); 371 | } 372 | //返回三墩组牌数 373 | inline int GetC() { return duns[DunFirst].GetC() + duns[DunSecond].GetC() + duns[DunLast].GetC(); } 374 | //打印指定墩牌型 375 | void PrintCardList(DunTy dt); 376 | //打印指定墩牌型 377 | void PrintCardList(std::string const& name, DunTy dt, HandTy ty); 378 | public: 379 | //从哪墩开始的 380 | DunTy start; 381 | //总体对应特殊牌型 382 | HandTy specialTy; 383 | //[0]头敦(3)/[1]中墩(5)/[2]尾墩(5) 384 | dundata_t duns[DunMax]; 385 | }; 386 | ////////////////////////////////////////////////////////////// 387 | //handinfo_t 一副手牌信息 388 | class handinfo_t { 389 | friend class CGameLogic; 390 | public: 391 | handinfo_t() 392 | :rootEnumList(NULL), specialTy_(TyNil), chairID(-1), 393 | manual_group_index(-1), 394 | select_group_index(-1), classify({ 0 }) { 395 | Reset(); 396 | } 397 | ~handinfo_t() { 398 | if (rootEnumList) { 399 | rootEnumList->Release(); 400 | delete rootEnumList; 401 | } 402 | } 403 | //初始化 404 | void Init(); 405 | void Reset(); 406 | //打印全部枚举墩牌型 407 | void PrintEnumCards(bool reverse = true); 408 | //返回特殊牌型字符串 409 | std::string StringSpecialTy(); 410 | //返回特殊牌型字符串 411 | static std::string StringSpecialTy(HandTy specialTy); 412 | protected: 413 | //确定手牌牌型 414 | void CalcHandCardsType(uint8_t const* src, int len); 415 | public: 416 | //手动选牌组墩,给指定墩(头/中/尾墩)选择一组牌(头敦3/中墩5/尾墩5) 417 | //dt DunTy 指定为哪墩 418 | //src uint8_t const* 选择的一组牌(5张或3张) 419 | //len int 3/5张,头敦3张/中墩5张/尾墩5张 420 | //ty HandTy 指定墩牌型 421 | bool SelectAs(DunTy dt, uint8_t const* src, int len, HandTy ty); 422 | //重置手动摆牌 423 | void ResetManual(); 424 | //手牌确定三墩牌型 425 | //groupindex int 若 >=0 从enum_groups中选择一组,对应groups中索引 426 | //groupindex int 若 <= -1 指向manual_group对应groups中索引 427 | bool Select(int groupindex); 428 | //返回手牌确定的三墩牌型 429 | groupdun_t const* GetSelected(); 430 | //手牌是否已确定三墩牌型 431 | inline bool HasSelected() { return select_group_index != -1; } 432 | //返回选择groups的索引 433 | inline int GetSelectedIndex() { return select_group_index; } 434 | //判断是否选择了手动摆牌 435 | inline bool IsManualSelected() { 436 | return (select_group_index != -1) && 437 | (select_group_index == manual_group_index); 438 | } 439 | //返回组墩后剩余牌/散牌 440 | //src uint8_t const* 一副手牌13张 441 | //cpy uint8_t *cpy 组墩后剩余牌 cpylen int& 余牌数量 442 | void GetLeftCards(uint8_t const* src, int len, uint8_t *cpy, int& cpylen); 443 | //返回手动摆牌组墩总牌数 444 | inline int GetManualC() { return manual_group.GetC(); } 445 | public: 446 | //玩家座椅ID 447 | int chairID; 448 | //优先特殊牌型 449 | HandTy specialTy_; 450 | //手牌重复牌型 451 | classify_t classify; 452 | //根节点:初始枚举所有牌型列表 453 | EnumTree *rootEnumList; 454 | //枚举几组最优墩,指向EnumTree::TraverseTreeNode成员 455 | std::vector enum_groups; 456 | //手动摆牌组墩[0]头敦(3)/[1]中墩(5)/[2]尾墩(5) 457 | groupdun_t manual_group; 458 | //manual_group对应groups索引 459 | int manual_group_index; 460 | //当前选择groups中的第几组优先 461 | int select_group_index; 462 | //合并 enum_groups & manual_group 463 | std::vector groups; 464 | //叶子节点列表 465 | //枚举几组最优墩(头墩&中墩&尾墩加起来为一组),由叶子节点向上往根节点遍历 466 | //叶子节点 dt_ 成员判断当前是从哪墩节点开始, 467 | //叶子节点 dt_ == DunFirst 时,叶子节点(头墩)/父节点(中墩)/根节点(尾墩) 468 | //叶子节点 dt_ == DunSecond 时,叶子节点(中墩)/父节点 = 根节点(尾墩) 469 | //叶子节点 dt_ == DunLast 时,叶子节点 = 根节点(尾墩) 470 | std::vector leafList; 471 | }; 472 | public: 473 | //枚举牌型测试 474 | static void TestEnumCards(int size); 475 | //枚举牌型测试 476 | //filename char const* 文件读取手牌 cardsList.ini 477 | static void TestEnumCards(char const* filename); 478 | //玩家发牌测试 479 | static void TestPlayerCards(); 480 | //开始游戏测试 481 | static void TestProtoCards(); 482 | //手动摆牌测试 483 | static void TestManualCards(); 484 | //确定牌型/比牌测试 485 | //先让每个玩家确定手牌三墩牌型,手动摆牌或者从枚举几组中任选一组作为手牌牌型与其他玩家比牌, 486 | //再玩家之间两两比牌,头敦与头敦比,中墩与中墩比,尾墩与尾墩比,并计算输赢积分(输赢多少水,统计打枪/全垒打) 487 | static void TestCompareCards(); 488 | public: 489 | //手牌牌型分析(特殊牌型判断/枚举三墩组合),算法入口 ///////// 490 | //src uint8_t const* 一副手牌(13张) 491 | //n int 最大枚举多少组墩(头墩&中墩&尾墩加起来为一组) 492 | //chairID int 玩家座椅ID 493 | //hand handinfo_t& 保存手牌信息 494 | static int AnalyseHandCards(uint8_t const* src, int len, int n, handinfo_t& hand); 495 | //单墩牌型判断(3/5张牌) 496 | //dt DunTy 指定为第几墩 497 | //src uint8_t const* 一墩5张或3张的牌 498 | static HandTy GetDunCardHandTy(DunTy dt, uint8_t const* src, int len); 499 | //牌型相同的src与dst比大小,牌数相同 500 | //src uint8_t const* 单墩牌(3/5张) 501 | //dst uint8_t const* 单墩牌(3/5张) 502 | //clr bool 是否比花色 503 | //ty HandTy 比较的两单墩牌的普通牌型 504 | static int CompareCards(uint8_t const* src, uint8_t const* dst, int n, bool clr, HandTy ty); 505 | //按照尾墩5张/中墩5张/头敦3张依次抽取枚举普通牌型 506 | //src uint8_t const* 手牌余牌(13/8/3),初始13张,按5/5/3依次抽,余牌依次为13/8/3 507 | //n int 抽取n张(5/5/3) 第一次抽5张余8张,第二次抽5张余3张,第三次取余下3张抽完 508 | //classify classify_t& 存放分类信息(所有重复四张/三张/二张/散牌/余牌) 509 | //enumList EnumTree& 存放枚举墩牌型列表数据 dt DunTy 指定为第几墩 510 | static void EnumCards(uint8_t const* src, int len, 511 | int n, classify_t& classify, EnumTree& enumList, DunTy dt); 512 | //返回组墩后剩余牌/散牌 513 | //src uint8_t const* 一副手牌13张 514 | //duns dundata_t const* 一组墩(头/中/尾墩) 515 | //cpy uint8_t *cpy 组墩后剩余牌 cpylen int& 余牌数量 516 | static void GetLeftCards(uint8_t const* src, int len, 517 | dundata_t const* duns, uint8_t *cpy, int& cpylen); 518 | private: 519 | //按照尾墩5张/中墩5张/头墩3张依次抽取枚举普通牌型 520 | //src uint8_t const* 手牌余牌(13/8/3),初始13张,按5/5/3依次抽,余牌依次为13/8/3 521 | //n int 抽取n张(5/5/3) 第一次抽5张余8张,第二次抽5张余3张,第三次取余下3张抽完 522 | //dst4 uint8_t(*)[4] 存放所有四张牌型,c4 四张牌型数 523 | //dst3 uint8_t(*)[4] 存放所有三张牌型,c3 三张牌型数 524 | //dst2 uint8_t(*)[4] 存放所有对子牌型,c2 对子牌型数 525 | //cpy uint8_t* 存放去重后的余牌/散牌(除去四张/三张/对子) 526 | //v123sc std::vector>& 存放所有同花色n张连续牌 527 | //v123 std::vector>& 存放所有非同花n张连续牌 528 | //vsc std::vector>& 存放所有同花n张非连续牌 529 | //v40 std::vector>& 存放所有铁支 530 | //v32 std::vector>& 存放所有葫芦 531 | //v30 std::vector>& 存放所有三条 532 | //v22 std::vector>& 存放所有两对 533 | //v20 std::vector>& 存放所有对子 534 | static void EnumCards(uint8_t const* src, int len, int n, 535 | uint8_t(*dst4)[4], int& c4, 536 | uint8_t(*dst3)[4], int& c3, 537 | uint8_t(*dst2)[4], int& c2, 538 | uint8_t *cpy, int& cpylen, 539 | std::vector>& v123sc, 540 | std::vector>& v123, 541 | std::vector>& vsc, 542 | std::vector>& v40, 543 | std::vector>& v32, 544 | std::vector>& v30, 545 | std::vector>& v22, 546 | std::vector>& v20); 547 | //简单牌型分类/重复(四张/三张/二张)/同花/顺子/同花顺/散牌 548 | //src uint8_t const* 牌源 549 | //n int 抽取n张(5/5/3) 550 | //pdst uint8_t(**const)[4] 衔接dst4/dst3/dst2 551 | //dst4 uint8_t(*)[4] 存放所有四张牌型,c4 四张牌型数 552 | //dst3 uint8_t(*)[4] 存放所有三张牌型,c3 三张牌型数 553 | //dst2 uint8_t(*)[4] 存放所有对子牌型,c2 对子牌型数 554 | //cpy uint8_t* 存放去重后的余牌/散牌(除去四张/三张/对子)/////// 555 | //dst0 std::vector>& 存放所有同花色n张连续牌 556 | //dst1 std::vector>& 存放所有非同花n张连续牌 557 | //dstc std::vector>& 存放所有同花n张非连续牌 558 | static void ClassifyCards(uint8_t const* src, int len, int n, 559 | uint8_t(**const pdst)[4], 560 | uint8_t(*dst4)[4], int& c4, 561 | uint8_t(*dst3)[4], int& c3, 562 | uint8_t(*dst2)[4], int& c2, 563 | uint8_t *cpy, int& cpylen, 564 | std::vector>& dst0, 565 | std::vector>& dst1, 566 | std::vector>& dstc); 567 | //返回去重后的余牌/散牌 568 | //src uint8_t const* 牌源 569 | //pdst uint8_t(**const)[4] 衔接dst4/dst3/dst2 570 | //dst4 uint8_t(*)[4] 存放所有四张牌型,c4 四张牌型数 571 | //dst3 uint8_t(*)[4] 存放所有三张牌型,c3 三张牌型数 572 | //dst2 uint8_t(*)[4] 存放所有对子牌型,c2 对子牌型数 573 | //cpy uint8_t* 去重后的余牌/散牌(除去四张/三张/对子)/////// 574 | static int RemoveRepeatCards(uint8_t const* src, int len, 575 | uint8_t(**const pdst)[4], 576 | uint8_t(*dst4)[4], int& c4, uint8_t(*dst3)[4], int& c3, 577 | uint8_t(*dst2)[4], int& c2, uint8_t *cpy, int& cpylen); 578 | //枚举所有不区分花色n张连续牌型(同花顺/顺子),先去重再补位,最后遍历查找 579 | //去重后的余牌/散牌与单张组合牌补位合并////// 580 | //psrc uint8_t(**const)[4] 衔接dst4/dst3/dst2 581 | //psrc uint8_t(**const)[4] 从所有四张/三张/对子中各取一张合成单张组合牌 582 | //cpy uint8_t const* 去重后的余牌/散牌(除去四张/三张/对子)牌源/////// 583 | //n int 抽取n张(3/5/13) 584 | //ctx std::vector>& 标记psrc的ctx信息 585 | //dst std::vector>& 存放所有连续牌型 586 | //clr std::vector& 对应dst是否同花 587 | static void EnumConsecCards( 588 | uint8_t(**const psrc)[4], int const psrclen, 589 | uint8_t const* cpy, int const cpylen, int n, 590 | std::vector>& ctx, 591 | std::vector>& dst, 592 | std::vector& clr); 593 | //枚举所有n张相同花色不连续牌型(同花),先去重再补位,最后遍历查找 594 | //去重后的余牌/散牌与单张组合牌补位合并////// 595 | //psrc uint8_t(**const)[4] 衔接dst4/dst3/dst2 596 | //psrc uint8_t(**const)[4] 从所有四张/三张/对子中各取一张合成单张组合牌 597 | //cpy uint8_t const* 去重后的余牌/散牌(除去四张/三张/对子)牌源/////// 598 | //n int 抽取n张(3/5/13) 599 | //ctx std::vector>& 标记psrc的ctx信息 600 | //dst std::vector>& 存放所有同花牌型 601 | static void EnumSameColorCards( 602 | uint8_t(**const psrc)[4], int const psrclen, 603 | uint8_t const* cpy, int const cpylen, int n, 604 | std::vector>& ctx, 605 | std::vector>& dst); 606 | //枚举所有同花顺/顺子(区分花色五张连续牌) 607 | //psrc uint8_t(**const)[4] 衔接dst4/dst3/dst2 608 | //psrc uint8_t(**const)[4] 从所有四张/三张/对子中各取一张合成单张组合牌 609 | //ctx std::vector>& 标记psrc的ctx信息 610 | //src std::vector> const& 所有单张组合牌源/////// 611 | //clr std::vector const& 对应src是否同花 612 | //dst1 std::vector>& 存放所有同花顺 613 | //dst2 std::vector>& 存放所有顺子 614 | static void EnumConsecCardsByColor( 615 | uint8_t(**const psrc)[4], 616 | std::vector> const& ctx, 617 | std::vector> const& src, 618 | std::vector const& clr, 619 | std::vector>& dst1, 620 | std::vector>& dst2); 621 | //枚举所有葫芦(一组三条加上一组对子) 622 | //psrc uint8_t(**const)[4] 衔接dst4/dst3/dst2 623 | //src4 uint8_t(*const)[4] 所有四张牌型牌源,c4 四张牌型数 624 | //src3 uint8_t(*const)[4] 所有三张牌型牌源,c3 三张牌型数 625 | //src2 uint8_t(*const)[4] 所有对子牌型牌源,c2 对子牌型数 626 | //dst std::vector>& 存放所有葫芦牌型 627 | static int EnumCards32( 628 | uint8_t(**const psrc)[4], 629 | uint8_t(*const src4)[4], int const c4, 630 | uint8_t(*const src3)[4], int const c3, 631 | uint8_t(*const src2)[4], int const c2, 632 | std::vector>& dst); 633 | //枚举所有三条(三张值相同的牌) 634 | //psrc uint8_t(**const)[4] 衔接dst4/dst3/dst2 635 | //src4 uint8_t(*const)[4] 所有四张牌型牌源,c4 四张牌型数 636 | //src3 uint8_t(*const)[4] 所有三张牌型牌源,c3 三张牌型数 637 | //src2 uint8_t(*const)[4] 所有对子牌型牌源,c2 对子牌型数 638 | //dst std::vector>& 存放所有三条牌型 639 | static int EnumCards30( 640 | uint8_t(**const psrc)[4], 641 | uint8_t(*const src4)[4], int const c4, 642 | uint8_t(*const src3)[4], int const c3, 643 | uint8_t(*const src2)[4], int const c2, 644 | std::vector>& dst); 645 | //枚举所有两对(两个对子加上一张单牌) 646 | //psrc uint8_t(**const)[4] 衔接dst4/dst3/dst2 647 | //src4 uint8_t(*const)[4] 所有四张牌型牌源,c4 四张牌型数 648 | //src3 uint8_t(*const)[4] 所有三张牌型牌源,c3 三张牌型数 649 | //src2 uint8_t(*const)[4] 所有对子牌型牌源,c2 对子牌型数 650 | //dst std::vector>& 存放所有两对牌型 651 | static int EnumCards22( 652 | uint8_t(**const psrc)[4], 653 | uint8_t(*const src4)[4], int const c4, 654 | uint8_t(*const src3)[4], int const c3, 655 | uint8_t(*const src2)[4], int const c2, 656 | std::vector>& dst); 657 | //枚举所有对子(一对) 658 | //psrc uint8_t(**const)[4] 衔接dst4/dst3/dst2 659 | //src4 uint8_t(*const)[4] 所有四张牌型牌源,c4 四张牌型数 660 | //src3 uint8_t(*const)[4] 所有三张牌型牌源,c3 三张牌型数 661 | //src2 uint8_t(*const)[4] 所有对子牌型牌源,c2 对子牌型数 662 | //dst std::vector>& 存放所有对子牌型 663 | static int EnumCards20( 664 | uint8_t(**const psrc)[4], 665 | uint8_t(*const src4)[4], int const c4, 666 | uint8_t(*const src3)[4], int const c3, 667 | uint8_t(*const src2)[4], int const c2, 668 | std::vector>& dst); 669 | private: 670 | //枚举所有指定重复牌型(四张/三张/二张) 671 | //src uint8_t const* 牌源 672 | //n int 抽取n张(4/3/2) 673 | //dst uint8_t(*)[4] 存放指定重复牌型 674 | //cpy uint8_t* 抽取后不符合要求的余牌 675 | static int EnumRepeatCards(uint8_t const* src, int len, int n, 676 | uint8_t(*dst)[4], int size, uint8_t *cpy, int& cpylen); 677 | //填充卡牌条码标记位 678 | //src uint8_t* 用A2345678910JQK来占位 size = MaxSZ 679 | //dst uint8_t const* 由单张组成的余牌或枚举组合牌 680 | static void FillCardsMarkLoc(uint8_t *src, int size, uint8_t const* dst, int dstlen, bool reset); 681 | //填充卡牌条码标记位 682 | //src uint8_t* 用2345678910JQKA来占位 size = MaxSZ 683 | //dst uint8_t const* 由单张组成的余牌或枚举组合牌 684 | static void FillCardsMarkLocByPoint(uint8_t *src, int size, uint8_t const* dst, int dstlen, bool reset); 685 | //从补位合并后的单张组合牌中枚举所有不区分花色n张连续牌型/////// 686 | //src uint8_t const* 单张组合牌源,去重后的余牌/散牌与从psrc每组中各抽一张牌补位合并 687 | //n int 抽取n张(3/5/13) 688 | //start int const 检索src/mark的起始下标 689 | //psrcctx short const* 标记psrc的ctx信息 690 | //dst std::vector>& 存放所有连续牌型(不区分花色) 691 | //clr std::vector& 对应dst是否同花 692 | static int EnumConsecCardsMarkLoc(uint8_t const* src, int len, int n, 693 | int const start, short const* psrcctx, 694 | std::vector>& ctx, 695 | std::vector>& dst, 696 | std::vector& clr); 697 | //从补位合并后的单张组合牌中枚举所有n张指定花色牌型/////// 698 | //src uint8_t const* 单张组合牌源,去重后的余牌/散牌与从psrc每组中各抽一张牌补位合并 699 | //n int 抽取n张(3/5/13) 700 | //clr CardColor 指定花色 701 | //psrcctx short const* 标记psrc的ctx信息 702 | //dst std::vector>& 存放所有同花牌型(非顺子) 703 | //consec bool false->不保留同花顺 true->保留同花顺 704 | //dst2 std::vector>& 存放所有同花顺牌型 705 | static int EnumSameColorCardsMarkLoc(uint8_t const* src, int len, int n, CardColor clr, 706 | short const* psrcctx, 707 | std::vector>& ctx, 708 | std::vector>& dst, 709 | bool consec, 710 | std::vector>& dst2); 711 | private: 712 | //求组合C(n,1)*C(n,1)...*C(n,1) 713 | //f(k)=C(n,1) 714 | //Muti(k)=f(1)*f(2)...*f(k) 715 | //n int 访问广度 716 | //k int 访问深度 717 | //深度优先遍历,由浅到深,广度遍历,由里向外 718 | static int DepthVisit(int n, 719 | int k, 720 | uint8_t(*const*const psrc)[4], 721 | int const* colc, 722 | std::vector const& vec, 723 | std::vector>& dst0, 724 | std::vector>& dst1); 725 | //递归求组合C(n,1)*C(n,1)...*C(n,1) 726 | //f(k)=C(n,1) 727 | //Muti(k)=f(1)*f(2)...*f(k) 728 | //n int 访问广度 729 | //k int 访问深度 730 | //深度优先遍历,由浅到深,广度遍历,由里向外 731 | static int DepthC(int n, 732 | int k, int *e, int& c, 733 | uint8_t(*const*const psrc)[4], 734 | int const* colc, 735 | std::vector const& vec, 736 | std::vector>& dst0, 737 | std::vector>& dst1); 738 | //求组合C(n,k) 739 | //n int 访问广度 740 | //k int 访问深度 741 | //深度优先遍历,由浅到深,广度遍历,由里向外 742 | static int FuncC(int n, int k, 743 | uint8_t(*const*const psrc)[4], int const r, 744 | std::vector>& dst); 745 | //递归求组合C(n,k) 746 | //n int 访问广度 747 | //k int 访问深度 748 | //深度优先遍历,由浅到深,广度遍历,由里向外 749 | static int FuncC(int n, int k, int *e, int& c, 750 | uint8_t(*const*const psrc)[4], int const r, 751 | std::vector>& dst); 752 | private: 753 | //是否连号n张牌 754 | static bool CheckConsecCards(uint8_t const* src, int len); 755 | //是否同花n张牌 756 | static bool CheckSameColorCards(uint8_t const* src, int len); 757 | //至尊青龙/一条龙(十三水)/十二皇族 758 | static HandTy CheckDragonRoyal(uint8_t const* src, int len); 759 | //凑一色:全是红牌(方块/红心)或黑牌(黑桃/梅花) 760 | static HandTy CheckAllOneColor(uint8_t const* src, int len); 761 | //全大:全是8至A的牌型 762 | static HandTy CheckAllBig(uint8_t const* src, int len); 763 | //全小:全是2至8的牌型 764 | static HandTy CheckAllSmall(uint8_t const* src, int len); 765 | }; 766 | }; 767 | 768 | #endif -------------------------------------------------------------------------------- /weights.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannisliang/QPAlgorithm/aec981cdcfe062a386aa4e849a7059fcbc055c6d/weights.cpp -------------------------------------------------------------------------------- /weights.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dannisliang/QPAlgorithm/aec981cdcfe062a386aa4e849a7059fcbc055c6d/weights.h -------------------------------------------------------------------------------- /zjh.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #include 6 | #include 7 | #include "math.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "cfg.h" 19 | #include "zjh.h" 20 | 21 | namespace ZJH { 22 | 23 | //一副扑克(52张) 24 | uint8_t s_CardListData[MaxCardTotal] = 25 | { 26 | 0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D, // 方块 A - K 27 | 0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D, // 梅花 A - K 28 | 0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D, // 红心 A - K 29 | 0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D, // 黑桃 A - K 30 | }; 31 | 32 | //构造函数 33 | CGameLogic::CGameLogic() 34 | { 35 | index_ = 0; 36 | memset(cardsData_, 0, sizeof(uint8_t)*MaxCardTotal); 37 | } 38 | 39 | //析构函数 40 | CGameLogic::~CGameLogic() 41 | { 42 | 43 | } 44 | 45 | //初始化扑克牌数据 46 | void CGameLogic::InitCards() 47 | { 48 | //printf("--- *** 初始化一副扑克...\n"); 49 | memcpy(cardsData_, s_CardListData, sizeof(uint8_t)*MaxCardTotal); 50 | } 51 | 52 | //debug打印 53 | void CGameLogic::DebugListCards() { 54 | //手牌按花色升序(方块到黑桃),同花色按牌值从小到大排序 55 | SortCardsColor(cardsData_, MaxCardTotal, true, true, true); 56 | for (int i = 0; i < MaxCardTotal; ++i) { 57 | printf("%02X %s\n", cardsData_[i], StringCard(cardsData_[i]).c_str()); 58 | } 59 | } 60 | 61 | //剩余牌数 62 | int8_t CGameLogic::Remaining() { 63 | return int8_t(MaxCardTotal - index_); 64 | } 65 | 66 | //洗牌 67 | void CGameLogic::ShuffleCards() 68 | { 69 | //printf("-- *** 洗牌...\n"); 70 | static uint32_t seed = (uint32_t)time(NULL); 71 | //int c = rand() % 20 + 5; 72 | int c = rand_r(&seed) % 20 + 5; 73 | for (int k = 0; k < c; ++k) { 74 | for (int i = 0; i < MaxCardTotal; ++i) { 75 | //int j = rand() % MaxCardTotal; 76 | int j = rand_r(&seed) % MaxCardTotal; 77 | if (i != j) { 78 | std::swap(cardsData_[i], cardsData_[j]); 79 | } 80 | } 81 | } 82 | index_ = 0; 83 | } 84 | 85 | //发牌,生成n张玩家手牌 86 | void CGameLogic::DealCards(int8_t n, uint8_t *cards) 87 | { 88 | //printf("-- *** %d张余牌,发牌 ...\n", Remaining()); 89 | if (cards == NULL) { 90 | return; 91 | } 92 | if (n > Remaining()) { 93 | return; 94 | } 95 | int k = 0; 96 | for (int i = index_; i < index_ + n; ++i) { 97 | assert(i < MaxCardTotal); 98 | cards[k++] = cardsData_[i]; 99 | } 100 | index_ += n; 101 | } 102 | 103 | //花色:黑>红>梅>方 104 | uint8_t CGameLogic::GetCardColor(uint8_t card) { 105 | return (card & 0xF0); 106 | } 107 | 108 | //牌值:A<2<3<4<5<6<7<8<9<10 v1; 131 | } 132 | //牌值相同比花色 133 | uint8_t c0 = CGameLogic::GetCardColor(card1); 134 | uint8_t c1 = CGameLogic::GetCardColor(card2); 135 | return c0 > c1; 136 | } 137 | 138 | static bool byCardValueColorGL(uint8_t card1, uint8_t card2) { 139 | uint8_t v0 = CGameLogic::GetCardValue(card1); 140 | uint8_t v1 = CGameLogic::GetCardValue(card2); 141 | if (v0 != v1) { 142 | //牌值不同比大小 143 | return v0 > v1; 144 | } 145 | //牌值相同比花色 146 | uint8_t c0 = CGameLogic::GetCardColor(card1); 147 | uint8_t c1 = CGameLogic::GetCardColor(card2); 148 | return c0 < c1; 149 | } 150 | 151 | static bool byCardValueColorLG(uint8_t card1, uint8_t card2) { 152 | uint8_t v0 = CGameLogic::GetCardValue(card1); 153 | uint8_t v1 = CGameLogic::GetCardValue(card2); 154 | if (v0 != v1) { 155 | //牌值不同比大小 156 | return v0 < v1; 157 | } 158 | //牌值相同比花色 159 | uint8_t c0 = CGameLogic::GetCardColor(card1); 160 | uint8_t c1 = CGameLogic::GetCardColor(card2); 161 | return c0 > c1; 162 | } 163 | 164 | static bool byCardValueColorLL(uint8_t card1, uint8_t card2) { 165 | uint8_t v0 = CGameLogic::GetCardValue(card1); 166 | uint8_t v1 = CGameLogic::GetCardValue(card2); 167 | if (v0 != v1) { 168 | //牌值不同比大小 169 | return v0 < v1; 170 | } 171 | //牌值相同比花色 172 | uint8_t c0 = CGameLogic::GetCardColor(card1); 173 | uint8_t c1 = CGameLogic::GetCardColor(card2); 174 | return c0 < c1; 175 | } 176 | 177 | //牌点大小:2<3<4<5<6<7<8<9<10 p1; 184 | } 185 | //牌点相同比花色 186 | uint8_t c0 = CGameLogic::GetCardColor(card1); 187 | uint8_t c1 = CGameLogic::GetCardColor(card2); 188 | return c0 > c1; 189 | } 190 | 191 | static bool byCardPointColorGL(uint8_t card1, uint8_t card2) { 192 | uint8_t p0 = CGameLogic::GetCardPoint(card1); 193 | uint8_t p1 = CGameLogic::GetCardPoint(card2); 194 | if (p0 != p1) { 195 | //牌点不同比大小 196 | return p0 > p1; 197 | } 198 | //牌点相同比花色 199 | uint8_t c0 = CGameLogic::GetCardColor(card1); 200 | uint8_t c1 = CGameLogic::GetCardColor(card2); 201 | return c0 < c1; 202 | } 203 | 204 | static bool byCardPointColorLG(uint8_t card1, uint8_t card2) { 205 | uint8_t p0 = CGameLogic::GetCardPoint(card1); 206 | uint8_t p1 = CGameLogic::GetCardPoint(card2); 207 | if (p0 != p1) { 208 | //牌点不同比大小 209 | return p0 < p1; 210 | } 211 | //牌点相同比花色 212 | uint8_t c0 = CGameLogic::GetCardColor(card1); 213 | uint8_t c1 = CGameLogic::GetCardColor(card2); 214 | return c0 > c1; 215 | } 216 | 217 | static bool byCardPointColorLL(uint8_t card1, uint8_t card2) { 218 | uint8_t p0 = CGameLogic::GetCardPoint(card1); 219 | uint8_t p1 = CGameLogic::GetCardPoint(card2); 220 | if (p0 != p1) { 221 | //牌点不同比大小 222 | return p0 < p1; 223 | } 224 | //牌点相同比花色 225 | uint8_t c0 = CGameLogic::GetCardColor(card1); 226 | uint8_t c1 = CGameLogic::GetCardColor(card2); 227 | return c0 < c1; 228 | } 229 | 230 | //手牌排序(默认按牌点降序排列),先比牌值/点数,再比花色 231 | //byValue bool false->按牌点 true->按牌值 232 | //ascend bool false->降序排列(即从大到小排列) true->升序排列(即从小到大排列) 233 | //clrAscend bool false->花色降序(即黑桃到方块) true->花色升序(即从方块到黑桃) 234 | void CGameLogic::SortCards(uint8_t *cards, int n, bool byValue, bool ascend, bool clrAscend) 235 | { 236 | if (byValue) { 237 | if (ascend) { 238 | if (clrAscend) { 239 | //LL 240 | std::sort(cards, cards + n, byCardValueColorLL); 241 | } 242 | else { 243 | //LG 244 | std::sort(cards, cards + n, byCardValueColorLG); 245 | } 246 | } 247 | else { 248 | if (clrAscend) { 249 | //GL 250 | std::sort(cards, cards + n, byCardValueColorGL); 251 | } 252 | else { 253 | //GG 254 | std::sort(cards, cards + n, byCardValueColorGG); 255 | } 256 | } 257 | } 258 | else { 259 | if (ascend) { 260 | if (clrAscend) { 261 | //LL 262 | std::sort(cards, cards + n, byCardPointColorLL); 263 | } 264 | else { 265 | //LG 266 | std::sort(cards, cards + n, byCardPointColorLG); 267 | } 268 | } 269 | else { 270 | if (clrAscend) { 271 | //GL 272 | std::sort(cards, cards + n, byCardPointColorGL); 273 | } 274 | else { 275 | //GG 276 | std::sort(cards, cards + n, byCardPointColorGG); 277 | } 278 | } 279 | } 280 | } 281 | 282 | //牌值大小:A<2<3<4<5<6<7<8<9<10 c1; 289 | } 290 | //花色相同比牌值 291 | uint8_t v0 = CGameLogic::GetCardValue(card1); 292 | uint8_t v1 = CGameLogic::GetCardValue(card2); 293 | return v0 > v1; 294 | } 295 | 296 | static bool byCardColorValueGL(uint8_t card1, uint8_t card2) { 297 | uint8_t c0 = CGameLogic::GetCardColor(card1); 298 | uint8_t c1 = CGameLogic::GetCardColor(card2); 299 | if (c0 != c1) { 300 | //花色不同比花色 301 | return c0 > c1; 302 | } 303 | //花色相同比牌值 304 | uint8_t v0 = CGameLogic::GetCardValue(card1); 305 | uint8_t v1 = CGameLogic::GetCardValue(card2); 306 | return v0 < v1; 307 | } 308 | 309 | static bool byCardColorValueLG(uint8_t card1, uint8_t card2) { 310 | uint8_t c0 = CGameLogic::GetCardColor(card1); 311 | uint8_t c1 = CGameLogic::GetCardColor(card2); 312 | if (c0 != c1) { 313 | //花色不同比花色 314 | return c0 < c1; 315 | } 316 | //花色相同比牌值 317 | uint8_t v0 = CGameLogic::GetCardValue(card1); 318 | uint8_t v1 = CGameLogic::GetCardValue(card2); 319 | return v0 > v1; 320 | } 321 | 322 | static bool byCardColorValueLL(uint8_t card1, uint8_t card2) { 323 | uint8_t c0 = CGameLogic::GetCardColor(card1); 324 | uint8_t c1 = CGameLogic::GetCardColor(card2); 325 | if (c0 != c1) { 326 | //花色不同比花色 327 | return c0 < c1; 328 | } 329 | //花色相同比牌值 330 | uint8_t v0 = CGameLogic::GetCardValue(card1); 331 | uint8_t v1 = CGameLogic::GetCardValue(card2); 332 | return v0 < v1; 333 | } 334 | 335 | //牌点大小:2<3<4<5<6<7<8<9<10 c1; 342 | } 343 | //花色相同比牌点 344 | uint8_t p0 = CGameLogic::GetCardPoint(card1); 345 | uint8_t p1 = CGameLogic::GetCardPoint(card2); 346 | return p0 > p1; 347 | } 348 | 349 | static bool byCardColorPointGL(uint8_t card1, uint8_t card2) { 350 | uint8_t c0 = CGameLogic::GetCardColor(card1); 351 | uint8_t c1 = CGameLogic::GetCardColor(card2); 352 | if (c0 != c1) { 353 | //花色不同比花色 354 | return c0 > c1; 355 | } 356 | //花色相同比牌点 357 | uint8_t p0 = CGameLogic::GetCardPoint(card1); 358 | uint8_t p1 = CGameLogic::GetCardPoint(card2); 359 | return p0 < p1; 360 | } 361 | 362 | static bool byCardColorPointLG(uint8_t card1, uint8_t card2) { 363 | uint8_t c0 = CGameLogic::GetCardColor(card1); 364 | uint8_t c1 = CGameLogic::GetCardColor(card2); 365 | if (c0 != c1) { 366 | //花色不同比花色 367 | return c0 < c1; 368 | } 369 | //花色相同比牌点 370 | uint8_t p0 = CGameLogic::GetCardPoint(card1); 371 | uint8_t p1 = CGameLogic::GetCardPoint(card2); 372 | return p0 > p1; 373 | } 374 | 375 | static bool byCardColorPointLL(uint8_t card1, uint8_t card2) { 376 | uint8_t c0 = CGameLogic::GetCardColor(card1); 377 | uint8_t c1 = CGameLogic::GetCardColor(card2); 378 | if (c0 != c1) { 379 | //花色不同比花色 380 | return c0 < c1; 381 | } 382 | //花色相同比牌点 383 | uint8_t p0 = CGameLogic::GetCardPoint(card1); 384 | uint8_t p1 = CGameLogic::GetCardPoint(card2); 385 | return p0 < p1; 386 | } 387 | 388 | //手牌排序(默认按牌点降序排列),先比花色,再比牌值/点数 389 | //clrAscend bool false->花色降序(即黑桃到方块) true->花色升序(即从方块到黑桃) 390 | //byValue bool false->按牌点 true->按牌值 391 | //ascend bool false->降序排列(即从大到小排列) true->升序排列(即从小到大排列) 392 | void CGameLogic::SortCardsColor(uint8_t *cards, int n, bool clrAscend, bool byValue, bool ascend) 393 | { 394 | if (byValue) { 395 | if (ascend) { 396 | if (clrAscend) { 397 | //LL 398 | std::sort(cards, cards + n, byCardColorValueLL); 399 | } 400 | else { 401 | //GL 402 | std::sort(cards, cards + n, byCardColorValueGL); 403 | } 404 | } 405 | else { 406 | if (clrAscend) { 407 | //LG 408 | std::sort(cards, cards + n, byCardColorValueLG); 409 | } 410 | else { 411 | //GG 412 | std::sort(cards, cards + n, byCardColorValueGG); 413 | } 414 | } 415 | } 416 | else { 417 | if (ascend) { 418 | if (clrAscend) { 419 | //LL 420 | std::sort(cards, cards + n, byCardColorPointLL); 421 | } 422 | else { 423 | //GL 424 | std::sort(cards, cards + n, byCardColorPointGL); 425 | } 426 | } 427 | else { 428 | if (clrAscend) { 429 | //LG 430 | std::sort(cards, cards + n, byCardColorPointLG); 431 | } 432 | else { 433 | //GG 434 | std::sort(cards, cards + n, byCardColorPointGG); 435 | } 436 | } 437 | } 438 | } 439 | 440 | //牌值字符串 441 | std::string CGameLogic::StringCardValue(uint8_t value) 442 | { 443 | if (0 == value) { 444 | return "?"; 445 | } 446 | switch (value) 447 | { 448 | case A: return "A"; 449 | case J: return "J"; 450 | case Q: return "Q"; 451 | case K: return "K"; 452 | } 453 | char ch[3] = { 0 }; 454 | sprintf(ch, "%d", value); 455 | return ch; 456 | } 457 | 458 | //花色字符串 459 | std::string CGameLogic::StringCardColor(uint8_t color) 460 | { 461 | switch (color) 462 | { 463 | case Spade: return "♠"; 464 | case Heart: return "♥"; 465 | case Club: return "♣"; 466 | case Diamond: return "♦"; 467 | } 468 | return "?"; 469 | } 470 | 471 | //单牌字符串 472 | std::string CGameLogic::StringCard(uint8_t card) { 473 | std::string s(StringCardColor(GetCardColor(card))); 474 | s += StringCardValue(GetCardValue(card)); 475 | return s; 476 | } 477 | 478 | //牌型字符串 479 | std::string CGameLogic::StringHandTy(HandTy ty) { 480 | switch (ty) 481 | { 482 | case SanPai: return "SanPai"; 483 | case DuiZi: return "DuiZi"; 484 | case ShunZi: return "ShunZi"; 485 | case JinHua: return "JinHua"; 486 | case ShunJin: return "ShunJin"; 487 | case BaoZi: return "BaoZi"; 488 | case TeShu235: return "TeShu235"; 489 | } 490 | return ""; 491 | } 492 | 493 | //打印n张牌 494 | void CGameLogic::PrintCardList(uint8_t const* cards, int n, bool hide) { 495 | for (int i = 0; i < n; ++i) { 496 | if (cards[i] == 0 && hide) { 497 | continue; 498 | } 499 | printf("%s ", StringCard(cards[i]).c_str()); 500 | } 501 | printf("\n"); 502 | } 503 | 504 | //拆分字符串"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 505 | void CGameLogic::CardsBy(std::string const& strcards, std::vector& vec) { 506 | std::string str(strcards); 507 | while (true) { 508 | std::string::size_type s = str.find_first_of(' '); 509 | if (-1 == s) { 510 | break; 511 | } 512 | vec.push_back(str.substr(0, s)); 513 | str = str.substr(s + 1); 514 | } 515 | if (!str.empty()) { 516 | vec.push_back(str.substr(0, -1)); 517 | } 518 | } 519 | 520 | //字串构造牌"♦A"->0x01 521 | uint8_t CGameLogic::MakeCardBy(std::string const& name) { 522 | uint8_t color = 0, value = 0; 523 | if (0 == strncmp(name.c_str(), "♠", 3)) { 524 | color = Spade; 525 | std::string str(name.substr(3, -1)); 526 | switch (str.front()) 527 | { 528 | case 'J': value = J; break; 529 | case 'Q': value = Q; break; 530 | case 'K': value = K; break; 531 | case 'A': value = A; break; 532 | case 'T': value = T; break; 533 | default: { 534 | value = atoi(str.c_str()); 535 | break; 536 | } 537 | } 538 | } 539 | else if (0 == strncmp(name.c_str(), "♥", 3)) { 540 | color = Heart; 541 | std::string str(name.substr(3, -1)); 542 | switch (str.front()) 543 | { 544 | case 'J': value = J; break; 545 | case 'Q': value = Q; break; 546 | case 'K': value = K; break; 547 | case 'A': value = A; break; 548 | case 'T': value = T; break; 549 | default: { 550 | value = atoi(str.c_str()); 551 | break; 552 | } 553 | } 554 | } 555 | else if (0 == strncmp(name.c_str(), "♣", 3)) { 556 | color = Club; 557 | std::string str(name.substr(3, -1)); 558 | switch (str.front()) 559 | { 560 | case 'J': value = J; break; 561 | case 'Q': value = Q; break; 562 | case 'K': value = K; break; 563 | case 'A': value = A; break; 564 | case 'T': value = T; break; 565 | default: { 566 | value = atoi(str.c_str()); 567 | break; 568 | } 569 | } 570 | } 571 | else if (0 == strncmp(name.c_str(), "♦", 3)) { 572 | color = Diamond; 573 | std::string str(name.substr(3, -1)); 574 | switch (str.front()) 575 | { 576 | case 'J': value = J; break; 577 | case 'Q': value = Q; break; 578 | case 'K': value = K; break; 579 | case 'A': value = A; break; 580 | case 'T': value = T; break; 581 | default: { 582 | value = atoi(str.c_str()); 583 | break; 584 | } 585 | } 586 | } 587 | assert(value != 0); 588 | return value ? MakeCardWith(color, value) : 0; 589 | } 590 | 591 | //生成n张牌<-"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 592 | void CGameLogic::MakeCardList(std::vector const& vec, uint8_t *cards, int size) { 593 | int c = 0; 594 | for (std::vector::const_iterator it = vec.begin(); 595 | it != vec.end(); ++it) { 596 | cards[c++] = MakeCardBy(it->c_str()); 597 | } 598 | } 599 | 600 | //生成n张牌<-"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 601 | int CGameLogic::MakeCardList(std::string const& strcards, uint8_t *cards, int size) { 602 | std::vector vec; 603 | CardsBy(strcards, vec); 604 | MakeCardList(vec, cards, size); 605 | return (int)vec.size(); 606 | } 607 | 608 | //比较散牌大小 609 | int CGameLogic::CompareSanPai(uint8_t *cards1, uint8_t *cards2) 610 | { 611 | //牌型相同按顺序比点 612 | for (int i = 0; i < 3; ++i) { 613 | uint8_t p0 = CGameLogic::GetCardPoint(cards1[i]); 614 | uint8_t p1 = CGameLogic::GetCardPoint(cards2[i]); 615 | if (p0 != p1) { 616 | return p0 - p1; 617 | } 618 | } 619 | //点数相同按顺序比花色 620 | for (int i = 0; i < 3; ++i) { 621 | uint8_t c0 = GetCardColor(cards1[i]); 622 | uint8_t c1 = GetCardColor(cards2[i]); 623 | if (c0 != c1) { 624 | return c0 - c1; 625 | } 626 | } 627 | return 0; 628 | } 629 | 630 | //比较对子大小 631 | int CGameLogic::CompareDuiZi(uint8_t *cards1, uint8_t *cards2) 632 | { 633 | //先比对牌点数 634 | uint8_t p0 = CGameLogic::GetCardPoint(cards1[1]); 635 | uint8_t p1 = CGameLogic::GetCardPoint(cards2[1]); 636 | if (p0 != p1) { 637 | return p0 - p1; 638 | } 639 | //对牌点数相同,比单牌点数 640 | uint8_t sp0 = CGameLogic::GetCardPoint(cards1[0]); 641 | if (sp0 == p0) { 642 | sp0 = CGameLogic::GetCardPoint(cards1[2]); 643 | } 644 | uint8_t sp1 = CGameLogic::GetCardPoint(cards2[0]); 645 | if (sp1 == p1) { 646 | sp1 = CGameLogic::GetCardPoint(cards2[2]); 647 | } 648 | if (sp0 != sp1) { 649 | return sp0 - sp1; 650 | } 651 | //单牌点数相同,比对牌里面最大的花色 652 | uint8_t c0, c1; 653 | if (sp0 == p0) { 654 | c0 = GetCardColor(cards1[0]); 655 | } 656 | else { 657 | c0 = GetCardColor(cards1[1]); 658 | } 659 | if (sp1 == p1) { 660 | c1 = GetCardColor(cards2[0]); 661 | } 662 | else { 663 | c1 = GetCardColor(cards2[1]); 664 | } 665 | return c0 - c1; 666 | } 667 | 668 | //比较顺子大小 669 | int CGameLogic::CompareShunZi(uint8_t *cards1, uint8_t *cards2) 670 | { 671 | //牌型相同按顺序比点 672 | for (int i = 0; i < 3; ++i) { 673 | uint8_t p0 = CGameLogic::GetCardPoint(cards1[i]); 674 | uint8_t p1 = CGameLogic::GetCardPoint(cards2[i]); 675 | if (p0 != p1) { 676 | return p0 - p1; 677 | } 678 | } 679 | //点数相同按顺序比花色 680 | for (int i = 0; i < 3; ++i) { 681 | uint8_t c0 = GetCardColor(cards1[i]); 682 | uint8_t c1 = GetCardColor(cards2[i]); 683 | if (c0 != c1) { 684 | return c0 - c1; 685 | } 686 | } 687 | return 0; 688 | } 689 | 690 | //比较金花大小 691 | int CGameLogic::CompareJinHua(uint8_t *cards1, uint8_t *cards2) 692 | { 693 | //牌型相同按顺序比点 694 | for (int i = 0; i < 3; ++i) { 695 | uint8_t p0 = CGameLogic::GetCardPoint(cards1[i]); 696 | uint8_t p1 = CGameLogic::GetCardPoint(cards2[i]); 697 | if (p0 != p1) { 698 | return p0 - p1; 699 | } 700 | } 701 | //点数相同按顺序比花色 702 | uint8_t c0 = GetCardColor(cards1[0]); 703 | uint8_t c1 = GetCardColor(cards2[0]); 704 | return c0 - c1; 705 | } 706 | 707 | //比较顺金大小 708 | int CGameLogic::CompareShunJin(uint8_t *cards1, uint8_t *cards2) 709 | { 710 | //牌型相同按顺序比点 711 | for (int i = 0; i < 3; ++i) { 712 | uint8_t p0 = CGameLogic::GetCardPoint(cards1[i]); 713 | uint8_t p1 = CGameLogic::GetCardPoint(cards2[i]); 714 | if (p0 != p1) { 715 | return p0 - p1; 716 | } 717 | } 718 | //点数相同按顺序比花色 719 | uint8_t c0 = GetCardColor(cards1[0]); 720 | uint8_t c1 = GetCardColor(cards2[0]); 721 | return c0 - c1; 722 | } 723 | 724 | //比较豹子大小 725 | int CGameLogic::CompareBaoZi(uint8_t *cards1, uint8_t *cards2) 726 | { 727 | //炸弹比较点数 728 | uint8_t p0 = CGameLogic::GetCardPoint(cards1[0]); 729 | uint8_t p1 = CGameLogic::GetCardPoint(cards2[0]); 730 | return p0 - p1; 731 | } 732 | 733 | //玩家手牌类型 734 | HandTy CGameLogic::GetHandCardsType(uint8_t *cards) { 735 | //手牌按牌点从大到小排序(AK...32) 736 | SortCards(cards, MaxCount, false, false, false); 737 | uint8_t p0 = GetCardPoint(cards[0]); 738 | uint8_t p1 = GetCardPoint(cards[1]); 739 | uint8_t p2 = GetCardPoint(cards[2]); 740 | if (p0 == p1) { 741 | if (p1 == p2) { 742 | //豹子(炸弹):三张值相同的牌 743 | return BaoZi; 744 | } 745 | //对子:二张值相同的牌 746 | return DuiZi; 747 | } 748 | if (p1 == p2) { 749 | //对子:二张值相同的牌 750 | return DuiZi; 751 | } 752 | //三张连续牌 753 | if ((p1 == p2 + 1) && (p0 == p1 + 1 || p0 == p2 + 12)) { 754 | uint8_t c0 = GetCardColor(cards[0]); 755 | uint8_t c1 = GetCardColor(cards[1]); 756 | uint8_t c2 = GetCardColor(cards[2]); 757 | if (p0 == p2 + 12) { 758 | //手牌按牌值从大到小排序 A32->32A 759 | SortCards(cards, MaxCount, true, false, false); 760 | } 761 | if (c0 == c1 && c1 == c2) { 762 | //顺金(同花顺):花色相同的顺子 763 | return ShunJin; 764 | } 765 | //顺子:花色不同的顺子 766 | return ShunZi; 767 | } 768 | uint8_t c0 = GetCardColor(cards[0]); 769 | uint8_t c1 = GetCardColor(cards[1]); 770 | uint8_t c2 = GetCardColor(cards[2]); 771 | if (c0 == c1 && c1 == c2) { 772 | //金花(同花):花色相同,非顺子 773 | return JinHua; 774 | } 775 | if (p0 == 0x05 && p1 == 0x03 && p2 == 0x02) { 776 | //特殊:散牌中的235 777 | return TeShu235; 778 | } 779 | //散牌(高牌/单张):三张牌不组成任何类型的牌 780 | return SanPai; 781 | } 782 | 783 | //比较手牌大小 >0-cards1大 <0-cards2大 784 | int CGameLogic::CompareHandCards(uint8_t *cards1, uint8_t *cards2) 785 | { 786 | HandTy t0 = GetHandCardsType(cards1); 787 | HandTy t1 = GetHandCardsType(cards2); 788 | if (t0 == t1) { 789 | //牌型相同情况 790 | if (t0 == TeShu235) { 791 | t0 = t1 = SanPai; 792 | } 793 | label: 794 | switch (t0) 795 | { 796 | case SanPai: 797 | { 798 | return CompareSanPai(cards1, cards2); 799 | } 800 | case DuiZi: 801 | { 802 | return CompareDuiZi(cards1, cards2); 803 | } 804 | case ShunZi: 805 | { 806 | return CompareShunZi(cards1, cards2); 807 | } 808 | case JinHua: 809 | { 810 | return CompareJinHua(cards1, cards2); 811 | } 812 | case ShunJin: 813 | { 814 | return CompareShunJin(cards1, cards2); 815 | } 816 | case BaoZi: 817 | { 818 | return CompareBaoZi(cards1, cards2); 819 | } 820 | } 821 | } 822 | else /*if (t0 != t1)*/ { 823 | //牌型不同情况 824 | if (t0 == TeShu235) { 825 | if (t1 == BaoZi) { 826 | return t0 - t1; 827 | } 828 | t0 = SanPai; 829 | } else if (t1 == TeShu235) { 830 | if (t0 == BaoZi) { 831 | return t1 - t0; 832 | } 833 | t1 = SanPai; 834 | } 835 | if (t0 == t1) { 836 | goto label; 837 | } 838 | //牌型不同比较 839 | return t0 - t1; 840 | } 841 | } 842 | 843 | //比较手牌大小 >0-cards1大 <0-cards2大 844 | bool CGameLogic::GreaterHandCards(boost::shared_ptr& cards1, boost::shared_ptr& cards2) 845 | { 846 | return CompareHandCards(boost::get_pointer(cards1), boost::get_pointer(cards2)) > 0; 847 | } 848 | }; -------------------------------------------------------------------------------- /zjh.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by andy_ro@qq.com 3 | // 5/26/2019 4 | // 5 | #ifndef GAME_LOGIC_ZJH_H 6 | #define GAME_LOGIC_ZJH_H 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifndef isZero 21 | #define isZero(a) ((a>-0.000001) && (a<0.000001)) 22 | #endif//isZero 23 | 24 | #define MAX_CARD_TOTAL ZJH::MaxCardTotal //牌总个数 25 | #define GAME_PLAYER ZJH::MaxPlayer //最多5人局 26 | #define MAX_COUNT ZJH::MaxCount //每人3张牌 27 | #define MAX_ROUND ZJH::MaxRound //最大局数 28 | 29 | //扎金花 30 | namespace ZJH { 31 | 32 | //大小:豹子>同花顺>金花>顺子>对子>散牌;特殊235>豹子(如AAA,KKK) 33 | //牌型:相同牌型按顺序比点,点数相同则按顺序比花色 34 | //牌值:A<2<3<4<5<6<7<8<9<10红>梅>方 37 | //顺子:AKQ>KQJ......432>32A,注:KA2非顺子 38 | //对子:先比对牌点数,对牌点数相同,比单牌点数,单牌点数相同,比对牌里面最大的花色 39 | 40 | const int MaxCardTotal = 52; //牌总个数 41 | const int MaxPlayer = 5; //最多5人局 42 | const int MaxCount = 3; //每人3张牌 43 | const int MaxRound = 1; //最大局数 44 | 45 | //手牌类型:从小到大 46 | //散牌<对子<顺子<金花<同花顺<豹子;AAA<特殊235 47 | enum HandTy { 48 | SanPai, //散牌(高牌/单张):三张牌不组成任何类型的牌(AKJ最大,235最小) 49 | DuiZi, //对子:二张值相同的牌(AAK最大,223最小) 50 | ShunZi, //顺子:花色不同的顺子(QKA最大,A23最小) 51 | JinHua, //金花(同花):花色相同,非顺子(AKJ最大,235最小) 52 | ShunJin, //顺金(同花顺):花色相同的顺子(QKA最大,A23最小) 53 | BaoZi, //豹子(炸弹):三张值相同的牌(AAA最大,222最小) 54 | TeShu235, //特殊:散牌中的235 55 | }; 56 | 57 | //花色:黑>红>梅>方 58 | enum CardColor { 59 | Diamond = 0x10, //方块(♦) 60 | Club = 0x20, //梅花(♣) 61 | Heart = 0x30, //红心(♥) 62 | Spade = 0x40, //黑桃(♠) 63 | }; 64 | 65 | //牌值:A<2<3<4<5<6<7<8<9<10红>梅>方 93 | static uint8_t GetCardColor(uint8_t card); 94 | //牌值:A<2<3<4<5<6<7<8<9<10按牌点 true->按牌值 102 | //ascend bool false->降序排列(即从大到小排列) true->升序排列(即从小到大排列) 103 | //clrAscend bool false->花色降序(即黑桃到方块) true->花色升序(即从方块到黑桃) 104 | static void SortCards(uint8_t *cards, int n, bool byValue, bool ascend, bool clrAscend); 105 | //手牌排序(默认按牌点降序排列),先比花色,再比牌值/点数 106 | //clrAscend bool false->花色降序(即黑桃到方块) true->花色升序(即从方块到黑桃) 107 | //byValue bool false->按牌点 true->按牌值 108 | //ascend bool false->降序排列(即从大到小排列) true->升序排列(即从小到大排列) 109 | static void SortCardsColor(uint8_t *cards, int n, bool clrAscend, bool byValue, bool ascend); 110 | //牌值字符串 111 | static std::string StringCardValue(uint8_t value); 112 | //花色字符串 113 | static std::string StringCardColor(uint8_t color); 114 | //单牌字符串 115 | static std::string StringCard(uint8_t card); 116 | //牌型字符串 117 | static std::string StringHandTy(HandTy ty); 118 | //打印n张牌 119 | static void PrintCardList(uint8_t const* cards, int n, bool hide = true); 120 | private: 121 | //拆分字符串"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 122 | static void CardsBy(std::string const& strcards, std::vector& vec); 123 | //字串构造牌"♦A"->0x01 124 | static uint8_t MakeCardBy(std::string const& name); 125 | //生成n张牌<-"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 126 | static void MakeCardList(std::vector const& vec, uint8_t *cards, int size); 127 | public: 128 | //生成n张牌<-"♦A ♦3 ♥3 ♥4 ♦5 ♣5 ♥5 ♥6 ♣7 ♥7 ♣9 ♣10 ♣J" 129 | static int MakeCardList(std::string const& strcards, uint8_t *cards, int size); 130 | private: 131 | //比较散牌大小 132 | static int CompareSanPai(uint8_t *cards1, uint8_t *cards2); 133 | //比较对子大小 134 | static int CompareDuiZi(uint8_t *cards1, uint8_t *cards2); 135 | //比较顺子大小 136 | static int CompareShunZi(uint8_t *cards1, uint8_t *cards2); 137 | //比较金花大小 138 | static int CompareJinHua(uint8_t *cards1, uint8_t *cards2); 139 | //比较顺金大小 140 | static int CompareShunJin(uint8_t *cards1, uint8_t *cards2); 141 | //比较豹子大小 142 | static int CompareBaoZi(uint8_t *cards1, uint8_t *cards2); 143 | public: 144 | //玩家手牌类型 145 | static HandTy GetHandCardsType(uint8_t *cards); 146 | //比较手牌大小 >0-cards1大 <0-cards2大 147 | static int CompareHandCards(uint8_t *cards1, uint8_t *cards2); 148 | //比较手牌大小 >0-cards1大 <0-cards2大 149 | static bool GreaterHandCards(boost::shared_ptr& cards1, boost::shared_ptr& cards2); 150 | private: 151 | int8_t index_; 152 | uint8_t cardsData_[MaxCardTotal]; 153 | }; 154 | }; 155 | 156 | #endif -------------------------------------------------------------------------------- /十三水手牌测试结果.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | --- *** chairID = [0] 3 | ♦A ♥2 ♦4 ♠4 ♣5 ♠7 ♥8 ♣9 ♦10 ♠10 ♣J ♠J ♥K 4 | 5 | --- *** -------------------------------------------------- 6 | --- *** 第[3]组 7 | --- *** 第[1]墩 - 乌龙[Tysp]:♠J ♥K ♦A 8 | --- *** 第[2]墩 - 对子[Ty20]:♠4 ♦4 ♥2 ♣5 ♦10 9 | --- *** 第[3]墩 - 顺子[Ty123]:♠7 ♥8 ♣9 ♠10 ♣J 10 | --- *** -------------------------------------------------- 11 | 12 | 13 | --- *** -------------------------------------------------- 14 | --- *** 第[2]组 15 | --- *** 第[1]墩 - 乌龙[Tysp]:♣J ♥K ♦A 16 | --- *** 第[2]墩 - 对子[Ty20]:♠4 ♦4 ♥2 ♣5 ♠10 17 | --- *** 第[3]墩 - 顺子[Ty123]:♠7 ♥8 ♣9 ♦10 ♠J 18 | --- *** -------------------------------------------------- 19 | 20 | 21 | --- *** -------------------------------------------------- 22 | --- *** 第[1]组 23 | --- *** 第[1]墩 - 乌龙[Tysp]:♣J ♥K ♦A 24 | --- *** 第[2]墩 - 对子[Ty20]:♠4 ♦4 ♥2 ♣5 ♦10 25 | --- *** 第[3]墩 - 顺子[Ty123]:♠7 ♥8 ♣9 ♠10 ♠J 26 | --- *** -------------------------------------------------- 27 | 28 | 29 | 30 | 31 | ♦4 ♠4 32 | ♦10 ♠10 33 | ♣J ♠J 34 | --- 35 | ♦A ♥2 ♣5 ♠7 ♥8 ♣9 ♥K 36 | 37 | 38 | --- *** c = 3 39 | 40 | 41 | 42 | 43 | 44 | ======================================================================== 45 | --- *** chairID = [1] 46 | ♠2 ♠3 ♣4 ♠5 ♦6 ♣6 ♠6 ♦8 ♠8 ♠9 ♥10 ♥Q ♦K 47 | 48 | --- *** -------------------------------------------------- 49 | --- *** 第[3]组 50 | --- *** 第[1]墩 - 乌龙[Tysp]:♥10 ♥Q ♦K 51 | --- *** 第[2]墩 - 对子[Ty20]:♣6 ♦6 ♠3 ♣4 ♦8 52 | --- *** 第[3]墩 - 同花[Tysc]:♠2 ♠5 ♠6 ♠8 ♠9 53 | --- *** -------------------------------------------------- 54 | 55 | 56 | --- *** -------------------------------------------------- 57 | --- *** 第[2]组 58 | --- *** 第[1]墩 - 乌龙[Tysp]:♥10 ♥Q ♦K 59 | --- *** 第[2]墩 - 对子[Ty20]:♣6 ♦6 ♠2 ♣4 ♦8 60 | --- *** 第[3]墩 - 同花[Tysc]:♠3 ♠5 ♠6 ♠8 ♠9 61 | --- *** -------------------------------------------------- 62 | 63 | 64 | --- *** -------------------------------------------------- 65 | --- *** 第[1]组 66 | --- *** 第[1]墩 - 乌龙[Tysp]:♠2 ♠3 ♣4 67 | --- *** 第[2]墩 - 乌龙[Tysp]:♠5 ♠9 ♥10 ♥Q ♦K 68 | --- *** 第[3]墩 - 葫芦[Ty32]:♠6 ♣6 ♦6 ♠8 ♦8 69 | --- *** -------------------------------------------------- 70 | 71 | 72 | 73 | 74 | ♦6 ♣6 ♠6 75 | ♦8 ♠8 76 | --- 77 | ♠2 ♠3 ♣4 ♠5 ♠9 ♥10 ♥Q ♦K 78 | 79 | 80 | --- *** c = 3 81 | 82 | 83 | 84 | 85 | 86 | ======================================================================== 87 | --- *** chairID = [2] 88 | ♦2 ♦3 ♥4 ♥5 ♦7 ♣7 ♥7 ♣8 ♥9 ♣10 ♥J ♦Q ♣Q 89 | 90 | --- *** -------------------------------------------------- 91 | --- *** 第[3]组 92 | --- *** 第[1]墩 - 对子[Ty20]:♣7 ♦7 ♣10 93 | --- *** 第[2]墩 - 对子[Ty20]:♣Q ♦Q ♦2 ♦3 ♣8 94 | --- *** 第[3]墩 - 同花[Tysc]:♥4 ♥5 ♥7 ♥9 ♥J 95 | --- *** -------------------------------------------------- 96 | 97 | 98 | --- *** -------------------------------------------------- 99 | --- *** 第[2]组 100 | --- *** 第[1]墩 - 乌龙[Tysp]:♦3 ♣8 ♣10 101 | --- *** 第[2]墩 - 两对[Ty22]:♣7 ♦7 ♣Q ♦Q ♦2 102 | --- *** 第[3]墩 - 同花[Tysc]:♥4 ♥5 ♥7 ♥9 ♥J 103 | --- *** -------------------------------------------------- 104 | 105 | 106 | --- *** -------------------------------------------------- 107 | --- *** 第[1]组 108 | --- *** 第[1]墩 - 乌龙[Tysp]:♦2 ♦3 ♥4 109 | --- *** 第[2]墩 - 乌龙[Tysp]:♥5 ♣8 ♥9 ♣10 ♥J 110 | --- *** 第[3]墩 - 葫芦[Ty32]:♥7 ♣7 ♦7 ♣Q ♦Q 111 | --- *** -------------------------------------------------- 112 | 113 | 114 | 115 | 116 | ♦7 ♣7 ♥7 117 | ♦Q ♣Q 118 | --- 119 | ♦2 ♦3 ♥4 ♥5 ♣8 ♥9 ♣10 ♥J 120 | 121 | 122 | --- *** c = 3 123 | 124 | 125 | 126 | 127 | 128 | ======================================================================== 129 | --- *** chairID = [3] 130 | ♣A ♥A ♠A ♣2 ♣3 ♥3 ♦5 ♥6 ♦9 ♦J ♠Q ♣K ♠K 131 | 132 | --- *** -------------------------------------------------- 133 | --- *** 第[3]组 134 | --- *** 第[1]墩 - 乌龙[Tysp]:♦9 ♦J ♠Q 135 | --- *** 第[2]墩 - 两对[Ty22]:♥3 ♣3 ♠K ♣K ♥6 136 | --- *** 第[3]墩 - 三条[Ty30]:♠A ♥A ♣A ♣2 ♦5 137 | --- *** -------------------------------------------------- 138 | 139 | 140 | --- *** -------------------------------------------------- 141 | --- *** 第[2]组 142 | --- *** 第[1]墩 - 乌龙[Tysp]:♦9 ♦J ♠Q 143 | --- *** 第[2]墩 - 对子[Ty20]:♥3 ♣3 ♣2 ♦5 ♥6 144 | --- *** 第[3]墩 - 葫芦[Ty32]:♠A ♥A ♣A ♠K ♣K 145 | --- *** -------------------------------------------------- 146 | 147 | 148 | --- *** -------------------------------------------------- 149 | --- *** 第[1]组 150 | --- *** 第[1]墩 - 乌龙[Tysp]:♦9 ♦J ♠Q 151 | --- *** 第[2]墩 - 对子[Ty20]:♠K ♣K ♣2 ♦5 ♥6 152 | --- *** 第[3]墩 - 葫芦[Ty32]:♠A ♥A ♣A ♥3 ♣3 153 | --- *** -------------------------------------------------- 154 | 155 | 156 | 157 | 158 | ♣A ♥A ♠A 159 | ♣3 ♥3 160 | ♣K ♠K 161 | --- 162 | ♣2 ♦5 ♥6 ♦9 ♦J ♠Q 163 | 164 | 165 | --- *** c = 3 166 | 167 | 168 | 169 | 170 | --- *** s13s.CMD_C_ManualCards 171 | null 172 | 173 | 174 | 175 | --- *** s13s.CMD_S_ManualCards 176 | {"enums":{"v123":[{"v123":"G8)JK"},{"v123":"G8)\u001AK"},{"v123":"G8)J+"},{"v123":"G8)\,{"v20":"J\u001A"},{"v20":"D\u0014"}],"v22":[{"v22":"J\u001AK+"},{"v22":"D\u0014K+"},{" 177 | 178 | 179 | 180 | --- *** s13s.CMD_C_ManualCards 181 | {"cards":"%G8)\u001A","dt":2} 182 | 183 | 184 | 185 | --- *** s13s.CMD_S_ManualCards 186 | {"cpy":"\u00112\u0014DJ+K=","dt":2,"enums":{"v20":[{"v20":"K+"},{"v20":"D\u0014"}],"v22:2} 187 | 188 | 189 | 190 | --- *** s13s.CMD_C_ManualCards 191 | {"cards":"\u00112\u0014DJ","dt":1} 192 | 193 | 194 | 195 | --- *** s13s.CMD_S_ManualCards 196 | {"cpy":"+K=","dt":1,"enums":{"v20":[{"v20":"K+"}]},"ty":3} 197 | 198 | 199 | 200 | --- *** s13s.CMD_C_ManualCards 201 | {"cards":"+K=","dt":0} 202 | 203 | 204 | 205 | --- *** s13s.CMD_S_ManualCards 206 | {"cpy":"","dt":0,"ty":3} 207 | 208 | 209 | 210 | --- *** s13s.CMD_C_ManualCards 211 | null 212 | 213 | 214 | 215 | --- *** s13s.CMD_S_ManualCards 216 | {"enums":{"v123":[{"v123":"BC$EF"},{"v123":"BC$E&"},{"v123":"BC$E\u0016"}],"v20":[{"v2020":"F\u0016"},{"v20":"&\u0016"}],"v22":[{"v22":"F&H\u0018"},{"v22":"F\u0016H\u0018"},{":[{"v30":"F&\u0016"}],"v32":[{"v32":"F&\u0016H\u0018"}],"vsc":[{"vsc":"CEFHI"},{"vsc":c":"BCEHI"},{"vsc":"BCEFI"},{"vsc":"BCEFH"}]}} 217 | 218 | 219 | 220 | --- *** s13s.CMD_C_ManualCards 221 | {"cards":"$E\u0016&F","dt":2} 222 | 223 | 224 | 225 | --- *** s13s.CMD_S_ManualCards 226 | {"cpy":"BC\u0018HI:<\u001D","dt":2,"enums":{"v20":[{"v20":"H\u0018"}]},"ty":5} 227 | 228 | 229 | 230 | --- *** s13s.CMD_C_ManualCards 231 | {"cards":"C\u0018HI:","dt":1} 232 | 233 | 234 | 235 | --- *** s13s.CMD_S_ManualCards 236 | {"cpy":"B<\u001D","dt":1,"ty":3} 237 | 238 | 239 | 240 | --- *** s13s.CMD_C_ManualCards 241 | {"cards":"B<\u001D","dt":0} 242 | 243 | 244 | 245 | --- *** s13s.CMD_S_ManualCards 246 | {"cpy":"","dt":0,"ty":2} 247 | 248 | 249 | 250 | --- *** s13s.CMD_C_ManualCards 251 | null 252 | 253 | 254 | 255 | --- *** s13s.CMD_S_ManualCards 256 | {"enums":{"v123":[{"v123":"(9*;,"},{"v123":"(9*;\u001C"},{"v123":"7(9*;"},{"v123":"'(9*20":[{"v20":",\u001C"},{"v20":"7'"},{"v20":"7\u0017"},{"v20":"'\u0017"}],"v22":[{"v22":\u001C"},{"v22":"'\u0017,\u001C"}],"v30":[{"v30":"7'\u0017"}],"v32":[{"v32":"7'\u0017,\"}]}} 257 | 258 | 259 | 260 | --- *** s13s.CMD_C_ManualCards 261 | {"cards":"\u001345\u0017'","dt":2} 262 | 263 | 264 | 265 | --- *** s13s.CMD_S_ManualCards 266 | {"cpy":"\u00127(9*;\u001C,","dt":2,"enums":{"v123":[{"v123":"(9*;,"},{"v123":"(9*;\u001{"v20":",\u001C"}]},"ty":3} 267 | 268 | 269 | 270 | --- *** s13s.CMD_C_ManualCards 271 | {"cards":"(9*;\u001C","dt":1} 272 | 273 | 274 | 275 | --- *** s13s.CMD_S_ManualCards 276 | {"cpy":"\u00127,","dt":1,"ty":6} 277 | 278 | 279 | 280 | --- *** s13s.CMD_C_ManualCards 281 | {"cards":"\u00127,","dt":0} 282 | 283 | 284 | 285 | --- *** s13s.CMD_S_ManualCards 286 | {"cpy":"","dt":0,"ty":2} 287 | 288 | 289 | 290 | --- *** s13s.CMD_C_ManualCards 291 | null 292 | 293 | 294 | 295 | --- *** s13s.CMD_S_ManualCards 296 | {"enums":{"v20":[{"v20":"A1"},{"v20":"A!"},{"v20":"1!"},{"v20":"M-"},{"v20":"3#"}],"v22-"},{"v22":"1!M-"},{"v22":"A13#"},{"v22":"A!3#"},{"v22":"1!3#"},{"v22":"3#M-"}],"v30":["A1!3#"},{"v32":"A1!M-"}]}} 297 | 298 | 299 | 300 | --- *** s13s.CMD_C_ManualCards 301 | {"cards":"#3\u00156\u0019","dt":2} 302 | 303 | 304 | 305 | --- *** s13s.CMD_S_ManualCards 306 | {"cpy":"!1A\"\u001BL-M","dt":2,"enums":{"v20":[{"v20":"A1"},{"v20":"A!"},{"v20":"1!"},{1M-"},{"v22":"A!M-"},{"v22":"1!M-"}],"v30":[{"v30":"A1!"}],"v32":[{"v32":"A1!M-"}]},"ty 307 | 308 | 309 | 310 | --- *** s13s.CMD_C_ManualCards 311 | {"cards":"\"\u001BL-M","dt":1} 312 | 313 | 314 | 315 | --- *** s13s.CMD_S_ManualCards 316 | {"cpy":"!1A","dt":1,"enums":{"v20":[{"v20":"A1"},{"v20":"A!"},{"v20":"1!"}],"v30":[{"v3 317 | 318 | 319 | 320 | --- *** s13s.CMD_C_ManualCards 321 | {"cards":"!1A","dt":0} 322 | 323 | 324 | 325 | --- *** s13s.CMD_S_ManualCards 326 | {"cpy":"","dt":0,"ty":5} 327 | 328 | 329 | 330 | --- *** s13s.CMD_C_MakesureDunHandTy 331 | {"groupindex":-1} 332 | 333 | 334 | 335 | --- *** s13s.CMD_C_MakesureDunHandTy 336 | {"groupindex":-1} 337 | 338 | 339 | 340 | --- *** s13s.CMD_C_MakesureDunHandTy 341 | {"groupindex":1} 342 | 343 | 344 | 345 | --- *** s13s.CMD_C_MakesureDunHandTy 346 | {"groupindex":-1} 347 | 348 | 349 | 32 31 30 21 20 10 350 | 351 | --- *** {"s13s.PlayerItem": 352 | {"chairId":0,"deltascore":-12,"peers":[{"chairId":3,"group":{"duns":[{"c":3,"cards":"!1ds":"\"\u001BL-M","id":1,"ty":3},{"c":5,"cards":"#3\u00156\u0019","id":2,"ty":3}],"specd":2,"group":{"duns":[{"c":3,"cards":"\u0013(*","id":0,"ty":2},{"c":5,"cards":"'\u0017,{"c":5,"cards":"4579;","id":2,"ty":7}],"specialTy":0,"start":0}},{"chairId":1,"group":{01D","id":0,"ty":2},{"c":5,"cards":"C\u0018HI:","id":1,"ty":3},{"c":5,"cards":"$E\u0016y":0,"start":0}}],"results":[{"items":[{"peerTy":5,"score":-3,"ty":3,"winLost":-1},{"penLost":-1},{"peerTy":3,"score":-1,"ty":2,"winLost":-1}],"score":-5,"shoot":-1},{"items"3,"winLost":1},{"peerTy":4,"score":-1,"ty":3,"winLost":-1},{"peerTy":7,"score":-1,"ty":shoot":0},{"items":[{"peerTy":2,"score":1,"ty":3,"winLost":1},{"peerTy":3,"score":-1,"t5,"score":-1,"ty":2,"winLost":-1}],"score":-1,"shoot":0}]} 353 | } 354 | 355 | 356 | --- *** {"s13s.PlayerItem": 357 | {"chairId":1,"deltascore":-8,"peers":[{"chairId":3,"group":{"duns":[{"c":3,"cards":"!1As":"\"\u001BL-M","id":1,"ty":3},{"c":5,"cards":"#3\u00156\u0019","id":2,"ty":3}],"speci":2,"group":{"duns":[{"c":3,"cards":"\u0013(*","id":0,"ty":2},{"c":5,"cards":"'\u0017,\"c":5,"cards":"4579;","id":2,"ty":7}],"specialTy":0,"start":0}},{"chairId":0,"group":{"id":0,"ty":3},{"c":5,"cards":"\u00112\u0014DJ","id":1,"ty":3},{"c":5,"cards":"%G8)\u001":0,"start":0}}],"results":[{"items":[{"peerTy":5,"score":-3,"ty":2,"winLost":-1},{"peeLost":-1},{"peerTy":3,"score":1,"ty":5,"winLost":1}],"score":-3,"shoot":0},{"items":[{"winLost":-1},{"peerTy":4,"score":-1,"ty":3,"winLost":-1},{"peerTy":7,"score":-1,"ty":5,oot":-1},{"items":[{"peerTy":3,"score":-1,"ty":2,"winLost":-1},{"peerTy":3,"score":1,"t,"score":1,"ty":5,"winLost":1}],"score":1,"shoot":0}]} 358 | } 359 | 360 | 361 | --- *** {"s13s.PlayerItem": 362 | {"chairId":2,"deltascore":6,"peers":[{"chairId":3,"group":{"duns":[{"c":3,"cards":"!1A"":"\"\u001BL-M","id":1,"ty":3},{"c":5,"cards":"#3\u00156\u0019","id":2,"ty":3}],"specia:1,"group":{"duns":[{"c":3,"cards":"B<\u001D","id":0,"ty":2},{"c":5,"cards":"C\u0018HI:s":"$E\u0016&F","id":2,"ty":5}],"specialTy":0,"start":0}},{"chairId":0,"group":{"duns":"ty":3},{"c":5,"cards":"\u00112\u0014DJ","id":1,"ty":3},{"c":5,"cards":"%G8)\u001A","idtart":0}}],"results":[{"items":[{"peerTy":5,"score":-3,"ty":2,"winLost":-1},{"peerTy":3},{"peerTy":3,"score":1,"ty":7,"winLost":1}],"score":-1,"shoot":0},{"items":[{"peerTy":1},{"peerTy":3,"score":1,"ty":4,"winLost":1},{"peerTy":5,"score":1,"ty":7,"winLost":1}]":[{"peerTy":3,"score":-1,"ty":2,"winLost":-1},{"peerTy":3,"score":1,"ty":4,"winLost":17,"winLost":1}],"score":1,"shoot":0}]} 363 | } 364 | 365 | 366 | --- *** {"s13s.PlayerItem": 367 | {"chairId":3,"deltascore":14,"peers":[{"chairId":2,"group":{"duns":[{"c":3,"cards":"\u0"cards":"'\u0017,\u001C\u0012","id":1,"ty":4},{"c":5,"cards":"4579;","id":2,"ty":7}],"sirId":1,"group":{"duns":[{"c":3,"cards":"B<\u001D","id":0,"ty":2},{"c":5,"cards":"C\u00"cards":"$E\u0016&F","id":2,"ty":5}],"specialTy":0,"start":0}},{"chairId":0,"group":{"dd":0,"ty":3},{"c":5,"cards":"\u00112\u0014DJ","id":1,"ty":3},{"c":5,"cards":"%G8)\u001A:0,"start":0}}],"results":[{"items":[{"peerTy":2,"score":3,"ty":5,"winLost":1},{"peerTyt":-1},{"peerTy":7,"score":-1,"ty":3,"winLost":-1}],"score":1,"shoot":0},{"items":[{"peLost":1},{"peerTy":3,"score":1,"ty":3,"winLost":1},{"peerTy":5,"score":-1,"ty":3,"winLo,{"items":[{"peerTy":3,"score":3,"ty":5,"winLost":1},{"peerTy":3,"score":1,"ty":3,"winL,"ty":3,"winLost":1}],"score":5,"shoot":1}]} 368 | } 369 | --------------------------------------------------------------------------------