CAR Class – The Interview Solution in Kotlin (2/2)

10 min
CAR Class – The Interview Solution in Kotlin (2/2)

In the first part I wrote more detailed instructions about this task. Now, in the second part, we will try to make our solution in Kotlin. Enjoy!

Below you can find the solution of this task.

/*
A simple exception class, which is based on a standard Exception class.
*/
class EnvironmentalError(message:String): Exception(message)

/*
The key class of the job interview task.
*/
class Car(brand:String, engine_type:String, tank_capacity:Double, tanked_fuel:Double) {

    /*
    Private basic variables and the one constant.
    */
    private val AVAILABLE_ENGINE_TYPES:Array<String> = arrayOf("gasoline", "diesel")
    private var brand:String = ""
    private var engine_type:String = ""
    private var tank_capacity:Double = 0.0
    private var tanked_fuel:Double = 0.0

    /*
    Class initialization.
    At the first point, validate the initial data and after that assign values
    to the instance variables and log the new creation.
    */
    init {
        this.validate_prerequisites(brand = brand, engine_type = engine_type,
                tank_capacity = tank_capacity, tanked_fuel = tanked_fuel)

        this.brand = brand
        this.engine_type = engine_type
        this.tank_capacity = tank_capacity
        this.tanked_fuel = tanked_fuel

        this.log(message = "New car of brand $brand, with thank full in " + this.to_one_decimal_place(this.get_percentage_fill()) + "%.")
    }

    /*
    The key method of validation, initial values are checked here.
    */
    private fun validate_prerequisites(brand:String, engine_type:String, tank_capacity:Double, tanked_fuel:Double) {
        if (brand.isNullOrEmpty())
            throw IllegalArgumentException("The car brand is not specified.")
        if (this.AVAILABLE_ENGINE_TYPES.contains(engine_type.toLowerCase()) == false)
            throw IllegalArgumentException("The specified engine type is not available, available types are Gasoline and Diesel.")
        if (tank_capacity <= 0)
            throw IllegalArgumentException("The tank capacity must be a positive Integer.")
        if (tanked_fuel < 0)
            throw IllegalArgumentException("The initial tanked fuel value may not be less than zero.")
        if (tanked_fuel > tank_capacity)
            throw IllegalArgumentException("Tanked fulel cannot be greater than tank capacity.")
    }

    /*
    A validation method, which is launched on a car tank fill.
    */
    private fun validate_fill(liters: Double, fill_full: Boolean) {
        if (liters > 0 && fill_full == true) {
            throw IllegalArgumentException("You cannot fill the tank with the specified number of liters and to maximum capacity at the same time.")
        }
        if (liters < 0) {
            throw IllegalArgumentException("The liters value may not be less than zero.")
        }
        if (this.engine_type.toLowerCase() == "diesel") {
            throw EnvironmentalError("ON fuel not available, because of environmental restrictions. Change engine as soon as possible.")
        }
    }
    /*
    A validation method, which is launched when emptying a car tank.
    */
    private fun validate_emptying(limit:Double) {
        if (limit < 0 || limit > 1) {
            throw IllegalArgumentException("The limit value may not be less than zero and not be greater than 1.")
        }
        if (limit > this.get_decimal_fill()) {
            throw IllegalArgumentException("The specified limit is larger than current fill. Current tank fill is " + to_two_decimal_places(this.get_decimal_fill()))
        }
    }

    private fun log(message:String) {
        println(message)
    }

    /*
    The method returns the percentages of a car tank fill.
    */
    private fun get_percentage_fill():Double {
        return this.tanked_fuel / this.tank_capacity * 100
    }

    /*
    The method returns a car tank fill in decimal unit.
    */
    private fun get_decimal_fill():Double {
        return this.tanked_fuel / this.tank_capacity
    }

    /*
    The method returns the number of liters filled after successful filling.
    */
    private fun get_filled_liters(old_tanked_fuel:Double, new_tanked_fuel:Double):Double {
        return new_tanked_fuel - old_tanked_fuel
    }

    /*
    The method, which rounds a decimal number to one decimal place.
    */
    fun to_one_decimal_place(result: Double):String {
        return "%.1f".format(result)
    }

    /*
    The method, which rounds a decimal number to two decimal places.
    */
    fun to_two_decimal_places(result: Double):String {
        return "%.2f".format(result)
    }

    /*
    Simply, print the current car status.
    */
    fun log_car_status() {
        this.log(message = "A car of brand $brand using a $engine_type engine, with thank full in " + this.to_one_decimal_place(this.get_percentage_fill()) + "%.")
    }

    /*
    The key method of the car tank fill. Accepts two parameters,
    and before any operation - first validating data.
    */
    fun fill_tank(liters:Double = 0.0, fill_full:Boolean = false):String {
        this.validate_fill(liters = liters, fill_full = fill_full)

        var old_tanked_fuel = this.tanked_fuel
        if (fill_full) {
            this.tanked_fuel = this.tank_capacity
        } else {
            if (liters + this.tanked_fuel > this.tank_capacity) {
                val maximum_liters_to_fill:Double = this.tank_capacity - this.tanked_fuel
                throw IllegalArgumentException("Warning! Fill is not possible - the tank capacity will be overfilled. The maximum possible number of liters to fill is " + this.to_one_decimal_place(maximum_liters_to_fill))
            }
            this.tanked_fuel += liters
        }
        return this.to_one_decimal_place(this.get_filled_liters(old_tanked_fuel = old_tanked_fuel, new_tanked_fuel = this.tanked_fuel))
    }

    /*
    A simple method for emptying the car tank. Similar to the "fill_tank" method,
    system will check that this operation is possible.
    */
    fun empty_tank(limit:Double):String {
        this.validate_emptying(limit = limit)

        val old_tanked_fuel = this.tanked_fuel
        val liters_to_left = this.tank_capacity * limit
        this.tanked_fuel = liters_to_left

        return this.to_one_decimal_place(old_tanked_fuel - this.tanked_fuel)
    }

}

var volvo = Car(brand = "Volvo", engine_type = "Gasoline", tank_capacity = 120.0, tanked_fuel = 25.4)
volvo.fill_tank(liters = 34.6, fill_full = false)
volvo.log_car_status()
volvo.empty_tank(0.25)

var diesel_fiat = Car(brand = "Fiat", engine_type = "Diesel", tank_capacity = 160.0, tanked_fuel = 80.0)
diesel_fiat.fill_tank(liters = 0.0, fill_full = true)

If you have some doubts about the above code, I will be glad to discuss it with you in the comments below.


Post a Comment

Your email address will not be published. Required fields are marked *

One thought on “CAR Class – The Interview Solution in Kotlin (2/2)