feat: UNO Kotlin Multiplatform app (Android, Desktop, Web)
- Full UNO game logic with AI opponents - Compose Multiplatform UI with animations - Shared module (commonMain) with game engine - Desktop app (Compose Desktop) - Android app (Compose Multiplatform) - Web app (Kotlin/Wasm) - Nix shell for reproducible dev environment
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
package com.uno.web
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import com.uno.game.GameEngine
|
||||
import com.uno.game.model.*
|
||||
import com.uno.shared.UnoGameScreen
|
||||
import kotlinx.browser.document
|
||||
import org.w3c.dom.HTMLElement
|
||||
|
||||
fun main() {
|
||||
val root = document.getElementById("root") as HTMLElement
|
||||
|
||||
root.innerHTML = ""
|
||||
|
||||
val container = document.createElement("div")
|
||||
container.id = "app"
|
||||
root.appendChild(container)
|
||||
|
||||
composeWebRoot(container)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun composeWebRoot(container: HTMLElement) {
|
||||
val engine = remember { GameEngine() }
|
||||
var gameState by remember { mutableStateOf(engine.startGame()) }
|
||||
var gameStarted by remember { mutableStateOf(false) }
|
||||
|
||||
if (!gameStarted) {
|
||||
WebStartScreen(
|
||||
onStartGame = { playerCount ->
|
||||
gameState = engine.startGame(playerCount)
|
||||
gameStarted = true
|
||||
}
|
||||
)
|
||||
} else {
|
||||
UnoGameScreen(
|
||||
state = gameState,
|
||||
onPlayCard = { card, color ->
|
||||
gameState = engine.playCard(gameState, 0, card, color)
|
||||
gameState = runAiTurns(engine, gameState)
|
||||
},
|
||||
onDrawCard = {
|
||||
gameState = engine.drawCard(gameState, 0)
|
||||
gameState = runAiTurns(engine, gameState)
|
||||
},
|
||||
onCallUno = {
|
||||
gameState = engine.callUno(gameState, 0)
|
||||
}
|
||||
)
|
||||
|
||||
if (gameState.isFinished) {
|
||||
WebGameOverScreen(
|
||||
winner = gameState.winner,
|
||||
onPlayAgain = {
|
||||
gameState = engine.startGame()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun runAiTurns(engine: GameEngine, state: GameState): GameState {
|
||||
var currentState = state
|
||||
while (currentState.currentPlayerIndex != 0 && !currentState.isFinished) {
|
||||
currentState = engine.aiPlay(currentState, currentState.currentPlayerIndex)
|
||||
}
|
||||
return currentState
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WebStartScreen(onStartGame: (Int) -> Unit) {
|
||||
androidx.compose.foundation.layout.Column(
|
||||
modifier = androidx.compose.foundation.layout.fillMaxSize().padding(32.dp),
|
||||
horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally,
|
||||
verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center
|
||||
) {
|
||||
androidx.compose.material3.Text(
|
||||
text = "UNO",
|
||||
style = androidx.compose.material3.MaterialTheme.typography.displayLarge,
|
||||
color = androidx.compose.material3.MaterialTheme.colorScheme.primary
|
||||
)
|
||||
androidx.compose.foundation.layout.Spacer(modifier = Modifier)
|
||||
androidx.compose.material3.Text(
|
||||
text = "Web Edition",
|
||||
style = androidx.compose.material3.MaterialTheme.typography.titleMedium,
|
||||
color = androidx.compose.material3.MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
androidx.compose.foundation.layout.Spacer(modifier = Modifier)
|
||||
androidx.compose.material3.Button(onClick = { onStartGame(4) }) {
|
||||
androidx.compose.material3.Text("Spiel starten (4 Spieler)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun WebGameOverScreen(winner: Player?, onPlayAgain: () -> Unit) {
|
||||
androidx.compose.material3.AlertDialog(
|
||||
onDismissRequest = onPlayAgain,
|
||||
title = { androidx.compose.material3.Text("Spiel vorbei!") },
|
||||
text = {
|
||||
androidx.compose.material3.Text(
|
||||
text = if (winner != null) "${winner.name} hat gewonnen!"
|
||||
else "Unentschieden!"
|
||||
)
|
||||
},
|
||||
confirmButton = {
|
||||
androidx.compose.material3.Button(onClick = onPlayAgain) {
|
||||
androidx.compose.material3.Text("Nochmal spielen")
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user