5

Is there a regex to calculate straight poker hand?

I'm using strings to represent the sorted cards, like:

AAAAK#sssss = 4 aces and a king, all of spades.
A2345#ddddd = straight flush, all of diamonds.

In Java, I'm using these regexes:

regexPair = Pattern.compile(".*(\\w)\\1.*#.*");
regexTwoPair = Pattern.compile(".*(\\w)\\1.*(\\w)\\2.*#.*");
regexThree = Pattern.compile(".*(\\w)\\1\\1.*#.*");
regexFour = Pattern.compile(".*(\\w)\\1{3}.*#.*");
regexFullHouse = Pattern.compile("((\\w)\\2\\2(\\w)\\3|(\\w)\\4(\\w)\\5\\5)#.*");
regexFlush = Pattern.compile(".*#(\\w)\\1{4}");

How to calculate straight (sequences) values with regex?

EDIT

I open another question to solve the same problem, but using ascii value of char, to regex be short. Details here.

Thanks!

Community
  • 1
  • 1
Topera
  • 12,223
  • 15
  • 67
  • 104
  • 12
    Of all the bizarre things I've seen regexes used for, this would have to be the second bizarrest :-) – paxdiablo Aug 12 '10 at 00:59
  • 5
    Don't use regular expressions to do this. – Thom Smith Aug 12 '10 at 01:00
  • @paxdiablo: That begs the question: What was the most bizarre? =) – Jens Aug 12 '10 at 06:42
  • 2
    @Jens: that would be the ever-present "How do I validate email addresses with a regular expression?". _Usually_ asked to ensure there's someone at the other end of the address, the questioner doesn't seem to understand that `nobody@nowhere.com` is valid but (probably, I haven't actually checked) doesn't have anyone behind it. The best way to check is to send an activation-type email. No activation in N hours, the request gets tossed. – paxdiablo Aug 12 '10 at 06:50
  • 1
    @pax I think it makes sense to use regex to verify if the email is valid. This way you catch typos that would otherwise leave your user waiting for an email that will never come. – NullUserException Aug 14 '10 at 06:15
  • A regex won't stop me from entering the erroneous `paxdiblo@this.bit.is.correct.com` - all it can do is to catch obviously illegal addresses. It also won't help if you have an aggressive spam filter on an otherwise valid address. The idea with sending a test mail is that it's the only way to verify the mail will get through to that address. You tell the user that, if they don't get something in two days (or whatever), they have to fix the problem then come back and try again. – paxdiablo Aug 14 '10 at 08:25
  • I just want to say it is an excellent application for regular expressions and I don't know why anyone would say not to use this approach (which is the reason found this in the first place, since I was looking to see whether anyone was doing this). – RegularExpression Jan 09 '15 at 21:16

2 Answers2

5

I have to admit that regular expressions are not the first tool I would have thought of for doing this. I can pretty much guarantee that any RE capable of doing that to an unsorted hand is going to be far more hideous and far less readable than the equivalent procedural code.

Assuming the cards are sorted by face value (and they seem to be otherwise your listed regexes wouldn't work either), and you must use a regex, you could use a construct like

2345A|23456|34567|...|9TJQK|TJQKA

to detect the face value part of the hand.

In fact, from what I gather here of the "standard" hands, the following should be checked in order of decreasing priority:

Royal/straight flush: "(2345A|23456|34567|...|9TJQK|TJQKA)#(\\w)\\1{4}"
Four of a kind:       ".*(\\w)\\1{3}.*#.*"
Full house:           "((\\w)\\2\\2(\\w)\\3|(\\w)\\4(\\w)\\5\\5)#.*"
Flush:                ".*#(\\w)\\1{4}"
Straight:             "(2345A|23456|34567|...|9TJQK|TJQKA)#.*"
Three of a kind:      ".*(\\w)\\1\\1.*#.*"
Two pair:             ".*(\\w)\\1.*(\\w)\\2.*#.*"
One pair:             ".*(\\w)\\1.*#.*"
High card:            (none)

Basically, those are the same as yours except I've added the royal/straight flush and the straight. Provided you check them in order, you should get the best score from the hand. There's no regex for the high card since, at that point, it's the only score you can have.

I also changed the steel wheel (wrap-around) straights from A2345 to 2345A since they'll be sorted that way.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • Agreed. Run the regexes above, and then run procedural code to check for straights. That should be pretty straightforward - step through the string and make sure they're sequential. – cincodenada Aug 12 '10 at 01:20
  • 1
    @cincodenada: yes, that's how I'd do it. But sometimes, OPs have a good reason for doing it a specific way (e.g., they may be using a tool/framework that can only use regexes). So, while I'll suggest there may be a better way, I'll still try to help them out. I didn't gel to the idea at first but I can see it would make their source code small and elegant :-) – paxdiablo Aug 12 '10 at 01:24
  • True, which is why I commented on your answer and didn't make my own. But a good reminder to give the OP the benefit of the doubt regardless. Thanks :) – cincodenada Aug 12 '10 at 15:37
  • I found your regex to be a little confusing and unreadable so I rewrote it in my own answer. – James May 30 '18 at 16:23
0

I rewrote the regex for this because I found it frustrating and confusing. Groupings make much more sense for this type of logic. The sorting is being done using a standard array sort method in javascript hence the strange order of the cards, they are in alphabetic order. I did mine in javascript but the regex could be applied to java.

hands = [
    { regex: /(2345A|23456|34567|45678|56789|6789T|789JT|89JQT|9JKQT|AJKQT)#(.)\2{4}.*/g , name: 'Straight flush' },
    { regex: /(.)\1{3}.*#.*/g , name: 'Four of a kind' },
    { regex: /((.)\2{2}(.)\3{1}#.*|(.)\4{1}(.)\5{2}#.*)/g , name: 'Full house' },
    { regex: /.*#(.)\1{4}.*/g , name: 'Flush' },
    { regex: /(2345A|23456|34567|45678|56789|6789T|789JT|89JQT|9JKQT|AJKQT)#.*/g , name: 'Straight' },
    { regex: /(.)\1{2}.*#.*/g , name: 'Three of a kind' },
    { regex: /(.)\1{1}.*(.)\2{1}.*#.*/g , name: 'Two pair' },
    { regex: /(.)\1{1}.*#.*/g , name: 'One pair' },
  ];
James
  • 1,514
  • 12
  • 30