PracHub
QuestionsCoachesLearningGuidesInterview Prep
|Home/Software Engineering Fundamentals/Rippling

Design an extensible poker-hand evaluator

Last updated: Jun 17, 2026

Quick Overview

This question evaluates object-oriented design and software architecture skills, specifically the ability to define modular classification and comparison responsibilities for a game-hand evaluator as part of Software Engineering Fundamentals.

  • medium
  • Rippling
  • Software Engineering Fundamentals
  • Software Engineer

Design an extensible poker-hand evaluator

Company: Rippling

Role: Software Engineer

Category: Software Engineering Fundamentals

Difficulty: medium

Interview Round: Technical Screen

Design and implement an object-oriented solution for a simplified two-player poker-like game called **Camel Cards**. The interviewer is explicitly evaluating your **OOP design** alongside correctness, so structure your code for clarity and extension, not just to pass the examples. ### Game Rules - There are **two players**. Each player has a **hand of exactly 4 cards**. - Card labels are one of `9, 8, 7, 6, 5, 4, 3, 2, 1`, where **9 is the highest** and **1 is the lowest**. - A hand is classified into **exactly one** hand type. From **strongest to weakest**: 1. **Four of a kind** — all four cards the same (e.g., `9999`) 2. **Two pair** — two cards the same + two other cards the same (e.g., `2332`) 3. **Three of a kind** — three cards the same + one different card (e.g., `9998`) 4. **One pair** — two cards the same + two distinct others (e.g., `5233`) 5. **High card** — all four cards distinct (e.g., `2345`) > This ordering is **intentional and non-standard**: e.g., **any two-pair beats any three-of-a-kind**. Encode the order the prompt gives, not real-poker convention. ### Tie-Breaking (Ordering Rules) 1. Hands are primarily ordered by **hand type** — the stronger type wins. 2. If both hands have the **same type**, compare cards **from most recently dealt to first dealt** (i.e., **right-to-left**), **without sorting the hand**: - Compare the rightmost card values; the higher value wins. - If equal, move one position left and repeat. - If all four positions are equal, the result is a **TIE**. ### Task Implement: ``` evaluate(hand1, hand2) -> "HAND_1" | "HAND_2" | "TIE" ``` Each hand may be given as a 4-character string like `"2332"` or as an array/list of 4 card labels. Return `"HAND_1"` if `hand1` is stronger, `"HAND_2"` if `hand2` is stronger, or `"TIE"`. ### Design Requirement Many more hand types will be introduced in the future. Design your solution so that **adding a new hand type requires no edits to the evaluator, comparator, or classification logic** — only adding new code. ```hint Where to start Separate the two concerns the prompt deliberately tangles: (1) *which type* a hand is — an order-independent property of the multiset of card values — and (2) *who wins a tie within a type* — an order-**dependent** comparison of the raw dealt cards. Don't let one leak into the other. ``` ```hint Detecting a type cheaply Notice every count-based type depends only on *how many of each value appear*, not on which values or their positions — `9998` and `2221` are "the same kind of hand." What compact, value-agnostic summary of a 4-card hand captures exactly that and lets each type's check stay a one-liner? ``` ```hint The extension point The design requirement ("add a type without editing the evaluator") is the Open/Closed Principle in disguise. What would each hand type have to *own* — about itself — so that the evaluator never names any type by hand? Think about what the classifier needs from a type to both pick it and rank it, and how you'd register a new one without renumbering the others. ``` ```hint The trap that passes the obvious tests Re-read the tie-break: it walks the cards as dealt, right-to-left. It's tempting to reuse the same normalized representation you used for *typing* here too — but ask yourself whether two same-type hands that share the same multiset of values can still resolve to different winners. If they can, what does that forbid you from doing to the cards before the tie-break? ``` ### Constraints & Assumptions - Each hand is exactly **4 cards**; labels are single characters `1`–`9` (no `0`, no `T/J/Q/K/A` in this version). - Inputs may be a string (`"5233"`) or a list (`['5','2','3','3']` or `[5,2,3,3]`) — your API should accept either. - You may assume valid input unless you choose to validate; state whichever you pick. - Optimize for **readability and extensibility** over micro-performance — `n = 4` cards, so asymptotics are not the point. - This is a ~40-minute coding round: a clean, working `evaluate` plus a clearly extensible class structure is the bar, not a full game engine. ### Clarifying Questions to Ask - Is the input guaranteed valid (exactly 4 cards, labels `1`–`9`), or should I validate and reject malformed hands? - Can a hand be passed as both a string and a list, and should both be supported by the same entry point? - When two hands have the same type, am I correct that the tie-break ignores pair rank and kickers entirely and only walks the raw dealt positions? - Will the *strength ordering* of existing types ever change, or do only new types get added between them? - Are card labels guaranteed to stay single digits `1`–`9`, or should the design anticipate `T/J/Q/K/A`? ### What a Strong Answer Covers - A clean separation of responsibilities: parsing/validation, type classification, and ordering/comparison live in distinct collaborators. - A type system that satisfies **Open/Closed** — a new hand type slots in without touching the evaluator, comparator, or classifier. - Correct handling of the **non-standard** type order (two-pair above three-of-a-kind). - Correct **right-to-left, no-sort** tie-break, and an articulated reason why sorting is wrong (permutation hands). - Acceptance of both string and list input through a single normalization point. - Clear naming, fail-fast validation (or a stated assumption), and a few targeted tests including the sort-vs-no-sort trap. - A statement of how a future type that needs more than frequency counts (e.g., a straight) would fit without disturbing existing code. ### Follow-up Questions - A new type **Straight** (four consecutive labels, in any dealt order) is added between two existing types. Walk through exactly what code you add and confirm nothing existing changes. - How would your design change if the label alphabet expanded to `2`–`9, T, J, Q, K, A`, and how do you keep that change to one place? - If two *different* types were ever assigned the same strength, what would break, and how does your design prevent it? - How would you unit-test this so adding a type later doesn't silently regress the comparison rules? What's the smallest set of cases that pins down the tie-break behavior?

Quick Answer: This question evaluates object-oriented design and software architecture skills, specifically the ability to define modular classification and comparison responsibilities for a game-hand evaluator as part of Software Engineering Fundamentals.

Related Interview Questions

  • Design several backend components - Rippling (hard)
  • Design an extensible expense rule evaluator - Rippling (medium)
  • Implement a RESTful Q&A service - Rippling
  • Design article voting and flip-tracking system - Rippling (medium)
  • Explain JS event loop and related concepts - Rippling (medium)
|Home/Software Engineering Fundamentals/Rippling

Design an extensible poker-hand evaluator

Rippling logo
Rippling
Jan 11, 2026, 12:00 AM
mediumSoftware EngineerTechnical ScreenSoftware Engineering Fundamentals
42
0

Design and implement an object-oriented solution for a simplified two-player poker-like game called Camel Cards. The interviewer is explicitly evaluating your OOP design alongside correctness, so structure your code for clarity and extension, not just to pass the examples.

Game Rules

  • There are two players . Each player has a hand of exactly 4 cards .
  • Card labels are one of 9, 8, 7, 6, 5, 4, 3, 2, 1 , where 9 is the highest and 1 is the lowest .
  • A hand is classified into exactly one hand type. From strongest to weakest :
    1. Four of a kind — all four cards the same (e.g., 9999 )
    2. Two pair — two cards the same + two other cards the same (e.g., 2332 )
    3. Three of a kind — three cards the same + one different card (e.g., 9998 )
    4. One pair — two cards the same + two distinct others (e.g., 5233 )
    5. High card — all four cards distinct (e.g., 2345 )

This ordering is intentional and non-standard: e.g., any two-pair beats any three-of-a-kind. Encode the order the prompt gives, not real-poker convention.

Tie-Breaking (Ordering Rules)

  1. Hands are primarily ordered by hand type — the stronger type wins.
  2. If both hands have the same type , compare cards from most recently dealt to first dealt (i.e., right-to-left ), without sorting the hand :
    • Compare the rightmost card values; the higher value wins.
    • If equal, move one position left and repeat.
    • If all four positions are equal, the result is a TIE .

Task

Implement:

evaluate(hand1, hand2) -> "HAND_1" | "HAND_2" | "TIE"

Each hand may be given as a 4-character string like "2332" or as an array/list of 4 card labels. Return "HAND_1" if hand1 is stronger, "HAND_2" if hand2 is stronger, or "TIE".

Design Requirement

Many more hand types will be introduced in the future. Design your solution so that adding a new hand type requires no edits to the evaluator, comparator, or classification logic — only adding new code.

Constraints & Assumptions

  • Each hand is exactly 4 cards ; labels are single characters 1 – 9 (no 0 , no T/J/Q/K/A in this version).
  • Inputs may be a string ( "5233" ) or a list ( ['5','2','3','3'] or [5,2,3,3] ) — your API should accept either.
  • You may assume valid input unless you choose to validate; state whichever you pick.
  • Optimize for readability and extensibility over micro-performance — n = 4 cards, so asymptotics are not the point.
  • This is a ~40-minute coding round: a clean, working evaluate plus a clearly extensible class structure is the bar, not a full game engine.

Clarifying Questions to Ask

  • Is the input guaranteed valid (exactly 4 cards, labels 1 – 9 ), or should I validate and reject malformed hands?
  • Can a hand be passed as both a string and a list, and should both be supported by the same entry point?
  • When two hands have the same type, am I correct that the tie-break ignores pair rank and kickers entirely and only walks the raw dealt positions?
  • Will the strength ordering of existing types ever change, or do only new types get added between them?
  • Are card labels guaranteed to stay single digits 1 – 9 , or should the design anticipate T/J/Q/K/A ?

What a Strong Answer Covers

  • A clean separation of responsibilities: parsing/validation, type classification, and ordering/comparison live in distinct collaborators.
  • A type system that satisfies Open/Closed — a new hand type slots in without touching the evaluator, comparator, or classifier.
  • Correct handling of the non-standard type order (two-pair above three-of-a-kind).
  • Correct right-to-left, no-sort tie-break, and an articulated reason why sorting is wrong (permutation hands).
  • Acceptance of both string and list input through a single normalization point.
  • Clear naming, fail-fast validation (or a stated assumption), and a few targeted tests including the sort-vs-no-sort trap.
  • A statement of how a future type that needs more than frequency counts (e.g., a straight) would fit without disturbing existing code.

Follow-up Questions

  • A new type Straight (four consecutive labels, in any dealt order) is added between two existing types. Walk through exactly what code you add and confirm nothing existing changes.
  • How would your design change if the label alphabet expanded to 2 – 9, T, J, Q, K, A , and how do you keep that change to one place?
  • If two different types were ever assigned the same strength, what would break, and how does your design prevent it?
  • How would you unit-test this so adding a type later doesn't silently regress the comparison rules? What's the smallest set of cases that pins down the tie-break behavior?
Loading comments...

Browse More Questions

More Software Engineering Fundamentals•More Rippling•More Software Engineer•Rippling Software Engineer•Rippling Software Engineering Fundamentals•Software Engineer Software Engineering Fundamentals

Write your answer

Your first approved answer each day earns 20 XP.

Sign in to write your answer.
PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.