Project Overview
This project involved developing a fully-functional C++ vending machine simulator
for a fictional pastry company. The primary focus was on implementing
robust programming techniques, clean code, and dynamic memory management
while following modern C++14 standards. The system simulates real-world vending operations with comprehensive state management, file persistence, and error handling.
Project Scope & Requirements
- Implement a fully functional vending machine supporting product display, purchases, stock management, coin handling, and administrator operations.
- Validate all input and file data (stock, coins) for correctness, handling malformed files, invalid delimiters, negative values, and empty input.
- Manage dynamic memory with proper allocation and deallocation, verified with Valgrind for memory safety.
- Operate entirely in a console environment with persistent storage via structured files.
- Design modular and extensible architecture allowing future enhancements without breaking existing functionality.
- Build custom data structures (singly/doubly linked lists, 2D lists) from scratch rather than using STL containers.
- Pass comprehensive test suites validating all features and edge cases.
Technology Stack:
- C++14 - Programming language
- Custom Linked Lists - Core data structures (ADTs)
- File I/O - Persistent data storage
- Standard C++ Library - Memory management, utilities
- Make - Build automation
- Valgrind - Memory leak detection
Key Objectives & Skills Demonstrated
- Abstract Data Types (ADTs): Design and implementation of singly, doubly, and linked lists from scratch without STL, including node management and pointer operations.
- Dynamic Memory Management: Manual allocation/deallocation with proper use of new/delete, dynamic cast for type conversion, and zero memory leaks verified by Valgrind.
- Object-Oriented Design: Abstract base classes, inheritance hierarchies, virtual methods, and encapsulation principles applied throughout.
- Design Patterns: Command pattern implementation with polymorphic command objects, strategy pattern for linked list switching.
- Exception Handling: Throws and catches for std::runtime_error, std::length_error, std::invalid_argument, and std::domain_error with meaningful error messages.
- File Processing: Parsing structured data formats (stock.dat, coins.dat) with comprehensive validation and error recovery.
- State Management: Tracking vending machine states (normal, purchasing, admin) and enforcing valid state transitions.
- Algorithm Implementation: Change calculation algorithm, binary search patterns, case-insensitive string comparison utilities.
- Testing & Debugging: 16+ test suites covering normal cases, edge cases, malformed input, and memory verification with Valgrind.
- Code Quality: Clean, maintainable code with proper documentation, meaningful variable names, and modular architecture.
Implementation Highlights
Custom Data Structures
Built from scratch without using STL containers:
- LinkedListSingle: Singly-linked list for managing inventory items with insertion, deletion, and traversal.
- LinkedListDouble: Doubly-linked list with bidirectional node traversal using prev/next pointers, enabling reverse display and efficient navigation.
- Abstract LinkedList Base Class: Defines interface with virtual methods for printLL, findItem, saveLL, resetStock, remove, addLL, convertToStock, and deleteLL.
- Node Class: Encapsulates product data including stock ID, name, description, price (dollars/cents), and on-hand quantity. NodeD extends this with prev pointer for doubly-linked lists.
- Comprehensive memory management with proper allocation/deallocation verified via Valgrind.
Core Features
- Product Management: Display inventory in ascending/descending order, add items, remove stock, and track availability in real-time.
- Transaction Processing: Handle purchases with exact change calculation, insufficient funds detection, out-of-stock management, and abort capabilities.
- Coin System: Manage 8 coin denominations (5¢, 10¢, 25¢, $1, $2, $5, $10), calculate change using greedy algorithm, display coin counts, and reset coin reserves.
- File Persistence: Load and save structured stock.dat and coins.dat files with comprehensive validation of format, data types, and constraints.
- Administrative Functions: Reset coins to defaults, restock all items, display inventory in reverse (doubly-linked list feature), abort transactions.
- Error Handling: Exception-based validation using std::runtime_error, std::length_error, std::invalid_argument, and std::domain_error for robust error management.
- Dynamic List Switching: Toggle enhancement feature that switches between LinkedListSingle and LinkedListDouble at runtime.
Architecture
The system follows a modular design with clear separation of concerns:
- VendingMachine (Core Orchestrator): Main system managing state transitions, inventory, coin system, and menu command dispatch.
- LinkedList Classes: Abstract base class with LinkedListSingle and LinkedListDouble implementations providing reusable ADTs.
- Command Pattern: Eight command classes (Abort, DisplayItem, PurchaseItem, Save, AddItem, RemoveItem, DisplayCoins, ResetCoins) encapsulate operations as objects for flexibility and extensibility.
- Menu: User interface layer handling command selection and user interaction.
- Coin Class: Manages coin denominations with static methods for change calculation (getChange), file I/O (saveCoinFile), and coin updates.
- Helper Utility: Static validation functions for stock format, coin values, string operations, and input reading.
- Node & Price Classes: Data structures for product information and currency representation.
Personal Contributions
As a key member of the development team, I was responsible for:
- Architecting the overall system design and module structure.
- Implementing the core vending machine logic and transaction handling.
- Designing and implementing custom linked list data structures from scratch.
- Developing the file processing module for data persistence and validation.
- Creating robust error handling and validation mechanisms.
- Writing and running comprehensive test cases to validate functionality.
- Debugging and optimizing code using Valgrind for memory safety.
- Collaborating with team members to integrate all components into a cohesive system.
Testing & Quality Assurance
The project includes extensive automated testing to ensure reliability and correctness:
- Test Coverage: 16+ comprehensive test suites covering all major features and edge cases.
- Functional Tests: All user workflows including purchases, restocking, coin management, and transaction handling.
- Purchase Tests: Exact change transactions, purchases with change due, out-of-stock detection, insufficient funds, and invalid item selection.
- Administrative Tests: Coin reset, stock replenishment, inventory display (forward and reverse), item addition/removal.
- Edge Case Testing: Malformed files, invalid delimiters, negative values, empty input, boundary conditions.
- Memory Safety: Valgrind verification ensuring zero memory leaks and proper pointer usage across all operations.
- File Validation: Stock and coin file integrity checks with corrupted file handling.
- State Validation: Verifying file updates after transactions and correct coin/stock changes.
- Integration Testing: All components working together through complete transaction workflows.
Challenges & Solutions
Challenge: Managing complex state transitions in a vending machine with multiple concurrent operations (coin insertion, product selection, change calculation).
Solution: Implemented a robust state machine pattern that clearly defines valid state transitions and prevents invalid operations, ensuring program stability even under edge cases.
Challenge: Implementing custom linked lists without using STL, requiring manual memory management and pointer manipulation.
Solution: Designed careful allocation/deallocation strategies with thorough testing to achieve zero memory leaks, verified with Valgrind.
Challenge: Validating complex file formats with multiple delimiters and data types, handling malformed input gracefully.
Solution: Built comprehensive validation logic that checks file structure, data types, and constraints before loading, providing meaningful error messages.