Help me cheat at Cheat

13

1

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.

Hovercouch

Posted 2016-10-26T18:56:31.430

Reputation: 659

7This is bullsh*t :) – jacksonecac – 2016-10-26T18:58:29.327

How many people are playing? – jacksonecac – 2016-10-26T18:59:52.387

@jacksonecac you're only looking at one play, so you don't have to worry about how many players there are. – Hovercouch – 2016-10-26T19:21:07.270

1This should be a king-of-the-hill challange – Vlo – 2016-10-26T20:41:11.667

The variant that I always played (BTW in Poland this game is called "chuj" which mean "dick" [or rather "dickhead" in that case]) there was rule that you are allowed to put 1, 2 or 4 cards, but not three. Also game was always for 4 players. – Hauleth – 2016-10-26T20:55:07.797

2Shouldn't you be challenging in the second falsey case? – StephenTG – 2016-10-27T13:35:01.267

@StephenTG yup, I messed up. Fixing now – Hovercouch – 2016-10-27T16:14:35.020

The test cases with cards you definitely know empty aren't really possible in a real game of Cheat, because you always know your own hand. ;) – Kevin Cruijssen – 2017-11-10T09:22:47.093

Answers

2

Pyth, 22 bytes

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

Try it online.

PurkkaKoodari

Posted 2016-10-26T18:56:31.430

Reputation: 16 699

1

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.

Kevin Cruijssen

Posted 2016-10-26T18:56:31.430

Reputation: 67 575

1

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

Neil

Posted 2016-10-26T18:56:31.430

Reputation: 95 035

1

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

Link Ng

Posted 2016-10-26T18:56:31.430

Reputation: 593

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. – Kevin Cruijssen – 2017-11-10T12:28:43.930