Quick Overview

This question evaluates implementation of card-hand evaluation logic, combinatorial reasoning about incomplete information, and deterministic tie-breaking rules for comparing complete and partial poker-like hands.

Compare Complete or Partial Hands

Company: Rippling

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: medium

Interview Round: Onsite

Implement a hand comparison engine for a simplified poker-like card game. Each player has a hand represented by an array of card strings. A card is encoded as `<rank><suit>`, where rank is one of `2-10`, `J`, `Q`, `K`, `A`, and suit is one of `S`, `H`, `D`, `C`. ## Part 1: Compare complete hands If both players have exactly 5 cards, return one of: - `"user1"` if player 1 wins - `"user2"` if player 2 wins - `"tie"` if the hands are exactly equal in strength Use the following hand rankings from strongest to weakest: 1. Four of a kind 2. Full house 3. Three of a kind 4. Two pair 5. One pair 6. High card Tie-breaking rules: - **Four of a kind**: compare the rank of the four matching cards, then the kicker. - **Full house**: compare the rank of the triple, then the pair. - **Three of a kind**: compare the rank of the triple, then the remaining two cards in descending order. - **Two pair**: compare the higher pair, then the lower pair, then the kicker. - **One pair**: compare the pair rank, then the remaining three cards in descending order. - **High card**: compare all five ranks in descending order. Assume suits do not affect hand strength. ## Part 2: Compare partial hands Because of network delay, a player may have fewer than 5 received cards. In this case, determine whether the result is already forced. Return: - `"user1"` if player 1 wins for **every** valid completion of the missing cards - `"user2"` if player 2 wins for **every** valid completion of the missing cards - `"tie"` if **every** valid completion ends in a tie - `"unknown"` otherwise For this follow-up, assume: - Each final hand must contain exactly 5 distinct cards. - Missing cards can be any distinct cards from the remaining standard 52-card deck. - No card may appear twice across the final 10 cards. Design the comparison logic cleanly so that ranking rules are modular and easy to extend.

Overview: This question evaluates implementation of card-hand evaluation logic, combinatorial reasoning about incomplete information, and deterministic tie-breaking rules for comparing complete and partial poker-like hands.

Read the full Rippling Software Engineer interview experience this question came from

Part 1: Compare Complete Hands

Implement a hand comparison engine for a simplified poker-like card game. Each player has exactly 5 cards. A card is encoded as '<rank><suit>', where rank is one of 2-10, J, Q, K, A, and suit is one of S, H, D, C. Suits do not affect hand strength. Only the following hand types exist, from strongest to weakest: 1. Four of a kind 2. Full house 3. Three of a kind 4. Two pair 5. One pair 6. High card Tie-breaking rules: - Four of a kind: compare the rank of the four matching cards, then the kicker. - Full house: compare the rank of the triple, then the pair. - Three of a kind: compare the triple, then the remaining two cards in descending order. - Two pair: compare the higher pair, then the lower pair, then the kicker. - One pair: compare the pair rank, then the remaining three cards in descending order. - High card: compare all five ranks in descending order. Return 'user1' if player 1 wins, 'user2' if player 2 wins, or 'tie' if the hands are exactly equal in strength.

Constraints

  • len(user1) == 5
  • len(user2) == 5
  • Each card is a valid standard 52-card deck card
  • All 10 cards are distinct
  • This simplified game does not include straights, flushes, or suit-based scoring

Examples

Input: (['AS', 'AH', 'AD', 'AC', '2S'], ['KS', 'KH', 'KD', 'KC', 'QH'])

Expected Output: 'user1'

Explanation: Both hands are four of a kind; four aces beats four kings.

Input: (['QS', 'QH', 'QD', '9C', '2D'], ['JS', 'JH', 'JD', '8C', '8D'])

Expected Output: 'user2'

Explanation: A full house beats three of a kind.

Hints

  1. Count how many times each rank appears. The sorted frequency pattern tells you the hand category.
  2. Create a score tuple like (category_strength, tie_break_values...) so two hands can be compared lexicographically.

Part 2: Compare Partial Hands

Implement a hand comparison engine for a simplified poker-like card game when some cards have not arrived yet. Each player has a partial hand represented by a list of card strings. A card is encoded as '<rank><suit>', where rank is one of 2-10, J, Q, K, A, and suit is one of S, H, D, C. Each final hand must contain exactly 5 distinct cards. Missing cards can be any distinct cards from the remaining standard 52-card deck, and no card may appear twice across the final 10 cards. Use these hand rankings, from strongest to weakest: 1. Four of a kind 2. Full house 3. Three of a kind 4. Two pair 5. One pair 6. High card Tie-breaking rules: - Four of a kind: compare the rank of the four matching cards, then the kicker. - Full house: compare the rank of the triple, then the pair. - Three of a kind: compare the triple, then the remaining two cards in descending order. - Two pair: compare the higher pair, then the lower pair, then the kicker. - One pair: compare the pair rank, then the remaining three cards in descending order. - High card: compare all five ranks in descending order. Return: - 'user1' if player 1 wins for every valid completion - 'user2' if player 2 wins for every valid completion - 'tie' if every valid completion ends in a tie - 'unknown' otherwise For this version, the total number of missing cards across both players is at most 4.

Constraints

  • 0 <= len(user1) <= 5
  • 0 <= len(user2) <= 5
  • All provided cards are valid standard deck cards
  • All provided cards are distinct across both lists
  • (5 - len(user1)) + (5 - len(user2)) <= 4
  • Each final hand must have exactly 5 cards, and all 10 final cards must be distinct
  • This simplified game does not include straights, flushes, or suit-based scoring

Examples

Input: (['AS', 'AH', 'AD', 'AC', '2S'], ['KS', 'KH', 'KD', '3C'])

Expected Output: 'user1'

Input: (['2S', '2H', '3D', '4C'], ['KS', 'KH', 'KD', 'QC', 'QD'])

Expected Output: 'user2'

Approach

The solution answers "who wins?" by brute-forcing every legal way to fill the missing cards and checking whether the outcome is the same in all of them. Scoring a complete 5-card hand — evaluate. It maps each card's rank to a number (2–10, then J=11…A=14), counts rank multiplicities with a Counter, and inspects the sorted frequency signature: - [4,1] → four of a kind, [3,2] → full house, [3,1,1] → trips, [2,2,1] → two pair, [2,1,1,1] → one pair, else high card. For each category it returns a comparison tuple whose first element is the category strength (5 down to 0) followed by the relevant tie-breaker ranks in the exact priority the problem dictates (e.g. trip rank then the two kickers descending). Python's lexicographic tuple ordering then makes >/< implement all ranking and tie-break rules at once. compare_complete turns two such tuples into 'user1', 'user2', or 'tie'. Handling unknowns. It builds the full 52-card deck, removes every card already held, and enumerates completions with itertools.combinations over the remaining cards. When both players are short, it picks player 1's fill first, then draws player 2's fill from the still-remaining cards so no card is reused. It records the first comparison result in forced; the instant any later completion disagrees, it returns 'unknown'. If every completion agrees, that unanimous result is returned. When both hands are already full it just compares directly. Why it's correct: suit is irrelevant to scoring here, every distinct deal is examined, and unanimity across all deals is exactly the definition of a forced user1/user2/tie.

Time complexity: O(C(R, m1) * C(R - m1, m2)), where R is the number of unseen cards (~44-52), m1/m2 are the players' missing-card counts (m1+m2 <= 4). Each completion's hand evaluation and comparison is O(1) (fixed 5 cards). Worst case is m1=m2=2, giving roughly C(46,2)*C(44,2) ~ 10^6 constant-time comparisons.

Space complexity: O(R) — the 52-card deck and the `remaining`/`rem2` lists of unseen cards dominate; each hand evaluation uses only O(1) extra space, and completions are streamed via `combinations` rather than materialized.

Hints

  1. Reuse a complete-hand evaluator from Part 1. The hard part here is exploring all valid completions.
  2. If you ever find two different outcomes across valid completions, you can stop early and return 'unknown'.

Loading coding console...

Show the approach

Approach

The solution reduces "which poker hand wins" to a single tuple comparison, leaning on Python's lexicographic tuple ordering to do every tie-break automatically.

Encoding ranks. A rank_value map turns each rank into a number: '2''10' map to 210, then J=11, Q=12, K=13, A=14. Card strings are '<rank><suit>', so card[:-1] strips the suit (suits are irrelevant here).

Evaluating one hand. evaluate counts how many times each rank value appears with a Counter, then sorts those counts descending into freqs. The shape of freqs uniquely identifies the hand type:

  • [4,1] → four of a kind, [3,2] → full house, [3,1,1] → trips, [2,2,1] → two pair, [2,1,1,1] → one pair, otherwise high card.

For each type it builds a tuple whose first element is a category rank (5 = four of a kind down to 0 = high card) followed by the tie-break keys in priority order:

  • Four of a kind → (5, four_rank, kicker)
  • Full house → (4, triple_rank, pair_rank)
  • Trips → (3, triple, kicker1, kicker2) with kickers sorted descending
  • Two pair → (2, high_pair, low_pair, kicker)
  • One pair → (1, pair, k1, k2, k3)
  • High card → (0, v1…v5) all five ranks descending.

Comparing. score1 > score2 compares tuples element by element: category first, then each tie-breaker, exactly matching the stated rules. Returns 'user1', 'user2', or 'tie' on equality. Hands of the same category always produce equal-length tuples, so the comparison is always well-defined.

Time complexity:
O(1)
Space complexity:
O(1)