📜  为一副通用卡片设计数据结构(类和对象)

📅  最后修改于: 2021-09-10 02:38:28             🧑  作者: Mango

为一副通用纸牌设计数据结构 解释如何将其子类化以实现特定的纸牌游戏,以及如何将数据结构子类化以实现二十一点。

解决方案:

首先,我们需要认识到一副“通用”的纸牌可能意味着很多东西。通用可能意味着可以玩类似扑克游戏的标准纸牌,或者甚至可以扩展到 Uno 或棒球卡。

实施特定的纸牌游戏

让我们假设这套牌是标准的 52 张牌,就像您在二十一点或扑克游戏中看到的那样。如果是这样,设计可能如下所示:

这里的结构很清楚:一副套牌包含四套花色,一套花色包含 13 张牌。每张牌都有一个从 1 到 13 的数值。如果你考虑一个纸牌游戏,不同的游戏在发牌和放牌的方式上是不同的。所以我们可以在类 ‘Deck’ 中有一组抽象方法来允许子类实现自己的处理方式。我画的类图在这里:

下面是这个想法的 C++ 实现。

/*1. Investigation on an individual card instead of 
   a collection of cards, focus on a card's state 
   and interface.
2. A card game has its own specific constrain and 
   requirement on cards, such that a generic card 
   cannot satisfy a blackjack card
3. Player manage multiple cards */
  
#include 
using namespace std;
  
namespace SUIT {
enum Enum {
    SPADE,
    HEART,
    CLUB,
    DIAMOND
};
};
  
class Card {
private:
    SUIT::Enum s;
    int v;
  
public:
    virtual SUIT::Enum suit() const
    {
        return s;
    };
  
    virtual int val() const
    {
        return v;
    };
  
    Card(int val, SUIT::Enum suit)
        : s(suit), v(val){};
};
  
class BlackJackCard : public Card {
public:
    virtual int val()
    {
        int v = Card::val();
        if (v < 10)
            return v;
        return 10;
    }
  
    BlackJackCard(int val, SUIT::Enum suit)
        : Card(val, suit){};
};
  
class player {
private:
    int id;
    int bet;
    set points;
    vector bjcs;
    bool addPoint(set& amp; points, BlackJackCard * card)
    {
        if (points.empty()) {
            points.insert(card->val());
            if (card->val() == 1)
                points.insert(11);
        } else {
  
            /* Set elements are ALWAYS CONST, they can't
               be modified once inserted. */
            set tmp;
            for (auto it = points.begin(); it != points.end(); ++it) {
                tmp.insert(*it + card->val());
                if (card->val() == 1)
                    tmp.insert(*it + 11);
            }
            points = tmp;
        }
    }
  
    void getPoints()
    {
        cout << "You All Possible Points : " << endl;
        for (auto it = points.begin(); it != points.end(); ++it) {
            cout << *it << endl;
        }
    };
  
    int getMinPoints()
    {
        /* set is implemented by commonly BST, so else 
          are in order!!!
          learn to use lower_bound() and upper_bound()
          "they allow the direct iteration on subsets 
           based on their order."
          which gives us another option to find min. preferable */
  
        // return *(points.lower_bound(0));
        return *(points.begin());
    };
  
    void printCards()
    {
        cout << "You Cards : " << endl;
        for (auto it = bjcs.begin(); it != bjcs.end(); ++it) {
            cout << (*it)->val() << endl;
        }
    }
  
public:
    player(int i, int j)
        : id(i), bet(j)
    {
        bjcs.push_back(new BlackJackCard(rand() % 13 + 1, SUIT::SPADE));
        bjcs.push_back(new BlackJackCard(rand() % 13 + 1, SUIT::SPADE));
        addPoint(points, bjcs[0]);
        addPoint(points, bjcs[1]);
    };
  
    void getAnotherCard()
    {
        for (set::iterator it = points.begin(); it != points.end(); ++it) {
           
            /* predefined strategy for the player    */
            if (*it <= 21 && 21 - *it <= 4) {
                printCards();
                getPoints();
                cout << "Stand" << endl;
                exit(1);
            }
        }
        bjcs.push_back(new BlackJackCard(rand() % 13 + 1, SUIT::SPADE));
        addPoint(points, bjcs.back());
        if (getMinPoints() > 21) {
            printCards();
            getPoints();
            cout << "Busted" << endl;
            exit(2);
        }
    };
  
    virtual ~player()
    {
        for (auto it = bjcs.begin(); it != bjcs.end(); ++it) {
            delete *it;
        }
    };
};
// Driver code
int main()
{
    srand(time(NULL));
    player p(1, 1000);
    p.getAnotherCard();
    p.getAnotherCard();
    p.getAnotherCard();
  
    return 0;
}

输出:

You Cards : 
10
10
You All Possible Points : 
20
Stand

实施二十一点。

注意:现在,假设我们正在构建一个二十一点游戏,所以我们需要知道卡片的价值。人脸牌是 10,一张 A 是 11(大多数时候,但那是 Hand 类的工作,而不是下一个类)。

在二十一点游戏开始时,玩家和庄家各收到两张牌。玩家的牌通常面朝上发,而庄家有一张面朝下(称为底牌)和一张面朝上。

最好的 21 点牌是任何一张 10 点牌的 A 开牌。这被称为“二十一点”,或自然的 21,持有它的玩家自动获胜,除非庄家也有二十一点。如果玩家和庄家各有一张 21 点,则结果是该玩家被推动。如果庄家有二十一点,所有没有持有二十一点的玩家都输了。

二十一点

Java中Blackjack的主要逻辑

public class BlackJackHand extends Hand {
  
    /* There are multiple possible scores for a blackjack 
   hand, since aces have 3 * multiple values. Return 
   the highest possible score that's under 21, or the
   4 * lowest score that's over. */
  
    public int score()
    {
        Arraylist scores = possibleScores();
        int maxUnder = Integer.MIN_VALUE;
        int minOver = Integer.MAX_VALUE;
        for (int score : scores) {
            if (score > 21 & amp; &score < minOver) {
                minOver = score;
            } else if (score <= 21 & amp; &score > maxUnder) {
                maxUnder = score;
            }
        }
        return maxUnder Integer.MIN_VALUE ? minOver maxUnder;
    }
  
    /* return a list of all possible scores this hand could have 
     (evaluating each * ace as both 1 and 11 */
    private Arraylist possibleScores() { ... }
  
    public boolean busted() { return score() > 21; }
    public boolean is21() { return score() == 21; }
    public boolean isBlackJack() { ... }
}
  
public class BlackJackCard extends Card {
    public BlackJackCard(int c, Suit s) { super(c, s); }
    public int value()
    {
        if (isAce())
            return 1;
        else if (faceValue >= 11 & amp; &faceValue <= 13)
            return 10;
        else
            return faceValue;
    }
  
    public int minValue()
    {
        if (isAce())
            return 1;
        else
            return value();
    }
  
    public int maxValue()
    {
        if (isAce())
            return 11;
        else
            return value();
    }
  
    public boolean isAce()
    {
        return faceValue == 1;
    }
  
    public boolean isFaceCard()
    {
        return faceValue >= 11 & amp;
        &faceValue <= 13;
    }
}
  
/* This is just one way of handling aces. We could, alternatively, create a class
of type Ace that extends BlackJackCard. */

参考 :
https://www.careercup.com/question?id=2983
http://stackoverflow.com/questions/37363008/a-singleton-class-to-design-a-generic-deck-of-card