扑克牌建模问题
我正在为扑克游戏建模,但我有一点设计疑问:
我有一个 PokerHand
,它由 5 个 PokerCard
组成。 Straight
、ThreeOfAKind
、Poker
等是否应该是 PokerHand
的子类?或者它们应该是由计算这手牌类型的 PokerHand
方法返回的符号?
我对 PokerHand
进行子类化的理由是,它将使检查获胜者手牌变得更加容易和更快,但我不确定这是否是一个好的工程......
是否有适合这里的设计模式?
谢谢!
I'm modeling a Poker game and I have a little design doubt:
I've a PokerHand
, which is composed by 5 PokerCard
s. Should Straight
, ThreeOfAKind
, Poker
, etc be subclasses of PokerHand
? Or should they be symbols returned by a PokerHand
method that computes what kind of hand it is?
My rationale for subclassing PokerHand
is that it would make checking winner hands much easier and faster, but I'm not sure this is good engineering...
Is there any design pattern that would fit here?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
上学期,我必须用Java设计这样一个系统作为作业。虽然我们需要使用责任链模式来检查手牌,但我相当确定这是解决问题的一个糟糕方法,而且主要只是将模式插入作业中的一种方法。
如果我必须在没有责任链模式的情况下重做它,并使用更理智、更有凝聚力的策略列表,我会使用如下设计。
将有一个
Card
类,带有“颜色”(黑桃、梅花、方块、红心)和一个数字(均为枚举
);一个Hand
类,可容纳 5 张牌(如果您愿意,也可容纳n
张牌);一个抽象HandRank
类,它实现了Comparable
接口,以及每种牌的子类(两种、三种、顺子等)每个都可以与另一个相比较(例如StraightFlush
优于TwoOfAKind
);和一个基类AbstractHandAnalyzer
。此AbstractHandAnalyzer
将具有一个Analyze(Hand)
方法,该方法将返回HandRank
对象。现在,您为每个
HandRank
子类创建一个AbstractHandAnalyzer
子类。这些子类检查给定的手牌,如果手牌匹配,则返回HandRank
实例(例如,如果TwoOfAKindAnalyzer
发现您有两个国王,则返回TwoOfAKindRank< /code> 告诉它找到了两个国王,并保存踢球以备稍后比较时需要)。
那么,要分析一手牌,您所要做的就是按降序排列一手牌分析器列表(因此您从同花顺开始),并运行该手牌上的每个分析器,直到有一个匹配且不返回
null
。这里重要的部分是将扑克牌与队伍本身脱钩。对于大多数语言(但 Smalltalk 可能不是这种情况),如果构造一个
Hand
对象,则无法神奇地将其变形为另一个类,因此子类化Hand
来限定根据您的对象实例化方案,排名可能会很困难,并且如果手牌可变(某些扑克变体允许交换牌),则排名几乎不可能。这种方法可以让您重用Hand
并轻松实现各种 Hand 分析器。Last semester, I had to design such a system in Java as a homework. While it was required we checked the hands using the chain of responsibility pattern, I'm fairly sure it was a bad approach to the problem and mostly just a way to plug the pattern into a homework.
If I had to redo it without the chain of responsibility pattern, and using a saner, more cohesive list of strategies, I would use a design like the following.
There would be a
Card
class, with a 'color' (spades, clubs, diamonds, hearts) and a number (both beingenum
s); aHand
class, that holds 5 cards (or justn
cards if you're into that); an abstractHandRank
class that implements theComparable<HandRank>
interface, and subclasses for each kinds of hands (two of a kind, three of a kind, straight, etc) that are each comparable to another (such thatStraightFlush
is better thanTwoOfAKind
); and a base classAbstractHandAnalyzer
. ThisAbstractHandAnalyzer
would have aAnalyze(Hand)
method that would return aHandRank
object.Now, you make one subclass of
AbstractHandAnalyzer
perHandRank
subclass. Those subclasses check a given hand and return aHandRank
instance if the hand matches (for instance, ifTwoOfAKindAnalyzer
finds that you have two kings, it returns aTwoOfAKindRank
that tells it found two kings, and saves the kicker in case it needs it during a comparison later).All you have to do to analyze a hand, then, is to have a list of hand analyzers in descendant order (so you start with the straight flush), and run each analyzer on the hand until one matches by not returning
null
.The important part here is to decouple the poker hands from the ranks themselves. With most languages (it might not be the case with Smalltalk though), if you construct a
Hand
object, you cannot magically morph it into another class, so subclassingHand
to qualify the ranks can be hard depending on your object instantiation scheme, and can be made next-to-impossible if the hand is mutable (some poker variants allow to swap cards). This approach lets you reuseHand
and easily implement various analyzers for hands.PokerHand
应该有一个方法:GetCombination
,它返回enum
或object
。手就是手,如果玩家有直,它不会添加任何新的行为或状态。所以组合是可以通过卡片计算出来的。编辑:我将创建具有以下属性的类
Combination
:Type
- 表示组合的枚举。Player
- 引用玩家。Cards
- 涉及卡片的引用数组。然后实现比较逻辑,以便可以比较任意两个组合:首先按
Type
比较,然后按Cards
(对于最高的卡片)。PokerHand
should have a method:GetCombination
that returnsenum
orobject
. Hand is hand, and if player has Straigt it doesn't add any new behavior or state. So combination is calculable from cards.Edit: I would create class
Combination
with these properties:Type
- enum that represents combination.Player
- ref to player.Cards
- array of ref to involved cards.Then implement comparison logic, so that any two combinations could be compared: first by
Type
then byCards
(for highest card).我可能会将一手扑克牌视为一组(大概是 5 张)牌。然后,为了检查它是什么样的手牌,我将创建一个 CalculateValue() 方法,该方法返回 1(表示对)、2(表示两对)、3(表示三对)等。该值可以是在构造手时进行计算,然后在需要时简单地重复使用。
祝你好运!
I would probably work with a poker hand as a set (5 presumably) of cards. Then, to check what kind of hand it is, I would create a
CalculateValue()
method that returns 1 for pair, 2 for two pairs, 3 for three of a kind, etc. This value could be computed when the hand is constructed, then simply reused whenever it is needed.Good luck!
我一直在思考:
我的推理是所有牌都可以分类为
HighCard
、Pair
、TwoPairs
、ThreeOfAKind< /code>、
Straight
、Flush
、FullHouse
、FourOfAKind
和同花顺
。它们都是手的种类(或类),而Hand
只是一个抽象类。所有这些子类只需要重写
<
和>
,然后询问一只手是否比另一只手更好就变得和执行aHand
一样简单。 anotherHand
,看起来非常自然。在现实生活中,我们会拿双手进行比较,首先查看它们的种类(类别),然后(并且仅在必要时)查看它们的牌的价值。因此,使用这种方法,
<
和>
的行为将与此完全相同:检查类是否不同,如果不同,我们会自动获得答案。如果不是,我们会递归地检查哪一张拥有最好的牌。I've been thinking about it:
My reasoning is that all hands can be categorized under
HighCard
,Pair
,TwoPairs
,ThreeOfAKind
,Straight
,Flush
,FullHouse
,FourOfAKind
andStraightFlush
. All of them are kinds (or classes) of hands, andHand
is just an abstract class.All these subclasses just need to override
<
and>
, then asking a hand if it's better than another one becomes just as simple as doingaHand < anotherHand
, which looks very natural.In real life, we would take both hands and compare them by looking first at their kind (class), then (and only if necessary) at the value of their cards. So with this approach,
<
and>
would behave exactly as this: check whether the classes are different, in case they are we get the answer automatically. In case they aren't, we recursively check which one has the best cards.