Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer

Pattern Matching Query

by Elgon (Curate)
on Sep 17, 2002 at 12:31 UTC ( #198468=perlquestion: print w/replies, xml ) Need Help??
Elgon has asked for the wisdom of the Perl Monks concerning the following question:

Yet another daft question from Elgon,

I am rewriting my Texas Hold'ems Tool as an object oriented module and I'm trying to increase the fluency of the code. Thanks to kschwab, John M. Dlugosz, ignatz and others for help so far. The problem I am currently working on is how to reduce out one of the patterns which matches to the list of values of the cards. At the moment I have:

# Now for unsuited straights (not too difficult... if ( $sorted_values eq 'abcde' or $sorted_values eq 'bcdef' or $sorted_values eq 'cdefg' or $sorted_values eq 'defgh' or $sorted_values eq 'efghi' or $sorted_values eq 'fghij' or $sorted_values eq 'ghijk' or $sorted_values eq 'hijkl' or $sorted_values eq 'ijklm') { # do stuff... }
but what I'd really like to say is something like...
if ($sorted_values =~ m/INSERT_PATTERN_HERE/) { # Do stuff... }

I've tried reading the Chapter on regexps and pattern matching in the Blue Camel but I'm not really making any progress. In essence I'm trying to match all combinations of characters where they form a contiguous sequence (I have thought about doing this using the return values from ord() but decided that this would be inelegant.)

Can anyone give me some pointers please?


"Rule #17 of Travel: Never try and score dope off Hassidic Jews while under the impression that they are Rastafarians."
       - Pete McCarthy, McCarthy's Bar

Replies are listed 'Best First'.
Re: Pattern Matching Query
by BrowserUk (Pope) on Sep 17, 2002 at 12:46 UTC

    Update: Added missing brackets and an afterthought at the bottom. And corrected the error blakem pointed out below.

    You don't need a regex, a simple index will do fine. This has the additional benefit that $run will give you a comparative value for determining the value of the hand.

    if (($run = index('abcdefghijklm', $sorted_values,0)) > -1) { # Do stuff... }

    In fact, if you arranged for your sort of the cards to sort aces above kings, then you could use the $run values to determine which run has the higher scoring value. (I think. I'm not much of a card player :^)

    Well It's better than the Abottoire, but Yorkshire!
      A return value of 0 from index actually means it found the substr at position 0. An rv of -1 indicates failure. Therefore:
      if (index('abcdefghijklm', $sorted_values) > -1) { # Do stuff... }


Re: Pattern Matching Query
by blakem (Monsignor) on Sep 17, 2002 at 12:49 UTC
    How about using $sorted_values as the regex?
    if ("abcdefghijklm" =~ /$sorted_values/) { ... }
    Update Or index would work as well.


      And of course to play it safe, if ("abcdefghijklm" =~ /\Q$sorted_values\E/) {

      Makeshifts last the longest.

Re: Pattern Matching Query
by davorg (Chancellor) on Sep 17, 2002 at 12:52 UTC

    Regexes aren't always the answer. This solution uses substr and the magical autoincrement properties of strings.

    #!/usr/bin/perl -w use strict; while (<DATA>) { chomp; my $card = substr $_, 0, 1; my $run = 1; foreach my $x (1 .. 4) { ++$card ne substr $_, $x, 1 and $run = 0, last; } print "$_ - ", $run ? 'yep' : 'nope', "\n"; } __DATA__ abcde abcef fghij acghm

    Update: Argh! Or either of the previous answers would probably be better :(


    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

Re: Pattern Matching Query
by rob_au (Abbot) on Sep 17, 2002 at 13:51 UTC
    In the spirit of TMTOWTDI ...

    my @matches = ( 'abcde', 'bcdef', 'cdefg', 'defgh', 'efghi', 'fghij', 'ghijk', 'hi +jkl', 'ijklm' ); if ( grep { $sorted_values eq $_ } @matches ) { # ... }

    This approach makes for easy maintenence, particularly, if there a number of points in the code where matching is to be carried out. However, this method should prove to be slower compared to other methods in that it executes in O(n), where n is the number of elements in @matches.



Re: Pattern Matching Query
by Solo (Deacon) on Sep 17, 2002 at 12:54 UTC
    I think you want the qr{} operator. See perldoc perlop.
    use warnings; use strict; my $hand = 'defgh'; my @tests = ( qr/abcde/, qr/bcdef/, qr/cdefg/, qr/defgh/, ); for my $test (@tests) { if ($hand =~ /$test/) { # do stuff # print "Got a straight\n"; } }
    Update: As others have suggested in the full thread there are more elegant ways to do this.
    May the Source be with you.

    You said you wanted to be around when I made a mistake; well, this could be it, sweetheart.

Re: Pattern Matching Query
by thunders (Priest) on Sep 17, 2002 at 20:50 UTC
    similar to some of the above and limited to only the cases you mentioned
    if ('abcdefghijklm' =~ qr/$sv/ && $sv =~/^[a-m]{5}$/){ &do_stuff }
      Good implementation, I consider it the best of those posted because it explicitly matches only those conditions that were given in the example as you say, as opposed to some of the others which match considerably more. With poker, you don't really want to screw up :)

      I offer a slight modification:

      if (join('','a'..'m') =~ qr/$sv/ && $sv =~/^[a-m]{5}$/){ print "Matched\n"; }

      Which just means you don't need to specify the whole of the range, just the start and end, you could sub it like this:

      sub match_range { my ($string, $start, $end, $length) = @_; if (join('',$start .. $end) !~ qr/$string/) { return 0; } if ($string !~ /^[${start}-${end}]{$length}$/) { return 0; } return 1; }
        Nice, but since boolean operators shortcircuit anyway (ie the right operand of && won't even be evaluated if the left one is already false), you just added a lot of blocks for no gain. Also, return 0 is a bad meme, if you want to return false then just return (which is equivalent to return wantarray ? () : undef).
        sub match_range { my ($string, $start, $end, $length) = @_; my $range = join '', $start .. $end; return $range =~ /$string/ && $string =~ /^[$range]{$length}$/; }
        Just a bit of nitpickery.. :-)

        Makeshifts last the longest.

Re: Pattern Matching Query
by Lexicon (Chaplain) on Sep 17, 2002 at 17:14 UTC
    Yay, another poker module!

    I wrote a fairly efficient Classify_Hand subroutine in my Poker Probability Processor. It works on arbitrarily large hands and returns a string indicating the rank of the hand. It, and the rest of the module, might be worth looking at. I had originally intended to extend it to calculate odds of winnning various types of poker, including Texas Holdem', but after all the time writing the Combinator module, I was done. ;)

      Hi Lexicon,

      Interesting stuff - I wish I'd searched PM before I started in on this! Although I probably would have written my version anyway as I have really improved my Perl over the past week or so.

      One of the things that I noticed was that you can use a lot of cheats rather than look for the exact hand (mine only work for five cards though) - for example, if a unique list of the card values has only two elements then it must be either a full house or a four-of-a-kind. This reduces by a long way the amount of work to be done. I've also realised that I can rank the hand using the standard gt, lt and eq operators because of the way I set out how the hand's score is formatted.

      The version I'm working on at the moment uses an object oriented (something I'm trying to get a handle on) interface to handle the card-related functions: Shuffling, dealing, flopping, turn, river and who wins. I've also added a sethand function so that it can be used for basic statistical analyses. The next thing for me to write is an overlying game & betting manager so that it can be used as the basis for some kind of AI Poker competition or game.

      Thanks, Elgon

      "What this book tells me is that goose-stepping morons, such as yourself, should read books instead of burning them."
             - Dr. Jones Snr, Indiana Jones and the Last Crusade

        Tis very try, but we played some three card games like Pineapple and some seven card games like Anaconda and 7 Card Stud. Plus, since I wasn't prepared to write an AI, it gives some indication of hand frequency when playing optimal 5 card draw.

        I originally was writing the module to be object oriented, but do to the sheer speed requirements, I went this direction. As I recall, method calls are an order of magnatude slower than mere subroutine calls. Can anyone verify that? Unless you're planning an exhaustive search of the hand space, there's not much need for that kind of speed though. And a poker AI isn't going to be a branching tree search like Go or Chess, I'd imagine it would be mostly statistics based, also not so speed dependent.

        The poker project drastically improved my Perl and general programming skills and math skills as well, especially the Math::Combinatorics::Combinator module, which required a heafty amount of analysis and then a heafty amount of optimization, and led to a couple of researching side projects like Fundamental Benchmarks.

        So yeah, I love this kind of useless project (well, mine was useless :).

Re: Pattern Matching Query
by perlguy (Deacon) on Sep 17, 2002 at 17:03 UTC
    more in the spirit of TMTOWTDI:

    UPDATE: I should have used the character class [a-z] instead of \l\w in the first part of the regex, that way numbers, uppercase characters and underscores wouldn't be matched. it would still work either way, though.

    if (/(\l\w)(?{local $lastchar = ord $1;})(??{chr(++$lastchar)}){4}/) { # INSERT YOUR CODE HERE }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://198468]
Approved by moxliukas
Front-paged by derby
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (3)
As of 2017-06-25 04:26 GMT
Find Nodes?
    Voting Booth?
    How many monitors do you use while coding?

    Results (564 votes). Check out past polls.