Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions assets/DataBaseArchitecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
classDiagram
direction TB

class GameRepository {
-SwintusDao dao
+saveGameResult(winnerId, winnerName, totalTurns, profiles) List~PlayerProfile~
+loadLeaderboard() List~PlayerProfile~
}

class SwintusDao {
-Connection connection
+getAllPlayersStats() List~PlayerStatsEntity~
+insertPlayerStats(entity PlayerStatsEntity)
+updatePlayerStats(entity PlayerStatsEntity)
+insertGameHistory(entity GameHistoryEntity)
}

class PlayerStatsEntity {
+UUID playerId
+String username
+int rating
+int gamesPlayed
+int wins
}

class GameHistoryEntity {
+UUID gameId
+UUID winnerId
+int totalTurns
+String dateTime
}

class SQLiteDatabase {
<<Database>>
+swintus.db
-- Tables --
+player_stats
+game_history
}

GameRepository o-- SwintusDao
SwintusDao --> SQLiteDatabase
SwintusDao ..> PlayerStatsEntity
SwintusDao ..> GameHistoryEntity
Binary file added assets/Screenshot at May 23 09-56-45.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 7 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
plugins {
kotlin("jvm") version "1.9.22"
id("org.jetbrains.compose") version "1.6.10"
application
}

repositories {
google()
mavenCentral()
}

application {
mainClass.set("MainKt")
}

kotlin {
jvmToolchain(21)
}
dependencies {
implementation(compose.desktop.currentOs)
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0")
implementation("org.xerial:sqlite-jdbc:3.45.2.0")
}
20 changes: 18 additions & 2 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
fun main() {
println("Hello, world!")
import androidx.compose.ui.window.Window
import androidx.compose.ui.window.application
import data.local.dao.SwintusDao
import data.repository.GameRepository
import view.Application
import viewmodel.SwintusViewModel

fun main() = application {
val dao = SwintusDao()
val repository = GameRepository(dao)
val viewModel = SwintusViewModel(repository)

Window(
onCloseRequest = ::exitApplication,
title = "Свинтус"
) {
Application(viewModel = viewModel)
}
}
141 changes: 141 additions & 0 deletions src/main/kotlin/data/local/dao/SwintusDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package data.local.dao

import data.local.entities.PlayerStatsEntity
import data.local.entities.GameHistoryEntity
import java.io.File
import java.sql.Connection
import java.sql.DriverManager

class SwintusDao {
private val dbFile = File(System.getProperty("user.home"), ".swintus_game.db")

private fun getConnection(): Connection {
return DriverManager.getConnection("jdbc:sqlite:${dbFile.absolutePath}")
}

init {
getConnection().use { conn ->
conn.createStatement().use { stmt ->
stmt.execute("""
CREATE TABLE IF NOT EXISTS player_stats (
playerId TEXT PRIMARY KEY,
username TEXT NOT NULL,
gamesPlayed INTEGER NOT NULL,
wins INTEGER NOT NULL,
rating INTEGER NOT NULL
)
""".trimIndent())

stmt.execute("""
CREATE TABLE IF NOT EXISTS game_history (
gameId TEXT PRIMARY KEY,
endTime INTEGER NOT NULL,
winnerId TEXT NOT NULL,
winnerName TEXT NOT NULL,
totalTurns INTEGER NOT NULL,
playersList TEXT NOT NULL
)
""".trimIndent())
}
}
}

fun getPlayerStats(playerId: String): PlayerStatsEntity? {
return getConnection().use { conn ->
val sql = "SELECT * FROM player_stats WHERE playerId = ?"
conn.prepareStatement(sql).use { stmt ->
stmt.setString(1, playerId)
val rs = stmt.executeQuery()
if (rs.next()) {
PlayerStatsEntity(
playerId = rs.getString("playerId"),
username = rs.getString("username"),
gamesPlayed = rs.getInt("gamesPlayed"),
wins = rs.getInt("wins"),
rating = rs.getInt("rating")
)
} else null
}
}
}

fun insertOrUpdatePlayer(stats: PlayerStatsEntity) {
getConnection().use { conn ->
val sql = """
INSERT OR REPLACE INTO player_stats (playerId, username, gamesPlayed, wins, rating)
VALUES (?, ?, ?, ?, ?)
""".trimIndent()
conn.prepareStatement(sql).use { stmt ->
stmt.setString(1, stats.playerId)
stmt.setString(2, stats.username)
stmt.setInt(3, stats.gamesPlayed)
stmt.setInt(4, stats.wins)
stmt.setInt(5, stats.rating)
stmt.executeUpdate()
}
}
}

fun getAllPlayersStats(): List<PlayerStatsEntity> {
val list = mutableListOf<PlayerStatsEntity>()
getConnection().use { conn ->
val sql = "SELECT * FROM player_stats"
conn.createStatement().use { stmt ->
val rs = stmt.executeQuery(sql)
while (rs.next()) {
list.add(
PlayerStatsEntity(
playerId = rs.getString("playerId"),
username = rs.getString("username"),
gamesPlayed = rs.getInt("gamesPlayed"),
wins = rs.getInt("wins"),
rating = rs.getInt("rating")
)
)
}
}
}
return list
}

fun insertGameHistory(history: GameHistoryEntity) {
getConnection().use { conn ->
val sql = """
INSERT INTO game_history (gameId, endTime, winnerId, winnerName, totalTurns, playersList)
VALUES (?, ?, ?, ?, ?, ?)
""".trimIndent()
conn.prepareStatement(sql).use { stmt ->
stmt.setString(1, history.gameId)
stmt.setLong(2, history.endTime)
stmt.setString(3, history.winnerId)
stmt.setString(4, history.winnerName)
stmt.setInt(5, history.totalTurns)
stmt.setString(6, history.playersList)
stmt.executeUpdate()
}
}
}

fun getGameHistory(): List<GameHistoryEntity> {
val list = mutableListOf<GameHistoryEntity>()
getConnection().use { conn ->
val sql = "SELECT * FROM game_history"
conn.createStatement().use { stmt ->
val rs = stmt.executeQuery(sql)
while (rs.next()) {
list.add(
GameHistoryEntity(
gameId = rs.getString("gameId"),
endTime = rs.getLong("endTime"),
winnerId = rs.getString("winnerId"),
winnerName = rs.getString("winnerName"),
totalTurns = rs.getInt("totalTurns"),
playersList = rs.getString("playersList")
)
)
}
}
}
return list
}
}
7 changes: 7 additions & 0 deletions src/main/kotlin/data/local/db/SwintusDatabase.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package data.local.db

import data.local.dao.SwintusDao

class SwintusDatabase {
fun swintusDao(): SwintusDao = SwintusDao()
}
10 changes: 10 additions & 0 deletions src/main/kotlin/data/local/entities/GameHistoryEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package data.local.entities

data class GameHistoryEntity(
val gameId: String,
val endTime: Long,
val winnerId: String,
val winnerName: String,
val totalTurns: Int,
val playersList: String
)
9 changes: 9 additions & 0 deletions src/main/kotlin/data/local/entities/PlayerStatsEntity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package data.local.entities

data class PlayerStatsEntity(
val playerId: String,
val username: String,
val gamesPlayed: Int,
val wins: Int,
val rating: Int
)
53 changes: 53 additions & 0 deletions src/main/kotlin/data/repository/GameRepository.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package data.repository

import Application.PlayerProfile
import data.local.dao.SwintusDao
import data.local.entities.GameHistoryEntity
import data.local.entities.PlayerStatsEntity
import java.util.UUID

class GameRepository(private val dao: SwintusDao) {

suspend fun saveGameResult(winnerId: UUID, winnerName: String, totalTurns: Int, players: List<PlayerProfile>) {
val gameHistory = GameHistoryEntity(
gameId = UUID.randomUUID().toString(),
endTime = System.currentTimeMillis(),
winnerId = winnerId.toString(),
winnerName = winnerName,
totalTurns = totalTurns,
playersList = players.joinToString(",") { it.id.toString() }
)
dao.insertGameHistory(gameHistory)

for (player in players) {
val currentStats = dao.getPlayerStats(player.id.toString())
?: PlayerStatsEntity(player.id.toString(), player.username, 0, 0, 0)

val isWinner = player.id == winnerId
val newWins = if (isWinner) currentStats.wins + 1 else currentStats.wins
val newRating = if (isWinner) currentStats.rating + 5 else maxOf(0, currentStats.rating - 2)

dao.insertOrUpdatePlayer(
PlayerStatsEntity(
playerId = player.id.toString(),
username = player.username,
gamesPlayed = currentStats.gamesPlayed + 1,
wins = newWins,
rating = newRating
)
)
}
}

suspend fun loadLeaderboard(): List<PlayerProfile> {
return dao.getAllPlayersStats().map {
PlayerProfile(
id = java.util.UUID.fromString(it.playerId),
username = it.username,
rating = it.rating,
gamesPlayed = it.gamesPlayed,
wins = it.wins
)
}
}
}
27 changes: 27 additions & 0 deletions src/main/kotlin/view/Application.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package view

import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.*
import view.screens.GameScreen
import view.screens.LobbyScreen
import viewmodel.SwintusViewModel

@Composable
fun Application() {
val viewModel = remember { SwintusViewModel() }
val gameState by viewModel.gameState.collectAsState()

LaunchedEffect(viewModel) {
viewModel.onResetToLobby = {
viewModel.gameState.value = null
}
}

MaterialTheme {
if (gameState == null) {
LobbyScreen(viewModel = viewModel)
} else {
GameScreen(viewModel = viewModel)
}
}
}
9 changes: 9 additions & 0 deletions src/main/kotlin/view/DatabaseProvider.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package view

import data.local.db.SwintusDatabase
import data.repository.GameRepository

object DatabaseProvider {
lateinit var database: SwintusDatabase
lateinit var repository: GameRepository
}
Loading
Loading