# Help me cheat at Cheat

Cheat is a card game where you're trying to get rid of your hand. A turn looks something roughly like this:

1. Determine what card rank you have to play that turn. In most variants this is one rank higher than the previous turn.
2. Play 1-4 cards, face down. These don't have to match the valid rank. If they don't, it's considered a cheat. At this point any player may challenge you.
• If nobody challenges you, play continues to the next player.
• If somebody challenges you and you didn't cheat, they have to take all of the played cards.
• If somebody challenges you and you did cheat, you have to take all of the played cards.

The strategy is mostly a mix of bluffing and card counting. I'm bad at math, though, so I'm going to cheat at Cheat and bring a bot with me.

# Input

The input will be, in any order or format you want:

1. The player's hand. If I know that they must have cards (for example, I've seen them pick them up), those will be listed in ascending order. Any unknowns will be listed afterwards as ?. For example, if they have six cards and I know that two are 1's and one is a 4, a valid representation of the hand is 114???. ?'s will always be listed after known cards. 141??? and 11???4 are both invalid inputs and your code doesn't need to handle them.
2. The cards I definitely know are not part of their hand (I have them, I saw someone else pick them up, etc). The list will be in ascending order of rank. The list may be empty.
3. The cards the player claimed to play. If they claimed to play 3 7's, a possible input here would be 777. The cards will always be the same rank.

The number of played cards will always be 1-4 and the ranks will always be 0-9. A rank will never appear more than four times in their hand + not their hand.

This is an example valid input:

33577??
01555688
55


This is an example invalid input:

35377?? # Out of order
7779    # Five 7's in total
23      # Two separate ranks played


# Output

A truthy value if we should definitely challenge. A falsey value if we might not want to challenge.

We always challenge if we know they cheated. We know they cheated if they played cards they couldn't possibly have:

12

3  # They don't have any 3's or ?'s
-------------
12?

33 # Fewer ?'s than played cards
-------------
123?
333
33 # Since we have three 3's they can't have two


The other time we challenge is if they play their last cards. Even if the play's legit it would end the game so we might as well challenge it.

1

1 # They'd win, so challenge anyway


# More Test Cases

Truthy (should challenge)

11445678?

22
-------------
????????
4
4444
-------------
12345678

9


Falsey (should not challenge)

1?
222
2
-------------
12?
22
22
-------------
?????

1111


# Scoring

Shortest code wins.

• This is bullsh*t :) Oct 26, 2016 at 18:58
• How many people are playing? Oct 26, 2016 at 18:59
• @jacksonecac you're only looking at one play, so you don't have to worry about how many players there are. Oct 26, 2016 at 19:21
• This should be a king-of-the-hill challange
– Vlo
Oct 26, 2016 at 20:41
• Shouldn't you be challenging in the second falsey case? Oct 27, 2016 at 13:35

# Pyth, 22 bytes

!}zS+*hzhS,/Q\?-4l@z+w


Try it online.

## JavaScript (ES6), 93 bytes

(h,s,c,g=(a,z=c[0])=>a.split(z).length-1)=>h.length==g(c)|g(h,'?')+g(h)<g(c)|g(h)+g(s)+g(c)>4


Accepts three strings of cards (characters 0-9 or ?); returns 1 for challenge, 0 otherwise. Explanation:

(h,s,c,                 Input parameters
g=(a,z=c[0])=>         Helper function defaults to claimed card
a.split(z).length-1   Count cards matching (g(c) == c.length)
)=>h.length==g(c)       Does hand length equal claim length
|g(h,'?')+g(h)<g(c)   Could hand not contain claimed cards
|g(h)+g(s)+g(c)>4     Are there too many claimed cards


# C#6, 134 bytes

using System.Linq;
bool f(string a,string b,string c)=>a.Length==1|a.Count(x=>x==c[0]|x=='?')<c.Length|b.Count(x=>x==c[0])+c.Length>4;


(Note: In line with OP's example, this answer returns false even if opponent has more than one card and is playing all of his hand. In terms of strategy this should return true.)

Explanation:

a: Player's hand
b: Cards I definitely know...
c: Cards claimed to play

Ungolfed:

bool f(string a, string b, string c) =>
a.Length == 1                               // Last card played
| a.Count(x => x == c[0] | x == '?' )       // Count no. of cards that surely/may match claimed cards
// Assuming all claimed cards are the same, just compare with c[0]
< c.Length                              // I'm sure you don't have that many cards...
| b.Count(x => x == c[0]) + c.Length > 4;   // ... Or that there can't be that many cards in play

• Shouldn't a.Length==1 be a.Length==c.Length. You seem to imply something like that in your note, but I don't know which OP's example you are referring to that makes it possible that more cards are being played then the amount of cards the opponent has in their hand. Nov 10, 2017 at 12:28

# Java 8, 169 135 bytes

(a,b,c)->{int C=c.length();char x=c.charAt(0);return a.length()==C|(a+0).split(x+"|\\?",-1).length<=C|5-(b+0).split(""+x,-1).length<C;}


Explanation:

Try it here.

(a,b,c)->{            // Method with three String parameters and boolean return-type
int C=c.length();   //  The amount of cards played by your opponent this turn
char x=c.charAt(0); //  The card played by your opponent this turn
return a.length()==C//  Return true if your opponent played his entire hand (final round)
|(a+0).split(x+"|\\?",-1).length
//   Or the amount of the played card and '?' in your opponent's hand
<=C             //   is smaller than the amount of cards played
|5-(b+0).split(""+x,-1).length
//   Or if 4 minus the amount of the played card are part of the
//   cards you definitely know,
<C;              //   is smaller than the amount of cards played
}                     // End of method


NOTE: (s+0).split("c",-1).length-1 gives the amount of times the character c occurs in String s. So the comments in the explanation above are correct, but the code might seem different because of it. The (a+0).split(x+"|\\?",-1).length-1<C is golfed to (a+0).split(x+"|\\?",-1).length<=C and the 4-(b+0).split(""+x,-1).length-1<C is golfed to 5-(b+0).split(""+x,-1).length<C.