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
2 changes: 2 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,6 @@ dependencies {

debugImplementation("androidx.compose.ui:ui-test-manifest")
debugImplementation("androidx.compose.ui:ui-tooling")

implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
}
62 changes: 50 additions & 12 deletions app/src/main/java/com/example/unscramble/ui/GameScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,20 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.example.unscramble.R
import com.example.unscramble.ui.theme.UnscrambleTheme
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue



@Composable
fun GameScreen() {
fun GameScreen(gameViewModel: GameViewModel = viewModel()) {

val gameUiState by gameViewModel.uiState.collectAsState()
val mediumPadding = dimensionResource(R.dimen.padding_medium)



Column(
modifier = Modifier
.statusBarsPadding()
Expand All @@ -74,6 +83,12 @@ fun GameScreen() {
style = typography.titleLarge,
)
GameLayout(
onUserGuessChanged = { gameViewModel.updateUserGuess(it) },
onKeyboardDone = { gameViewModel.checkUserGuess() },
userGuess = gameViewModel.userGuess,
wordCount = gameUiState.currentWordCount,
currentScrambledWord = gameUiState.currentScrambledWord,
isGuessWrong = gameUiState.isGuessedWordWrong,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
Expand All @@ -87,9 +102,17 @@ fun GameScreen() {
horizontalAlignment = Alignment.CenterHorizontally
) {

if (gameUiState.isGameOver) {
FinalScoreDialog(
score = gameUiState.score,
onPlayAgain = { gameViewModel.resetGame() }
)
}


Button(
modifier = Modifier.fillMaxWidth(),
onClick = { }
onClick = { gameViewModel.checkUserGuess() }
) {
Text(
text = stringResource(R.string.submit),
Expand All @@ -98,7 +121,7 @@ fun GameScreen() {
}

OutlinedButton(
onClick = { },
onClick = { gameViewModel.skipWord() },
modifier = Modifier.fillMaxWidth()
) {
Text(
Expand All @@ -108,7 +131,7 @@ fun GameScreen() {
}
}

GameStatus(score = 0, modifier = Modifier.padding(20.dp))
GameStatus(score = gameUiState.score, modifier = Modifier.padding(20.dp))
}
}

Expand All @@ -126,9 +149,17 @@ fun GameStatus(score: Int, modifier: Modifier = Modifier) {
}

@Composable
fun GameLayout(modifier: Modifier = Modifier) {
fun GameLayout(
onUserGuessChanged: (String) -> Unit,
onKeyboardDone: () -> Unit,
wordCount: Int,
userGuess: String,
currentScrambledWord: String,
isGuessWrong: Boolean,
modifier: Modifier = Modifier) {
val mediumPadding = dimensionResource(R.dimen.padding_medium)


Card(
modifier = modifier,
elevation = CardDefaults.cardElevation(defaultElevation = 5.dp)
Expand All @@ -144,21 +175,24 @@ fun GameLayout(modifier: Modifier = Modifier) {
.background(colorScheme.surfaceTint)
.padding(horizontal = 10.dp, vertical = 4.dp)
.align(alignment = Alignment.End),
text = stringResource(R.string.word_count, 0),
text = stringResource(R.string.word_count, wordCount),
style = typography.titleMedium,
color = colorScheme.onPrimary
)
Text(
text = "scrambleun",
text = currentScrambledWord, //
style = typography.displayMedium
)

Text(
text = stringResource(R.string.instructions),
textAlign = TextAlign.Center,
style = typography.titleMedium


)
OutlinedTextField(
value = "",
value = userGuess,
singleLine = true,
shape = shapes.large,
modifier = Modifier.fillMaxWidth(),
Expand All @@ -167,14 +201,18 @@ fun GameLayout(modifier: Modifier = Modifier) {
unfocusedContainerColor = colorScheme.surface,
disabledContainerColor = colorScheme.surface,
),
onValueChange = { },
label = { Text(stringResource(R.string.enter_your_word)) },
isError = false,
onValueChange = onUserGuessChanged,
label = { if (isGuessWrong) {
Text(stringResource(R.string.wrong_guess))
} else {
Text(stringResource(R.string.enter_your_word))
} },
isError = isGuessWrong,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = { }
onDone = { onKeyboardDone() }
)
)
}
Expand Down
10 changes: 10 additions & 0 deletions app/src/main/java/com/example/unscramble/ui/GameUiState.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.example.unscramble.ui

data class GameUiState(
val currentScrambledWord: String ="",
val currentWordCount: Int = 1,
val isGuessedWordWrong: Boolean = false,
val score: Int = 0,
val isGameOver: Boolean = false

)
115 changes: 115 additions & 0 deletions app/src/main/java/com/example/unscramble/ui/GameViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.example.unscramble.ui
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import com.example.unscramble.data.allWords

import kotlinx.coroutines.flow.asStateFlow
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import kotlinx.coroutines.flow.update
import com.example.unscramble.data.SCORE_INCREASE
import com.example.unscramble.data.MAX_NO_OF_WORDS


class GameViewModel : ViewModel() {

var userGuess by mutableStateOf("")
private set

// Game UI state
private val _uiState = MutableStateFlow(GameUiState())

// Read-only state
val uiState: StateFlow<GameUiState> = _uiState.asStateFlow()

private lateinit var currentWord: String
private var usedWords: MutableSet<String> = mutableSetOf()

private fun pickRandomWordAndShuffle(): String {
currentWord = allWords.random()
if (usedWords.contains(currentWord)) {
return pickRandomWordAndShuffle()
} else {
usedWords.add(currentWord)
return shuffleCurrentWord(currentWord)
}
}

private fun shuffleCurrentWord(word: String): String {
val tempWord = word.toCharArray()
//Scramble the word
tempWord.shuffle()
while (String(tempWord).equals(word)) {
tempWord.shuffle()
}
return String(tempWord)
}

fun resetGame() {
usedWords.clear()
_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
}

fun updateUserGuess(guessedWord: String) {
userGuess = guessedWord
}


fun checkUserGuess() {

if (userGuess.equals(currentWord, ignoreCase = true)) {
val updatedScore = _uiState.value.score.plus(SCORE_INCREASE)
updateGameState(updatedScore)
} else {
// User's guess is wrong, show an error
_uiState.update { currentState ->
currentState.copy(isGuessedWordWrong = true)
}
// Reset user guess
updateUserGuess("")
}


}

private fun updateGameState(updatedScore: Int) {
if (usedWords.size == MAX_NO_OF_WORDS) {
//Last round in the game, update isGameOver to true, don't pick a new word
_uiState.update { currentState ->
currentState.copy(
isGuessedWordWrong = false,
score = updatedScore,
isGameOver = true
)
}
} else {
// Normal round in the game
_uiState.update { currentState ->
currentState.copy(
isGuessedWordWrong = false,
currentScrambledWord = pickRandomWordAndShuffle(),
currentWordCount = currentState.currentWordCount.inc(),
score = updatedScore
)
}
}



}

fun skipWord() {
updateGameState(_uiState.value.score)

//Reset user guess
updateUserGuess("")
}



init {
resetGame()
}
}