views:

1956

answers:

9

Hello, for a homework assignment I was given a Card class that has enumerated types for the Rank and Suit. I am required to compare two pokerhands (each hand is an ArrayList of 5 cards) and decide the winner.

The isStraight() function is really bothering me, because I have to start over the count after the Ace. For example,

QUEEN, KING, ACE, TWO, THREE

Is still considered a straight. What is the best way to code this functionality?

Here is the Rank/Suit enumerated type code, if that helps.

public enum Rank
{
    TWO(2), THREE(3), FOUR(4), FIVE(5), SIX(6), SEVEN(7), EIGHT(8), NINE(9),
    TEN(10), JACK(11), QUEEN(12), KING(13), ACE(14);

 private final int points;

 private Rank(int points)
 {
  this.points = points;
 }

 public int points()
 {
  return this.points;
 }
}

public enum Suit
{
    DIAMONDS, CLUBS, HEARTS, SPADES;
}
+6  A: 

You do realize that by the rules of any poker game I've ever played or heard of a straight cannot wrap right? Ace can be low [A,2,3,4,5] or high [10,J,Q,K,A] but it can't wrap. According to those rules (not yours) I've implemented something similar before. Basically you sort the array and walk it, making sure the current card is one higher than the previous. In the first iteration, if it is an ace, then you explicitly check for [A,2,3,4,5]. If it is you return true and if it isn't you continue with the normal straight logic. This should set you in the right direction.

shsteimer
A: 

you could write a class that converts every card to an specific card value

Joker = 11 Queen = 12 King = 13 Ace = 0 or 14

it will make a lot easier card handling and looking for possible hands.

GerManson
the constructor of his enum is doing that already
matt b
A: 

I'd argue that given that definition of RANK, that straights can only start with a max of ACE.points() - 4.

So if you sort your hand and the lowest RANK is > ACE.points() - 4 then you can't have a straight, otherwise you just iterate over the hand to see that each card is previous RANK + 1.

If ACE can be high or low then go with what SHS answered.

Instantsoup
A: 

With an inner loop it's pretty trivial, the challenge would be to do it without an inner loop...

Also, it depends on if you understood your teacher or your teacher misunderstood (or misrepresented) the rules of the game.

I think I'd be tempted to just create an array [2..14] and place the cards in the location that corresponds to their rank. If you hit a duplicate, it's not a straight, and when you are done, you should have 8 spaces in a row. If you have less than 8 spaces in a row, it's not a straight.

All the other solutions I can come up with require an inner loop--and inner loops are one of those sloppy programming things you need to avoid whenever you can if you're going to ever be a respectable programmer.

edit: Also, if you misunderstood the teacher and the only wrapping condition is "10,j,q,k,a" (like in the real rules), then you need an additional test that if all of 2, 13 and 14 are set, it's also a failure (2-a-k wraparound).

(Edited again to replace 1 for ace with 14 after re-reading the question)

Bill K
What about aces?
Michael Myers
Oh, when you say "8 spaces in a row", I guess that's where you're allowing it to wrap; is that it?
Michael Myers
Yeah, see the edit to stop illegal wraps.
Bill K
Wouldn't it be better to just check for 5 "non-spaces" in a row? You wouldn't have 8 spaces in a row, for example, if your cards were 5, 6, 7, 8, 9
Adnan
A: 

I dont use enum much, i prefer named constants but i'll assume going from "ACE" to "14" is trivial

i'm too lazy to write real java code (beside you actually have to do your homework ^^)

check if the list has 5 cards
convert card names to a card number list named array
sort the list array
for i=1 to 4
if not (array[i] + 1) % 13 == (array[i+1]) % 13
then it is not a straight

The % operator is called modulo so (15 % 13) == 2 I use this operator whenever I face the "wrap over" challenge

Edit : After re-reading your question my solution cannot work out of the box. You should reorder your enum so that TWO == 0

Eric
+1  A: 

Since there's only 5 cards in you list, you could sort it and determine the difference between 2 consecutive cards. If it contains an ace, you need to consider it as a low card too. if all the differences are 1 (or -1, depending on the sort order), you have your straight.

Rik
A: 

I recommend using a bit vector to represent the cards. This avoids having to sort. You can add the ace twice (once as a 1 the other times as a king) or you can special case the starting situation by checking if the ace bit is set before checking if the 2 is set). You can build a big look up table if speed matters. This approach also cleaning scales to find the rest of the hands (flushes, 2 pair, full houses, trips, and so on). It also makes it easy to figure out if a given straight is higher than another. And it expands cleanly to 7 card evaluator

In pseudo code it looks something like this for a very general case (you can have any number of cards. It returns the first straight)

 long cardBitMask
 for each card in hand
   setBit in cardBitMask

 hearts = mask(cardBitMask)
 diamonds = mask(cardBitMask)
 clubs = mask(cardBitMask)
 spades = mask(cardBitMask)

 // find straight
 uniqueCards = hearts|diamonds|clubs|spades
 int cardsInaRow = 0
 if uniqueCards&AceCardMask:
    cardsInaRow = 1
 for card = 2...King
   if uniqueCards&(1<<card)
      cardsInARow++
   else 
      if cardsInARow == 5
         break
      cardsInARow = 0
 if cardsInARow==5:
     return true
 return false
hacken
Going to bits when an array can do the same thing--probably more efficiently? (Bitfields tend to require a read+write instead of just a write). Dude, you should re-evaluate your programming priorities. Readability before all others, optimization last, etc...
Bill K
Bitfields are orders of magnitude more efficient if your writing a hand evaluator. You turn all the hand evaluation into a half dozen table look ups. I find the resulting code easier to use in a poker program but ymmv. If your interest in this program a google will run up a bunch of fast one.
hacken
Strange assumption there. Source? I know setting a single bit is less efficient than writing a byte to an array, but maybe you're thinking of something else. I work with them all the time (processing video streams), it's not like I'm afraid or anything, just a bad solution unless necessary.
Bill K
Setting single bit is slower. But you don't set a single bit. You set all the bits in 1 register for all the cards and then write out that register. Most of the speed is from avoiding having to do a sort and being able to tell if something is a straight with some math and then 1 memory access.
hacken
I have a soft spot in my heart for bitfields, but this is going pretty far out of your way to avoid sorting five cards. With these constraints, selection sort will outperform Merge Sort and QuickSort. If you were building the game to serve thousands of users, sure, but in this context it's overkill.
rtperson
A: 

Add all the ranks in order to a list, twice. Then, to check if a hand is a straight, sort the hand by rank and then check if the hand is a sublist of that list.

Apocalisp
A: 

You could write a fancy algorithm to return true despite the number of possible cards but if you realize there are only 10 valid combinations on a sorted hand, you could just look for those...

2-6, 3-7, 4-8, 5-9, 6-T, 7-J, 8-Q, 9-K, T-A, (2-5,A)

Austin Salonen