ATM Machine Simulator

Problem

Simulate an ATM. The account starts with balance 5000 and the correct PIN is 1234. Commands: pin X (a right PIN logs in and prints welcome; a wrong PIN prints wrong pin, N left, where N is the number of tries that remain out of 3; the third wrong PIN in a row locks the card and prints card locked; a locked card prints card locked for every later pin command, even with the right PIN; a right PIN resets the count of wrong tries). All other commands print login first when nobody is logged in. balance prints balance B. withdraw n needs a positive multiple of 100 (else invalid amount) and at most the balance (else insufficient funds); on success it prints the new balance as balance B. deposit n needs a positive amount (else invalid amount) and prints balance B. logout prints bye and logs out.

Constraints

  • 1 <= commands <= 10^4
  • |amounts| <= 10^9

Examples

Input

balance
pin 1234
withdraw 1200
logout

Output

login first
welcome
balance 3800
bye

Solutions

Best approachTime O(n)Space O(1)

The ATM is a small state machine with four pieces of state: balance, logged in, number of wrong tries and locked. Every rule is checked in a fixed order (lock, login, amount, funds), so two rules never fight over the answer. Real ATMs never keep PINs in code; this is only a model.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Process lines.
 * Input   : Several lines.
 * Output  : One answer per command.
 * Approach: State in a class.
 * Time    : O(n)
 * Space   : O(1)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: The ATM keeps its whole state in fields. Every command changes the state or reads it.
        static class Atm {
            private long balance = 5000;
            private boolean loggedIn = false;
            private int wrongTries = 0;
            private boolean locked = false;

            // Step 2: The PIN check follows the lock rule. A locked card never opens again.
            String pin(String entered) {
                if (locked) {
                    return "card locked";
                }
                if (entered.equals("1234")) {
                    loggedIn = true;
                    wrongTries = 0;
                    return "welcome";
                }
                wrongTries++;
                if (wrongTries == 3) {
                    locked = true;
                    return "card locked";
                }
                return "wrong pin, " + (3 - wrongTries) + " left";
            }

            // Step 3: All other commands first check that someone is logged in.
            String run(String[] part) {
                if (!loggedIn) {
                    return "login first";
                }
                switch (part[0]) {
                    case "balance":
                        return "balance " + balance;
                    case "withdraw": {
                        long amount = Long.parseLong(part[1]);
                        if (amount <= 0 || amount % 100 != 0) {
                            return "invalid amount";
                        }
                        if (amount > balance) {
                            return "insufficient funds";
                        }
                        balance -= amount;
                        return "balance " + balance;
                    }
                    case "deposit": {
                        long amount = Long.parseLong(part[1]);
                        if (amount <= 0) {
                            return "invalid amount";
                        }
                        balance += amount;
                        return "balance " + balance;
                    }
                    default:
                        loggedIn = false;
                        return "bye";
                }
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(String[] lines) {
        Atm atm = new Atm();
        String[] output = new String[lines.length];
        for (int i = 0; i < lines.length; i++) {
            String[] part = lines[i].split(" ");
            output[i] = part[0].equals("pin") ? atm.pin(part[1]) : atm.run(part);
        }
        return output;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        java.util.List<String> all = new java.util.ArrayList<>();
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine().trim();
            if (!line.isEmpty()) {
                all.add(line);
            }
        }
        String[] lines = all.toArray(new String[0]);
        System.out.println(String.join("\n", solve(lines)));
    }
}
Hints (1)
  1. Why is the lock check first in pin?