feat: visible AI turns with 800ms delay between each move
This commit is contained in:
@@ -13,6 +13,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import com.uno.game.GameEngine
|
import com.uno.game.GameEngine
|
||||||
import com.uno.game.model.*
|
import com.uno.game.model.*
|
||||||
import com.uno.shared.UnoGameScreen
|
import com.uno.shared.UnoGameScreen
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
@@ -33,6 +34,23 @@ fun UnoApp() {
|
|||||||
val engine = remember { GameEngine() }
|
val engine = remember { GameEngine() }
|
||||||
var gameState by remember { mutableStateOf(engine.startGame()) }
|
var gameState by remember { mutableStateOf(engine.startGame()) }
|
||||||
var gameStarted by remember { mutableStateOf(false) }
|
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) {
|
if (!gameStarted) {
|
||||||
StartScreen(onStartGame = { playerCount ->
|
StartScreen(onStartGame = { playerCount ->
|
||||||
@@ -44,29 +62,22 @@ fun UnoApp() {
|
|||||||
state = gameState,
|
state = gameState,
|
||||||
onPlayCard = { card, color ->
|
onPlayCard = { card, color ->
|
||||||
gameState = engine.playCard(gameState, 0, card, color)
|
gameState = engine.playCard(gameState, 0, card, color)
|
||||||
gameState = runAiTurns(engine, gameState)
|
|
||||||
},
|
},
|
||||||
onDrawCard = {
|
onDrawCard = {
|
||||||
gameState = engine.drawCard(gameState, 0)
|
gameState = engine.drawCard(gameState, 0)
|
||||||
gameState = runAiTurns(engine, gameState)
|
|
||||||
},
|
},
|
||||||
onCallUno = { gameState = engine.callUno(gameState, 0) }
|
onCallUno = { gameState = engine.callUno(gameState, 0) }
|
||||||
)
|
)
|
||||||
|
|
||||||
if (gameState.isFinished) {
|
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
|
@Composable
|
||||||
fun StartScreen(onStartGame: (Int) -> Unit) {
|
fun StartScreen(onStartGame: (Int) -> Unit) {
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import androidx.compose.ui.window.application
|
|||||||
import com.uno.game.GameEngine
|
import com.uno.game.GameEngine
|
||||||
import com.uno.game.model.*
|
import com.uno.game.model.*
|
||||||
import com.uno.shared.UnoGameScreen
|
import com.uno.shared.UnoGameScreen
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
|
||||||
fun main() = application {
|
fun main() = application {
|
||||||
Window(
|
Window(
|
||||||
@@ -29,6 +30,24 @@ fun UnoDesktopApp() {
|
|||||||
val engine = remember { GameEngine() }
|
val engine = remember { GameEngine() }
|
||||||
var gameState by remember { mutableStateOf(engine.startGame()) }
|
var gameState by remember { mutableStateOf(engine.startGame()) }
|
||||||
var gameStarted by remember { mutableStateOf(false) }
|
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) {
|
if (!gameStarted) {
|
||||||
DesktopStartScreen(onStartGame = { playerCount ->
|
DesktopStartScreen(onStartGame = { playerCount ->
|
||||||
@@ -40,11 +59,9 @@ fun UnoDesktopApp() {
|
|||||||
state = gameState,
|
state = gameState,
|
||||||
onPlayCard = { card, color ->
|
onPlayCard = { card, color ->
|
||||||
gameState = engine.playCard(gameState, 0, card, color)
|
gameState = engine.playCard(gameState, 0, card, color)
|
||||||
gameState = runAiTurns(engine, gameState)
|
|
||||||
},
|
},
|
||||||
onDrawCard = {
|
onDrawCard = {
|
||||||
gameState = engine.drawCard(gameState, 0)
|
gameState = engine.drawCard(gameState, 0)
|
||||||
gameState = runAiTurns(engine, gameState)
|
|
||||||
},
|
},
|
||||||
onCallUno = { gameState = engine.callUno(gameState, 0) }
|
onCallUno = { gameState = engine.callUno(gameState, 0) }
|
||||||
)
|
)
|
||||||
@@ -52,20 +69,15 @@ fun UnoDesktopApp() {
|
|||||||
if (gameState.isFinished) {
|
if (gameState.isFinished) {
|
||||||
DesktopGameOverScreen(
|
DesktopGameOverScreen(
|
||||||
winner = gameState.winner,
|
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
|
@Composable
|
||||||
fun DesktopStartScreen(onStartGame: (Int) -> Unit) {
|
fun DesktopStartScreen(onStartGame: (Int) -> Unit) {
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
@@ -1,51 +1,65 @@
|
|||||||
package com.uno.web
|
package com.uno.web
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.*
|
||||||
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
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.GameEngine
|
||||||
import com.uno.game.model.*
|
import com.uno.game.model.*
|
||||||
import com.uno.shared.UnoGameScreen
|
import com.uno.shared.UnoGameScreen
|
||||||
import kotlinx.browser.document
|
import kotlinx.browser.document
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import org.w3c.dom.HTMLElement
|
import org.w3c.dom.HTMLElement
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
val root = document.getElementById("root") as HTMLElement
|
val root = document.getElementById("root") as HTMLElement
|
||||||
|
|
||||||
root.innerHTML = ""
|
root.innerHTML = ""
|
||||||
|
|
||||||
val container = document.createElement("div")
|
val container = document.createElement("div")
|
||||||
container.id = "app"
|
container.id = "app"
|
||||||
root.appendChild(container)
|
root.appendChild(container)
|
||||||
|
composeWebRoot()
|
||||||
composeWebRoot(container)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun composeWebRoot(container: HTMLElement) {
|
fun composeWebRoot() {
|
||||||
val engine = remember { GameEngine() }
|
val engine = remember { GameEngine() }
|
||||||
var gameState by remember { mutableStateOf(engine.startGame()) }
|
var gameState by remember { mutableStateOf(engine.startGame()) }
|
||||||
var gameStarted by remember { mutableStateOf(false) }
|
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) {
|
if (!gameStarted) {
|
||||||
WebStartScreen(
|
WebStartScreen(onStartGame = { playerCount ->
|
||||||
onStartGame = { playerCount ->
|
gameState = engine.startGame(playerCount)
|
||||||
gameState = engine.startGame(playerCount)
|
gameStarted = true
|
||||||
gameStarted = true
|
})
|
||||||
}
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
UnoGameScreen(
|
UnoGameScreen(
|
||||||
state = gameState,
|
state = gameState,
|
||||||
onPlayCard = { card, color ->
|
onPlayCard = { card, color ->
|
||||||
gameState = engine.playCard(gameState, 0, card, color)
|
gameState = engine.playCard(gameState, 0, card, color)
|
||||||
gameState = runAiTurns(engine, gameState)
|
|
||||||
},
|
},
|
||||||
onDrawCard = {
|
onDrawCard = {
|
||||||
gameState = engine.drawCard(gameState, 0)
|
gameState = engine.drawCard(gameState, 0)
|
||||||
gameState = runAiTurns(engine, gameState)
|
|
||||||
},
|
},
|
||||||
onCallUno = {
|
onCallUno = { gameState = engine.callUno(gameState, 0) }
|
||||||
gameState = engine.callUno(gameState, 0)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if (gameState.isFinished) {
|
if (gameState.isFinished) {
|
||||||
@@ -53,60 +67,36 @@ fun composeWebRoot(container: HTMLElement) {
|
|||||||
winner = gameState.winner,
|
winner = gameState.winner,
|
||||||
onPlayAgain = {
|
onPlayAgain = {
|
||||||
gameState = engine.startGame()
|
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
|
@Composable
|
||||||
fun WebStartScreen(onStartGame: (Int) -> Unit) {
|
fun WebStartScreen(onStartGame: (Int) -> Unit) {
|
||||||
androidx.compose.foundation.layout.Column(
|
Column(
|
||||||
modifier = androidx.compose.foundation.layout.fillMaxSize().padding(32.dp),
|
modifier = Modifier.fillMaxSize().padding(32.dp),
|
||||||
horizontalAlignment = androidx.compose.ui.Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
androidx.compose.material3.Text(
|
Text("UNO", style = MaterialTheme.typography.displayLarge, color = MaterialTheme.colorScheme.primary)
|
||||||
text = "UNO",
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
style = androidx.compose.material3.MaterialTheme.typography.displayLarge,
|
Text("Web Edition", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant)
|
||||||
color = androidx.compose.material3.MaterialTheme.colorScheme.primary
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
)
|
Button(onClick = { onStartGame(4) }) { Text("Spiel starten (4 Spieler)") }
|
||||||
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
|
@Composable
|
||||||
fun WebGameOverScreen(winner: Player?, onPlayAgain: () -> Unit) {
|
fun WebGameOverScreen(winner: Player?, onPlayAgain: () -> Unit) {
|
||||||
androidx.compose.material3.AlertDialog(
|
AlertDialog(
|
||||||
onDismissRequest = onPlayAgain,
|
onDismissRequest = onPlayAgain,
|
||||||
title = { androidx.compose.material3.Text("Spiel vorbei!") },
|
title = { Text("Spiel vorbei!") },
|
||||||
text = {
|
text = { Text(if (winner != null) "${winner.name} hat gewonnen!" else "Unentschieden!") },
|
||||||
androidx.compose.material3.Text(
|
|
||||||
text = if (winner != null) "${winner.name} hat gewonnen!"
|
|
||||||
else "Unentschieden!"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
confirmButton = {
|
confirmButton = {
|
||||||
androidx.compose.material3.Button(onClick = onPlayAgain) {
|
Button(onClick = onPlayAgain) { Text("Nochmal spielen") }
|
||||||
androidx.compose.material3.Text("Nochmal spielen")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user