开发者

Poker Hands modeling question

开发者 https://www.devze.com 2023-03-17 22:49 出处:网络
I\'m modeling a Poker game and I have a little design doubt: I\'ve a PokerHand, which is composed by 5 PokerCards. Should Straigh开发者_如何学Got, ThreeOfAKind, Poker, etc be subclasses of PokerHand?

I'm modeling a Poker game and I have a little design doubt:

I've a PokerHand, which is composed by 5 PokerCards. Should Straigh开发者_如何学Got, 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!


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 being enums); a Hand class, that holds 5 cards (or just n cards if you're into that); an abstract HandRank class that implements the Comparable<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 that StraightFlush is better than TwoOfAKind); and a base class AbstractHandAnalyzer. This AbstractHandAnalyzer would have a Analyze(Hand) method that would return a HandRank object.

Now, you make one subclass of AbstractHandAnalyzer per HandRank subclass. Those subclasses check a given hand and return a HandRank instance if the hand matches (for instance, if TwoOfAKindAnalyzer finds that you have two kings, it returns a TwoOfAKindRank 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 subclassing Hand 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 reuse Hand and easily implement various analyzers for hands.


PokerHand should have a method: GetCombination that returns enum or object. 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 by Cards (for highest card).


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!


I've been thinking about it:

My reasoning is that all hands can be categorized under HighCard, Pair, TwoPairs, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind and StraightFlush. All of them are kinds (or classes) of hands, and Hand 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 doing aHand < 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消