Перейти к содержанию

🗒 Задача

Научно-исследовательский корабль может приступить к долгосрочному плаванию при выполнении следующих условий:

  • корабль не имеет повреждений;

  • число экипажа составляет от 55 (включительно) до 70 человек (включительно);

  • на борту есть более 50 ящиков провизии (не включительно);

  • погода благоприятна или неблагоприятна.

Альтернативно, корабль может отплыть даже при наличии незначительных повреждений, при условии что:

  • на борту рекомендованный состав экипажа 70 человек;

  • погода благоприятная;

  • на борту есть 50 и более ящиков провизии.

В качестве входных данных используй информацию, введенную через консоль:

  • наличие повреждений корпуса (Boolean переменная);

  • текущий состав экипажа;

  • количество ящиков с провизией на борту;

  • благоприятность метеоусловий (Boolean переменная).

Напиши программу, которая будет определять, может ли корабль отправиться в плавание. Программа должна анализировать эти данные и выводить результат в консоль. Для анализа должно использоваться единое составное условие, состоящие только из логических операторов.

❌ Ошибки

  • в первом кейсе пишут условие про погоду (не нужно)

  • не выносят в константы переменные, с которыми сравнивается условие — в коде они являются магическими числами (дать ссылку на определение в вики)

  • либо магических чисел нет, но и констант тоже нет

  • неверный нейминг Boolean переменных

  • предлагать делать проверку вхождений с помощью диапазона

✏️ Комментарии

В ветвлениях местами код продублирован. Чуть поменяем подход – чтобы сначала проинициализировать эти данные 1 раз. Затем создаем одно составное условие без if else, которое будет покрывать оба кейса. То есть примерно так будет выглядеть условно: (это и это и это) ИЛИ (это и это и это).
`== false` дописывать необязательно, так как переменная уже в себе хранит определенный Boolean
Рекомендуется Boolean переменные называть, "отвечая на вопрос“ да/нет. Ну и принято название начинать для них с `is`, в редких случаях `has`. Например, hasDamage, isDamaged.
У тебя почти верно, но более читаемо будет (и принято) начинать с `is`
Scanner - это джавовская фича. в Котлин и лучше использовать readln()

Крутой подход! А знаешь про то, что еще можно строку из 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