Early Access: 87 spots left.

Claim
AI Coding InterviewAI Coding InterviewCart Discount Engine: Fix, Extend, Optimize

Problems

Cart Discount Engine: Fix, Extend, Optimize

Medium·Tagsai-coding-interview3-phasebug-fixfeature-extensiondiscount-engine

Problem Statement

This is a 60-minute, three-phase simulation. Use whichever AI tool you prefer (ChatGPT, Claude, Cursor, Copilot). Read the code before you prompt, scope each prompt narrowly, and run the tests after every change. The codebase is a small e-commerce checkout: a `Cart` of `CartLine` objects, a `Discount` interface, two concrete discounts (`PercentDiscount` and `FlatDiscount`), and a `Checkout` orchestrator. The starter is intentionally laid out as if it were multi-file, with section comments marking what would be each file in a real repo. Phase 1 (Fix the bug, roughly 15 minutes). A failing test points at `PercentDiscount.computeDiscount`. A 10 percent discount on a $100 cart returns $0.10 instead of $10.00. Find the bug, make the smallest possible fix, re-run the test. The bug is local. Do not rewrite the class. Phase 2 (Add a feature, roughly 25 minutes). Product wants a Buy-One-Get-One-Free promotion in which the cheapest line in the cart is free. The starter ships a `BogoDiscount` class that throws `UnsupportedOperationException`. Implement it. The discount equals the smallest `lineSubtotal()` among all lines. If the cart has fewer than two lines, the discount is 0. For example, a cart with `2 × Apple @ $1` (line subtotal $2) and `1 × Bread @ $5` (line subtotal $5) has a BOGO discount of $2, because the apple line is the cheapest. Phase 3 (Compose discounts, roughly 20 minutes). Product wants multiple discounts to apply at once. The starter ships a `StackedDiscount` class. Its constructor takes a `List<Discount>`, and `computeDiscount` should sum each discount's value, capped at the cart's subtotal so the cart can never go negative. Implement it. The stacking rule is `total = min(subtotal, sum of each d.computeDiscount(cart))`. Each individual discount is computed against the original cart subtotal, not against the running total. This matches the contract the rest of the codebase expects, and it is what most production checkout systems do for combinable promotions. The validator runs three scenarios that map to the three phases. 1. phase1_percent_discount_correct: `new PercentDiscount(10).computeDiscount(cart)` on a $100 cart returns $10.00. The bug currently makes it return $0.10. 2. phase2_bogo_correct: `new BogoDiscount().computeDiscount(cart)` returns the smallest line's subtotal, and returns $0 for a single-line cart. 3. phase3_stacking_correct: `new StackedDiscount(List.of(percent10, flat5)).computeDiscount(cart)` on a $100 cart returns $15.00, and stacking enough discounts to exceed the subtotal caps at the subtotal. The stub `BogoDiscount` and `StackedDiscount` classes throw `UnsupportedOperationException`, so phases 2 and 3 fail until you implement them. Phase 1 fails until you fix the percent-discount bug.

Examples

Example 1
Input
var cart = new Cart(); cart.add(new Item("Apple", 1.00), 2); new PercentDiscount(10).computeDiscount(cart)
Output
"0.20"
Why
The cart subtotal is $2.00. A 10 percent discount should be $0.20. The Phase 1 bug returns $0.0002 instead. The fix is to correct the divisor.
Example 2
Input
Cart with 2 × Apple at $1 and 1 × Bread at $5; new BogoDiscount().computeDiscount(cart)
Output
"2.0"
Why
The smallest line is the apple line, with a line subtotal of $2. The BOGO discount equals that line's subtotal.
Example 3
Input
$100 cart; new StackedDiscount(List.of(new PercentDiscount(10), new FlatDiscount(5))).computeDiscount(cart)
Output
"15.0"
Why
Percent gives $10. Flat gives $5. The stacked total is $15, capped at the subtotal so the cart cannot go negative.

Constraints

  • Phase 1: fix only PercentDiscount, with the smallest possible change. Do not rewrite the class.
  • Phase 2: implement BogoDiscount.computeDiscount. The discount is the smallest lineSubtotal across all lines, or 0 if the cart has fewer than 2 lines.
  • Phase 3: implement StackedDiscount.computeDiscount. Sum each discount's computeDiscount(cart), then cap the result at the cart's subtotal.
  • Do not change the Discount interface, the Cart class, or the Checkout class. The validator references them by their existing API.
  • Do not introduce side effects in computeDiscount methods. No logging, no mutation of the cart. Discounts are pure functions of the cart.

Hints

Stuck? Reveal a nudge toward the right pattern, one step at a time.

Hint 1
Phase 1 hint (read this only after you have tried for five minutes): the percent-to-fraction conversion divides by 10000. It should divide by 100. The fix is one character.
Hint 2
Phase 2 hint: cart.getLines().stream().mapToDouble(CartLine::lineSubtotal).min().orElse(0.0) gets you the smallest line. Remember the size < 2 short-circuit so a single-line cart returns 0.
Hint 3
Phase 3 hint: a simple for-loop summing discount.computeDiscount(cart) for each discount, then Math.min(sum, cart.getSubtotal()). Each discount is computed against the original cart, not against the running total.
Hint 4
Test cadence: run scenario 1 first, fix the bug, re-run. Then implement Phase 2 and run scenario 2. Then Phase 3. Avoid trying to do all three at once.
Hint 5
AI usage tip: when you ask the LLM about a phase, paste only the relevant class (PercentDiscount for phase 1, BogoDiscount for phase 2, and so on). Narrower context produces better answers than the whole file.