Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

Re^2: RFC: Cribbage::Hand

by Limbic~Region (Chancellor)
on Mar 31, 2006 at 17:58 UTC ( #540519=note: print w/replies, xml ) Need Help??

in reply to Re: RFC: Cribbage::Hand
in thread RFC: Cribbage::Hand

You have good points. I just find it odd that with everything under the sun, there isn't already one out there. With regards to your point on clarity and explanation - let me take this opportunity now to do so.

Precalculating Scores

When calculating points for sums of 15 you do not need to consider the suit of the card. You can also consider 10, Jack, Queen, and King as the same since they all have the value of 10. This means that there are only 1993 unique hands necessary to calculate any cribbage hand for 15s. I used a brute-force approach of summing all combinations of cards in group sizes of 2-5.

I then realized that if there was no card present that had a value of 10 (T/J/Q/K), I could also safely determine the points resulting from 2/3/4 of a kind. The reason the code works may not be obvious so I have included comments.

my %card; ++$card{$_} for @hand; $score += $_ * ($_ - 1) for values %card; # 1 * 0 = 0 (0 points for 1 of a kind) # 2 * 1 = 2 (2 points for 2 of a kind) # 3 * 2 = 6 (6 points for 3 of a kind) # 4 * 3 = 12 (12 points for 4 of a kind)

If you have more than 1 2 of a kind or 3/4 of a kind then you can't possibly have a flush. I added a flag if I knew it was safe not to check. You also can't possibly have right-jack if no card has a value of 10 - another flag.

I could also determine the value of any straights if no card had a value of 10. Since there are only 10 possible sequences of cards that can score points for a run, I avoided using loops. I am just going to explain the algorithm and hope that the code is clear as a result.

  • To be a run, each card must have a difference of 1 with its adjacent card
  • Sort the unique values in your hand
  • Determine the number of unique values
  • Check for possible runs of that size in descending order - end if none
  • Multiply the length of the run by the product of the count of cards at each position in the run

The hand, the flags, and the score are outputed in 8 bytes. 5 for the hand, 1 for the flags, and 2 for the score.

Calculate Total Score

The first step in calculating the total score is to convert the argument into the same format used to precalulate. We then lookup that hand and get back a 3 element array.

0 = calculated score so far 1 = flag indicating if any card has a value of 10 2 = flag indicating if it is necessary to check for flush

We know that we only have to check for 2/3/4 of a kind, straights, and right-jack if a card with the value of 10 is present. The method for determining 2/3/4 of a kind and straights has already been covered. To determine if we have right-jack:

# Find suits of any jack in the first 4 cards my %jack = map { $_ => 1 } substr($str, 0, 8) =~ /(?<=J)(.)/g; # Determine if the suit of the 5th card matches ++$score if $jack{ substr($str, -1, 1) };

Finally, we address potential flushes if necessary.

# Get the unique list of suits in the first 4 cards my %suit = map {$_ => undef} unpack('xAxAxAxA', $str); # If all the same, count 1 per card if (keys %suit == 1) { $score += 4; # If cut-card matches, add 1 for that too $score += 1 if substr($str, 1, 1) eq substr($str, -1, 1); }

I am not sure how fast this is compared to other approaches but I think it is a great start for someone interested in working on a Games::Cards::Cribbage.

Cheers - L~R

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://540519]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2018-02-25 08:34 GMT
Find Nodes?
    Voting Booth?
    When it is dark outside I am happiest to see ...

    Results (312 votes). Check out past polls.