为项目制作uno游戏。
所有108张牌都位于名为cardDeck [108]
的填充数组中启动功能随机抽取7张牌并通过添加填充玩家手牌 它们是一个名为playerHand []
的数组我需要帮助。
1)当我们将卡片拉入playerHand []时,我不知道如何让卡片从cardDeck数组中消失。
2)我也不知道如何创建一些能够计算cardDeck数组中非空值的东西,这样它就会显示两个玩家抽牌后牌组剩余的牌数。
答案 0 :(得分:12)
#include <cstdlib>
#include <vector>
#include <algorithm>
using namespace std;
将牌组设为vector
。
vector<Card> deck_;
将每张卡插入卡座。
deck_.push_back(Yellow0);
deck_.push_back(WildDraw4);
洗牌“
srand((unsigned)time(0));
random_shuffle(deck_.begin(), deck_.end());
将牌从牌组中取出把它们放在玩家手中。
vector<Card> player_hand_;
for( size_t i = 0; i < 7; ++i )
{
player_hand_.push_back(deck_[0]);
deck_.erase(deck_.begin());
}
修改强>
根据以下评论中的请求,我将解释为什么我认为应该有多个无状态卡向量而不是单个有状态卡向量。
OOP试图接近的理想之一是尽可能地模拟现实世界。现在显然vector
不是OOP,但理论上包含的卡片可以是。虽然在许多情况下肯定无法完美实现,或者甚至应该尝试在尽可能多的情况下完美实现,但在现实世界IMO超越任何特定编程范例之后,尝试对软件组件进行建模。
所以考虑一下Uno牌。 Uno卡有几个不同的属性。他们有一个等级(0-9),他们有一套(红色,蓝色,黄色,绿色)。还有一些卡片具有特殊含义,既没有套装也没有等级(WildDraw4,Wild,Draw2,Skip,reverse)。
因此,如果我们要用C ++建模Uno卡,它会是什么样子? Uno卡一旦打印就不会改变。例如,黄色2永远不会是绿色5或野生抽奖4。如果你从盒子里拿出绿色的7并把它交给你的朋友,它仍然是绿色的7。它现在在你朋友的手中,但这不是关于卡的更改的内容。相反,改变的是你朋友的手。它现在拥有一张Green 7 Uno卡,而不是空的。
在Uno游戏中,每位玩家获得7张牌。有一张牌面朝上放置成弃牌堆,其余牌面朝下放置形成抽牌堆。当您将牌从抽牌堆移到玩家手中时,即使位置有卡,卡仍然没有变化。但不要挂在人类语言上。 “它的位置”并不意味着卡的位置是卡的属性。但是当你移动卡片时,已经改变了 - 抽签的状态和玩家的手。
所以我们最终得到了一个用于绘图堆的向量,另一个用于弃牌堆,以及每个玩家的一个向量,代表他们的手。
这种设计易于维护程序员理解,易于扩展,并且易于第一次开发。因为它很简单,所以也不容易出现缺陷。毕竟,这更容易被打破 - 滑板还是航天飞机?
答案 1 :(得分:2)
只需使用std::vector<card>
即可。它是一个动态可调整大小的容器,您可以从中删除元素。
答案 2 :(得分:1)
你可以为抽出的卡片分配一张没有卡片的值/字符。从而告诉你哪些牌被抽出......
答案 3 :(得分:1)
保持一个int(我们称之为N),代表牌组中留下的牌数。要从卡座中移除卡,在0和N之间选择一个随机数r(即0 <= r 这样,您永远不会在数组中引入NULL,因此完全避免了您的问题。如果你使用stl向量而不是数组,这就变得更容易了,因为向量知道它的大小而你不必自己存储它。
答案 4 :(得分:1)
考虑这种替代实施和逻辑。
将CardCollection
定义为一个类
那个'有一个'
std::deque<boost::shared_ptr<Card> >
定义三个CardCollection
- 一个是
甲板,另外两个是球员
手
按所有push_back
初始化套牌
Card
个对象(按随机顺序)到deque
。
从中抽取Card
s
在deque
将它们移动到相应的
玩家手push_back
到那个
deque
,在卡片deque
中删除
(这解决了1)
2)通过调用解决
size()
deque
{/ 1}}
当手牌结束时,将Card
返回给
使用push_back()
答案 5 :(得分:1)
我假设您正在使用某种自定义类型的卡片。所以我们称之为t_card_kind
。
你可以做一些阵列转换来从玩家手中“删除”牌。但这没有多大意义。
我建议定义一个类似
的枚举namespace uno { enum play_status { DRAW_PILE,IN_HAND,DISCARD }; };
这样你就可以简单地声明一个新的类型定义的结构
typedef struct s {
t_card_kind card;
uno::play_status status;
} t_game_card;
...最后声明一个数组,如
t_game_card my_cards[108];
或矢量如: vector my_cards [108];
然后填充它。
要更改卡的状态,只需访问该会员即可。
e.g。
my_cards[i].status = uno::IN_HAND;
这种设计执行得更快,更优雅。
要解决第二个问题,只需实施类似
的方法unsigned int count_status(const t_game_card * my_card,
uno::play_status status_kind) {
const unsigned int DECK_SIZE = 108; //size of a standard uno deck
unsigned int matches;
for (unsigned int counter=0; counter < DECK_SIZE;counter++) {
if (t_game_card[counter].play_status==status_kind) {
matches++;
}
}
return matches;
}
...或者只是切换到向量并使用erase()方法。
编辑1
基于我与John的上述讨论,对于这种单一容器设计与多容器设计存在争议。以下是我对该主题的看法:
我相信这种使用带有状态信息的单一矢量卡的设计比基于多矢量的设计更健壮,更容易维护。这就是原因。
在生成的代码中,您会有类似的内容:
namespace uno { enum play_status { DRAW_PILE,IN_HAND,DISCARD }; };
typedef struct s { t_card_kind card; uno::play_status status; } t_game_card;
static vector<t_game_card> my_cards[108];
基于多向量的方法将具有:
static t_game_card draw_pile[108];
static t_game_card in_hand;
static t_game_card discards;
......还有三个项目,虽然我的线长更长。
如前所述,要使用我的方法更改状态,您只需使用以下内容:
my_cards[i]=uno::IN_HAND;
而使用基于矢量的方法,您必须执行以下操作:
in_hand.append(draw_pile[i]);
draw_pile.erase(draw_pile.begin()+i);
更长,更多计算密集型,使用更多内存,在我看来不那么直观。
现在让我们考虑可扩展性。假设您想出一个包含“BONUS”堆的uno变体。使用我的方法,这很简单 - 只需在枚举中添加一个值:
namespace uno { enum play_status { DRAW_PILE,IN_HAND,DISCARD,BONUS }; };
使用向量方法,您需要创建并维护一个完整的额外向量:
static t_game_card draw_pile[108];
static t_game_card in_hand;
static t_game_card discards;
static t_game_card bonus;
我们现在有4个(!)变量采用基于矢量的方法,而单个直观变量采用我的方法。
为单独的状态维护多个容器占用更多内存,计算成本更高,并且与使用单个容器(向量,数组等)来保存附加了状态信息的结构相比,不太直观。
答案 6 :(得分:0)
我会推荐这样的东西(它有点复杂,但应该有效):
Add all cards to a deque (push back)
(optionally) Shuffle (randomly sort) the collection
Loop 7 times
{
For each player
{
Removing the first card from the collection and add it to the player's hand
}
}
你应该最终得到7张牌,所有留在牌面上的东西都很容易计算或使用(它都留在了双端队列中)。
现在,我建议使用向量作为玩家的手而不是数组,虽然这里的差异非常小,因为你有一个已知数量的元素。矢量可能更容易使用。如果你还没有,我还会制作一个Card
课程,并将牌组和指针保持为deque<Card*>
和vector<Card*>
,这将使移动卡片变得轻而易举(复制指针,这是一个指令)并且在小数据类型上洗牌也会非常快。