#include #include #include #include #include #include #include #include #include #include using namespace std; const int sr=400; struct poker { int type; int content[5]; }; 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; // 上一个出牌的人出了什么牌? void substractFromHand(vector cards); // 从当前手牌中删去cards中的牌 void select(int a[ ],int n) { int min,temp; for(int i=0;ia[j]) min=a[j]; for(int j=i;j cards); // 将cards中的牌加入手牌 void setPosition(int pos); // 初始化用,决定地主后设置 void showHand(); // 打印手牌 void observed(int pos, vector cards); // 观测到玩家出牌 vector play(); // 轮到自己时决定出什么牌 bool leftNoCard(); // 返回是否打完了牌? void leadin(char temp_card[ ],int i,int card[ ]) { //将temp_card中的牌面置入card数组的第i格 if(strcmp(temp_card,"3")==0) card[i]=3; else if(strcmp(temp_card,"4")==0) card[i]=4; else if(strcmp(temp_card,"5")==0) card[i]=5; else if(strcmp(temp_card,"6")==0) card[i]=6; else if(strcmp(temp_card,"7")==0) card[i]=7; else if(strcmp(temp_card,"8")==0) card[i]=8; else if(strcmp(temp_card,"9")==0) card[i]=9; else if(strcmp(temp_card,"10")==0) card[i]=10; else if(strcmp(temp_card,"J")==0) card[i]=11; else if(strcmp(temp_card,"Q")==0) card[i]=12; else if(strcmp(temp_card,"K")==0) card[i]=13; else if(strcmp(temp_card,"A")==0) card[i]=14; else if(strcmp(temp_card,"2")==0) card[i]=20; else if(strcmp(temp_card,"joker")==0) card[i]=50; else if(strcmp(temp_card,"JOKER")==0) card[i]=100; } void trans_array(vector& card,int _card[ ]) { //将card容器中的牌置入_card数组中,并对存储完成的_card数组进行排序 char temp_card[10]; int cards_number=card.size( ); for(int i=0;i& card,int n) { //将大小为n的牌置入card容器中 char temp_card[10]; leadout(n,temp_card); Card _card(temp_card); card.push_back(_card); } vector begin(int _card[ ],int number) { //从_cand数组中number张已经排序的手牌中随意出牌,并将出的牌返回 vector card; bool flag=1; int count=0,temp,i=0; //顺子 while(_card[i]==0) i++; while(i0) { if(_card[i]==temp+1) { temp=_card[i]; count++; i++; while(i=number&&count<5) { flag=0; break; } if(count==5) { flag=1; break; } } if(flag==1) { int te=temp; temp=temp-4; for(int j=0;jte) break; } return card; } else flag=1; } //对子 for(int i=0;i0&&_card[i]==_card[i+1]) { trans_vector(card,_card[i]); trans_vector(card,_card[i+1]); return card; } } //单张 for(int i=0;i0) { trans_vector(card,_card[i]); return card; } } } poker judge(int card[ ],int n) { //判断出的牌属于什么牌型,并将结果返回 poker po; bool flag=1; for(int i=0;i choose(poker po,int card[ ],int n) { //从n张牌的card数组中找出能压过po的最小的牌并返回 vector _card; switch(po.type) { case 1://对子 { for(int i=0;ipo.content[0]) { trans_vector(_card,card[i]); trans_vector(_card,card[i+1]); return _card; } } break; } case 4://顺子 { bool flag=1; int count=0,temp,i=0; while(card[i]<=po.content[0]) i++; while(i0) { if(card[i]==temp+1) { temp=card[i]; count++; i++; while(i=n&&count=begin+5) break; } return _card; } else flag=1; } break; } case 7://炸弹 { for(int i=0;ipo.content[0]) { trans_vector(_card,card[i]); trans_vector(_card,card[i+1]); trans_vector(_card,card[i+2]); trans_vector(_card,card[i+3]); return _card; } } break; } case 9://单张 { for(int i=0;ipo.content[0]) { trans_vector(_card,card[i]); return _card; } } break; } } if(po.type!=7&&po.type!=8)//炸弹 { for(int i=0;i0&&card[i]==card[i+1]&&card[i]==card[i+2]&&card[i]==card[i+3]) { trans_vector(_card,card[i]); trans_vector(_card,card[i+1]); trans_vector(_card,card[i+2]); trans_vector(_card,card[i+3]); return _card; } } } if(card[n-2]==50)//王炸 { trans_vector(_card,card[n-2]); trans_vector(_card,card[n-1]); return _card; } return _card; } }; 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(); // 执行游戏流程 }; // ---------------------------------------------------------------------------- int main() { srand(sr); DDZPlayer p1("Alice"), p2("Bob"), p3("Charlie"); DDZGame g(&p1, &p2, &p3); g.run(); system("pause"); 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变量。 int numbers=hand.size( ); //将手牌从hand容器转入card_on_hand数组 trans_array(hand,card_on_hand); vector cards; if (prePos == position || prePos == -1) { // 出任意牌 cards=begin(card_on_hand,numbers); } else { // 位于prePos的玩家打出了prePlay的牌,你需要出什么牌? int _numbers=prePlay.size( ); trans_array(prePlay,card_play); poker pok=judge(card_play,_numbers); cards=choose(pok,card_on_hand,numbers); } // 将打出的牌从手牌中删去 substractFromHand(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; } }