Against the House
A medium Python interview practice problem on DataDriven. Write the Python and run it against test cases, with instant feedback.
- Domain
- Python
- Difficulty
- medium
- Seniority
- L5
- Asked in
- Optimove
Problem
Given exactly 5 dice values (integers 1-6), return the best score using these priorities: five-of-a-kind = 50; four-of-a-kind = 40; full-house (three of one value + two of another) = 25; three-of-a-kind = sum of all 5 dice; otherwise = sum of the dice.
Five little fates land, and only the bold read them right.
Example 1
Input:
dice = [4,4,4,4,4]
Output:
50
Example 2
Input:
dice = [2,2,2,2,5]
Output:
40
Worked solution and explanation
What this really is
Strip the dice costume and this is a frequency-count problem with a priority ladder bolted on. The real skill: turn 'the best pattern wins' into a count of how many times each face shows up, then test the patterns strongest-first. Anyone can add five numbers. What separates candidates is the ordering. A five-of-a-kind also contains a three-of-a-kind, so if you check the small pattern first you hand back the sum when the answer should be 50. The quieter trap: three-of-a-kind and 'nothing matches' both return the plain sum, so people invent a special case for the triple that does not exist.
The trap
Build it
Step 1: Count how often each face appears
Walk the five dice and tally each face into a dict. Now the whole hand is described by those counts, not by the raw order of the dice.
Step 2: Read the pattern off the counts
The single most useful fact is the largest count: 5, 4, or 3 names the top three tiers directly. For the full house you also need to know a pair rides alongside the triple, which is just asking whether any face has a count of exactly 2.
Step 3: Walk the ladder strongest-first
Test top count 5, then 4, then (3 with a pair) for the full house. Everything else, including a bare triple, falls through to the sum of the dice. Highest-first ordering is what keeps a big hand from being caught in a smaller rung.
def dice_roll_scoring(dice):
counts = {}
for value in dice:
if value not in counts:
counts[value] = 0
counts[value] += 1
total = 0
for value in dice:
total += value
top_count = 0
for value in counts:
if counts[value] > top_count:
top_count = counts[value]
if top_count == 5:
return 50
if top_count == 4:
return 40
if top_count == 3 and 2 in counts.values():
return 25
return totalNo sorting needed: the largest count alone names the top tiers, and a lone check for a pair separates the full house.
- Smallest-first (wrong)
- Check 'any face appears 3 times?' before the bigger hands. A five-of-a-kind has a face appearing 5 times, which is also >= 3, so it matches the triple rung and scores the sum. Five 4s returns 20 instead of 50.
- Strongest-first (correct)
- Check top count == 5, then == 4, then the full house, then fall through. Each bigger hand is caught before the ladder ever reaches the triple test, so containment never mis-scores.
Common follow-up questions
- What if you needed to support straights (sequential values)? (Tests detecting sorted consecutive sequences in the dice values.)
- How would you rank two hands against each other? (Tests defining a total ordering on hand types with tiebreakers.)
- What if the number of dice is variable? (Tests generalizing the frequency pattern matching beyond fixed-size input.)
- How would you compute the expected score over all possible rolls? (Tests probability: enumerate all 6^5 outcomes or use combinatorics to weight each hand type.)