HackerRank Python (Basic) certification
Vending Machine
A classes question about state and exceptions. The object has to remember how many items are left, and the error messages have to match HackerRank’s text exactly.
What the question asks
Write a class VendingMachine(num_items, item_price). num_items is how many items the machine holds at the start, and item_price is the number of coins one item costs.
It has one method, buy(req_items, money): a customer wants req_items items and puts in money coins. Three things can happen:
- The machine has fewer items than requested: raise a
ValueErrorwith the messageNot enough items in the machine. - There are enough items, but the money is less than
req_items * item_price: raise aValueErrorwith the messageNot enough coins. - Otherwise the sale goes through: reduce the stock by
req_itemsand return the change as an integer.
The stub creates one machine, then runs up to 100 buy requests on it. For each one it writes either the change or the text of the ValueError it caught.
Function to write
class VendingMachine:
def __init__(self, num_items, item_price): ...
def buy(self, req_items, money): ...Solution
class VendingMachine:
def __init__(self, num_items, item_price):
self.num_items = num_items
self.item_price = item_price
def buy(self, req_items, money):
if req_items > self.num_items:
raise ValueError("Not enough items in the machine")
cost = req_items * self.item_price
if money < cost:
raise ValueError("Not enough coins")
self.num_items -= req_items
return money - costHow it works
- The constructor stores the stock and the price on the object, so every later
buycall sees the current stock. - The stock check comes first. If both problems are true at once (too few items and too little money), the expected message is the items one.
raise ValueError("...")stops the method. The stub catches it withexcept ValueError as eand writesstr(e), which is exactly the message you passed.- Only a successful sale changes
self.num_items. A failed request leaves the machine as it was. - Paying the exact amount is a valid sale and returns 0.
Mistakes that fail the hidden tests
- Changing the message text. No full stop at the end, capital N, and “machine” not “stock”. “Not enough money” or “Insufficient coins” fail.
- Checking money before stock. A request like 10 items for 3 coins on a machine with 9 items must say “Not enough items in the machine”.
- Reducing the stock before the checks. If you subtract first and then raise, the next request sees the wrong stock.
- Using
>=for the stock check. Buying all the remaining items is allowed. Onlyreq_items > num_itemsis an error. - Returning
money - item_price. The change ismoneyminus the price of all the items bought, not one item.
A note on sources: the question text says to raise ValueError, and the stub catches ValueError. Some public solutions return the message as a string instead, and that also prints the right line because the stub writes whatever buy returns. One repo uses all-lowercase messages (“not enough coins”). Go with the question: raise ValueError with the capitalised messages above. If the text in your test shows a different wording, copy their wording exactly.
Try it on sample data
A machine with 10 items at 2 coins each, then four requests, in the stub’s format:
10 2
4
1 5
10 100
7 100
2 3
Output from my run with a copy of the stub’s loop:
3
Not enough items in the machine
86
Not enough coins
Buying 1 item with 5 coins returns 3 and leaves 9 items. Asking for 10 fails. Buying 7 with 100 coins returns 86 and leaves 2. The last request has enough items but 3 coins is less than the 4 needed.