概念难度 c++ 扑克牌
Posted
技术标签:
【中文标题】概念难度 c++ 扑克牌【英文标题】:Conceptual Difficulty c++ Deck of Cards 【发布时间】:2016-06-30 15:43:59 【问题描述】:我知道关于这个永恒的实现有很多问题,但作为一个新的 OOP 程序员,我正在努力掌握必要的概念来建立任何基础。
我是否在一个数组中构建了一个实际的随机牌组,可以作为任何纸牌游戏的纸牌牌组?或者我是通过创建 4 个花色然后创建 13 个不同的面来“复制”一个随机的扑克牌套牌吗?我见过多种实现,但我不太明白他们在做什么。 int deck[];
是我计划存放卡片的地方。当创建纸牌类的实例时,我会填充该纸牌数组吗?
我的 main 只调用了 print 函数(我还没有写)
//Texas holdem build
//Will attempt using Classes and inheritance
//Full build for up to 6 players
#include <iostream>
#include "deckOfCards.h"
int main()
DeckOfCards deck;
deck.printDeck();
return(0);
标题
* deckOfCards.h
*
* Created on: Jun 28, 2016
* Author: TAmend
*/
#ifndef DECKOFCARDS_H_
#define DECKOFCARDS_H_
class DeckOfCards
public:
DeckOfCards();
void printDeck() const;
void shuffle();
private:
int currentCard;
int deck[];
;
#endif /* DECKOFCARDS_H_ */
【问题讨论】:
为了学习和说话作为OOP设计。Deck of Cards
将是 52 objects
的容器,而不仅仅是 int
s。因此,另一个小结构/类将代表card
。那张卡(类)有什么?它有一套西装(4 个中的 1 个)、一个值(1/13)和一个脸(1/13)。然后在你的Deck of cards
类中,会有一个函数将那个小类(卡片)的 52 个对象填充到它自己的私有成员容器中,确保卡片中没有重复。
【参考方案1】:
好吧,拥有一个 Card
class
或 struct
和一个充当专用容器的 DeckOfCards
类是正确的方法(正如 @Thomas' answer 中提到的那样):
struct Card
enum Suit_Type
Diamonds,
Hearts,
Spades,
Clubs,
suit;
enum Value_Type
Two = 2, // <<<<<<<<< Note starts at 2
Three ,
// Four, Five, Six, aso. ...
Ten ,
Jack ,
Queen ,
King ,
Ace , // <<<<<<<<< Note has the highest value here
value;
void printCard();
;
void Card::printCard()
switch(suit)
case Hearts:
std::cout << "♥";
break;
case Diamonds:
std::cout << "♦";
break;
case Clubs:
std::cout << "♣";
break;
case Spades:
std::cout << "♠";
break;
if(value < Jack)
std::cout << (int)value;
else
switch(value)
case Jack:
std::cout << 'J';
break;
case Queen:
std::cout << 'Q';
break;
case King:
std::cout << 'K';
break;
case Ace:
std::cout << 'A';
break;
如前所述,应该在Card
上实现一些比较运算符,以使游戏玩法的实现更容易:
bool operator<(const Card& lhs, const Card& rhs)
return (lhs.suite < rhs.suite) &&
(lhs.value < rhs.value);
bool operator>(const Card& lhs, const Card& rhs)
return (lhs.suite > rhs.suite) &&
(lhs.value > rhs.value);
请注意,从语义角度来看,相等测试的实现没有多大意义,除非您想同时使用多个 DeckOfCards
。
Cards
在特定游戏中的行为方式可能完全委托给 Strategy Pattern 类。
DeckOfCards
可以从适当的初始化列表中初始化:
class DeckOfCards
DeckOfCards() : cards_(
Diamonds, Two ,
// ...
Diamonds, Ace ,
Hearts, Two ,
// ...
Hearts, Ace ,
Spades, Two ,
// ...
Spades, Ace , // !!! Extremely important !!!
Clubs, Two ,
// ...
Clubs, Ace ,
)
void printDeck();
void shuffle();
private:
std::array<Card,52> cards_;
;
那么其他功能就可以这么简单实现了:
void DeckOfCards::printDeck()
bool first = true;
for(auto card : cards_)
if(!first)
std::cout << ", ";
card.printCard();
first = false;
std::cout << std::endl;
void DeckOfCards::shuffle()
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(cards_.begin(), cards_.end(), g);
;
我不是 100% 确定你想用 DeckOfCards
中的 currentCard
成员实现什么,但我想你不希望这成为下一个 Card
的偏移量DeckOfCards
,因此您可以简单地将其用作cards_
数组的索引,以分发对底层Card
实例的引用,然后将其递增:
const Card& getNextCard(bool& cardsAvailable)
cardsAvailable = true;
if(currentCard < 52)
return cards_[currentCard++];
// Reset the deck
cardsAvailable = false;
currentCard = 0;
shuffle();
去找彩蛋
【讨论】:
我从来没有听说过叫“cross”的球杆。此外,王牌的价值取决于游戏。在某些游戏中,所有的面卡都具有相同的价值。 @RobK THX 对于洞察力,我不是母语人士,而是从翻译网站获得的。嗯,当然值的顺序取决于实际玩的游戏,但大多数纸牌游戏都使用这种顺序(套件中的小修正)。 在大多数地方你使用Deck
,但是类被定义为DeckOfCards
。我猜这只是复制/粘贴错误。
@JamesAdkison 是的,我错过了将 Deck
更改为 DeckOfCards
的原始答案。希望我现在抓住了所有发生的事情。
我很确定现在还不是复活节,但是 +1【参考方案2】:
我以前回答过这些,所以我会再回答一次。
恕我直言,有两个对象:卡片的容器和卡片。不要混合它们。
让我们从一张卡片开始。一张牌有花色和价值:
struct Card
Suit_Type suit;
Value_Type value;
;
容器可以是任何东西,例如std::vector
、std::list
,或者我最喜欢的std::deque
。 ;-)
typedef std::vector<Card> Deck_Of_Cards;
您可以制作自己的容器,但对于大多数使用卡片的任务来说,没有必要。首选现有的容器数据结构。
就Card
结构中的类型而言,这是一个偏好问题。您可以对Suit_Type
使用枚举、字符串或其他任何内容。与Value_Type
类似。
为了使卡片更有用,您应该在Card
结构中实现以下方法:
-
构造函数、赋值运算符、析构函数。
等式和排序运算符(例如 == 和
流插入和提取(例如 >> 和
同时查看函数std::random_shuffle
。
【讨论】:
“这些我已经回答过了,所以我再回答一次。”那这不是骗人的吗? 我之前没有给出完整的答案,只是建议。 :-) 好吧,那你现在可以试着给出一个完整的答案(顺便说一句,由于 一副牌 中的牌数通常是固定的,我宁愿推荐std::array<>
作为内部容器类型)。
std::random_shuffle
已弃用。只需使用std::shuffle
。
@πάντα ῥεῖ 对于只有 52 个元素的套牌,它们永远不会增长/收缩我想说这实际上并不重要 - 性能方面。【参考方案3】:
好的,只是为了说得非常清楚,你的甲板类将充当一个“容器”类。这意味着它将持有一堆卡片类型的卡片;不是int。
最后,你用来存储卡片的数组看起来像 卡片组[];而不是 int 甲板 [];这将允许您将您喜欢的任何属性添加到每个单独的卡中。
您可以在构造时或之前随机化 Card 类的每个属性,然后将随机值传入。
为了帮助你理解:
class Card
public:
Card(int value): value(value)
int Getvalue() return value;
private:
int value;
;
class DeckOfCards
public:
// DeckOfCards();
// void printDeck() const;
// void shuffle();
void createDeck()
for(int i = 0; i < deck_size; i++) //Implementation of createDeck
deck[i] = new Card(rand()%10-1);//whatever val you want to generate
private:
// int currentCard;
// Card deck[];
;
通过这种方式,您可以随时获取卡片,并添加您想要的任何属性,例如西装。
注意:向量比原始数组更可取,但不要只删除 DeckOfCards 类,因为如果这样做,那么将 shuffledeck 函数或 printdeck 函数存储在哪里?等等...而是简单地用向量替换成员数组。
【讨论】:
“一个向量会更好......” 事实上,std::array<Card,52>
将是正确的内部标准容器类型。在这种情况下不需要动态内存分配。
@πάνταῥεῖ 同意 100%
不清楚应该是什么类型的纸牌游戏/套牌,这就是为什么我省略了套装属性。另外,是的,一个普通的数组,从堆栈中分配它的成员就可以了,但是如果你想删除一个元素怎么办,同样不清楚它是什么类型的游戏/套牌。您可以使用标准阵列,这完全取决于您希望如何管理从阵列中移除每张卡(如果有的话)。【参考方案4】:
这真的取决于你想用你的一副牌实现什么,你想如何使用它。在某些情况下,一个简单的int[]
将完全满足您的需求。在其他情况下,您将需要完整的卡片和甲板类以及其他助手类。其他答案中给出的纸牌和套牌实现(无意中?)专门用于某些纸牌游戏,而对其他人完全不可用。不要问你能拥有什么,问问你自己你需要什么。 Do the simplest thing that could possibly work.
(实际上这个问题过于宽泛/基于意见,可能更适合于programmers.stackexchange.com)
【讨论】:
以上是关于概念难度 c++ 扑克牌的主要内容,如果未能解决你的问题,请参考以下文章
华为OD机试真题 C++ 实现整理扑克牌2022.11 Q4 新题