ATM State Machine
Insert card, enter PIN, withdraw, deposit — the ATM is the canonical finite-state machine, made judge-able.
The state machine
The ATM moves through three states; each command's effect depends on the current state.
| State | Meaning |
|---|---|
| NO_CARD | No card inserted (the initial state). |
| CARD | A card is inserted but the PIN is not yet verified. |
| AUTH | The inserted card's PIN is verified — the transactional state. |
Rules
createAccountregisters an account in the bank in any state and never changes the current session.insertCardworks only fromNO_CARD: it succeeds (ok, →CARD) when the card exists, otherwise returnserrorand stays put. A secondinsertCardwhile a card is already in is anerror.enterPincompares against the inserted card's PIN. A match authenticates the session (→AUTH) and returnstrue; a mismatch returnsfalseand stays inCARD. Called with no card in, it returnsfalse.withdraw,deposit, and a realbalancerequireAUTH. Without it,withdrawreturnserror,depositis a no-op, andbalancereturns-1.withdraw amountdispenses only whenamount ≤ balance(returns the amount as a string and debits it); otherwiseinsufficientwith no debit.ejectCardalways returns toNO_CARDand clears authentication.- Balances never go negative, so
-1frombalanceunambiguously means "no authenticated session".
API to implement
Implement the class ATM. The I/O driver is already written in the starter code — it parses the command script below and calls your methods. You only implement the class.
| Command | Returns | Behavior |
|---|---|---|
| createAccount <cardId> <pin> <balance> | — | Register a bank card cardId with pin and starting balance. Overwrites any existing account for that card and does not touch the current session. |
| insertCard <cardId> | string | Insert card cardId. Returns ok when no card is currently inserted and the card exists (session moves to CARD); otherwise error and nothing changes. |
| enterPin <pin> | boolean | Verify the inserted card's PIN. Returns true and authenticates the session when pin matches; a mismatch returns false (retries allowed). Returns false if no card is inserted. |
| withdraw <amount> | string | Withdraw from the authenticated card. Returns the dispensed amount as a string on success (and debits it), insufficient when the balance is too low (no debit), or error with no authenticated session. |
| deposit <amount> | — | Add amount to the authenticated card's balance. Does nothing without an authenticated session. |
| balance | int | Return the authenticated card's current balance, or -1 when there is no authenticated session. |
| ejectCard | — | Eject any inserted card and end the session, returning the machine to the no-card state. |
Input format
The first line contains Q, the number of operations. Each of the next Q lines is one command as listed above. String arguments contain no spaces.
Output format
For each command with a non-void return, print its result on its own line, in order. The driver does this for you — your methods just return values.
This is a design problem: the hidden tests exercise edge cases and interaction sequences, not performance tricks. Model the state cleanly and the tests will pass.
Sample cases
12
createAccount 1 1234 500
insertCard 1
enterPin 9999
enterPin 1234
balance
withdraw 200
balance
withdraw 1000
deposit 100
balance
ejectCard
balanceok
false
true
500
200
300
insufficient
400
-110
createAccount 7 4321 1000
withdraw 50
insertCard 9
insertCard 7
insertCard 7
withdraw 50
enterPin 4321
withdraw 400
balance
ejectCarderror
error
ok
error
error
true
400
600