🗒 Задача¶
Научно-исследовательский корабль может приступить к долгосрочному плаванию при выполнении следующих условий:
-
корабль не имеет повреждений;
-
число экипажа составляет от 55 (включительно) до 70 человек (включительно);
-
на борту есть более 50 ящиков провизии (не включительно);
-
погода благоприятна или неблагоприятна.
Альтернативно, корабль может отплыть даже при наличии незначительных повреждений, при условии что:
-
на борту рекомендованный состав экипажа 70 человек;
-
погода благоприятная;
-
на борту есть 50 и более ящиков провизии.
В качестве входных данных используй информацию, введенную через консоль:
-
наличие повреждений корпуса (Boolean переменная);
-
текущий состав экипажа;
-
количество ящиков с провизией на борту;
-
благоприятность метеоусловий (Boolean переменная).
Напиши программу, которая будет определять, может ли корабль отправиться в плавание. Программа должна анализировать эти данные и выводить результат в консоль. Для анализа должно использоваться единое составное условие, состоящие только из логических операторов.
❌ Ошибки¶
-
в первом кейсе пишут условие про погоду (не нужно)
-
не выносят в константы переменные, с которыми сравнивается условие — в коде они являются магическими числами (дать ссылку на определение в вики)
-
либо магических чисел нет, но и констант тоже нет
-
неверный нейминг Boolean переменных
-
предлагать делать проверку вхождений с помощью диапазона
✏️ Комментарии¶
В ветвлениях местами код продублирован. Чуть поменяем подход – чтобы сначала проинициализировать эти данные 1 раз. Затем создаем одно составное условие без if else, которое будет покрывать оба кейса. То есть примерно так будет выглядеть условно: (это и это и это) ИЛИ (это и это и это).
Рекомендуется Boolean переменные называть, "отвечая на вопрос“ да/нет. Ну и принято название начинать для них с `is`, в редких случаях `has`. Например, hasDamage, isDamaged.
Крутой подход! А знаешь про то, что еще можно строку из readln() приводить к Boolean? также, как это делается ниже с Int:
val isDefect = readln() == "0”
Использование оператора !! подразумевает, что ты уверен в том, что значение не может быть null. Однако, если это не так, то приложение "упадет" с ошибкой.
Это противоречит основной идее безопасности типов в Kotlin, поэтому лучше использовать альтернативные способы обработки нулабельных значений. такие как оператор безопасного вызова ?., элвис-оператор ?: или оператор let
В данном случае лучше использовать функцию readln() для чтения с консоли, которая не будет выбрасывать исключение, если в нее придет null, а просто вернет строку (строка будет конфликтовать с приведением к целочисленному типу, но это другой кейс, важнее разобраться с нулябельностью). Она появилась относительно недавно, поэтому ее нет в видео гайдах.
Значения в этом коде являются [магическими числами](https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D0%B3%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D1%87%D0%B8%D1%81%D0%BB%D0%BE_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5)#%D0%9F%D0%BB%D0%BE%D1%85%D0%B0%D1%8F_%D0%BF%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F). Не лучшая практика. добавь, пожалуйста, переменные) Эти переменные корректнее будет сделать константами, так как они не будут изменяться в коде после компиляции
Неочевидный нейминг переменных. также напоминаю, что boolean переменные именуются в основном начиная с `is`
Давай ограничимся флагом для повреждений только есть или нет. И инициализировать эту переменную будем также с консоли, но еще можно сразу делать приведение типа к Boolean. точно также, как делаем приведение к целочисленному значению)
Для длинных условий, которые не помещаются в одну строку, лучше сделать перенос строки после оператора || или &&
Официальная документация [Kotlin Coding Conventions](https://kotlinlang.org/docs/coding-conventions.html) не дает строгих указаний на тему переноса строк внутри условий. Но такой формат я встречал чаще
Можно использовать функцию приведение типа к `Boolean`. То есть по отношению к строке, например, `true` можно вызывать `.toBoolean`
В видео я использовал readLine() – этот метод возвращает нулябельный тип, поэтому вынужденно нужно было приводить его к обычному. Но это крайне не рекомендуется делать в продакшене, есть более безопасные способы обработки нулябельности (подробнее в темах про нуллябельность).
Начиная с версии Kotlin 1.6 в библиотеке появилась новая более удобная функция readln(). Она возвращает ненулябельный тип и не нужно ничего приводить.
Поэтому моя рекомендация в комментариях именно такая с объяснением почему плохая практика использовать оператор "утверждение это не null".
🧾 Решение¶
fun main() {
println("Введите данные о повреждениях (true или false)")
val isDamage = readln().toBoolean()
println("Введите количество экипажа")
val crew = readln().toInt()
println("Введите количество провизии")
val provision = readln().toInt()
println("Введите данные о благоприятных метеоусловиях (true или false)")
val isWeatherGood = readln().toBoolean()
if ((isDamage == IS_CASE_DAMAGE) &&
(crew >= CREW_MIN) &&
(crew <= CREW_MAX) &&
(provision > PROVISION_MIN)
) {
println("Корабль может выходить в плавание: true")
} else if ((isDamage != IS_CASE_DAMAGE) &&
(crew == CREW_MAX) &&
(provision >= PROVISION_MIN) &&
(isWeatherGood == IS_WEATHER_GOOD)
) {
println("Корабль может выходить в плавание: true")
} else {
println("Корабль может выходить в плавание: false")
}
}
const val IS_CASE_DAMAGE = false
const val CREW_MIN = 55
const val CREW_MAX = 70
const val PROVISION_MIN = 50
const val IS_WEATHER_GOOD = true