Menu
Coddy logo textTech

Bank Ledger

Part of the Object Oriented Programming section of Coddy's Swift journey. Lesson 57 of 57.

challenge icon

Challenge

Hard

Build a small bank. Account is a class with id, owner and a private(set) var balance, and the methods deposit(_:) and withdraw(_:) that throw BankError.invalidAmount (below 1) and BankError.insufficient(id:). Checking allows an overdraft of 100 (the balance may go down to -100); Savings refuses withdrawals that would make the balance negative, adds 1% interest (rounded down) in monthEnd(), and allows at most 2 withdrawals per month (BankError.limit(id:)), reset by monthEnd(). Account.monthEnd() does nothing. The class Bank stores accounts by id and has transfer(from:to:amount:), which withdraws and deposits or undoes nothing on failure.

The supplied code reads commands open checking 1 ada, open savings 2 bo, dep 1 100, wd 2 30, tr 1 2 50 or month, prints ok or the error (invalid amount, insufficient funds in 2, withdrawal limit on 2, no account 9), and finally prints each account sorted by id as 1 ada checking: -20.

Your code goes in BankError.swift, Account.swift, Checking.swift, Savings.swift and Bank.swift. main.swift holds the supplied input/output code and cannot be edited.

Try it yourself

// Supplied input/output code: keep it as it is
var input: [String] = []
while let line = readLine() { input.append(line) }
let bank = Bank()
for cmd in input {
    let p = cmd.split(separator: " ").map(String.init)
    do {
        switch p[0] {
        case "open":
            let id = Int(p[2])!
            bank.accounts[id] = p[1] == "savings" ? Savings(id: id, owner: p[3]) : Checking(id: id, owner: p[3])
        case "dep": try bank.account(Int(p[1])!).deposit(Int(p[2])!)
        case "wd": try bank.account(Int(p[1])!).withdraw(Int(p[2])!)
        case "tr": try bank.transfer(from: Int(p[1])!, to: Int(p[2])!, amount: Int(p[3])!)
        default: bank.accounts.values.forEach { $0.monthEnd() }
        }
        print("ok")
    } catch BankError.invalidAmount {
        print("invalid amount")
    } catch BankError.insufficient(let id) {
        print("insufficient funds in \(id)")
    } catch BankError.limit(let id) {
        print("withdrawal limit on \(id)")
    } catch BankError.noAccount(let id) {
        print("no account \(id)")
    } catch {
        print("error")
    }
}
for id in bank.accounts.keys.sorted() {
    let a = bank.accounts[id]!
    print("\(a.id) \(a.owner) \(a.kind): \(a.balance)")
}

All lessons in Object Oriented Programming

Practice on your own: Swift playground