KTB-07 Реализовать функционал изучения слов¶
📝 Описание¶
Разработка функционала изучения слов
Согласно ТЗ, при выборе вариантов ответа должно использоваться максимальное количество невыученных слов, чтобы предотвратить возможность угадывания правильного ответа методом исключения.
Логика режима изучения
В режиме изучения слов пользователю необходимо каждый раз показывать следующее неизученное слово и варианты ответов, независимо от правильности предыдущего ответа. Это продолжается до тех пор, пока пользователь не выучит все слова в базе данных или не выйдет в главное меню.
Таким образом, потребуется запустить вложенный цикл для режима изучения слов (пункта "1" в меню).
Инициализация данных для обучения
В цикле обучения сначала должна выполняться проверка – остались ли еще в словаре слова для изучения (слово остается невыученным, пока его не угадали 3 и больше раз). Если все слова уже выучены, приложение должно уведомить пользователя об этом и выйти в меню.
В противном случае программа переходит к изучению слов и отображает блок в следующем формате:
Реализация слова и вариантов ответа
- Необходимо отобразить изучаемое слово и 4 невыученных слова. Слова брать в произвольном порядке (чтобы нельзя было запомнить порядковый номер правильного слова).
- Правильное слово берется из полученного списка вариантов ответов и устанавливается в качестве вопроса. Это слово будет считаться правильным ответом.
🗒 Задание¶
- Проинициализировать переменную со списком невыученных слов (
notLearnedList). - Добавить проверку на наличие невыученных слов. Если все слова выучены – выводить сообщение “Все слова в словаре выучены” и выходить в меню.
- Создать и проинициализировать переменную со списком слов для изучения (
questionWords). Список должен содержать 4 невыученных слова. Рекомендуется использовать методtake(). Для перемешивания списка рекомендуется использовать методshuffled(). - В режиме изучения слов отображать одно загаданное (
correctAnswer) слово и четыре варианта ответа в случайном порядке. После отображения ожидать ввод номера ответа от пользователя.
❌ Ошибки¶
- сначала берут 4 слова, а только потом перемешивают
- [bug] – если слов для изучения осталось 3 и меньше, то при обращении по индексу будет IndexOutOfBoundsException. В таком случае см. комментарий про
mapIndexed.
✏️ Комментарии¶
Давай возьмем `questionWords` и с помощью `mapIndexed {}` и `joinToString` получим строку с вариантами ответа.
В `joinToString` используем: параметр `separator` для переноса строки, `prefix` непосредственно для оригинального слова на английском, а `postfix` переносы строки и пункт меню для выхода.
val variants = questionWords
.mapIndexed { index: Int, word: Word -> " ${index + 1} – ${word.translate}" }
.joinToString(
separator = "\n",
prefix = "\n${correctAnswer.original}\n",
postfix = "\n 0 – выйти в меню",
)
println(variants)
Давай возьмем `questionWords` и с помощью `mapIndexed {}` и `joinToString` получим строку с вариантами ответа.
В `joinToString` используем: параметр `separator` для переноса строки, `prefix` непосредственно для оригинального слова на английском, а `postfix` переносы строки и пункт меню для выхода.
Лучше не использовать `indexOf` внутри цикла, потому что `indexOf` каждый раз пробегает по всему циклу.
`filter` - не самая дешевая операция. Во-первых, происходит перечисление всех элементов списка `dictionary`. Во-вторых, создается новая коллекция. Давай создадим переменную для хранения невыученных слов.
Ты можешь просто применить `take()` к `learnedWord`, чтобы получить требуемое количество выученных слов **и избежать цикла**.
`map` — это "преобразующая" функция. Она возвращает новый список. В твоем случае уместнее использовать `forEachIndexed`.
`mapIndexed` нужно использовать правильно, с возвращаемым значением. Иначе лучше использовать `forEachIndexed`.
Внутри цикла делай проверку на наличие слов: если список пуст, показывай сообщение "выучены все слова" и выходи.
⌨️ Решение¶
"1" -> {
while (true) {
val notLearnedList = dictionary.filter { it.correctAnswersCount < 3 }
if (notLearnedList.isEmpty()) {
println("Все слова в словаре выучены")
continue
}
val questionWords = notLearnedList.shuffled().take(4)
val correctAnswer = questionWords.random()
// --- вариант 1
println("""
${correctAnswer.original}:
1 - ${questionWords[0].translate}
2 - ${questionWords[1].translate}
3 - ${questionWords[2].translate}
4 - ${questionWords[3].translate}
""".trimIndent())
// --- продвинутое правильное решение (решает проблему индекса)
val variants = questionWords
.mapIndexed { index: Int, word: Word -> " ${index + 1} – ${word.translate}" }
.joinToString(
separator = "\n",
prefix = "\n${correctAnswer.original}\n",
postfix = "\n 0 – выйти в меню",
)
println(variants)
readln()
}
}