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

🗒 Задача

Создай класс Chat, который реализует обсуждение в мессенджере, аналогичному Discord. Класс должен иметь следующие методы:

  • addMessage() — добавляет обычное сообщение в чат, принимает на вход текст и автора сообщения;

  • addThreadMessage() — добавляет сообщение в тред к предыдущему сообщению (для начала обсуждения), дополнительно принимает на вход parentMessageId для идентификации сообщения, под которым создается ветка обсуждения;

Сообщения чата должны храниться в списке, в классе Chat. Для создания сообщений соответствующих типов используй классы Message и ChildMessage в соответствующей иерархии. У каждого типа сообщения должен быть id.

  • printChat() — печатает все сообщения чата. Если создано дочернее сообщение, необходимо применить для вывода табуляцию и печатать его под родительским сообщением. Используй groupBy() для группировки сообщений по parentMessageId, если сообщение является экземпляром ChildMessage, или по id если это обычное сообщение.

❌ Ошибки

  • вместо символа \t используют набор из нескольких пробелов

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

Рекомендую использовать специальный символ для таба `\t`. Применяется по аналогии с символом переноса строки. 
`groupBy` возвращает Map. Map возвращает нуллябельный тип значения. Оператор `!!` (утверждение “это не null”) не рекомендуется использовать, так как если в это место придет таки null – программа упадет с ошибкой, которую будет относительно сложно найти в большом проекте. Предлагаю добавить более безопасную проверку на null.
Кажется тут лучше поможет [raw-строки](https://kotlinlang.org/docs/strings.html#raw-strings)

// объяснение

Для простоты понимания я предлагаю использовать 2 списка: список сообщений и список дочерних сообщений (они добавляются в методе addThreadMessage).

Далее нам нужно только сгруппировать только дочерние сообщения по parentMessageId.

И наконец нужно провернуть правильный вывод этих сообщений. Можно использовать два цикла: один выводит базовое сообщение, а второй цикл проходит по ключам в виде id базового сообщения и печатает сообщение треда с отступом (табуляцией)

🧾 Решение

class Chat {

    val messageList: MutableList<Message> = mutableListOf()
    val childMessageList: MutableList<ChildMessage> = mutableListOf()

    fun addMessage(_author: String, _text: String) {
        val newMessage = Message(
            id = messageList.size,
            author = _author,
            text = _text,
        )
        messageList.add(newMessage)
    }

    fun addThreadMessage(_author: String, _text: String, _parentMessageId: Int) {
        val threadMessage = ChildMessage(
            id = messageList.size,
            author = _author,
            text = _text,
            parentMessageId = _parentMessageId,
        )
        childMessageList.add(threadMessage)
    }

    fun printChat() {
        val groupedChildMessage: Map<Int, List<ChildMessage>> = 
            childMessageList.groupBy { it.parentMessageId }

        messageList.forEach { baseMessage ->
            println("${baseMessage.author}: ${baseMessage.text}")

            groupedChildMessage[baseMessage.id]?.forEach { childMessage ->
                println("\t${childMessage.author}: ${childMessage.text}")
            }
        }
    }

}

open class Message(val id: Int, val author: String, val text: String)

class ChildMessage(id: Int, author: String, text: String, val parentMessageId: Int) : Message(id, author, text)

fun main() {

    val chat = Chat()
    chat.addMessage("Dima", "Привет 1")
    chat.addThreadMessage("None", "Привет 2", chat.messageList[0].id)
    chat.addThreadMessage("ANone", "Привет 3", chat.messageList[0].id)
    chat.addMessage("Dima1", "Привет 2")
    chat.addMessage("Dima2", "Привет 3")
    chat.addThreadMessage("ANone", "Привет 3", chat.messageList[1].id)
    chat.addThreadMessage("ANone", "Привет 3", chat.messageList[1].id)
    chat.addThreadMessage("ANone", "Привет 3", chat.messageList[1].id)
    chat.addThreadMessage("ANone", "Привет 3", chat.messageList[1].id)

    chat.printChat()

}
open class Message(val id: Int, val author: String, val text: String)

class ChildMessage(id: Int, author: String, text: String, val parentMessageId: Int) : Message(id, author, text)

class Chat {
    private val messages = mutableListOf<Message>()
    private var nextMessageId = 0

    fun addMessage(author: String, text: String) {
        messages.add(Message(nextMessageId++, author, text))
    }

    fun addThreadMessage(parentMessageId: Int, author: String, text: String) {
        if (messages.any { it.id == parentMessageId }) {
            messages.add(ChildMessage(nextMessageId++, author, text, parentMessageId))
        } else {
            println("Parent message with id $parentMessageId not found.")
        }
    }

    fun printChat() {

        val threadMap: Map<Int, List<Message>> = messages.groupBy {
            if (it is ChildMessage)
                it.parentMessageId
            else
                it.id
        }

        threadMap.forEach { (_, messageList) ->
            messageList.forEach { message ->
                val tab = if (message is ChildMessage) "\t" else ""
                println("$tab${message.id}. ${message.author}: ${message.text}")
            }
        }
    }
}

fun main() {
    val chat = Chat()
    chat.addMessage("Alice", "Hello everyone!")
    chat.addMessage("Bob", "Hi Alice!")
    chat.addThreadMessage(0, "Charlie", "Hey Alice!")
    chat.addThreadMessage(0, "Charlie", "Hey Alice!")
    chat.addThreadMessage(0, "Charlie", "Hey Alice!")
    chat.addThreadMessage(1, "Dave", "Hi Bob!")
    chat.printChat()
}