// Please use UTF-8 encoding so that the comments can be displayed correctly. // 标注TODO的是你需要完善的地方 #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; class Card : public string { public: static const int N_CARD_VALUES;//15 static const int N_CARD_SUITS;//4 static const string CARD_VALUES[]; static const string CARD_SUITS[]; Card(const char* str) :string(str) {}; Card() :string() {}; Card(string str) :string(str) {}; static vector get_new_deck(); // 重载操作符,使得牌面可以比较大小 //bool operator <(const Card &other) const; //bool operator >(const Card &other) const; }; class DDZPlayer { protected: string name; // 玩家名 int position; // 你的位置编号,0为地主,1为地主下家,2为地主上家 vector hand; // 手牌 int prePos; //上一个出牌的人位置编号,-1表示还没有人出过牌 vector prePlay; // 上一个出牌的人出了什么牌? bool legal(vector cards); // 判断当前打出cards是否合法 void substractFromHand(vector cards); // 从当前手牌中删去cards中的牌 public: DDZPlayer(string name); // 构造函数,初始化玩家名 string getName(); virtual void draw(Card card); // 将cards中的牌加入手牌 virtual void draw(vector cards); // 将cards中的牌加入手牌 virtual void setPosition(int pos); // 初始化用,决定地主后设置 virtual void showHand(); // 打印手牌 virtual void observed(int pos, vector cards); // 观测到玩家出牌 virtual vector play(); // 轮到自己时决定出什么牌 bool leftNoCard(); // 返回是否打完了牌? int* case1(int* a, int other[15]) {//pairs 3-1 //continuous_one for (int i = 14; i >= 0; i--) { if (a[i] == 2) { a[i] -= 2; other[i] = 2; return a; } } for (int i = 14; i >= 0; i--) { if (a[i] == 3) { for (int j = 14; j >= 0; j--) { if (a[j] == 1 && j != i) { a[i] -= 3; a[j]--; other[i] = 3; other[j] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i] >= 1) { int j; for (j = i - 1; j >= 2; j--) if (!a[j]) break; if (i - j >= 5) { for (int k = j + 1; k <= i; k++) { a[k]--; other[k] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i]) { other[i] = a[i]; a[i] = 0; return a; } } } int* case2(int* a, int other[15]) {//3-1 pairs continus_one for (int i = 14; i >= 0; i--) { if (a[i] == 3) { for (int j = 14; j >= 0; j--) { if (a[j] == 1 && j != i) { a[i] -= 3; a[j]--; other[i] = 3; other[j] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i] == 2) { a[i] -= 2; other[i] = 2; return a; } } for (int i = 14; i >= 0; i--) { if (a[i] >= 1) { int j; for (j = i - 1; j >= 2; j--) if (!a[j]) break; if (i - j >= 5) { for (int k = j + 1; k <= i; k++) { a[k]--; other[k] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i]) { other[i] = a[i]; a[i] = 0; return a; } } } int* case3(int* a, int other[15]) {//continuous_pairs continuous_one 3-1 pairs for (int i = 14; i >= 0; i--) { if (a[i] >= 2) { int j; for (j = i - 1; j >= 2; j--) if (a[j] < 2) break; if (i - j >= 3) { for (int k = j + 1; k <= i; k++) { a[k] -= 2; other[k] = 2; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i] >= 1) { int j; for (j = i - 1; j >= 2; j--) if (!a[j]) break; if (i - j >= 5) { for (int k = j + 1; k <= i; k++) { a[k]--; other[k] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i] == 3) { for (int j = 14; j >= 0; j--) { if (a[j] == 1 && j != i) { a[i] -= 3; a[j]--; other[i] = 3; other[j] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i] == 2) { a[i] -= 2; other[i] = 2; return a; } } for (int i = 14; i >= 0; i--) { if (a[i]) { other[i] = a[i]; a[i] = 0; return a; } } } int* case4(int* a, int other[15]) {//continuous_one pairs 3-1 for (int i = 14; i >= 0; i--) { if (a[i] >= 1) { int j; for (j = i - 1; j >= 2; j--) if (!a[j]) break; if (i - j >= 5) { for (int k = j + 1; k <= i; k++) { a[k]--; other[k] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i] == 2) { a[i] -= 2; other[i] = 2; return a; } } for (int i = 14; i >= 0; i--) { if (a[i] == 3) { for (int j = 14; j >= 0; j--) { if (a[j] == 1 && j != i) { a[i] -= 3; a[j]--; other[i] = 3; other[j] = 1; return a; } } } } for (int i = 14; i >= 0; i--) { if (a[i]) { other[i] = a[i]; a[i] = 0; return a; } } } int* chu_pai(int* a, int other[15]) { bool is_one = true; for (int i = 0; i < 15; i++) { if (a[i] > 1) is_one = false; } if (is_one) { for (int i = 14; i >= 0; i--) { if (a[i]) { a[i]--; other[i] = 1; return a; } } } else { srand((unsigned)time(NULL)); int key = rand() % 4 + 1;//1,2,3,4 switch (key) { case 1:a = case1(a, other); break; case 2:a = case2(a, other); break; case 3:a = case1(a, other); break; case 4:a = case2(a, other); } return a; } } int* play1(int* my, int other[15]) { int b = 0, c = 0, d = 0; if (one(other, &b)) my = judge_one(my, b, other); else if (pairs(other, &b)) my = judge_pairs(my, b, other); else if (three(other, &b, &c)) my = judge_three(my, b, c, other); else if (continuous_pairs(other, &b, &c)) my = judge_continuous_pairs(my, b, c, other); else if (continuous_one(other, &b, &c)) my = judge_continuous_one(my, b, c, other); else if (four_and_two(other, &b, &c)) my = judge_four_and_two(my, b, c, other); else if (plane(other, &b, &c, &d)) my = judge_plane(my, b, c, d, other); else if (bomb(other, &b)) my = judge_bomb(my, b, other); else if (king_bomb(other)) my = judge_king_bomb(my, other); return my; } int card_number(int* a) { int number = 0; for (int i = 0; i < 15; i++) number += a[i]; return number; } bool one(int* a, int* b) { if (card_number(a) == 1) { for (int i = 0; i < 15; i++) if (a[i]) { *b = i; return true; } } return false; } bool pairs(int* a, int* b) { if (card_number(a) == 2) { for (int i = 2; i < 15; i++) if (a[i] == 2) { *b = i; return true; } } return false; } bool three(int* a, int* three_card, int *bring_num) { if (card_number(a) >= 3 && card_number(a) <= 5) { for (int i = 2; i < 15; i++) { if (a[i] == 3) { *three_card = i; *bring_num = card_number(a) - 3; return true; } } } return false; } bool continuous_pairs(int* a, int *start, int *length) {//连对 int count = 0, i; for (i = 2; i < 15; i++) { if (a[i] == 2) { count++; if (i == 14 || a[i + 1] != 2) break; } } *start = i; *length = count; if (count > 2) return true; else return false; } bool continuous_one(int* a, int* start, int* length) { int count = 0, i; for (i = 2; i < 15; i++) {//从2开始 if (a[i] == 1) { count++; if (i == 14 || a[i + 1] != 1) break; } } *start = i; *length = count; if (count > 4) return true; else return false; } bool four_and_two(int* a, int* four_card, int* bring_2or4) { if (card_number(a) == 6 || card_number(a) == 8) { for (int i = 0; i < 15; i++) { if (a[i] == 4) { *four_card = i; *bring_2or4 = card_number(a) - 4; return true; } } } return false; } bool plane(int* a, int* start, int* num, int* type) {//num=2 or 3,type=2 or 3 or 4 or 6 if (card_number(a) == 8) { for (int i = 2; i < 14; i++) { if (a[i] == 3 && a[i + 1] == 3) { *start = i + 1; *num = 2; *type = 2; return true; } } } if (card_number(a) == 10) { for (int i = 2; i < 14; i++) { if (a[i] == 3 && a[i + 1] == 3) { *start = i + 1; *num = 2; *type = 4; return true; } } } if (card_number(a) == 12) { for (int i = 2; i < 13; i++) { if (a[i] == 3 && a[i + 1] == 3 && a[i + 2] == 3) { *start = i + 2; *num = 3; *type = 3; return true; } } } if (card_number(a) == 15) { for (int i = 2; i < 13; i++) { if (a[i] == 3 && a[i + 1] == 3 && a[i + 2] == 3) { *start = i + 2; *num = 3; *type = 6; return true; } } } return false; } bool bomb(int* a, int* b) { for (int i = 0; i < 15; i++) { if (a[i] == 4 && card_number(a) == 4) { *b = i; return true; } } return false; } bool king_bomb(int* a) { if (a[0] == 1 && a[1] == 1) return true; else return false; } int* judge_one(int* a, int b, int re[15]) { for (int i = b - 1; i >= 0; i--) { if (a[i]) { a[i]--; for (int h = 0; h < 15; h++) re[h] = 0; re[i] = 1; return a; } } return judge_bomb(a, 15, re); } int* judge_pairs(int* a, int b, int re[15]) { for (int i = b - 1; i >= 0; i--) { if (a[i] >= 2) { a[i] -= 2; for (int h = 0; h < 15; h++) re[h] = 0; re[i] = 2; return a; } } return judge_bomb(a, 15, re); } int* judge_three(int* a, int three_card, int bring_num, int re[15]) { for (int i = three_card - 1; i >= 0; i--) { if (a[i] >= 3 && card_number(a) >= 3 + bring_num) { for (int h = 0; h < 15; h++) re[h] = 0; a[i] -= 3; re[i] = 3; if (bring_num == 2) { int temp[2], t = 0; for (int j = 14; j >= 0; j--) { if (bring_num == 0) { re[temp[1]] = re[temp[0]] = 1; //cout << array[temp[1]] << " " << array[temp[0]]; return a; } if (a[j]) { temp[t++] = j; a[j++]--; bring_num--; } } } if (bring_num == 0) return a; for (int j = 14; j >= 0; j--) {//bring_num==1 if (a[j]) { re[j] = 1; //cout << array[j]; a[j]--; bring_num--; return a; } } } } return judge_bomb(a, 15, re); } int* judge_continuous_pairs(int* a, int start, int length, int re[15]) { if (card_number(a) < 2 * length) { return judge_bomb(a, 15, re); } for (int i = start - 1; i >= 2; i--) { if (a[i] >= 2) { int k; for (k = i - 1; k >= 2; k--) { if (a[k] < 2) break; } if (i - k >= length) { for (int j = i - length + 1; j <= i; j++) { for (int h = 0; h < 15; h++) re[h] = 0; re[j] = 2; a[j] -= 2; } return a; } } } return judge_bomb(a, 15, re); } int* judge_continuous_one(int* a, int start, int length, int re[15]) { if (card_number(a) < length) { return judge_bomb(a, 15, re); } for (int i = start - 1; i >= 2; i--) { if (a[i] >= 1) { int k; for (k = i - 1; k >= 2; k--) { if (a[k] == 0) break; } if (i - k >= length) { for (int j = i - length + 1; j <= i; j++) { for (int h = 0; h < 15; h++) re[h] = 0; re[j] = 1; a[j] -= 1; } return a; } } } return judge_bomb(a, 15, re); } int* judge_four_and_two(int* a, int four_card, int bring_2or4, int re[15]) { if (card_number(a) < bring_2or4 + 4) return judge_bomb(a, 15, re); for (int i = four_card - 1; i >= 2; i--) { if (a[i] == 4) { if (bring_2or4 == 2) { a[i] = 0; for (int h = 0; h < 15; h++) re[h] = 0; re[i] = 4; int temp[2], t = 0; for (int j = 14; j >= 0; j--) { if (a[j]) { if (bring_2or4 == 0) { re[temp[1]] = re[temp[0]] = 1; return a; } temp[t++] = j; a[j++]--; bring_2or4--; } } } if (bring_2or4 == 4) { for (int j = 14; j >= 2; j--) { if (a[j] >= 2) { for (int k = j - 1; k >= 2; k--) { if (a[k] >= 2) { for (int h = 0; h < 15; h++) re[h] = 0; re[i] = 4; re[k] = re[j] = 2; a[i] = 0; a[j] -= 2; a[k] -= 2; return a; } } } } } } } return judge_bomb(a, 15, re); } int* judge_plane(int* a, int start, int num, int type, int re[15]) { if (card_number(a) < num * 3 + type) return judge_bomb(a, 15, re); if (num == 2 && type == 2) { for (int i = start - 1; i >= 3; i--) { if (a[i] >= 3 && a[i - 1] >= 3) { for (int h = 0; h < 15; h++) re[h] = 0; re[i] = re[i - 1] = 3; a[i] -= 3; a[i - 1] -= 3; int temp[2], t = 0; for (int j = 14; j >= 0; j--) { if (type == 0) { re[temp[1]] = re[temp[0]] = 1; return a; } if (a[j]) { temp[t++] = j; a[j++]--; type--; } } } } } if (num == 2 && type == 4) { for (int i = start - 1; i >= 3; i--) { if (a[i] >= 3 && a[i - 1] >= 3) { int count = 0, temp[2]; for (int j = 14; j >= 0; j--) { if (count == 2) { for (int h = 0; h < 15; h++) re[h] = 0; re[i] = re[i - 1] = 3; re[temp[0]] = re[temp[1]] = 2; a[i] -= 3; a[i - 1] -= 3; a[temp[1]] -= 2; a[temp[0]] -= 2; return a; } if (j != i&&j != i - 1 && a[j] >= 2) { temp[count] = j; count++; } } } } } if (num == 3 && type == 3) { for (int i = start - 1; i >= 4; i--) { if (a[i] >= 3 && a[i - 1] >= 3 && a[i - 2] >= 3) { for (int h = 0; h < 15; h++) re[h] = 0; re[i] = re[i - 1] = re[i - 2] = 3; a[i] -= 3; a[i - 1] -= 3; a[i - 2] -= 3; int temp[3], t = 0; for (int j = 14; j >= 0; j--) { if (type == 0) { for (int k = 2; k >= 0; k--) { re[temp[k]] = 1; } return a; } if (a[j]) { temp[t++] = j; a[j++]--; type--; } } } } } if (num == 3 && type == 6) { for (int i = start - 1; i >= 3; i--) { if (a[i] >= 3 && a[i - 1] >= 3 && a[i - 2] >= 3) { int count = 0, temp[3]; for (int j = 14; j >= 0; j--) { if (count == 3) { for (int k = 0; k < 3; k++) { for (int h = 0; h < 15; h++) re[h] = 0; a[i - k] -= 3; a[temp[k]] -= 2; re[i - k] = 3; re[temp[k]] = 2; } return a; } if (j != i&&j != i - 1 && j != i - 1 && a[j] >= 2) { temp[count] = j; count++; } } } } } return judge_bomb(a, 15, re); } int* judge_bomb(int* a, int b, int re[15]) { for (int i = b - 1; i >= 2; i--) { if (a[i] == 4) { a[i] = 0; for (int h = 0; h < 15; h++) re[h] = 0; re[i] = 4; return a; } } return judge_king_bomb(a, re); } int* judge_king_bomb(int* a, int re[15]) { if (a[0] == 1 && a[1] == 1) { a[0] = a[1] = 0; for (int h = 0; h < 15; h++) re[h] = 0; re[0] = re[1] = 1; return a; } for (int h = 0; h < 15; h++) re[h] = 0;//yao bu qi return a; } int decide(string s) { for (int i = 0; i < 15; i++) { Card card; if (s == card.CARD_VALUES[14 - i]) return i; } } int* convert_vector_to_my(vector cards) { int *a = new int[15](); for (int i = 0; i < cards.size(); i++) { a[decide(cards[i])]++; } return a; } vector convert_my_to_vector(int a[15]) { Card card; vector re; for (int i = 0; i < 15; i++) { for (int j = 0; j < a[i]; j++) { re.push_back(card.CARD_VALUES[14 - i]); } } return re; } }; class DDZGame { private: static int my_random(int i); // 洗牌时用到的随机函数 vector players; // 保存三个玩家的指针 void showCards(vector cards); // 输出一组牌 public: DDZGame(DDZPlayer *p1, DDZPlayer *p2, DDZPlayer *p3); // 构造函数 void run(); // 执行游戏流程 }; class DDZHumanPlayer : public DDZPlayer { public: DDZHumanPlayer(string name) : DDZPlayer(name) {}; vector play(); }; // ---------------------------------------------------------------------------- int main() { srand(0x5942B); DDZPlayer p1("Alice"), p2("Bob"), p3("Charlie"); DDZGame g(&p1, &p2, &p3); g.run(); return 0; } /*int main2() { string name; cout << "Please input your name:" << endl; getline(cin, name); srand(0x5942B); DDZPlayer p1("Alice"), p2("Bob"); DDZHumanPlayer p3(name); DDZGame g(&p1, &p2, &p3); g.run(); return 0; } */ /* bool Card::operator <(const Card &other) const { int a = -1, b = -1; for (int i = 0; i < N_CARD_VALUES; ++i) { if (*this == CARD_VALUES[i]) a = i; if (other == CARD_VALUES[i]) b = i; } return a < b; } bool Card::operator >(const Card &other) const { return other < *this; } */ DDZPlayer::DDZPlayer(string name) : name(name) { // 玩家类的构造函数 prePos = -1; } string DDZPlayer::getName() { return name; } void DDZPlayer::substractFromHand(vector cards) { // 这个函数从hand中删除cards。假设cards中的牌hand可以拿得出来(否则会出错)。 sort(hand.begin(), hand.end(), greater()); sort(cards.begin(), cards.end(), greater()); vector::iterator i = hand.begin(), k = cards.begin(); for (vector::iterator j = hand.begin(); j != hand.end(); ++j) { if (k == cards.end() || *k != *j) *(i++) = *j; else if (k != cards.end()) ++k; } hand.erase(i, hand.end()); } void DDZPlayer::showHand() { // 输出玩家名和手牌。 cout << name << " holds: "; for (vector::iterator i = hand.begin(); i != hand.end(); ++i) { cout << *i << " "; } cout << endl; } void DDZPlayer::draw(Card card) { // 将card加入手牌 hand.push_back(card); sort(hand.begin(), hand.end(), greater()); } void DDZPlayer::draw(vector cards) { // 将cards中的牌加入手牌 hand.insert(hand.end(), cards.begin(), cards.end()); sort(hand.begin(), hand.end(), greater()); } void DDZPlayer::setPosition(int pos) { position = pos; } void DDZPlayer::observed(int pos, vector cards) { // 将上一个出牌的人和出了什么牌记录下来。 // 如果你想记录更多的信息供你的策略使用,可以改动这个函数。 // 例如,记录已经有哪些牌被打出(记牌器),以推测场上是否可能还存在炸弹。 if (cards.size() == 0) return; prePos = pos; prePlay = cards; } vector DDZPlayer::play() { // 轮到你出牌,返回打出的牌。 // TODO:(第一题)请完善这个函数 // 如果你使用不同的数据结构进行处理,你可以现将hand变量转换为你使用的结构, // 处理过后再将打出的牌转换为vector,存入card变量。 vector cards; int *a = new int[15]; int *b = new int[15]; for (int i = 0; i < 15; i++) b[i] = a[i] = 0; a = convert_vector_to_my(hand); if (prePos == position || prePos == -1) { // 出任意牌 a = chu_pai(a, b);//a: hand; b: card played } else { b = convert_vector_to_my(prePlay); a = play1(a, b); // 位于prePos的玩家打出了prePlay的牌,你需要出什么牌? } // 你需要保证打出的牌是合法的 // assert函数在参数为false的时候会使程序报错退出。 // 这样做的好处是,如果你有没注意到的错误导致程序在此报错退出, // 你就知道是在出牌的合法性上出了问题,而不用排查程序的其他部分。 // assert(legal(cards)); hand = convert_my_to_vector(a); showHand(); // 将打出的牌从手牌中删去 //substractFromHand(cards); cards = convert_my_to_vector(b); return cards; } bool DDZPlayer::leftNoCard() { // 返回当前手牌为空 return hand.empty(); } const int Card::N_CARD_VALUES = 15; const int Card::N_CARD_SUITS = 4; const string Card::CARD_VALUES[] = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2", "joker", "JOKER" }; const string Card::CARD_SUITS[] = { "Spades", "Hearts", "Diamonds", "Clubs" }; vector Card::get_new_deck() { // 生成一副新牌 vector deck; for (int i = 0; i < N_CARD_VALUES - 2; ++i) { for (int j = 0; j < N_CARD_SUITS; ++j) { Card card(CARD_VALUES[i]); deck.push_back(card); } } deck.push_back(Card(CARD_VALUES[13])); deck.push_back(Card(CARD_VALUES[14])); return deck; } int DDZGame::my_random(int i) { return std::rand() % i; } DDZGame::DDZGame(DDZPlayer *p1, DDZPlayer *p2, DDZPlayer *p3) { // 牌局类的构造函数,需要接受三个玩家作为参数 players.push_back(p1); players.push_back(p2); players.push_back(p3); } void DDZGame::showCards(vector cards) { sort(cards.begin(), cards.end(), greater()); for (vector::iterator i = cards.begin(); i != cards.end(); ++i) { cout << *i << " "; } if (cards.size() == 0) cout << "YAO BU QI"; cout << endl << endl; } void DDZGame::run() { // 斗地主游戏的主要流程 // 取一副新牌并洗牌 vector deck = Card::get_new_deck(); random_shuffle(deck.begin(), deck.end(), my_random); // 每个玩家抽17张牌,留下三张底牌 for (int i = 0; i < 54 - 3; ++i) players[i % 3]->draw(deck[i]); // 随机选取地主,发给地主最后三张牌 // * 你可以实现自己的叫地主流程, // * 你需要在DDZPlayer类里面加入相应的变量(存储其他玩家叫地主的情况) // * 和函数bool DDZPlayer::bid()(返回自己是否要叫地主)。 // * 请参阅play()函数和叫地主的规则设计这个流程。 int landlordPos = my_random(3); for (int i = 54 - 3; i < 54; ++i) players[landlordPos]->draw(deck[i]); for (int i = 0; i < 3; ++i) players[i]->setPosition((i + 3 - landlordPos) % 3); // 计算与地主的相对位置 cout << players[landlordPos]->getName() << " is the landlord." << endl; int currentPlayer = landlordPos; while (1) { // 当前玩家打牌 vector currentCards = players[currentPlayer]->play(); cout << players[currentPlayer]->getName() << " plays:"; showCards(currentCards); // 其他玩家看到了打出的牌。(并不是只有下家看到,上家也能看到) for (int i = 0; i < 3; ++i) { // 玩家看到的位置编号都是从地主为0开始的 int relativePos = (currentPlayer + 3 - landlordPos) % 3; players[i]->observed(relativePos, currentCards); } // 如果刚出完牌的玩家没有牌了游戏结束 if (players[currentPlayer]->leftNoCard()) { bool landlordwins = (currentPlayer == landlordPos); cout << (landlordwins ? "Landlord wins!" : "Farmers win!") << endl; break; } // 计算下一个玩家的下标 currentPlayer = (currentPlayer + 1) % 3; } }