Mahjong play rules are numerous, the core of the game is consistent, this article will be based on MediaTek 2017 programming challenge of the rules to achieve the title.
How the cards are represented
ABCDEFGHI
Representing one to nine, representing one to abcdefghi
nine, 123456789
representing one to nine loaves
Three kinds of Hu brand type
- Ordinary card type, 14 cards, shaped like:
3+3+3+3+2
. Where 2
the number represents two identical cards can be a group, shaped like XX
. 3
the number represents three identical or consecutive cards that can be formed into a set of XXX
shapes XYZ
.
- Dragon Seven pairs, 14 sheets as:
2+2+2+2+2+2+2
.
- With a bar, that is, ordinary card type three cards
XXX
can be upgraded XXXX
to, called a bar. Each number of bars, the total number of cards can be added one. There can be up to 4 bars, so the number of cards with bars can be up to 18.
Sample Example
ABCeee345456DD
Hu Card, the Group of Cards for ABC+EEE+345+456+DD, ordinary card type.
ABeeee345456DD
Fried, because AB two cards failed to form a group card.
AAAABC123456333
Fried hu, although looks like the group card OK (aaa+abc+124+345+456+333) but does not conform to any kind of Hu card type.
AADDFF1133aagg
Hu, dark seven pair.
AAAABBBBCCCCDDDD88
Hu brand, 3+3+3+3+2 card type, upgraded 4-way bar.
AAA123789
Blows, does not conform to any kind of card type.
AAA111345666DEF88
Blows, does not conform to any kind of card type.
Algorithm realization Idea
1, the ordinary card type is the form of 3n+2, and the Dragon 7 pair are 14 cards, if there is a bar of up to 18 cards, so the first step can be judged, if the number of cards is less than 14 or greater than, it must not be HU card;
2, the card from small to large sorting, convenient follow-up judgment. If the number of hands is 14, you can first determine whether it is the Dragon 7 pair (pair of Hu), which is characterized by each odd bit of cards are equal to the card after one . If not to Hu, then go to step 3;
3, 3n+2 form of the ordinary card type inside there is a pair, so judge is not a card type, you can first find one of the pairs. A card may have 2 or 4, you can make up a pair or a dark bar or a bar, or the back of the cards to form a straight son. Regardless of the number of situations, the pair must appear in a repeating card, as long as each traverse removes a pair . Next go to step 4;
4, after the removal of a pair, determine whether it is a 3n card type, that is, whether it is all composed of straight or dark bars. Since the cards have been sorted, just watch the first card.
- If the number of the first card is only one or two , then this card must be the same as the following cards to make a straight, otherwise you can not be a card. If there is such a straight, remove the straight
- If the number of the first card is three or four , it may be composed of a dark bar, or the following cards make up a straight (regardless of the case of the bar), remove the Dark Bar (CIS)
Always cycle above the judgment, meet the conditions to remove the three cards, until the number of cards is 0 o'clock, return to "Hu ", or back to step 3, put the previously removed pairs back, continue to delete the next pair. if all the pairs in step 3 have not satisfied the HU condition, then return "no card";
5, if the number of cards is 15, it will contain at least a 4-card bar, or not a card. If there are multiple bars, then walk through the deletion of a bar, and then go to step 3 to determine whether the 3n card type. If after traversing all the bars can not be a card, then return "no card";
6, if the number of cards is 16, then at least 2 bars, followed by the deletion of the combination of a pair of bars, the remaining similar to step 5. Similarly, the number of cards is 17 and 18 when the method is similar.
C + + source code
#include <iostream> #include <vector> #include <algorithm>using std::vector;using std::cout; Template <typename t>void showvector (vector <T> & lst), vector <int> Findreptpos (vector <char > & LST), bool Isddh (const vector <char> & LST), bool ishu3n (vector <char> & lst), Vector <char > deldui (const vector <char> & LST, const int x), bool is3n (vector <char> lst), int numoffirst (vector < ;char> lst); bool CheckGroup (vector <char> LST, const int num), void Delgroup (vector <char> & LST, const int num), vector <char> Delgang (const vector <char> & LST, const int x), vector <int> Findgangpos (cons T vector <char> & LST); int main (int argc, char **argv) {char *mahjong = argv[1]; Vector <char> lst; for (int i = 0; Mahjong[i]! = ' + '; ++i) {lst.push_back (mahjong[i]); } std::sort (Lst.begin (), Lst.end ()); From small to large sort/*cout << "Sort: "; Showvector (LST); */int num = Lst.size (); Number of Mahjong tiles if (num < 14) | | (num > 18)) {cout << "bad"; return 0; } if (num = = 14)//14 cards, 2 kinds of Hu FA {if (ISDDH (LST))///If yes to Hu {cout << "good"; return 0; } if (Ishu3n (LST)) {cout << "good"; } else {cout << "bad"; } return 0; } if (num = =) {Vector <int> pos = findgangpos (LST); Find the position of the bar if (Pos.size () < 1) {cout << "bad"; } else {//delete a bar in turn, and then determine if it is a 3N card type for (int i = 0; i < pos.size (); ++i) { Vector <char> newlst = Delgang (LST, pos[i]); /*cout << "delgang/"; Showvector (NEWLST); */if (ishu3n (Newlst)) {cout << "good"; return 0; }} cout << "bad"; }} if (num = =) {Vector <int> pos = findgangpos (LST); Find the position of the bar if (Pos.size () < 2)//Less than 2 bars is definitely not a flop {cout << "bad"; } else {//delete the different 2-bar combinations in turn, and then determine if it is a 3N card type for (int i = 0; i < pos.size ()-1; ++i) {for (int j = i + 1; j < Pos.size (); ++j) {//note remove the rear bar first, otherwise the position will change Vector <char> newLst1 = Delgang (LST, pos[j]); Vector <char> newLst2 = Delgang (NewLst1, pos[i]); /*cout << "delgang/"; Showvector (NEWLST2); */if (ishu3n (NewLst2)) {cout << " Good "; return 0; }}} cout << "Bad"; }} if (num = =) {Vector <int> pos = findgangpos (LST); Find the position of the bar if (Pos.size () < 3)//Less than 3 bars is definitely not a flop {cout << "bad"; } else {//delete the different 3-bar combinations in turn, and then determine if it is a 3N card type for (int i = 0; i < pos.size ()-2; ++i) {for (int j = i + 1, J < Pos.size ()-1; ++j) {for (int k = j + 1; K < Pos.size (); ++K) {//note remove the rear bar first, otherwise the position will change vector <char> newLst1 = Delgang (LST, pos[k]); Vector <char> newLst2 = Delgang (NewLst1, pos[j]); Vector <char> newLst3 = Delgang (NewLst2, pos[i]); /*cout << "delgang/"; Showvector (NEWLST3); */if (ishu3n (NEWLST3)) {Cou T << "good"; return 0; }}}} cout << "bad"; }} if (num = =) {Vector <int> pos = findgangpos (LST); Find the position of the bar if (pos.size ()! = 4)//Not 4 bar definitely not a flop {cout << "bad"; } else {//delete 4 bar vectors <char> newLst1 = Delgang (LST, pos[3]); Vector <char> newLst2 = Delgang (NewLst1, pos[2]); Vector <char> newLst3 = Delgang (NewLst2, pos[1]); Vector <char> newLst4 = Delgang (NewLst3, pos[0]); /*cout << "delgang/"; Showvector (NEWLST4); */if (newlst4[0] = = Newlst4[1]) {cout << "good"; } else {cout << "bad"; }}} return 0;} Display List contents template <typename t>void showvector (vector <T> & LST) { Vector <t>::iterator iter; Iterator for (iter = Lst.begin (); ITER! = Lst.end (); iter++) {cout << *iter << ""; } cout << "\ n";} Find the position of the duplicate hand vector <int> Findreptpos (vector <char> & lst) {vector <int> pos; The position where the duplicate card is stored int temp_pos = 0; if (Lst.size () <= 1)//card number is less than or equal to 1, directly return {return pos; }//Lst.size () >= 2 vector <char>::iterator iter2; Iter2 = Lst.begin (); ++iter2; The iterator does not support arithmetic operations, only ++/--/advance chained operations if (lst.front () = = *iter2) {pos.push_back (temp_pos); } vector <char>::iterator It_front; Vector <char>::iterator It_back; for (Auto iter1 = iter2; Iter1! = (--lst.end ()); iter1++)//from second to penultimate {++temp_pos; Location update it_front = Iter1; --it_front; It_back = Iter1; ++it_back; Not equal to the previous if (*iter1! = *it_front) && (*iter1 = = *it_back)) {Pos.push_back (temp_p OS); } } return POS;} Whether it is pair of HU bool Isddh (const vector <char> & LST) {vector <char> newlst = LST; for (int i = 0; I <=; ++i) {if (Newlst[i]! = newlst[i + 1]) {return false; } ++i; } return true; is the normal card type 3nbool ishu3n (vector <char> & lst) {vector <int> pos = findreptpos (LST); Find the position of the duplicate card for (int i = 0; i < pos.size (); ++i)//Remove duplicate pairs {vector <char> newlst = Deldui (LST, p Os[i]); Delete a pair of cards/*cout << "deldui/"; Showvector (NEWLST); */if (is3n (Newlst)) {return true; }} return false;} Whether it is n straight or dark bar bool is3n (vector <char> lst) {if (lst.size ()% 3! = 0) {return false; } while (Lst.size () > 0) {if (Lst.size () >= 3) {int num = Numoffirst (LST); Calculates the number of repetitions of the first card if (CheckGroup (LST, num))//Check if there is a first straight or dark bar { Delgroup (LST, num); Delete this set of straight or dark bars} else {return false; }}/*cout << "//"; Showvector (LST); */} return true; Check if there is a first straight or dark bar bool CheckGroup (vector <char> LST, const int num) {if (num = 1) && (lst[1] = = Lst[0] + 1) {//second number may have duplicate for (int i = 2; I < lst.size (); ++i) {if (Lst[i]! = lst[1]) {if (lst[i] = = Lst[0] + 2) {return true; } else {return false; }}}} if ((num = = 2) && (lst[2] = = Lst[1] + 1) {//The third number may be duplicated for (int i = 3; I < lst.size (); ++i) {if (Lst[i]! = lst[2]) {if (Lst[i] = = Lst[1] + 2) { return true; } else {return false; }}}} if (num >= 3) {return true; } return false;} Delete this set of straight or dark bars void Delgroup (vector <char> & LST, const int num) {if (num = = 1) {vector <char >::iterator iter = ++lst.begin (); for (int i = 2; I < lst.size (); ++i) {++iter; if (lst[i] = = (1 + lst[1])) {lst.erase (ITER); Lst.erase (Lst.begin ()); Lst.erase (Lst.begin ()); Break }}} if (num = = 2) {vector <char>::iterator iter = + + (++lst.begin ()); for (int i = 3; I < lst.size (); ++i) {++iter; if (lst[i] = = (1 + lst[2])) {lst.erase (ITER); Lst.erase (++lst.begin ()); Remove the second-digit card lst.erase (++lst.begIn ()); Break }}} if (num >= 3) {lst.erase (Lst.begin ()); Lst.erase (Lst.begin ()); Lst.erase (Lst.begin ()); }}//calculates the number of repetitions of the first card int numoffirst (vector <char> lst) {if (lst[0]! = lst[1]) {return 1; } if ((lst[0] = = lst[1]) && (lst[1]! = lst[2])) {return 2; } if (lst[0] = = Lst[2]) {if (lst.size () = = 3) {return 3; } if ((Lst.size () >= 4) && (lst[2]! = lst[3]))//lst[3] must be guaranteed size>=4 {return 3; }} if ((lst[0] = = Lst[3]) && (Lst.size () >= 4)) {return 4; } return 0;} Remove the X and x+1 positions of a pair of vector <char> Deldui (const vector <char> & LST, const int x) {vector <char> newls T for (int i = 0; i < lst.size (); ++i) {if ((i! = x) && (i! = (x + 1)) {Newlst.pus H_back (Lst[i]); }} returnNewlst;} Remove the bar starting at x (4 cards) vector <char> Delgang (const vector <char> & LST, const int x) {vector <char> NE WLst; for (int i = 0; i < lst.size (); ++i) {if ((I < x) | | (i > x + 3)) {Newlst.push_back (lst[i]); }} return newlst;} Find the position of the bar vector <int> findgangpos (const vector <char> & LST) {vector <int> pos; int temp_pos = 0; if (Lst.size () < 4) {return pos; } for (int i = 0; i < lst.size ()-3; ++i) {if (lst[i] = = Lst[i + 3]) {Pos.pus H_back (Temp_pos); } ++temp_pos; Location update} return POS;}
Program Run Results
The program obtains input data from command-line parameters, and the data is a string representing a deck of cards. If this deck reaches the condition of the license, the output good, otherwise the output bad.
[C + +] Mahjong Poker algorithm