扎金花

来源:互联网 发布:c语言中flag=1 编辑:程序博客网 时间:2024/04/30 21:55

 

18岁以下少年儿童请自觉远离赌博,18岁以上少年儿童请把赌博游戏转变成健康的休闲游戏,别掺进¥。

这两天弄了一个扎金花,体会到一个问题:软件工程是提高编程工作效率的必由之路。我们意识不到是因为我们现阶段涉及不到太复杂的设计。在必要的时候,还是得饿补一下OOAD,UML这些东西呀

如果知道扎金花怎么玩的可以直接跳过这一段:扎金花是我国广泛流传的一款扑克牌游戏,参与游戏者可为2-6人。游戏采用52张牌(去除大小王),庄家会给每人发三张牌,拿牌之后开始下注。按照“比较规则”决定胜负。下边按大小顺序依次介绍:三张一样的叫“暴子”,同花顺叫“顺金”,同花但不顺叫“金”,对子(大家都知道),普通牌,然后是不同花的235,以上的一级比一级小,如果两个人级别相同,就比较谁的牌面大。不同花235可以管暴子。

这个类图肯定有错误,因为我就没学过UML

如果上来就编什么也不想的话,弯路一定不会少走地。下面是实现。

#include <stdio.h>

#include <conio.h>

#include <iostream>

#include <vector>

#include <string>

using namespace std;

 

enum Color { diamond = 0, club, heart, spade, joker };

 

扑克牌作为一个类。一张扑克牌的实例包括2个数据成员Color和iint,通过这两个值来指示唯一的一张扑克。A的int值用14来表示,joker用15,16,这样便于排序工作。

 

class Card {

private:

  Color color;

  int   number;

public:

  void set(Color color, int number) {

    this->color = color; this->number = number;

  }

  Card operator =(const Card &card) {

    this->color = card.color; this->number = card.number;

    return *this;

  }

  void put(int x, int y) {

    gotoxy(x, y);

    switch(color) {

      case spade  : putch(6); break;

      case heart  : textcolor(4); putch(3); break;

      case club   : putch(5); break;

      case diamond: textcolor(4); putch(4); break;

      case joker  :

        if(number == 15) { putch('j'); putch('k'); }

        else if(number == 16) {

          textcolor(4); putch('J'); putch('K'); textcolor(7);

        }

        return;

    }

    switch(number) {

      case 10: putch('1'); putch('0'); break;

      case 11: putch('J'); putch(' '); break;

      case 12: putch('Q'); putch(' '); break;

      case 13: putch('K'); putch(' '); break;

      case 14: putch('A'); putch(' '); break;

      default: putch(number+48); putch(' ');

    }

    textcolor(7);

  }

  Color getClr() { return color; }

  int getNum() { return number; }

};

在这个程序里的一幅扑克牌里的扑克牌,以及参赛选手,我都放在一个vector里,这样可以不关心他们的数量。扩展vector,提供一个sort()函数以对一幅扑克牌进行基数排序:数字是第一关键字,花色是第二关键字。

class vectorx : public vector<Card> {

public:

  void sort() {

    int i, j;

    Card temp;

    for(i = 0; i < this->size()-1; i++)

      for(j = 0; j < this->size()-1; j++)

        if(this->at(j).getNum() <= this->at(j+1).getNum()) {

          temp = this->at(j);

          this->at(j) = this->at(j+1);

          this->at(j+1) = temp;

        }

    for(i = 0; i < this->size()-1; i++)

      for(j = 0; j < this->size()-1; j++)

        if(this->at(j).getNum() == this->at(j+1).getNum() &&

           this->at(j).getClr() <= this->at(j+1).getClr()) {

          temp = this->at(j);

          this->at(j) = this->at(j+1);

          this->at(j+1) = temp;

        }

  }

};

 

每一个玩家Player有以下几个我们需要关心的属性:他的名字name,他手头的牌hand,他手头的筹码数chips。这里浪费时间最长的就是给3张牌打分的函数了,似乎写得不好,没什么扩充性,很死板。

 

class Player {

private:

  string name;

  vectorx hand;

  int chips;

  int x, y;

public:

  Player(string name, int chips, int x, int y) {

    this->name = name; this->chips = chips;

    this->x = x; this->y = y;   

  }

  void get(Card card) { hand.push_back(card); }

  //通过get()函数接收扑克牌。

  void clear() { while(!hand.empty()) hand.pop_back(); }

  //通过clear()函数清空手中的扑克牌。

  void hide() {

  //这个函数用于显示对手的扑克牌的牌背。

    gotoxy(x+16, y+1); printf("$%5d", chips);

    vectorx::iterator Iter;

    int i = x+4;

    for(Iter = hand.begin(); Iter != hand.end(); Iter++) {

      gotoxy(i, y+3); printf("%c%c%c", 177, 177, 177); //177就是一个灰色的ASCII码,作为牌背。

      i += 6;

    }

  }

  void status() {

  //显示完整的状态,包括当前筹码数和手中的三张牌

    gotoxy(x+16, y+1); printf("$%5d", chips);

    vectorx::iterator Iter;

    int i = x+4;

    for(Iter = hand.begin(); Iter != hand.end(); Iter++) {

      Iter->put(i, y+3); i += 6;

    }

  }

  void frame() {

  //用户状态的框架。

    gotoxy(x, y);

    printf("%c", 218);

    for(int i = 0; i < 21; i++) printf("%c", 196);

    printf("%c", 183);

    gotoxy(x, y+1); printf("%c                     %c", 179, 186);

    gotoxy(x+1, y+1); cout << name;

    gotoxy(x, y+2);

    printf("%c", 195);

    for(int i = 0; i < 21; i++) printf("%c", 196);

    printf("%c", 182);

    gotoxy(x, y+3); printf("%c  [   ] [   ] [   ]  %c", 179, 186);

    gotoxy(x, y+4);

    printf("%c", 212);

    for(int i = 0; i < 21; i++) printf("%c", 205);

    printf("%c/n", 188);

  }

  int score() {

  //为手中三张牌打分的函数。

    vectorx temp;

    temp.assign(hand.begin(), hand.end());

    temp.sort();

    unsigned result;

    result = temp[2].getNum() - 1;

    result += ((temp[1].getNum()-1) << 4);

    result += ((temp[0].getNum()-1) << 8);

    //顺子

    bool series   = (temp[0].getNum()-temp[1].getNum()==1 &&

                    temp[1].getNum()-temp[2].getNum()==1) ||

                    (temp[0].getNum()==14 && temp[1].getNum()==3 &&

                    temp[2].getNum()==2);

    //

    bool suit     = temp[0].getClr()==temp[1].getClr() &&

                    temp[1].getClr()==temp[2].getClr();

    //暴子(不知道英语怎么说:

    bool elephant = temp[0].getNum()==temp[1].getNum() &&

                    temp[1].getNum()==temp[2].getNum();

    //2,3,5,老鼠吃大象

    bool mause    = temp[0].getNum()==5 && temp[1].getNum()==3 &&

                    temp[2].getNum()==2 && !suit;

    if(!suit && temp[0].getNum()==temp[1].getNum()) {

      result += ((temp[0].getNum()-1) << 12); return result;

    }

    if(!suit && temp[1].getNum()==temp[2].getNum()) {

      result += ((temp[1].getNum()-1) << 12); return result;

    }

    if(!suit && series) { result += ((temp[0].getNum()-1) << 16); return result; }

    if(suit && !series) { result += ((temp[0].getNum()-1) << 20); return result; }

    if(suit && series)  { result += ((temp[0].getNum()-1) << 24); return result; }

    if(elephant) { result += ((temp[0].getNum()-1) << 28); return result; }

    if(mause) { return -1; }

    return result;

  }

  int go(int gc) {

  //压筹码

    chips -= gc;

    return gc;

  }

  void win(int wc) { chips += wc; }

  //获胜结账

  int getChp() { return chips; }

  string getName() { return name; }

};

 

下边这个类用来随机发生姓名。这个挺有一般性的,以后也会用得到。

 

class Name {

  vector<string> names;

public:

  Name() {

    names.push_back("Adam");

    names.push_back("Ben");

    names.push_back("Michael");

    names.push_back("Jack");

    names.push_back("Philips");

    names.push_back("Eve");

    names.push_back("Susan");

    names.push_back("Jill");

    names.push_back("Rose");

    names.push_back("Maggie");

  }

  string nextName() {

    int i = ( (double)rand() / (double)RAND_MAX * names.size() );

    string ret = names[i];

    names.erase(names.begin()+i);

    return ret;

  }

};

以下是最中心的类。这里完成的是发牌,压注,结算等等工作。

class Playground {

private:

  vectorx poker;

  vector<Player> players;

  int totalgo;

public:

  Playground(int numplayer, int chips) {

     Player temp("You", chips, 55, 20);

     players.push_back(temp);

     Name name;

     for(int i = 1; i < numplayer; i++) {

       Player temp(name.nextName(), chips, 1, i*5-4);

       players.push_back(temp);

     }

     clrscr();

     vector<Player>::iterator Iter = players.begin();

     for(; Iter != players.end(); Iter++)

       Iter->frame();

  }

  void reshuffle() {

  //洗牌,就是重新建立一幅按顺序排列的扑克牌,把各位手中的牌清空。

    while(!poker.empty()) poker.pop_back();

    Card card;

    for(int i = 0; i < 4; i++)

      for(int j = 2; j <= 14; j++) {

        card.set(i, j);

        poker.push_back(card);

      }

     //card.set(joker, 15); poker.push_back(card);

     //card.set(joker, 16); poker.push_back(card);

     //注释掉的这两行是Jokers,在扎金花中用不到。

     vector<Player>::iterator Iter = players.begin();

     for(; Iter != players.end(); Iter++)

       Iter->clear();

     totalgo = 0;

  }

  void deal() {

  //发牌,由于reshuffle()中的牌实际上是按顺序排列的,这里就是从vector中随机抽出一张牌来,然后在vector中将其删除。

    for(int i = 0; i < players.size(); i++) {

      int todeal = ( (double)rand() / (double)RAND_MAX * poker.size() );

      players[i].get(poker[todeal]);

      poker.erase(poker.begin()+todeal);

    }

  }

  void go() {

  //简化了一下,玩家永远坐庄,所有人一定会跟同样的筹码(我懒得想了)

    int igo;

    gotoxy(1, 23); cout << "How many do you want to go?    ";

    gotoxy(28, 23); cin >> igo;

    totalgo += players[0].go(igo);

    vector<Player>::iterator Iter = players.begin();

    for(Iter++; Iter != players.end(); Iter++)

      totalgo += Iter->go(igo);

    int max = 0;

    for(int i = 1; i < players.size(); i++)

      if(players[i].score() > players[max].score())

        max = i;

    players[max].win(totalgo);

    gotoxy(40, 10); cout << players[max].getName() << " win!       ";

  }

  bool finish() {

  //判断是不是继续玩下去,就得有人要输衣服了...

    bool flag = false;

    vector<Player>::iterator Iter = players.begin();

    for(; Iter != players.end(); Iter++)

      if(Iter->getChp() <= 0)

        flag = true;

    return flag;

  }

  void show() {

  //显示自己的牌,对手的显示牌背。

     vector<Player>::iterator Iter = players.begin();

     Iter->status();

     for(Iter++; Iter != players.end(); Iter++)

       Iter->hide();

  }

  void reveal() {

  //显示所有人的牌。

     vector<Player>::iterator Iter = players.begin();

     for(; Iter != players.end(); Iter++)

       Iter->status();

  }

};

这样的设计虽然“面向对象了”,可我总觉得在哪儿有什么别扭的??不怕你笑话,我以前没学过C++,刚刚接触一个多月。一挠头全是头皮削...

 

下载(BCC5.5编译)>>>

 

原创粉丝点击