296. Design an ATM System
Asked in
Design an ATM System
Design an ATM system that allows a customer to insert a card, enter a PIN, check the account balance, deposit cash, withdraw cash, cancel a session, and eject the card.
The ATM supports notes with denominations 100, 200, 500, and 2,000. Only one card can be active in the ATM at a time.

Constructor

ATMSystem()
  • Creates an ATM with no accounts and no cash.
  • The ATM initially has no active card.

Add an Account

boolean addAccount(String cardNumber, String pin, int openingBalance)
  • Adds an account identified by cardNumber.
  • pin must contain exactly four digits.
  • Returns true when the account is added.
  • Returns false if the card number already exists or any parameter is invalid.

Load Cash

boolean loadCash(int denomination, int count)
  • Adds count notes of the given denomination to the ATM.
  • Repeated calls add to the existing number of notes.
  • Returns true when the notes are added.
  • Returns false if the denomination is unsupported or count is not positive.

Customer Operations

Insert a Card

boolean insertCard(String cardNumber)
  • Returns true and starts a session when the card exists, is not blocked, and no other card is active.
  • Returns false otherwise.
  • A newly inserted card is not authenticated until the correct PIN is entered.

Enter a PIN

boolean enterPin(String pin)
  • Returns true and authenticates the active card when the PIN is correct.
  • Returns false when there is no active card or the PIN is incorrect.
  • An incorrect PIN increases the failed-attempt count for that card.
  • After three consecutive incorrect attempts, the card is permanently blocked and automatically ejected.
  • Failed attempts are counted across sessions for the same card.
  • A successful PIN entry resets the card's failed-attempt count to zero.
  • If the current session is already authenticated, this method returns false and makes no changes.

Check Balance

int getBalance()
  • Returns the balance of the authenticated account.
  • Returns -1 if there is no authenticated session.

Withdraw Cash

List<Integer> withdrawCash(int amount)
  • Withdraws exactly amount from the authenticated account.
  • The amount must be positive and divisible by 100.
  • The account must have enough balance, and the ATM must be able to dispense the exact amount using its available notes.
  • The ATM uses the smallest possible number of notes.
  • If multiple selections use the same number of notes, prefer more notes of higher denominations in this order: 2,000, 500, 200, 100.
  • Returns the dispensed note values in descending order.
  • Returns List.of(-1) if the withdrawal cannot be completed, the amount is not positive, or the amount is not divisible by 100.
  • A failed withdrawal does not change the account balance or ATM cash.

Deposit Cash

boolean depositCash(List<Integer> notes)
  • Deposits the supplied notes into the authenticated account.
  • Every value in notes must be a supported denomination.
  • Returns true after adding the total value to the account balance and adding the notes to the ATM.
  • Returns false if there is no authenticated session, the list is empty, or any note is invalid.
  • Returns false and makes no changes if the resulting account balance would exceed 1,000,000.
  • A failed deposit does not change the account balance or ATM cash.

Cancel the Session

boolean cancelSession()
  • Cancels the current session, clears authentication, and ejects the active card.
  • It can be called before or after the card is authenticated.
  • Returns true when an active session is cancelled.
  • Returns false when no card is active.
  • It does not reverse any deposit or withdrawal that already completed successfully.
  • It does not reset failed PIN attempts for the card.

Eject the Card

boolean ejectCard()
  • Ejects the active card, clears authentication, and ends the current session.
  • Returns true when a card is ejected.
  • Returns false when no card is active.
  • It does not reset failed PIN attempts for the card.

Method Call Order

  • enterPin returns false if no card is active.
  • enterPin returns false and makes no changes if the current session is already authenticated.
  • getBalance returns -1 if the active card has not been authenticated.
  • withdrawCash returns List.of(-1) if the active card has not been authenticated.
  • depositCash returns false if the active card has not been authenticated.
  • insertCard returns false if another card is already active.
  • cancelSession and ejectCard return false if no card is active.
  • After a session is cancelled or a card is ejected, customer operations fail until another card is inserted and authenticated.
  • A method called in the wrong order makes no changes, except that an incorrect PIN entered before authentication increases the card's failed-attempt count.

Rules

  • Card numbers are case-sensitive.
  • Account balances and ATM note counts must never become negative.
  • An account balance must never exceed 1,000,000.
  • Deposit, withdrawal, and balance operations require an authenticated session.
  • Every deposit and withdrawal is completed as one atomic operation.
  • A failed operation must not make partial changes.
  • Calls are processed sequentially in the order received.
  • Deposited notes are immediately available for later withdrawals.
  • Cancelling or ejecting a card does not reset its failed PIN attempts.
  • Cancelling a session cannot undo an operation that has already completed.
  • Administrative methods may be called at any time because all calls are processed sequentially.

Constraints

  • 1 ≤ cardNumber.length() ≤ 20
  • cardNumber contains only uppercase English letters and digits.
  • pin.length() == 4
  • pin contains only digits.
  • 0 ≤ openingBalance ≤ 1,000,000
  • 1 ≤ amount ≤ 1,000,000
  • denomination is one of 100, 200, 500, or 2,000.
  • 1 ≤ count ≤ 1,000,000
  • 0 ≤ notes.size() ≤ 1,000
  • At most 100,000 method calls will be made.

Examples

Parameter names in the examples are shown only for readability and are not part of Java syntax.

Example 1: Deposit and Withdrawal

ATMSystem atm = new ATMSystem()
atm.addAccount(cardNumber = "CARD81", pin = "4826", openingBalance = 1600) -> true
atm.loadCash(denomination = 500, count = 1) -> true
atm.loadCash(denomination = 200, count = 3) -> true
atm.insertCard(cardNumber = "CARD81") -> true
atm.enterPin(pin = "4826") -> true
atm.enterPin(pin = "9999") -> false
atm.withdrawCash(amount = 600) -> [200, 200, 200]
atm.getBalance() -> 1000
atm.depositCash(notes = [500, 100]) -> true
atm.withdrawCash(amount = 600) -> [500, 100]
atm.getBalance() -> 1000
atm.ejectCard() -> true
The second PIN call returns false because the session is already authenticated. The first withdrawal uses three 200 notes because the available 500 note cannot form 600. After the deposit, the second withdrawal uses the minimum of two notes.

Example 2: Card Blocking

ATMSystem atm = new ATMSystem()
atm.addAccount(cardNumber = "CARD25", pin = "7314", openingBalance = 900) -> true
atm.insertCard(cardNumber = "CARD25") -> true
atm.enterPin(pin = "1111") -> false
atm.enterPin(pin = "2222") -> false
atm.enterPin(pin = "3333") -> false
atm.getBalance() -> -1
atm.insertCard(cardNumber = "CARD25") -> false
The third consecutive incorrect PIN blocks and ejects the card, so it cannot be inserted again.

Example 3: Failed Withdrawal

ATMSystem atm = new ATMSystem()
atm.addAccount(cardNumber = "CARD92", pin = "5081", openingBalance = 1500) -> true
atm.loadCash(denomination = 500, count = 1) -> true
atm.loadCash(denomination = 200, count = 1) -> true
atm.insertCard(cardNumber = "CARD92") -> true
atm.enterPin(pin = "5081") -> true
atm.withdrawCash(amount = 800) -> [-1]
atm.getBalance() -> 1500
Although the account has enough balance, the ATM contains only 700, so the withdrawal fails without changing the balance.

Example 4: Cancel a Session

ATMSystem atm = new ATMSystem()
atm.addAccount(cardNumber = "CARD47", pin = "6492", openingBalance = 2400) -> true
atm.loadCash(denomination = 500, count = 4) -> true
atm.insertCard(cardNumber = "CARD47") -> true
atm.enterPin(pin = "6492") -> true
atm.getBalance() -> 2400
atm.cancelSession() -> true
atm.getBalance() -> -1
atm.withdrawCash(amount = 500) -> [-1]
atm.ejectCard() -> false
Cancelling the session clears authentication and ejects the card. Therefore, later customer operations fail until a card is inserted and authenticated again.

Example 5: Deposit Exceeds the Balance Limit

ATMSystem atm = new ATMSystem()
atm.addAccount(cardNumber = "CARD63", pin = "2750", openingBalance = 999500) -> true
atm.insertCard(cardNumber = "CARD63") -> true
atm.enterPin(pin = "2750") -> true
atm.depositCash(notes = [500, 100]) -> false
atm.getBalance() -> 999500
The deposit would increase the balance to 1,000,100, which exceeds the maximum balance of 1,000,000. The deposit fails without changing the account balance or ATM cash.


Please use Laptop/Desktop or any other large screen to add/edit code.