Skip to content

Intermediate Project 6 — Vending Machine

Difficulty: Intermediate · Estimated effort: 10–14 hours · Prerequisites: Module 13 — Exception Handling, Module 12 — Templates, Module 14 — The STL with OOP · Combines: a state machine, refusals on the failure path, a stock model, a menu loaded from a file

This is one of the designated integration projects. It must use, explicitly and in writing: multiple classes · relationships between classes · encapsulation · inheritance or composition · polymorphism · the STL · exception handling.

No complete solution is provided. The states are described as behaviour; naming them and deciding what may happen in each is the exercise.


1. Scenario

A vending machine takes coins, dispenses a product when enough credit has been inserted, and returns change. It must refuse what it cannot do — a product that is sold out, an amount above what it can give change for, a coin it does not accept — and it must never take money without either dispensing a product or returning the money.

The machine's control program is also its test suite: a script of coin inserts and button presses must produce exactly one documented outcome each.


2. Problem statement

Model the machine as a state machine with explicit states and transitions, a stock of products, a coin store used for change, and a refusal for every impossible request. Change-making must respect the coins actually in the machine, not the coins the ideal machine would have.


3. User requirements

  • [ ] Insert coins and see the current credit.
  • [ ] Select a product; it dispenses if credit suffices and it is in stock.
  • [ ] Receive change in coins the machine actually holds.
  • [ ] Request a refund of the current credit at any time before dispensing.
  • [ ] See an out-of-service message when the machine cannot give change for any purchase.
  • [ ] Load a menu and initial stock from a file; save the closing state.

4. Functional requirements

  • [ ] Explicit states, at minimum: idle, has credit, dispensing, out of service.
  • [ ] Transitions that are only legal from particular states, enforced rather than assumed.
  • [ ] A Product with a price, and a stock level that cannot go negative.
  • [ ] A coin store counted per denomination, mutated only by the machine's own operations.
  • [ ] Change computed greedily with the available coins, and a documented fallback when greedy fails.
  • [ ] Refusals as distinct exception types: sold out, insufficient credit, cannot make change, invalid coin.
  • [ ] Every operation is a transaction: either it happens completely or nothing changed.

5. Non-functional requirements

  • [ ] The credit and the coins inserted but not yet committed are accounted for separately, or the design says why they are the same value.
  • [ ] Total money in the machine is conserved: insert + load = dispensed value + change + held.
  • [ ] Illegal transitions are impossible to perform, not merely detected.
  • [ ] A refused purchase leaves credit, stock and the coin store all unchanged.
  • [ ] Builds warning-free with g++ -std=c++17 -Wall -Wextra -Werror.

6. Suggested features

  • A restocking mode with an authorization code, and a note on whether that belongs in the same class.
  • A sales log with a daily summary.
  • A CoinCounter template used for both coins and notes, if it earns its generality.
  • A price-rise operation applied to a whole category at once, with the refusal amount recomputed.

7. OOP concepts involved

Concept Required Where it appears
Multiple classes yes Machine, Product, CoinStore, state representation, Menu, error types
Relationships yes Machine ◆ menu and coin store; sale ──> product (a record of a completed act)
Encapsulation yes Stock, credit and coin counts change only through the machine's own operations; conservation holds
Inheritance or composition yes States as objects is one honest answer; an enum plus guard functions is another — argue for yours
Polymorphism yes A Dispenser or state interface with at least two concrete behaviours, or an equally real use of dispatch
The STL yes std::map keyed by denomination, std::vector for the sales log, algorithms for change
Exception handling yes Five refusal types, each rolled back and tested

8. Suggested design considerations

Try "states as objects" once. A MachineState interface with Idle, HasCredit and OutOfService implementations removes the switch and makes "which operation is legal now" a property of the type. It is more code; decide whether it is clearer, and say so either way.

Money conservation is your invariant. Write it down as a formula — loaded + inserted == dispensed_value + change_given + still_held — and check it in the tests after every operation, including refusals. It catches nearly every bug in this project.

Change-making is a real algorithm. Greedy fails for some coin systems. Either prove your coin set is safe for greedy (many are, and the proof is short), or implement the fallback and document it. Do not simply assume.

Decide what "refund" means mid-dispense. If the machine is jammed between committing credit and releasing the product, what happens? A one-paragraph answer in the report is enough; silence is not.


9. Minimum viable version

Products with stock, a coin store, insert/select/refund working, a price check, and one refusal type per failure. State handling may be a simple enum at this stage — but documented.


10. Intermediate extension

Add change-making with a documented fallback, the out-of-service state, and the conservation test that runs after every operation in a scripted session. Then induce the sold-out and cannot-make-change refusals deliberately and confirm the conservation formula still holds.


11. Advanced extension

Convert the state handling to state objects, or justify in writing why you kept the enum — with the line count of the switch as evidence. Then add the sales log and the restocking mode and count the files each change touched.


12. Testing checklist

  • [ ] Exact payment dispenses and leaves credit at zero
  • [ ] Overpayment returns the correct change from the coins available
  • [ ] Selecting a sold-out product is refused, and credit is preserved or refunded as documented
  • [ ] Insufficient credit is refused with the shortfall in the message
  • [ ] Change that the machine cannot make is refused before the product dispenses
  • [ ] Conservation holds after every operation in the scripted session, refusals included
  • [ ] A refund returns exactly the credit to the coin store and the customer
  • [ ] Stock never goes below zero under any scripted sequence
  • [ ] Reloading a saved state reproduces stock, coin counts and prices exactly
  • [ ] An invalid coin is rejected without changing anything

13. Documentation checklist

  • [ ] A state table: state, legal operations, resulting state
  • [ ] The money conservation invariant, as a formula
  • [ ] The change-making rule and its justification or fallback
  • [ ] The menu and stock file format
  • [ ] The scripted session, recorded as evidence, with the observed output

14. Self-evaluation rubric

Criterion Excellent looks like Weight
State machine Explicit states and transitions; illegal operations impossible or cleanly refused 25%
Invariants Money conserved and stock non-negative, checked after every operation 25%
Transactional behaviour Every refusal rolls back completely and is tested 20%
Change algorithm Correct for the coin set, with the reasoning or the fallback documented 10%
STL use Containers and algorithms chosen with reasons 10%
Documentation State table, invariant and evidence written down 10%

Related: Intermediate projects · Project roadmap · All projects · Module 13 — Exception Handling