// Please use UTF-8 encoding so that the comments can be displayed correctly. // 标注TODO的是你需要完善的地方 #include #include #include #include #include #include #include #include #include #include using namespace std; class Card : public string { public: static const int N_CARD_VALUES; static const int N_CARD_SUITS; 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(); // 返回是否打完了牌? }; 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 main2() { srand(0x5942B); DDZPlayer p1("Alice"), p2("Bob"), p3("Charlie"); DDZGame g(&p1, &p2, &p3); g.run(); return 0; } int main() { 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; } bool DDZPlayer::legal(vector cards) { // 通过上家打出的牌prePlay和手牌hand判断cards作为打出牌是否合法 // TODO:(第二题)请补全这个函数 int HAND[15]; memset(HAND, 0, sizeof(int) * 15); int count0 = hand.size(); for (int i = 0; i < count0; i++) { if (hand[i] == "JOKER") HAND[14]++; else if (hand[i] == "joker") HAND[13]++; else if (hand[i] == "2") HAND[12]++; else if (hand[i] == "A") HAND[11]++; else if (hand[i] == "K") HAND[10]++; else if (hand[i] == "Q") HAND[9]++; else if (hand[i] == "J") HAND[8]++; else if (hand[i] == "10") HAND[7]++; else if (hand[i] == "9") HAND[6]++; else if (hand[i] == "8") HAND[5]++; else if (hand[i] == "7") HAND[4]++; else if (hand[i] == "6") HAND[3]++; else if (hand[i] == "5") HAND[2]++; else if (hand[i] == "4") HAND[1]++; else if (hand[i] == "3") HAND[0]++; } int deal[15]; memset(deal, 0, sizeof(int) * 15); int count = cards.size(); if (count == 0) return true; int other = 0; for (int i = 0; i < count; i++) { if (cards[i] == "JOKER") deal[14]++; else if (cards[i] == "joker") deal[13]++; else if (cards[i] == "2") deal[12]++; else if (cards[i] == "A") deal[11]++; else if (cards[i] == "K") deal[10]++; else if (cards[i] == "Q") deal[9]++; else if (cards[i] == "J") deal[8]++; else if (cards[i] == "10") deal[7]++; else if (cards[i] == "9") deal[6]++; else if (cards[i] == "8") deal[5]++; else if (cards[i] == "7") deal[4]++; else if (cards[i] == "6") deal[3]++; else if (cards[i] == "5") deal[2]++; else if (cards[i] == "4") deal[1]++; else if (cards[i] == "3") deal[0]++; else other++; } for (int i = 0; i < 15; i++) if (deal[i] > HAND[i]) return false; if (other > 0) return false; if (prePos == position || prePos == -1) { // 出任意牌 int flag = 0; int num1 = 0, num2 = 0, num3 = 0, num4 = 0, num = 0, num0 = 0; for (int i = 0; i < 15; i++) { if (deal[i] >= 5) num++; else if (deal[i] == 4) num4++; else if (deal[i] == 3) num3++; else if (deal[i] == 2) num2++; else if (deal[i] == 1) num1++; else if (deal[i] == 0) num0++; } if (num > 0 || num0 == 15) return false; if (deal[13] == 1 && deal[14] == 1) return true; //王炸 if (num1 == 1 && num2 == 0 && num3 == 0 && num4 == 0) return true; //单张 if (num1 == 0 && num2 == 1 && num3 == 0 && num4 == 0) return true; //对子 if (num3 == 1 && num4 == 0 && ((num1 == 1 && num2 == 0) || (num1 == 0 && num2 == 1) || (num1 == 0 && num2 == 0))) return true; //三带 if (num1 == 0 && num2 == 0 && num3 == 0 && num4 == 1) return true; //炸弹 if (num4 == 1 && (num1 == 2 || num2 == 1 || num2 == 2) && num3 == 0) return true; //四带二 //判断飞机、连对、顺子 int maxn = -1; for (int i = 0; i < 15; i++) { if (maxn < deal[i]) maxn = deal[i]; } if (maxn == 1 && num1 >= 5) { int y = -1; for (int i = 0; i <= 12; i++) if (deal[i] == 1) { y = i; break; } for (int t = y; t <= y + num1 - 1; t++) { if (deal[t] == 1) flag = 1; else { flag = 0; break; } } if (flag == 1) return true; if (flag == 0) return false; } if (maxn == 2 && num1 == 0 && num2 >= 3) { int y = -1; for (int i = 0; i <= 12; i++) if (deal[i] == 2) { y = i; break; } for (int t = y; t <= y + num2 - 1; t++) { if (deal[t] == 2) flag = 1; else { flag = 0; break; } } if (flag == 1) return true; if (flag == 0) return false; } if (maxn == 3 && num3 >= 2) { int y = -1; for (int i = 0; i <= 12; i++) if (deal[i] == 3) { y = i; break; } for (int t = y + 1; t <= y + num3 - 1; t++) { if (deal[t] == 3) flag = 1; else { flag = 0; break; } } if (flag == 1) return true; if (flag == 0) return false; } } else { int max = -1; int PLAY[15]; memset(PLAY, 0, sizeof(int) * 15); int count1 = prePlay.size(); for (int i = 0; i < count1; i++) { if (prePlay[i] == "JOKER") PLAY[14]++; else if (prePlay[i] == "joker") PLAY[13]++; else if (prePlay[i] == "2") PLAY[12]++; else if (prePlay[i] == "A") PLAY[11]++; else if (prePlay[i] == "K") PLAY[10]++; else if (prePlay[i] == "Q") PLAY[9]++; else if (prePlay[i] == "J") PLAY[8]++; else if (prePlay[i] == "10") PLAY[7]++; else if (prePlay[i] == "9") PLAY[6]++; else if (prePlay[i] == "8") PLAY[5]++; else if (prePlay[i] == "7") PLAY[4]++; else if (prePlay[i] == "6") PLAY[3]++; else if (prePlay[i] == "5") PLAY[2]++; else if (prePlay[i] == "4") PLAY[1]++; else if (prePlay[i] == "3") PLAY[0]++; } for (int i = 0; i < 15; i++) if (max < PLAY[i]) max = PLAY[i]; if (max == 1) { int flag = 0, num = 0, max = -1; for (int i = 0; i < 15; i++) //判断顺子or单张 if (PLAY[i] == 1) { num++; max = i; //存储最大的牌 } if (num == 1) //单张 { for (int i = max + 1; i < 15; i++) if (deal[i] >= 1) { flag = 1; return true; } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) return true; } return false; } else if (num >= 5) { int p; for (int t = max - num + 2; t <= 12 - num + 1; t++) { for (int r = t; r <= t + num - 1; r++) { if (deal[r] >= 1) { flag = 1; p = r; } else { flag = 0; break; } } if (flag == 1) return true; } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { flag = 1; return true; } } return false; } } if (max == 2) { int flag = 0, num = 0, max = -1; for (int i = 0; i < 15; i++) //判断连对or对子 if (PLAY[i] == 2) { num++; max = i; //存储最大的牌 } if (num == 1) //对子 { for (int i = max + 1; i < 15; i++) if (deal[i] >= 2) { flag = 1; return true; } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { flag = 1; return true; } }return false; } else if (num >= 3) //连对 { int p; for (int t = max - num + 2; t <= 12 - num + 1; t++) { for (int r = t; r <= t + num - 1; r++) { if (deal[r] >= 2) { flag = 1; p = r; } else { flag = 0; break; } } if (flag == 1) return true; } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { flag = 1; return true; } } return false; } } if (max == 3) { int flag = 0, num = 0, max = -1, num2 = 0, num1 = 0; int left[100], t; for (int i = 0; i < 15; i++) //判断飞机or三带 { if (PLAY[i] == 3) { num++; max = i; //存储最大的牌 } else if (PLAY[i] == 2) { num2++; //统计带一对的数量 } else if (PLAY[i] == 1) { num1++; //统计带一张的数量 } } if (num == 1) //三带 { for (t = max + 1; t < 15; t++) if (deal[t] >= 3) break; if (t <= 13) //三带一or三带二or三带 { if (num1 == 1) //三带一 { for (int r = 0; r < 15; r++) if (deal[r] >= 1 && r != t) { flag = 1; return true; } } else if (num2 == 1) //三带二 { for (int r = 0; r < 15; r++) if (deal[r] >= 2 && r != t) { flag = 1; return true; } } else //三带 { flag = 1; return true; } } else { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { flag = 1; return true; } } return false; } else if (num >= 2) { int p; for (int w = max - num + 2; w <= 12 - num + 1; w++) { for (int r = w; r <= w + num - 1; r++) { if (deal[r] >= 3) { flag = 1; p = r; } else { flag = 0; break; } } } if (flag == 1) //大翼or小翼or无翼 { if (num1 == num) //小翼 { int u = 0; for (int i = 0; i < 15 && u < 2; i++) { if (deal[i] >= 2) { left[u] = i; left[u + 1] = i; u = u + 2; } else if (deal[i] == 1) { left[u] = i; u++; } } if (u == num1) { return true; flag = 1; } else flag = 0; } else if (num2 == num) //大翼 { int u = 0; for (int r = 0; u < num2&&r < 15; r++) { if (deal[r] >= 2) { left[u] = r; u++; } } if (u == num2) { flag = 1; return true; } else flag = 0; } else //不带翼 { flag = 1; return true; } } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { flag = 1; return true; } } return false; } } if (max == 4) { int flag = 0, num1 = 0, num2 = 0, max = -1, t, left[10]; for (int i = 0; i < 15; i++) if (PLAY[i] == 2) num2++; else if (PLAY[i] == 1) num1++; for (int i = 0; i < 15; i++) if (PLAY[i] == 4) { max = i; break; } for (t = max + 1; t<15; t++) if (deal[t] == 4) { flag = 1; break; } if (flag == 1) //存在四连 { int u = 0; if (num1 == 2 || num2 == 1) //四带二 { for (int i = 0; i < 15 && u < 2; i++) { if (deal[i] >= 2 && i != t) { left[u] = i; left[u + 1] = i; u = u + 2; } else if (deal[i] == 1 && i != t) { left[u] = i; u++; } } if (u == 2) { flag = 1; return true; } else flag = 0; } else if (num1 == 0 && num2 == 2) //四带两对 { for (int i = 0; i < 15 && u < 2; i++) { if (deal[i] >= 2 && i != t) { left[u] = i; u++; } } if (u == 2) { flag = 1; return true; } else flag = 0; } if ((num1 == 0 && num2 == 0) || flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { flag = 1; return true; } substractFromHand(cards); return false; } } else if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { flag = 1; return true; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { flag = 1; return true; } return false; } } } return false; } 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; Card ctmp; int deal[15]; memset(deal, 0, sizeof(int) * 15); for (int i = 0; i < hand.size(); i++) { if (hand[i] == "JOKER") deal[14]++; else if (hand[i] == "joker") deal[13]++; else if (hand[i] == "2") deal[12]++; else if (hand[i] == "A") deal[11]++; else if (hand[i] == "K") deal[10]++; else if (hand[i] == "Q") deal[9]++; else if (hand[i] == "J") deal[8]++; else if (hand[i] == "10") deal[7]++; else if (hand[i] == "9") deal[6]++; else if (hand[i] == "8") deal[5]++; else if (hand[i] == "7") deal[4]++; else if (hand[i] == "6") deal[3]++; else if (hand[i] == "5") deal[2]++; else if (hand[i] == "4") deal[1]++; else if (hand[i] == "3") deal[0]++; } if (prePos == position || prePos == -1) { // 出任意牌 int maxn = -1; int flag = 0; for (int i = 0; i < 15; i++) { if (maxn < deal[i]) maxn = deal[i]; } if (maxn >= 3) { int p; for (int i = 0; i <= 11; i++) //寻找三连的飞机 { if (deal[i] >= 3 && deal[i + 1] >= 3) { flag = 1; p = i + 1; break; } else flag = 0; } if (flag == 1) { int num2 = 0; int num1 = 0; int left2[10], left1[10]; for (int i = 0; i < 15; i++) if (deal[i] >= 2 && i != p&&i != p - 1) left2[num2++] = i; else if (deal[i] >= 1 && i != p&&i != p - 1) left1[num1++] = i; if (num2 >= 2) { for (int i = 0; i < 3; i++) cards.push_back(ctmp.CARD_VALUES[p]); for (int i = 3; i<6; i++) cards.push_back(ctmp.CARD_VALUES[p - 1]); for (int i = 6; i<8; i++) cards.push_back(ctmp.CARD_VALUES[left2[0]]); for (int i = 8; i<10; i++) cards.push_back(ctmp.CARD_VALUES[left2[1]]); substractFromHand(cards); return cards; } else if (num1 >= 2) { for (int i = 0; i < 3; i++) cards.push_back(ctmp.CARD_VALUES[p]); for (int i = 3; i<6; i++) cards.push_back(ctmp.CARD_VALUES[p - 1]); cards.push_back(ctmp.CARD_VALUES[left1[0]]); cards.push_back(ctmp.CARD_VALUES[left1[1]]); substractFromHand(cards); return cards; } else { for (int i = 0; i < 3; i++) cards.push_back(ctmp.CARD_VALUES[p]); for (int i = 3; i<6; i++) cards.push_back(ctmp.CARD_VALUES[p - 1]); substractFromHand(cards); return cards; } } else //三带一 { int left; for (int i = 0; i < 15; i++) { if (deal[i] >= 3) { p = i; break; } } for (int i = 0; i < 15; i++) { if (deal[i] >= 1&&i!=p) { left = i; break; } } if (deal[left] >= 2) { for (int i = 0; i < 3; i++) cards.push_back(ctmp.CARD_VALUES[p]); for (int i = 3; i<5; i++) cards.push_back(ctmp.CARD_VALUES[left]); substractFromHand(cards); return cards; } else if (deal[left] >= 1) { for (int i = 0; i < 3; i++) cards.push_back(ctmp.CARD_VALUES[p]); cards.push_back(ctmp.CARD_VALUES[left]); substractFromHand(cards); return cards; } else { for (int i = 0; i < 3; i++) cards.push_back(ctmp.CARD_VALUES[p]); substractFromHand(cards); return cards; } } } if (maxn == 2) { int p; for (int i = 0; i <= 10; i++) { if (deal[i] >= 2 && deal[i + 1] >= 2 && deal[i + 2] >= 2) { flag = 1; p = i + 2; break; } else flag = 0; } if (flag == 1) { for (int i = 0; i < 2; i++) cards.push_back(ctmp.CARD_VALUES[p]); for (int i = 2; i < 4; i++) cards.push_back(ctmp.CARD_VALUES[p - 1]); for (int i = 4; i < 6; i++) cards.push_back(ctmp.CARD_VALUES[p - 2]); substractFromHand(cards); return cards; } else { for (int i = 0; i < 15; i++) if (deal[i] >= 2) { p = i; for (int i = 0; i < 2; i++) cards.push_back(ctmp.CARD_VALUES[p]); substractFromHand(cards); return cards; } } } if (maxn == 1) { int num = 0, flag = 0, max = -1; for (int i = 0; i <= 7; i++) { for (int t = 0; t <= 5; t++) { if (deal[t] != 0) { flag = 1; num = t; } else { flag = 0; num = 0; break; } } } if (flag == 1) { cards.push_back(ctmp.CARD_VALUES[num]); cards.push_back(ctmp.CARD_VALUES[num - 1]); cards.push_back(ctmp.CARD_VALUES[num - 2]); cards.push_back(ctmp.CARD_VALUES[num - 3]); cards.push_back(ctmp.CARD_VALUES[num - 4]); cards.push_back(ctmp.CARD_VALUES[num - 5]); substractFromHand(cards); return cards; } else { for (int i = 0; i <= 8; i++) { for (int t = 0; t <= 4; t++) { if (deal[t] != 0) { flag = 1; num = t; } else { flag = 0; num = 0; break; } } } if (flag == 1) { cards.push_back(ctmp.CARD_VALUES[num]); cards.push_back(ctmp.CARD_VALUES[num - 1]); cards.push_back(ctmp.CARD_VALUES[num - 2]); cards.push_back(ctmp.CARD_VALUES[num - 3]); cards.push_back(ctmp.CARD_VALUES[num - 4]); substractFromHand(cards); return cards; } else { for (int i = 0; i <= 12; i++) if (deal[i] != 0) { cards.push_back(ctmp.CARD_VALUES[i]); substractFromHand(cards); return cards; } } } } } else { // 位于prePos的玩家打出了prePlay的牌,你需要出什么牌? cards.clear(); int PLAY[15]; memset(PLAY, 0, sizeof(int) * 15); int count1 = prePlay.size(); for (int i = 0; i < count1; i++) { if (prePlay[i] == "JOKER") PLAY[14]++; else if (prePlay[i] == "joker") PLAY[13]++; else if (prePlay[i] == "2") PLAY[12]++; else if (prePlay[i] == "A") PLAY[11]++; else if (prePlay[i] == "K") PLAY[10]++; else if (prePlay[i] == "Q") PLAY[9]++; else if (prePlay[i] == "J") PLAY[8]++; else if (prePlay[i] == "10") PLAY[7]++; else if (prePlay[i] == "9") PLAY[6]++; else if (prePlay[i] == "8") PLAY[5]++; else if (prePlay[i] == "7") PLAY[4]++; else if (prePlay[i] == "6") PLAY[3]++; else if (prePlay[i] == "5") PLAY[2]++; else if (prePlay[i] == "4") PLAY[1]++; else if (prePlay[i] == "3") PLAY[0]++; } int max = 0; for (int i = 0; i < 15; i++) if (max < PLAY[i]) max = PLAY[i]; if (max == 1) { int flag = 0, num = 0, max = -1; for (int i = 0; i < 15; i++) //判断顺子or单张 if (PLAY[i] == 1) { num++; max = i; //存储最大的牌 } if (num == 1) //单张 { for (int i = max + 1; i < 15; i++) if (deal[i] >= 1) { cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } } substractFromHand(cards); return cards; } else if (num >= 5) { int p; for (int t = max - num + 2; t <= 12 - num + 1; t++) { for (int r = t; r <= t + num - 1; r++) { if (deal[r] >= 1) { flag = 1; p = r; } else { flag = 0; break; } } if (flag == 1) break; } if (flag == 1) for (int i = p; i >= p - num + 1; i--) cards.push_back(ctmp.CARD_VALUES[i]); else { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } } substractFromHand(cards); return cards; } } if (max == 2) { int flag = 0, num = 0, max = -1; for (int i = 0; i < 15; i++) //判断连对or对子 if (PLAY[i] == 2) { num++; max = i; //存储最大的牌 } if (num == 1) //对子 { for (int i = max + 1; i < 15; i++) if (deal[i] >= 2) { cards.push_back(ctmp.CARD_VALUES[i]); cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } }substractFromHand(cards); return cards; } else if (num >= 3) //连对 { int p; for (int t = max - num + 2; t <= 12 - num + 1; t++) { for (int r = t; r <= t + num - 1; r++) { if (deal[r] >= 2) { flag = 1; p = r; } else { flag = 0; break; } } if (flag == 1) break; } if (flag == 1) for (int i = p; i >= p - num + 1; i--) { cards.push_back(ctmp.CARD_VALUES[i]); cards.push_back(ctmp.CARD_VALUES[i]); } else { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } } substractFromHand(cards); return cards; } } if (max == 3) { int flag = 0, num = 0, max = -1, num2 = 0, num1 = 0; int left[100], t; for (int i = 0; i < 15; i++) //判断飞机or三带 { if (PLAY[i] == 3) { num++; max = i; //存储最大的牌 } else if (PLAY[i] == 2) { num2++; //统计带一对的数量 } else if (PLAY[i] == 1) { num1++; //统计带一张的数量 } } if (num == 1) //三带 { for (t = max + 1; t < 15; t++) if (deal[t] >= 3) break; if (t <= 13) //三带一or三带二or三带 { if (num1 == 1) //三带一 { for (int r = 0; r < 15; r++) if (deal[r] >= 1 && r != t) { if (r > t) { cards.push_back(ctmp.CARD_VALUES[r]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); flag = 1; break; } else { cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[r]); flag = 1; break; } } } else if (num2 == 1) //三带二 { for (int r = 0; r < 15; r++) if (deal[r] >= 2 && r != t) { if (r > t) { cards.push_back(ctmp.CARD_VALUES[r]); cards.push_back(ctmp.CARD_VALUES[r]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); flag = 1; break; } else { cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[r]); cards.push_back(ctmp.CARD_VALUES[r]); flag = 1; break; } } } else //三带 { cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); flag = 1; } } else { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } } substractFromHand(cards); return cards; } else if (num >= 2) { int p; for (int w = max - num + 2; w <= 12 - num + 1; w++) { for (int r = w; r <= w + num - 1; r++) { if (deal[r] >= 3) { flag = 1; p = r; } else { flag = 0; break; } } } if (flag == 1) //大翼or小翼or无翼 { if (num1 == num) //小翼 { int u = 0; for (int i = 0; i < 15 && u < 2; i++) { if (deal[i] >= 2) { left[u] = i; left[u + 1] = i; u = u + 2; } else if (deal[i] == 1) { left[u] = i; u++; } } if (u == num1) { for (int b = p; b >= p - num + 1; b--) { cards.push_back(ctmp.CARD_VALUES[b]); cards.push_back(ctmp.CARD_VALUES[b]); cards.push_back(ctmp.CARD_VALUES[b]); } for (int b = num1 - 1; b >= 0; b--) cards.push_back(ctmp.CARD_VALUES[left[b]]); flag = 1; } else flag = 0; } else if (num2 == num) //大翼 { int u = 0; for (int r = 0; u < num2&&r < 15; r++) { if (deal[r] >= 2) { left[u] = r; u++; } } if (u == num2) { for (int b = p; b >= p - num + 1; b--) { cards.push_back(ctmp.CARD_VALUES[b]); cards.push_back(ctmp.CARD_VALUES[b]); cards.push_back(ctmp.CARD_VALUES[b]); } for (int b = num2 - 1; b >= 0; b--) { cards.push_back(ctmp.CARD_VALUES[left[b]]); cards.push_back(ctmp.CARD_VALUES[left[b]]); } flag = 1; } else flag = 0; } else //不带翼 { for (int b = p; b >= p - num + 1; b--) { cards.push_back(ctmp.CARD_VALUES[b]); cards.push_back(ctmp.CARD_VALUES[b]); cards.push_back(ctmp.CARD_VALUES[b]); } flag = 1; } } if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } } substractFromHand(cards); return cards; } } if (max == 4) { int flag = 0, num1 = 0, num2 = 0, max = -1, t, left[10]; for (int i = 0; i < 15; i++) if (PLAY[i] == 2) num2++; else if (PLAY[i] == 1) num1++; for (int i = 0; i < 15; i++) if (PLAY[i] == 4) { max = i; break; } for (t = max + 1; t<15; t++) if (deal[t] == 4) { flag = 1; break; } if (flag == 1) //存在四连 { int u = 0; if (num1 == 2 || num2 == 1) //四带二 { for (int i = 0; i < 15 && u < 2; i++) { if (deal[i] >= 2 && i != t) { left[u] = i; left[u + 1] = i; u = u + 2; } else if (deal[i] == 1 && i != t) { left[u] = i; u++; } } if (u == 2) { cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[left[0]]); cards.push_back(ctmp.CARD_VALUES[left[1]]); flag = 1; } else flag = 0; } else if (num1 == 0 && num2 == 2) //四带两对 { for (int i = 0; i < 15 && u < 2; i++) { if (deal[i] >= 2 && i != t) { left[u] = i; u++; } } if (u == 2) { cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[t]); cards.push_back(ctmp.CARD_VALUES[left[0]]); cards.push_back(ctmp.CARD_VALUES[left[0]]); cards.push_back(ctmp.CARD_VALUES[left[1]]); cards.push_back(ctmp.CARD_VALUES[left[1]]); flag = 1; } else flag = 0; } if ((num1 == 0 && num2 == 0) || flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } substractFromHand(cards); return cards; } } else if (flag == 0) { for (int i = 0; i <= 12; i++) //寻找有没有炸弹 if (deal[i] == 4) { for (int t = 0; t < 4; t++) cards.push_back(ctmp.CARD_VALUES[i]); flag = 1; break; } if (flag == 0) //寻找王炸 if (deal[13] == 1 && deal[14] == 1) { cards.push_back(ctmp.CARD_VALUES[14]); cards.push_back(ctmp.CARD_VALUES[13]); flag = 1; } substractFromHand(cards); return cards; } } return cards; } // 你需要保证打出的牌是合法的 // assert函数在参数为false的时候会使程序报错退出。 // 这样做的好处是,如果你有没注意到的错误导致程序在此报错退出, // 你就知道是在出牌的合法性上出了问题,而不用排查程序的其他部分。 // assert(legal(cards)); // 将打出的牌从手牌中删去 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 (true) { // 当前玩家打牌 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; } } vector DDZHumanPlayer::play() { vector cards; string s, c; while (true) { showHand(); cout << "Please input the cards you want to play." << endl; getline(cin, s); istringstream iss(s); while (iss >> c) { cards.push_back(Card(c)); } // 现在cards是一个vector,存储了用户输入的牌 // 你需要检测输入的牌是持有的牌,并且合法。请完成legal函数。 if (legal(cards)) { break; } else { cout << "Illegal cards. Input again." << endl; cards.clear(); } } substractFromHand(cards); return cards; }