initial commit

This commit is contained in:
2026-05-09 22:39:06 +03:00
commit 99800e9d37
60 changed files with 2276 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '2.2.0'
id 'org.jetbrains.kotlin.plugin.serialization' version '2.2.0'
id 'org.jetbrains.dokka' version '2.2.0'
}
group = 'lab6.prog'
version = '1.0'
repositories {
mavenCentral()
}
dependencies {
testImplementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0'
}
kotlin {
jvmToolchain(17)
}
@@ -0,0 +1,13 @@
package commands
import models.HumanBeing
import network.Response
interface Command {
val name: String
val description: String
val args: List<CommandArgType>
val type: CommandType
fun execute(args: List<String>, humanBeing: HumanBeing? = null): Response
}
@@ -0,0 +1,10 @@
package commands
import kotlinx.serialization.Serializable
// why there's only two types? yes.
@Serializable
enum class CommandArgType {
STRING,
NONE
}
@@ -0,0 +1,6 @@
package commands
enum class CommandType {
SIMPLE,
MODEL
}
+13
View File
@@ -0,0 +1,13 @@
package models
import kotlinx.serialization.Serializable
/**
* Автомобиль, которым владеет [HumanBeing].
*
* @property cool признак того, что автомобиль крутой
*/
@Serializable
data class Car(
val cool: Boolean
)
@@ -0,0 +1,16 @@
package models
import kotlinx.serialization.Serializable
/**
* Координаты местоположения [HumanBeing].
*
* @property x координата X
* @property y координата Y
*/
@Serializable
data class Coordinates(
val x: Long,
val y: Int
)
@@ -0,0 +1,84 @@
package models
import kotlinx.serialization.Serializable
import network.utils.LocalDateSerializer
import network.utils.UUIDSerializer
import java.time.LocalDate
import java.util.UUID
/**
* Основная сущность коллекции — Райан Гослинг.
*
* @property id уникальный идентификатор, генерируется автоматически
* @property name имя героя (Райан Гослинг), не может быть null или пустой строкой
* @property coordinates координаты героя, не может быть null
* @property creationDate дата создания записи, генерируется автоматически
* @property realHero является ли настоящим героем (конечно)
* @property hasToothpick есть ли зубочистка (естественно)
* @property impactSpeed скорость удара, не может быть null
* @property soundtrackName название саундтрека, не может быть null (Nightcall - Kavinsky)
* @property minutesOfWaiting количество минут ожидания
* @property weaponType тип оружия, может быть null
* @property car автомобиль героя, не может быть null
*/
@Serializable
data class HumanBeing(
@Serializable(with = UUIDSerializer::class)
val id: UUID = UUID.randomUUID(),
val name: String,
val coordinates: Coordinates,
@Serializable(with = LocalDateSerializer::class)
val creationDate: LocalDate = LocalDate.now(),
val realHero: Boolean,
val hasToothpick: Boolean,
val impactSpeed: Double,
val soundtrackName: String,
val minutesOfWaiting: Float,
val weaponType: WeaponType?,
val car: Car
) : Comparable<HumanBeing> {
init {
require(name.isNotBlank()) { "Имя не может быть пустым" }
}
/**
* Сравниваем по имени и id
*/
override fun compareTo(other: HumanBeing): Int {
val byName = this.name.compareTo(other.name)
if (byName != 0) return byName
return this.id.toString().compareTo(other.id.toString())
}
/**
* Два объекта считаются одинаковыми, если совпадают их [id].
*/
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is HumanBeing) return false
return id == other.id
}
override fun hashCode(): Int = id.hashCode()
/**
* Красивое строковое представление для команды [show].
*/
override fun toString(): String =
"""
|HumanBeing (It Drives) {
| id = $id
| name = $name (a.k.a. Ryan Gosling)
| coordinates = (x=${coordinates.x}, y=${coordinates.y})
| creationDate = $creationDate
| realHero = $realHero
| hasToothpick = $hasToothpick
| impactSpeed = $impactSpeed
| soundtrackName = $soundtrackName
| minutesOfWait = $minutesOfWaiting
| weaponType = ${weaponType ?: "null"}
| car.cool = ${car.cool}
|}
""".trimMargin()
}
@@ -0,0 +1,14 @@
package models
import kotlinx.serialization.Serializable
/**
* Перечисление типов оружия, которым может владеть [HumanBeing].
* Поле [weaponType] в [HumanBeing] может быть null.
*/
@Serializable
enum class WeaponType {
HAMMER,
SHOTGUN,
BAT;
}
+12
View File
@@ -0,0 +1,12 @@
package network
import kotlinx.serialization.json.Json
/**
* Общий экземпляр Json для всего приложения.
* ignoreUnknownKeys — устойчивость к добавлению новых полей в протокол.
*/
val AppJson = Json {
ignoreUnknownKeys = true
encodeDefaults = true
}
@@ -0,0 +1,13 @@
package network
import commands.CommandArgType
import commands.CommandType
import kotlinx.serialization.Serializable
@Serializable
data class CommandInfo(
val name: String,
val description: String,
val args: List<CommandArgType>,
val type: CommandType
)
+18
View File
@@ -0,0 +1,18 @@
package network
import kotlinx.serialization.Serializable
import models.HumanBeing
/**
* Запрос от клиента к серверу.
*
* @property commandName имя команды ("add", "show", "remove_by_id" ...)
* @property args строковые аргументы (UUID для update/remove_by_id и т.п.)
* @property humanBeing объект для команд: add, update, add_if_max, add_if_min
*/
@Serializable
data class Request(
val commandName: String,
val args: List<String> = emptyList(),
val humanBeing: HumanBeing? = null
)
@@ -0,0 +1,21 @@
package network
import kotlinx.serialization.Serializable
/**
* Ответ сервера клиенту.
*
* @property success true — команда выполнена, false — ошибка
* @property message текст для вывода пользователю
*
* -- только при синхронизации --
* @property knownCommands - общий список известных команд
* @property humanBeingCommands - команды, требующие ввода коллекции [models.HumanBeing]
* @property commandsWArgs - команды, требующие ввода аргументов
*/
@Serializable
data class Response(
val success: Boolean,
val message: String,
val commands: List<CommandInfo>? = null,
)
@@ -0,0 +1,20 @@
package network.utils
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import java.time.LocalDate
/**
* Кастомный KSerializer для LocalDate.
* Сериализует как ISO строку: "2025-04-12"
*/
object LocalDateSerializer : KSerializer<LocalDate> {
override val descriptor = PrimitiveSerialDescriptor("LocalDate", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: LocalDate) =
encoder.encodeString(value.toString())
override fun deserialize(decoder: Decoder): LocalDate =
LocalDate.parse(decoder.decodeString())
}
@@ -0,0 +1,20 @@
package network.utils
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import java.util.UUID
/**
* Кастомный KSerializer для UUID.
* UUID не поддерживается kotlinx.serialization из коробки.
*/
object UUIDSerializer : KSerializer<UUID> {
override val descriptor = PrimitiveSerialDescriptor("UUID", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: UUID) =
encoder.encodeString(value.toString())
override fun deserialize(decoder: Decoder): UUID =
UUID.fromString(decoder.decodeString())
}