Satira has asked for the wisdom of the Perl Monks concerning the following question:

hi, I'm trying to create a little poker game and since I'm new at perl, I'm already stuck. I've gotten my program to shuffle, deal, and sort the hand. Now I need my program to check for winning hands. Let's say that the player's hand has: 3 3 4 4 7 What kind of function can I write that will talie up the cards in the hand to give me 2 2 1? Right now 3 3 4 4 7 is a string. I can't use hashes on this.

Replies are listed 'Best First'.
Re: Keeping track of Pairs
by kschwab (Vicar) on Jul 12, 2001 at 08:22 UTC
      Be careful though. The Classify_Hand subroutine is broken, in that it doesn't count A-2-3-4-5 as being a straight. I'll go fix that now though, and update this message when I'm done. Sorry about that!

      Update: The Poker Probability Processor should be fixed now. No promises though. I have to run the stats again to check, and that takes about 30+ hours for 7 cards. If you want to use it, check it against the stats on that page, as they are correct (stolen from the rec.games.poker faq)

Re: Keeping track of Pairs
by mattr (Curate) on Jul 12, 2001 at 09:11 UTC
    Is this some pseudo-poker or are you trying to simulate a 52 card deck? What are all the rules, or do you only care about two of a kind?

    I'd seriously suggest taking a step back and organizing how you want to represent a card, a deck, and some pseudocode (English) description of scoring rules. Also when you process those strings you are really going to be splitting them into an array anyway.. but how come no hashes? They are nice because you can check if a key exists and you can do something like foreach (sort keys %myhash). If this is an assignment then work it out with hashes yourself later okay?

    You could give each card a two letter code, like 5H for five of hearts. It would even be faster if you add a letter for which color it is because you could use regular expressions to see what color a card is, to check for flushes and straights.

    This solves the question you asked.

    #!/usr/bin/perl -w use strict; my $handstr = "3S 4H 3C 4C 7D"; my @hand = split(' ',$handstr); my @sorthand = sort @hand; my $uniquevals = my $ans = ""; my ($faceval,$numdups); foreach my $card (@sorthand) { $faceval = substr($card,0,1); $uniquevals .= "$faceval " unless $uniquevals =~ /$faceval/; } foreach my $v (split (' ',$uniquevals)) { $numdups = $handstr =~ s/$v/$v/g; $ans .= "$numdups "; } chop $uniquevals; chop $ans; print "Your hand is ",join(' ',@sorthand),", unique face\n"; print "values $uniquevals. The hand reduces to $ans.\n";

      Of course, no Perlmonks thread would be complete without the obligatory CPAN referral... believe it or not, even this has its own module: Games::Cards. It's thoroughly generic, so you'll still have to write your own scoring function (or adapt the Poker Probability processor as suggested by kscwab) but hand management at least is taken care of for you.

      To reiterate what mattr said: this is what hashes are for. Why can't you use them? They will simplify your life greatly, really.

      And of course, whatever internal representation you choose, don't forget flushes. :-)



      If God had meant us to fly, he would *never* have give us the railroads.
          --Michael Flanders

        I monkchatted with Satira and he was very cool. It was for an assignment but I think he probably got a lot out of the thread. Next time he'll say so up front so we can help the learning process and not guess! Good luck Satira.
Re: Keeping track of Pairs
by MeowChow (Vicar) on Jul 12, 2001 at 09:09 UTC
    You're looking for something like this:
    # without using hashes, as you requested sub group_cards_nohash { # convert initial string param into a sorted list of cards my @cards = sort { $a <=> $b } split / /, shift; my @tally; my $cnt = 1; # generate running tally of cards - we're going to remove # cards one at a time from the list, until it's empty while (@cards) { # remove a card my ($card, $tally) = (shift @cards, 1); # remove successive cards until there are none left, or # a card of a different value is encountered while (defined $cards[0] and $cards[0] == $card) { shift @cards; $tally++; # increment tally for every identical card } # add this tally to the results push @tally, $tally; } # return the tally sorted in reverse sort { $b <=> $a } @tally; } # though it's much more straightforward with the hash-based approach b +elow sub group_cards_hash { # convert initial string param into a sorted list of cards # notice that we don't need to sort this one my @cards = split / /, pop; my %tally; # tally the cards $tally{$_}++ foreach @cards; # return the tally sorted in reverse sort { $b <=> $a } values %tally; } print join ',', group_cards_hash('9 9 5 5 1'); print "\n"; print join ',', group_cards_nohash('9 9 5 5 1');
       MeowChow                                   
                   s aamecha.s a..a\u$&owag.print
Re: Keeping track of Pairs
by joecamel (Hermit) on Jul 12, 2001 at 08:35 UTC
    This is the best I could come up with. This assumes you've already sorted the cards.

    #!/usr/bin/perl -w use strict; my $hand = "33447"; # Check the hand for each card foreach my $card (2..10, "J", "Q", "K", "A") { # Count the number of cards in hand, by substituting each with its +elf # and getting the number of substitutions my $numCards = $hand =~ s/$card/$card/g; # Substitute the groups of similar cards with their quantity $hand =~ s/$card+/$numCards/g; } print $hand;


    There is probably a more compact solution out there. :)

    joecamel

      How about this to replace your loop (though destroying the hand may not be a good idea in the long run):

      $hand =~ s/((.)\2*)/length $1/ge

      Update: Removed useless brackets

      --
      I'd like to be able to assign to an luser