Pyth, 73 bytes
eo_S+*-5l@\AN}SPMJ+NZSM.:+\AT5+-4l{eMJlM.gPkJ-sM*=T+`M}2Tc4"JQKA""hscd"=Zc
This is pretty terrible. Parsing cards, sorting the values, ... Everything takes so many chars. But the approach is interesting.
Try it online: Demonstration or Test Suite
Explanation:
I generate all 52 cards, remove the four cards of the input, generate a score for each card (score of the hand), and print the card with the maximal score.
The score is a little bit odd. If I compare the score of two completely different hands, it may pick the wrong winner. E.g. a straight would beat 4 aces. But it works, if the first 4 cards are the same in both hands. And my computed score is actually not a value, but a list of values:
- G: First I group the 5 cards by rank and take the lengths:
5h 5d 6c 5s Jd
->
[3, 1, 1]
- F: Then I append 4 minus the number of different suites to this list.
Flush
->
3
gets appended, not flush
->
2/1/0
gets appended.
- S: Add another number.
0
if it is not a straight, 4
if it is the straight A2345
, or 5
if it is a higher straight.
These lists of 4-7 numbers get sorted in decreasing order and the list with maximal value is picked.
Why does this work? Here you see the possible configurations for all types. The letter beside the numbers, tell you with which rule this number got generated.
- Straight flush:
[5S, 3F, 1G, 1G, 1G, 1G, 1G]
or [4S, 3F, 1G, 1G, 1G, 1G, 1G]
- Four of a kind:
[4G, 1G, 0F, 0S]
- Full house:
[3G, 2G, 1F, 0S]
or [3G, 2G, 0F, 0S]
- Flush:
[3F, 1G, 1G, 1G, 1G, 1G, 0S]
- Straight:
[5S, 2F, 1G, 1G, 1G, 1G, 1G]
, [5S, 1F, 1G, 1G, 1G, 1G, 1G]
, [5S, 1G, 1G, 1G, 1G, 1G, 0F]
, [4S, 2F, 1G, 1G, 1G, 1G, 1G]
, [4S, 1F, 1G, 1G, 1G, 1G, 1G]
, [4S, 1G, 1G, 1G, 1G, 1G, 0F]
- Three of a kind:
[3G, 1G, 1G, 1F, 0S]
, [3G, 1G, 1G, 0F, 0S]
- Two pair:
[2G, 2G, 2F, 1G, 0S]
, [2G, 2G, 1F, 1G, 0S]
, [2G, 2G, 1G, 0F, 0S]
- One pair:
[2G, 2F, 1G, 1G, 1G, 0S]
, [2G, 1G, 1G, 1G, 1F, 0S]
, [2G, 1G, 1G, 1G, 0F, 0S]
- High card:
[2F, 1G, 1G, 1G, 1G, 1G, 0S]
, [1F, 1G, 1G, 1G, 1G, 1G, 0S]
, [1G, 1G, 1G, 1G, 1G, 0S, 0F]
Pyth compares lists element-wise. So it's obvious that a Straight flush will always beat Four of a kind. Most of the typical poker rules are obvious with these lists. Some seem conflicting.
- A Straight will win against Four of a kind or a Full house: Not a problem. If you have a chance to get Four of a kind / Full house with the river card, than you can't reach a straight at the same time (since you already have 2 or 3 different suites in your hand).
- A Straight will win against a flush. If you can reach a flush and a straight with the river card, then you also can reach a straight flush. And the straight flush has a better score than both the straight and the flush.
- One pair
[2G, 2F, 1G, 1G, 1G, 0S]
will win against some two pair hands. Also no problem. If you get a two pair with the river card, than you had at least one pair before the river. But this means, that you can improve to three of a kind, which is better. So a two pair will actually never be the answer.
- High card
[2F, 1G, 1G, 1G, 1G, 1G, 0S]
will win against some one pair hands. If this is the best score you can reach, before the river you will have 3 cards of one suite and one card of a different suite. But then you can choose the card with one of these two suites and with a value that already appears, and you'll end up with the score [2F, 2G, ...]
, which is also better.
So this chooses the correct type of solution. But how do I get the best one-pair (out of 4 possibilities), how do I choose the best straight, ...? Because two different one-pair solutions can have the same score.
That's easy. Pyth guaranties stable sorting (when taking the maximum). So I simple generate the cards in the order 2h 2s 2c 2d 3h 3s ... Ad
. So the card with the highest value will automatically be the maximum.
Implementation details
=Zc
splits the input string and stores the list of cards in Z
.
=T+`M}2Tc4"JQKA"
generates the list of ranks ['2', ..., '10', 'J', 'Q', 'K', 'A']
and stores them in T
. -sM*T..."hscd"Z
generates each combination of rank with the suites, and removes the cards of Z
.
o...
orders these remaining cards by: lM.gPkJ
the lenght of the groups of the ranks, +-4l{eMJlM
appends 4 - length(suites), +*-5l@\AN}SPMJ+NZSM.:+\AT5
appends 0/4/5 depending on suite (generate each substring of length 5 of "A"+T, check if the hand one of them (requires sorting the hand and sorting all subsets), multiply by 5 - number of "A"s in the card), _S
sorts the list decreasing.
e
pick the maximum and print.