ATM Machine
Imagine walking to an ATM.
You insert your card. You enter your PIN. You withdraw money.
It feels simple.
But behind that simplicity is structure.
This project is about building that structure.
Not visually. Not with databases. Not with real money.
But with logic.
What You Are Building
You will design a console-based ATM system that:
- Authenticates a user using a PIN
- Allows balance checking
- Allows withdrawals
- Allows deposits
- Ends session safely
- Locks after multiple failed attempts
There is no GUI. No database. No external libraries.
Only structured logic.
Why This Project Matters
This project trains:
- State management
- Conditional control
- Defensive programming
- Flow control
- Edge-case thinking
- User-driven loops
An ATM is a controlled system.
Nothing random happens.
Every action follows rules.
That is engineering.
System Rules (Define Before Coding)
Your ATM must:
- Start with an initial balance
- Allow only 3 incorrect PIN attempts
- Prevent withdrawal before authentication
- Prevent withdrawing more than available balance
- Prevent negative deposits or withdrawals
- Exit cleanly when user chooses
These rules define system integrity.
Before writing code, write the rules. Systems fail when rules are unclear.
Think Like a Designer
Before coding, answer mentally:
- What is the state of the ATM?
- When does the session begin?
- When does it end?
- What conditions block action?
- What can go wrong?
If you cannot answer these clearly, pause.
Watch First - How Systems Enforce Rules
While watching, focus on:
- State transitions
- Authentication logic
- Defensive checks
- Controlled termination
Now we build carefully.
Step One - Identify the State
Your ATM needs:
stored_pinbalanceattempts_remainingis_authenticated
These represent system condition.
Everything else depends on them.
Step Two - Outline the Flow
There are two major phases:
Authentication phase
Operation phase
The system must not allow the second without the first.
Pseudocode (Before Python)
Initialize balance
Initialize stored PIN
Initialize attempt counter
While not authenticated and attempts remain:
Ask for PIN
If correct:
Authenticate
Else:
Reduce attempts
If attempts reach zero:
Lock system
If authenticated:
Repeat:
Show menu
Process user choice
Update balance if needed
Exit if chosen
Notice the separation of phases.
That separation is structure.
Basic Implementation
stored_pin = "1234"
balance = 1000
attempts_remaining = 3
is_authenticated = False
while attempts_remaining > 0 and not is_authenticated:
entered_pin = input("Enter PIN: ")
if entered_pin == stored_pin:
is_authenticated = True
print("Access granted.")
else:
attempts_remaining -= 1
print("Incorrect PIN.")
print("Attempts left:", attempts_remaining)
if not is_authenticated:
print("Account locked.")
else:
while True:
print("\n1. Check Balance")
print("2. Withdraw")
print("3. Deposit")
print("4. Exit")
choice = input("Choose option: ")
if choice == "1":
print("Balance:", balance)
elif choice == "2":
amount = float(input("Enter withdrawal amount: "))
if amount <= 0:
print("Invalid amount.")
elif amount > balance:
print("Insufficient funds.")
else:
balance -= amount
print("Withdrawal successful.")
elif choice == "3":
amount = float(input("Enter deposit amount: "))
if amount <= 0:
print("Invalid amount.")
else:
balance += amount
print("Deposit successful.")
elif choice == "4":
print("Session ended.")
break
else:
print("Invalid choice.")
Edge Cases You Must Handle
Ask yourself:
- What if withdrawal amount equals balance?
- What if user enters text instead of number?
- What if PIN attempts reach zero exactly?
- What if user never chooses exit?
This is defensive thinking.
Growth Reflection
Right now:
One user. One balance. One session.
But imagine:
1,000 users.
Now state must be isolated per account.
Now memory management matters.
Now data structures matter.
Now architecture matters.
Even simple systems hint at scaling problems.
Interview Extension
Improve the system by adding:
- Transaction history
- Daily withdrawal limit
- PIN change feature
- Lockout timer
- Decimal-based balance handling
Every enhancement tests structure.
Final Reflection
The ATM is small.
But it forces clarity.
It forces rule definition.
It forces state control.
It forces defensive thinking.
If you design this well, you are not just coding.
You are engineering behavior.
