Think about the short conversation you have with an ATM: insert a card, enter a PIN, request cash, and collect it. The same button can mean something completely different at each step. A withdrawal before authentication should be refused, while a withdrawal during cash dispensing should wait for the current transaction to finish.
The Atm context is already implemented for you. It starts idle with a balance of 10000 and the correct PIN "1234". It also stores the current state, exposes the balance and PIN through helper methods, and delegates every operation to the active state.
Your task is to implement the State pattern pieces:
AtmState contract;IdleState, CardInsertedState, AuthenticatedState, TransactionState, and OutOfServiceState.Each state must answer all seven operations: insertCard, enterPin, withdraw, collectCash, ejectCard, reportError, and reset, plus its state name. Even when an action is not allowed, the active state is responsible for returning the refusal message.
While idle:
insertCard() returns "Card inserted. Enter your PIN." and moves to card inserted.enterPin, withdraw and ejectCard return "No card inserted."collectCash() returns "No cash to collect."While a card is inserted:
insertCard() returns "Card already inserted."enterPin("1234") returns "PIN accepted. You are authenticated." and moves to authenticated. Any other PIN returns "Incorrect PIN. Card ejected." and moves back to idle.withdraw(amount) returns "Enter your PIN first."collectCash() returns "No cash to collect."ejectCard() returns "Card ejected. Returning to idle." and moves to idle.While authenticated:
insertCard() returns "Card already inserted."enterPin(pin) returns "Already authenticated."withdraw(amount) with an amount of 0 or less returns "Invalid amount." An amount above the balance returns "Insufficient funds. Balance: $<balance>." Otherwise it subtracts the amount, moves to the transaction state, and returns "Dispensing $<amount>. New balance: $<balance>." Both refusals leave the balance and the state untouched.collectCash() returns "No cash to collect."ejectCard() returns "Card ejected. Returning to idle." and moves to idle.While a transaction is running:
collectCash() returns "Cash collected." and moves back to authenticated.insertCard, enterPin, withdraw and ejectCard all return "Transaction in progress."From any of those four states, reportError() returns "ATM error reported. Shutting down." and moves the machine out of service. While out of service:
insertCard, enterPin, withdraw, collectCash and ejectCard return "ATM is out of service."reportError() returns "ATM is already out of service."reset() returns "ATM back in service." and moves to idle, keeping the balance.In every state other than out of service, reset() returns "ATM is already in service."
Amounts are whole numbers, so a balance of seven thousand is written $7000.
Do not rewrite Atm. Complete only the marked state interface and state classes. Use the context's provided helpers to read the PIN and balance, update the balance, and install the next state. The tests call the provided Atm class and check that rejected operations preserve both the state and the balance.
Input:
Output:
Explanation: A wrong PIN returns the card, so the machine drops back to idle and the session has to start again. The second attempt uses the right PIN, and the withdrawal takes 3000 off the balance.
Input:
Output:
Explanation: The second withdrawal asks for more than the machine still holds, so it is refused. The state is still AUTHENTICATED and the balance is unchanged, which is why the next withdrawal succeeds.
-1000 <= amount <= 20000pin is a string of 4 digits.10000 and the correct PIN is "1234".100 calls in total are made across all methods.Full marks when all five states are their own classes implementing every operation behind one contract, and `Atm` forwards each call without asking which state it holds. Lose points heavily when `Atm` branches on a state name, or when it tracks the session with `hasCard` and `isAuthenticated` booleans instead of a state object.
Full marks when a withdrawal above the balance returns its message with both the balance and the state untouched, a wrong PIN returns the card and leaves the machine idle, and `reportError` reaches out of service from every state because every state implements it. Lose points when a refused withdrawal changes the balance or the state, or when error handling is a check inside `Atm` that runs before it delegates.
Full marks when the balance and the PIN live on the `Atm` and the states read them back through it, out of service is left only through `reset`, and the transaction phase is a real state that answers every operation rather than a flag. Lose points for printing to stdout.
Passing every test is not enough on its own. A submission is accepted only when the design also clears the bar.
| Call | Returns |
|---|---|
| new Atm() | null |
| insertCard() | "Card inserted. Enter your PIN." |
| enterPin("0000") | "Incorrect PIN. Card ejected." |
| currentState() | "IDLE" |
| insertCard() | "Card inserted. Enter your PIN." |
| enterPin("1234") | "PIN accepted. You are authenticated." |
| currentState() | "AUTHENTICATED" |
| withdraw(3000) | "Dispensing $3000. New balance: $7000." |
| balance() | 7000 |
A wrong PIN returns the card, so the machine drops back to idle and the session has to start again. The second attempt uses the right PIN, and the withdrawal takes 3000 off the balance.
Run checks these cases. Submit also runs a larger hidden set.

