Menu
Coddy logo textTech

Bank Ledger

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

challenge icon

Challenge

Hard

Build a small bank.

  • BankError(message) is a sealed class that extends Exception, with the subclasses InvalidAmount (invalid amount), Insufficient(id) (insufficient funds in 2), WithdrawalLimit(id) (withdrawal limit on 2) and NoAccount(id) (no account 9).
  • Account(id, owner) is abstract. Its balance can be read everywhere and changed only by the account classes. deposit(amount) and withdraw(amount) throw InvalidAmount for amounts below 1, and withdraw throws Insufficient when the balance would drop below the account's lowestBalance. It declares the abstract kind and an open monthEnd() that does nothing.
  • Checking allows an overdraft down to -100. Savings never goes below 0, allows at most 2 withdrawals per month (WithdrawalLimit) and, in monthEnd(), adds 1% interest (rounded down) and resets the withdrawal count.
  • Bank has open(kind, id, owner), account(id) (throws NoAccount), transfer(from, to, amount), which looks up both accounts first and then withdraws and deposits, monthEnd() for every account and accounts() sorted by id.

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's message, and finally every account as 1 ada checking: -20.

Your code goes in BankError.kt, InvalidAmount.kt, Insufficient.kt, WithdrawalLimit.kt, NoAccount.kt, Account.kt, Checking.kt, Savings.kt and Bank.kt. Main.kt holds the supplied input/output code and cannot be edited.

Try it yourself

fun main() {
    // Supplied input/output code: keep it as it is
    val input = generateSequence(::readLine).toList()
    val bank = Bank()
    for (cmd in input) {
        val p = cmd.split(" ")
        try {
            when (p[0]) {
                "open" -> bank.open(p[1], p[2].toInt(), p[3])
                "dep" -> bank.account(p[1].toInt()).deposit(p[2].toInt())
                "wd" -> bank.account(p[1].toInt()).withdraw(p[2].toInt())
                "tr" -> bank.transfer(p[1].toInt(), p[2].toInt(), p[3].toInt())
                else -> bank.monthEnd()
            }
            println("ok")
        } catch (e: BankError) {
            println(e.message)
        }
    }
    for (a in bank.accounts()) println("${a.id} ${a.owner} ${a.kind}: ${a.balance}")
}

All lessons in Object Oriented Programming

Practice on your own: Kotlin playground