From db2232338152699e148f4fcb55f4b7c878203b26 Mon Sep 17 00:00:00 2001 From: Dmitriy Bulygin Date: Sat, 23 Aug 2025 15:56:29 +0300 Subject: [PATCH] added tasks solutions --- src/main/kotlin/ru/otus/cars/Car.kt | 2 + src/main/kotlin/ru/otus/cars/CarOutput.kt | 10 +- .../kotlin/ru/otus/cars/ExploseanException.kt | 3 + src/main/kotlin/ru/otus/cars/GasStation.kt | 36 +++++++ src/main/kotlin/ru/otus/cars/Tank.kt | 11 ++ src/main/kotlin/ru/otus/cars/TankMouth.kt | 44 ++++++++ src/main/kotlin/ru/otus/cars/Taz.kt | 25 +++++ src/main/kotlin/ru/otus/cars/Vaz2107.kt | 8 ++ src/main/kotlin/ru/otus/cars/Vaz2108.kt | 8 ++ src/main/kotlin/ru/otus/cars/VazPlatform.kt | 54 +++++++++- src/main/kotlin/ru/otus/cars/main.kt | 101 ++++++++++++++++++ 11 files changed, 300 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/ru/otus/cars/ExploseanException.kt create mode 100644 src/main/kotlin/ru/otus/cars/GasStation.kt create mode 100644 src/main/kotlin/ru/otus/cars/Tank.kt create mode 100644 src/main/kotlin/ru/otus/cars/TankMouth.kt diff --git a/src/main/kotlin/ru/otus/cars/Car.kt b/src/main/kotlin/ru/otus/cars/Car.kt index 559978c..baeb4ae 100644 --- a/src/main/kotlin/ru/otus/cars/Car.kt +++ b/src/main/kotlin/ru/otus/cars/Car.kt @@ -28,4 +28,6 @@ interface Car : CarInput { * Внутренний статический класс - номерой знак */ data class Plates(val number: String, val region: Int) + + fun fillTank(fuelType: String, volume: Int): Int } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/CarOutput.kt b/src/main/kotlin/ru/otus/cars/CarOutput.kt index 875339f..d707801 100644 --- a/src/main/kotlin/ru/otus/cars/CarOutput.kt +++ b/src/main/kotlin/ru/otus/cars/CarOutput.kt @@ -5,7 +5,15 @@ package ru.otus.cars */ interface CarOutput { /** - * Скажи текущую скорость + * Скажи текущее состояние */ + + // Текущая скорость fun getCurrentSpeed(): Int + + // Уровень топлива в баке + fun getFuelIndicator(): Int + + // Общая информация о баке + fun getTankInfo(): String } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/ExploseanException.kt b/src/main/kotlin/ru/otus/cars/ExploseanException.kt new file mode 100644 index 0000000..1110a93 --- /dev/null +++ b/src/main/kotlin/ru/otus/cars/ExploseanException.kt @@ -0,0 +1,3 @@ +package ru.otus.cars + +class ExplosionException(message: String) : Exception(message) diff --git a/src/main/kotlin/ru/otus/cars/GasStation.kt b/src/main/kotlin/ru/otus/cars/GasStation.kt new file mode 100644 index 0000000..3b4cb9d --- /dev/null +++ b/src/main/kotlin/ru/otus/cars/GasStation.kt @@ -0,0 +1,36 @@ +package ru.otus.cars + +/** + * Заправочная станция + */ +object GasStation { + fun refuel(car: Car, fuelType: String, volume: Int) { + println("Заправляем машину ${car::class.simpleName} ($volume л. $fuelType)...") + + // Проверка на отрицательные значения и 0 + if (volume < 0) { + println("Ошибка: Нельзя заправить $volume топлива") + return + } + + if (volume == 0) { + println("Заправка $volume литров - ничего не делаем") + return + } + + try { + val filled = car.fillTank(fuelType, volume) + if (filled > 0) { + println("Успешно заправлено $filled литров $fuelType") + } else { + println("Бак полный, заправка не требуется") + } + } catch (e: ExplosionException) { + println("${e.message}") + } catch (e: IllegalArgumentException) { + println("Проблема: ${e.message}") + } catch (e: Exception) { + println("Неизвестная ошибка: ${e.message}") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/Tank.kt b/src/main/kotlin/ru/otus/cars/Tank.kt new file mode 100644 index 0000000..a2523c3 --- /dev/null +++ b/src/main/kotlin/ru/otus/cars/Tank.kt @@ -0,0 +1,11 @@ +package ru.otus.cars + +/** + * Часть топливной системы: Бак + */ +interface Tank { + val capacity: Int + var currentFuel: Int + fun fill(volume: Int): Int + fun getCurrentFuelVolume(): Int +} \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/TankMouth.kt b/src/main/kotlin/ru/otus/cars/TankMouth.kt new file mode 100644 index 0000000..ac1dc01 --- /dev/null +++ b/src/main/kotlin/ru/otus/cars/TankMouth.kt @@ -0,0 +1,44 @@ +package ru.otus.cars + +/** + * Часть топливной системы: Горловина + */ +sealed class TankMouth { + abstract val fuelType: String + abstract fun canAccept(fuel: String): Boolean + + // Разные методы заправки для разных типов горловин + abstract fun refuel(tank: Tank, volume: Int): Int + + // Горловина для бензина + data class GasolineMouth(override val fuelType: String = "Бензин") : TankMouth() { + override fun canAccept(fuel: String): Boolean = fuel == "Бензин" + + override fun refuel(tank: Tank, volume: Int): Int { + println("Заправка бензином через специальную горловину для бензина...") + return tank.fill(volume) + } + } + + // Горловина для газа + data class GasMouth(override val fuelType: String = "Газ") : TankMouth() { + override fun canAccept(fuel: String): Boolean = fuel == "Газ" + + override fun refuel(tank: Tank, volume: Int): Int { + println("Заправка газом через газовую горловину...") + return tank.fill(volume) + } + } + + // Горловина для ТАЗа (взрывающаяся) + object TazMouth : TankMouth() { + override val fuelType: String = "Любой тип топлива" + + override fun canAccept(fuel: String): Boolean = true + + override fun refuel(tank: Tank, volume: Int): Int { + println("Попытка заправки ТАЗа...") + throw ExplosionException("БА-БАХ! ТАЗ взорвался при заправке!") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/Taz.kt b/src/main/kotlin/ru/otus/cars/Taz.kt index 49df937..2457465 100644 --- a/src/main/kotlin/ru/otus/cars/Taz.kt +++ b/src/main/kotlin/ru/otus/cars/Taz.kt @@ -36,4 +36,29 @@ object Taz: Car { override fun wheelToLeft(degrees: Int) { throw NotImplementedError("Руля нет") } + + override fun fillTank(fuelType: String, volume: Int): Int { + // Проверяем можно ли заправить через горловину + if (!tazTankMouth.canAccept(fuelType)) { + throw IllegalArgumentException("Нельзя заправить этот тип топлива") + } + // Используем горловину для заправки (она взорвется) + return tazTankMouth.refuel(tazTank, volume) + } + + private val tazTank = TazTank + private val tazTankMouth = TankMouth.TazMouth + + private object TazTank : Tank { + override val capacity: Int = 0 + override var currentFuel: Int = 0 + + override fun fill(volume: Int): Int { + // Этот метод никогда не вызовется, т.к. горловина взорвется раньше + currentFuel += volume + return volume + } + + override fun getCurrentFuelVolume(): Int = currentFuel + } } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/Vaz2107.kt b/src/main/kotlin/ru/otus/cars/Vaz2107.kt index be857d2..b1afcd6 100644 --- a/src/main/kotlin/ru/otus/cars/Vaz2107.kt +++ b/src/main/kotlin/ru/otus/cars/Vaz2107.kt @@ -16,10 +16,14 @@ class Vaz2107 private constructor(color: String) : VazPlatform(color) { else -> VazEngine.LADA_2107(1600) } } + private fun createTank(): Tank = VazTank(40) + private fun createTankMouth(): TankMouth = TankMouth.GasMouth() override fun build(plates: Car.Plates): Vaz2107 = Vaz2107("Зеленый").apply { this.engine = getRandomEngine() this.plates = plates + setFuelTank(createTank()) + setTankMouth(createTankMouth()) } /** @@ -74,5 +78,9 @@ class Vaz2107 private constructor(color: String) : VazPlatform(color) { override fun getCurrentSpeed(): Int { return this@Vaz2107.currentSpeed } + + override fun getFuelIndicator(): Int = this@Vaz2107.getFuelLevel() + + override fun getTankInfo(): String = "${this@Vaz2107.getTankCapacity()} л" } } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/Vaz2108.kt b/src/main/kotlin/ru/otus/cars/Vaz2108.kt index 27b83b8..b39cff5 100644 --- a/src/main/kotlin/ru/otus/cars/Vaz2108.kt +++ b/src/main/kotlin/ru/otus/cars/Vaz2108.kt @@ -17,10 +17,14 @@ class Vaz2108 private constructor(color: String) : VazPlatform(color) { else -> VazEngine.SAMARA_2108(1500) } } + private fun createTank(): Tank = VazTank(40) + private fun createTankMouth(): TankMouth = TankMouth.GasolineMouth() override fun build(plates: Car.Plates): Vaz2108 = Vaz2108("Красный").apply { this.engine = getRandomEngine() this.plates = plates + setFuelTank(createTank()) + setTankMouth(createTankMouth()) } fun alignWheels(vaz2108: Vaz2108) { @@ -53,6 +57,7 @@ class Vaz2108 private constructor(color: String) : VazPlatform(color) { } private var currentSpeed: Int = 0 // Скока жмёт + private var currentFuelVolume: Int = 0 // Сколько бензина в баке /** * Доступно сборщику @@ -78,5 +83,8 @@ class Vaz2108 private constructor(color: String) : VazPlatform(color) { override fun getCurrentSpeed(): Int { return this@Vaz2108.currentSpeed } + + override fun getFuelIndicator(): Int = this@Vaz2108.getFuelLevel() + override fun getTankInfo(): String = "${this@Vaz2108.getTankCapacity()} л" } } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/VazPlatform.kt b/src/main/kotlin/ru/otus/cars/VazPlatform.kt index 079c2da..5ab5881 100644 --- a/src/main/kotlin/ru/otus/cars/VazPlatform.kt +++ b/src/main/kotlin/ru/otus/cars/VazPlatform.kt @@ -1,5 +1,7 @@ package ru.otus.cars +import kotlin.system.exitProcess + abstract class VazPlatform(override val color: String) : Car { // Положение руля. Доступно только внутри класса и наследникам protected var wheelAngle: Int = 0 // Положение руля @@ -9,8 +11,38 @@ abstract class VazPlatform(override val color: String) : Car { // Реализация интерфейса CarInput override fun wheelToLeft(degrees: Int) { wheelAngle -= degrees } + // Скрываем реализацию бака и горловину, используем только внутри класса + private lateinit var fuelTank: Tank + private lateinit var tankMouth: TankMouth + + protected fun setFuelTank(tank: Tank) { + this.fuelTank = tank + } + + protected fun setTankMouth(mouth: TankMouth) { + this.tankMouth = mouth + } + + override fun fillTank(fuelType: String, volume: Int): Int { + if (!tankMouth.canAccept(fuelType)) { + throw IllegalArgumentException("Нельзя заправить $fuelType") + } + // В зависимости от типа горловины! + return tankMouth.refuel(fuelTank, volume) + } + + // Метод для получения уровня топлива (через CarOutput) + protected fun getFuelLevel(): Int { + return fuelTank.getCurrentFuelVolume() + } + + // Метод для получения вместимости бака + protected fun getTankCapacity(): Int { + return fuelTank.capacity + } + // Получить оборудование - override fun getEquipment(): String = "Кузов, колеса, движок" + override fun getEquipment(): String = "Кузов, колеса, движок, топливная система" // Абстрактное свойство двигателя abstract val engine: VazEngine @@ -23,4 +55,24 @@ sealed class VazEngine { data class LADA_2107(override val volume: Int) : VazEngine() data class SAMARA_2108(override val volume: Int) : VazEngine() +} +open class VazTank(override val capacity: Int = 40) : Tank { + override var currentFuel: Int = 0 + + override fun fill(volume: Int): Int { + if (volume < 0) { + throw IllegalArgumentException("Нельзя заправить отрицательное количество топлива") + } + + val availableSpace = capacity - currentFuel + val actualFill = minOf(volume, availableSpace) + + if (actualFill > 0) { + currentFuel += actualFill + } + + return actualFill + } + + override fun getCurrentFuelVolume(): Int = currentFuel } \ No newline at end of file diff --git a/src/main/kotlin/ru/otus/cars/main.kt b/src/main/kotlin/ru/otus/cars/main.kt index 978d0ef..dac5707 100644 --- a/src/main/kotlin/ru/otus/cars/main.kt +++ b/src/main/kotlin/ru/otus/cars/main.kt @@ -16,6 +16,13 @@ fun main() { techChecks() println("\n===> Taz...") println(Taz.color) + + println("\n===> Тест заправки разным горючим") + testFuelSystem() + println("\n===> Тест частичной/порционной заправки бака") + testPartialRefuel() + println("\n===> Тест переполнения бака") + testTankOverflow() } fun driveCars() { @@ -90,4 +97,98 @@ fun repairEngine(car: VazPlatform) { is VazEngine.LADA_2107 -> println("Чистка карбюратора у двигателя объемом ${car.engine.volume} куб.см у машины $car") is VazEngine.SAMARA_2108 -> println("Угол зажигания у двигателя объемом ${car.engine.volume} куб.см у машины $car") } +} + +fun testFuelSystem() { + val cars = listOf( + Vaz2107.build(Car.Plates("777", 77)), + Vaz2108.build(Car.Plates("888", 78)), + Taz + ) + + // Показываем начальный уровень топлива + println("Информация по машинам:") + cars.forEach { car -> + if (car != Taz) { // У Taz нет приборов + println("${car::class.simpleName}: " + + "Начальный уровень топлива ${car.carOutput.getFuelIndicator()} л., " + + "Вместимость бака ${car.carOutput.getTankInfo()}.") + } else { + println("Taz: приборов нет") + } + } + + // Тестируем заправку БЕНЗИНОМ через заправку + println("\n--- Заправка БЕНЗИНОМ ---") + cars.forEach { car -> + GasStation.refuel(car, "Бензин", 30) + } + + // Тестируем заправку ГАЗОМ через заправку + println("\n--- Заправка ГАЗОМ ---") + cars.forEach { car -> + GasStation.refuel(car, "Газ", 30) + } + + // Показываем конечный уровень топлива + println("\nКонечный уровень топлива:") + cars.forEach { car -> + if (car != Taz) { + println("${car::class.simpleName}: ${car.carOutput.getFuelIndicator()} / ${car.carOutput.getTankInfo()}") + } + } +} + +fun testTankOverflow() { + val vaz7 = Vaz2107.build(Car.Plates("777", 77)) + + println("Начальный уровень топлива: ${vaz7.carOutput.getFuelIndicator()} л.") + println("Вместимость бака: ${vaz7.carOutput.getTankInfo()}") + println("---") + + // Тест 1: Пробуем заправить больше чем вмещает бак + println("1. Пробуем заправить 50 литров (больше чем вмещает бак 40л):") + GasStation.refuel(vaz7, "Газ", 50) + println("Текущий уровень: ${vaz7.carOutput.getFuelIndicator()} л.") + println("---") + + // Тест 2: Пробуем дозаправить когда бак полный + println("2. Пробуем дозаправить ещё 10 литров (бак уже полный):") + GasStation.refuel(vaz7, "Газ", 10) + println("Текущий уровень: ${vaz7.carOutput.getFuelIndicator()} л.") + println("---") + + // Тест 3: Пробуем заправить отрицательное количество + println("3. Пробуем заправить отрицательное количество (-5 литров):") + GasStation.refuel(vaz7, "Газ", -5) + println("---") + + // Тест 4: Пробуем заправить 0 литров + println("4. Пробуем заправить 0 литров:") + GasStation.refuel(vaz7, "Газ", 0) +} + +fun testPartialRefuel() { + val vaz8 = Vaz2108.build(Car.Plates("888", 78)) + + println("Начальный уровень топлива: ${vaz8.carOutput.getFuelIndicator()} л.") + println("Вместимость бака: ${vaz8.carOutput.getTankInfo()}") + println("---") + + // Тест 1: Частичная заправка + println("1. Заправляем 20 литров бензина:") + GasStation.refuel(vaz8, "Бензин", 20) + println("Текущий уровень: ${vaz8.carOutput.getFuelIndicator()} л.") + println("---") + + // Тест 2: Ещё частичная заправка + println("2. Дозаправим ещё 15 литров:") + GasStation.refuel(vaz8, "Бензин", 15) + println("Текущий уровень: ${vaz8.carOutput.getFuelIndicator()} л.") + println("---") + + // Тест 3: Пробуем заправить больше чем осталось места + println("3. Пробуем заправить 20 литров (осталось места только ${vaz8.carOutput.getFuelIndicator()}):") + GasStation.refuel(vaz8, "Бензин", 20) + println("Текущий уровень: ${vaz8.carOutput.getFuelIndicator()} л.") } \ No newline at end of file