为一副通用纸牌设计数据结构 解释如何将其子类化以实现特定的纸牌游戏,以及如何将数据结构子类化以实现二十一点。
解决方案:
首先,我们需要认识到一副“通用”的纸牌可能意味着很多东西。通用可能意味着可以玩类似扑克游戏的标准纸牌,或者甚至可以扩展到 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