diff --git a/androidApp/src/androidMain/kotlin/com/uno/android/MainActivity.kt b/androidApp/src/androidMain/kotlin/com/uno/android/MainActivity.kt index b5d2774..7fe0ad3 100644 --- a/androidApp/src/androidMain/kotlin/com/uno/android/MainActivity.kt +++ b/androidApp/src/androidMain/kotlin/com/uno/android/MainActivity.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.unit.dp import com.uno.game.GameEngine import com.uno.game.model.* import com.uno.shared.UnoGameScreen +import kotlinx.coroutines.delay class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -33,6 +34,23 @@ fun UnoApp() { val engine = remember { GameEngine() } var gameState by remember { mutableStateOf(engine.startGame()) } var gameStarted by remember { mutableStateOf(false) } + var isAiThinking by remember { mutableStateOf(false) } + + LaunchedEffect(gameState.currentPlayerIndex, gameState.phase) { + if (gameState.currentPlayerIndex != 0 + && gameState.phase == GamePhase.PLAYING + && !gameState.isFinished + ) { + isAiThinking = true + var currentState = gameState + while (currentState.currentPlayerIndex != 0 && !currentState.isFinished) { + delay(800) + currentState = engine.aiPlay(currentState, currentState.currentPlayerIndex) + gameState = currentState + } + isAiThinking = false + } + } if (!gameStarted) { StartScreen(onStartGame = { playerCount -> @@ -44,29 +62,22 @@ fun UnoApp() { 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) { - GameOverScreen(winner = gameState.winner, onPlayAgain = { gameState = engine.startGame() }) + GameOverScreen(winner = gameState.winner, onPlayAgain = { + gameState = engine.startGame() + gameStarted = false + }) } } } -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 StartScreen(onStartGame: (Int) -> Unit) { Column( diff --git a/desktopApp/src/jvmMain/kotlin/com/uno/desktop/Main.kt b/desktopApp/src/jvmMain/kotlin/com/uno/desktop/Main.kt index a410392..9a06a76 100644 --- a/desktopApp/src/jvmMain/kotlin/com/uno/desktop/Main.kt +++ b/desktopApp/src/jvmMain/kotlin/com/uno/desktop/Main.kt @@ -13,6 +13,7 @@ import androidx.compose.ui.window.application import com.uno.game.GameEngine import com.uno.game.model.* import com.uno.shared.UnoGameScreen +import kotlinx.coroutines.delay fun main() = application { Window( @@ -29,6 +30,24 @@ fun UnoDesktopApp() { val engine = remember { GameEngine() } var gameState by remember { mutableStateOf(engine.startGame()) } var gameStarted by remember { mutableStateOf(false) } + var isAiThinking by remember { mutableStateOf(false) } + + // KI-Züge mit Verzögerung + LaunchedEffect(gameState.currentPlayerIndex, gameState.phase) { + if (gameState.currentPlayerIndex != 0 + && gameState.phase == GamePhase.PLAYING + && !gameState.isFinished + ) { + isAiThinking = true + var currentState = gameState + while (currentState.currentPlayerIndex != 0 && !currentState.isFinished) { + delay(800) + currentState = engine.aiPlay(currentState, currentState.currentPlayerIndex) + gameState = currentState + } + isAiThinking = false + } + } if (!gameStarted) { DesktopStartScreen(onStartGame = { playerCount -> @@ -40,11 +59,9 @@ fun UnoDesktopApp() { 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) } ) @@ -52,20 +69,15 @@ fun UnoDesktopApp() { if (gameState.isFinished) { DesktopGameOverScreen( winner = gameState.winner, - onPlayAgain = { gameState = engine.startGame() } + onPlayAgain = { + gameState = engine.startGame() + gameStarted = false + } ) } } } -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 DesktopStartScreen(onStartGame: (Int) -> Unit) { Column( diff --git a/webApp/src/wasmJsMain/kotlin/com/uno/web/Main.kt b/webApp/src/wasmJsMain/kotlin/com/uno/web/Main.kt index 88fe31a..f8cdb02 100644 --- a/webApp/src/wasmJsMain/kotlin/com/uno/web/Main.kt +++ b/webApp/src/wasmJsMain/kotlin/com/uno/web/Main.kt @@ -1,51 +1,65 @@ package com.uno.web +import androidx.compose.foundation.layout.* +import androidx.compose.material3.* import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import com.uno.game.GameEngine import com.uno.game.model.* import com.uno.shared.UnoGameScreen import kotlinx.browser.document +import kotlinx.coroutines.delay 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) + composeWebRoot() } @Composable -fun composeWebRoot(container: HTMLElement) { +fun composeWebRoot() { val engine = remember { GameEngine() } var gameState by remember { mutableStateOf(engine.startGame()) } var gameStarted by remember { mutableStateOf(false) } + var isAiThinking by remember { mutableStateOf(false) } + + LaunchedEffect(gameState.currentPlayerIndex, gameState.phase) { + if (gameState.currentPlayerIndex != 0 + && gameState.phase == GamePhase.PLAYING + && !gameState.isFinished + ) { + isAiThinking = true + var currentState = gameState + while (currentState.currentPlayerIndex != 0 && !currentState.isFinished) { + delay(800) + currentState = engine.aiPlay(currentState, currentState.currentPlayerIndex) + gameState = currentState + } + isAiThinking = false + } + } if (!gameStarted) { - WebStartScreen( - onStartGame = { playerCount -> - gameState = engine.startGame(playerCount) - gameStarted = true - } - ) + 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) - } + onCallUno = { gameState = engine.callUno(gameState, 0) } ) if (gameState.isFinished) { @@ -53,60 +67,36 @@ fun composeWebRoot(container: HTMLElement) { winner = gameState.winner, onPlayAgain = { gameState = engine.startGame() + gameStarted = false } ) } } } -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 + Column( + modifier = Modifier.fillMaxSize().padding(32.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = 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)") - } + Text("UNO", style = MaterialTheme.typography.displayLarge, color = MaterialTheme.colorScheme.primary) + Spacer(modifier = Modifier.height(8.dp)) + Text("Web Edition", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + Spacer(modifier = Modifier.height(24.dp)) + Button(onClick = { onStartGame(4) }) { Text("Spiel starten (4 Spieler)") } } } @Composable fun WebGameOverScreen(winner: Player?, onPlayAgain: () -> Unit) { - androidx.compose.material3.AlertDialog( + 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!" - ) - }, + title = { Text("Spiel vorbei!") }, + text = { Text(if (winner != null) "${winner.name} hat gewonnen!" else "Unentschieden!") }, confirmButton = { - androidx.compose.material3.Button(onClick = onPlayAgain) { - androidx.compose.material3.Text("Nochmal spielen") - } + Button(onClick = onPlayAgain) { Text("Nochmal spielen") } } ) }