Tugas Pertemuan 11
Game Unscramble
Nama : Nadya Zuhria Amana
NRP : 5025211058
Kelas : Pemrograman Perangkat Bergerak B
Tahun : 2024
# File Kode Awal
WordsData.kt
File ini menyimpan daftar kata yang digunakan dalam game, serta konstanta untuk jumlah maksimum kata per game dan poin skor untuk setiap kata yang benar.
## MainActivity.kt
File ini berisi sebagian besar kode yang dihasilkan dari template. Anda menampilkan composable `GameScreen` dalam blok `setContent{}`.
## GameScreen.kt
Semua composable UI didefinisikan di sini. Panduan untuk beberapa fungsi composable diberikan di bawah ini.
### GameStatus
Fungsi composable ini menampilkan skor game di bagian bawah layar. Skor saat ini di-hardcode menjadi 0.
### GameLayout
Fungsi composable ini menampilkan elemen utama game, termasuk kata acak, petunjuk game, dan kolom teks untuk menerima tebakan pengguna.
### GameScreen
Composable ini mencakup `GameStatus`, `GameLayout`, judul game, jumlah kata, serta tombol Submit dan Skip.
### FinalScoreDialog
Fungsi composable ini menampilkan dialog yang memberikan opsi kepada pengguna untuk bermain lagi atau keluar dari game. Anda akan mengimplementasikan logika untuk menampilkan dialog ini di akhir game.
## Menambahkan ViewModel
1. Buka `build.gradle.kts (Module :app)`, scroll ke blok dependencies, dan tambahkan dependensi berikut untuk ViewModel.
```kotlin
dependencies {
// other dependencies
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1")
//...
}
```
2. Di paket `ui`, buat class/file Kotlin bernama `GameViewModel` yang merupakan subclass dari `ViewModel`.
```kotlin
import androidx.lifecycle.ViewModel
class GameViewModel : ViewModel() {
}
```
3. Tambahkan class data `GameUiState` di paket `ui` untuk status UI game dengan variabel `currentScrambledWord`.
```kotlin
data class GameUiState(
val currentScrambledWord: String = ""
)
```
## StateFlow
1. Tambahkan properti `_uiState` berikut di class `GameViewModel`.
```kotlin
import kotlinx.coroutines.flow.MutableStateFlow
// Game UI state
private val _uiState = MutableStateFlow(GameUiState())
```
2. Tambahkan properti pendukung `uiState` yang bernama `_uiState` dan berjenis `StateFlow<GameUiState>`.
```kotlin
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
// Game UI state
private val _uiState = MutableStateFlow(GameUiState())
val uiState: StateFlow<GameUiState> = _uiState.asStateFlow()
```
## Menampilkan Kata Acak
1. Di `GameViewModel`, tambahkan properti `currentWord` dari jenis `String` untuk menyimpan kata acak saat ini.
```kotlin
private lateinit var currentWord: String
```
2. Tambahkan metode `pickRandomWordAndShuffle()` untuk memilih kata acak dari daftar dan mengacaknya.
```kotlin
import com.example.unscramble.data.allWords
private fun pickRandomWordAndShuffle(): String {
currentWord = allWords.random()
if (usedWords.contains(currentWord)) {
return pickRandomWordAndShuffle()
} else {
usedWords.add(currentWord)
return shuffleCurrentWord(currentWord)
}
}
```
3. Tambahkan properti untuk menyimpan kata yang telah digunakan dalam game.
```kotlin
// Set of words used in the game
private var usedWords: MutableSet<String> = mutableSetOf()
```
4. Tambahkan metode `shuffleCurrentWord()` untuk mengacak kata saat ini.
```kotlin
private fun shuffleCurrentWord(word: String): String {
val tempWord = word.toCharArray()
tempWord.shuffle()
while (String(tempWord).equals(word)) {
tempWord.shuffle()
}
return String(tempWord)
}
```
5. Tambahkan fungsi `resetGame()` untuk menginisialisasi game.
```kotlin
fun resetGame() {
usedWords.clear()
_uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
}
```
6. Tambahkan blok `init` ke `GameViewModel` dan panggil `resetGame()`.
```kotlin
init {
resetGame()
}
```
## Merancang Compose UI dan Meneruskan Data
1. Pada fungsi `GameScreen`, teruskan argumen kedua dari jenis `GameViewModel` dengan nilai default `viewModel()`.
```kotlin
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun GameScreen(
gameViewModel: GameViewModel = viewModel()
) {
// ...
}
```
2. Tambahkan variabel `gameUiState` pada fungsi `GameScreen` dengan delegasi `by` dan panggil `collectAsState()` pada `uiState`.
```kotlin
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@Composable
fun GameScreen(
gameViewModel: GameViewModel = viewModel()
) {
val gameUiState by gameViewModel.uiState.collectAsState()
// ...
}
```
3. Teruskan `gameUiState.currentScrambledWord` ke `GameLayout`.
```kotlin
GameLayout(
currentScrambledWord = gameUiState.currentScrambledWord,
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight()
.padding(mediumPadding)
)
```
4. Tambahkan `currentScrambledWord` sebagai parameter ke fungsi `GameLayout`.
```kotlin
@Composable
fun GameLayout(
currentScrambledWord: String,
modifier: Modifier = Modifier
) {
}
```
5. Perbarui fungsi `GameLayout` untuk menampilkan `currentScrambledWord`.
```kotlin
@Composable
fun GameLayout(
currentScrambledWord: String,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
Text(
text = currentScrambledWord,
// ...
)
// ...
}
}
```
6. Jalankan dan bangun aplikasi untuk melihat kata yang ejaannya diacak.
## Menampilkan Kata Tebakan
1. Pada `GameLayout`, setel `onValueChange` ke `onUserGuessChanged` dan `onKeyboardDone()` ke tindakan keyboard `onDone`.
```kotlin
OutlinedTextField(
value = "",
singleLine = true,
modifier = Modifier.fillMaxWidth(),
onValueChange = onUserGuessChanged,
label = { Text(stringResource(R.string.enter_your_word)) },
isError = false,
keyboardOptions = KeyboardOptions.Default.copy(
imeAction = ImeAction.Done
),
keyboardActions = KeyboardActions(
onDone = { onKeyboardDone() }
),
)
```
2. Tambahkan argumen `onUserGuessChanged` dan `onKeyboardDone` ke `GameLayout`.
```kotlin
@Composable
fun GameLayout(
currentScrambledWord: String,
onUserGuessChanged: (String) -> Unit,
onKeyboardDone: () -> Unit,
modifier: Modifier = Modifier
) {
}
```
3. Pada `GameScreen`, tambahkan lambda untuk `onUserGuessChanged` dan `onKeyboardDone`.
```kotlin
GameLayout(
currentScrambledWord = gameUiState.currentScrambledWord,
onUserGuessChanged = { gameViewModel.updateUserGuess(it) },
onKeyboardDone = { gameViewModel.checkUserGuess() }
)
```
4. Tambahkan metode `updateUserGuess` di `GameViewModel` untuk memperbarui tebakan pengguna.
```kotlin
fun updateUserGuess(guessedWord: String) {
userGuess = guessedWord
}
```
5. Tambahkan properti `userGuess` di `GameViewModel`.
```kotlin
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
var userGuess by mutableStateOf("")
private set
```
6. Tambahkan parameter `userGuess` ke `GameLayout`.
```kotlin
fun GameLayout(
currentScrambledWord: String,
userGuess: String,
onUserGuessChanged: (String) -> Unit,
onKeyboardDone: () -> Unit,
modifier: Modifier = Modifier
) {
Column(
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
OutlinedTextField(
value = userGuess,
//...
)
}
}
```
7. Perbarui panggilan fungsi `GameLayout` untuk menyertakan `userGuess`.
```kotlin
GameLayout(
currentScrambledWord = gameUiState.currentScrambledWord,
userGuess = gameViewModel.userGuess,
onUserGuessChanged = { gameViewModel.updateUserGuess(it) },
onKeyboardDone = { gameViewModel.checkUserGuess() }
)
```
8. Bangun dan jalankan aplikasi untuk melihat kolom teks yang dapat menampilkan tebakan pengguna.
## Memverifikasi Kata Tebakan dan Memperbarui Skor
1. Tambahkan metode `checkUserGuess` di `GameViewModel`.
```kotlin
fun checkUserGuess() {
if (userGuess.equals(currentWord, ignoreCase = true)) {
// User's guess is correct
} else {
// User's guess is wrong
_uiState.update { currentState ->
currentState.copy(isGuessedWordWrong = true)
}
}
// Reset user guess
updateUserGuess("")
}
```
2. Tambahkan `isGuessedWord
Wrong` ke `GameUiState`.
```kotlin
data class GameUiState(
val currentScrambledWord: String = "",
val isGuessedWordWrong: Boolean = false
)
```
3. Tambahkan metode `updateGameState` ke `GameViewModel` untuk memperbarui skor dan jumlah kata.
```kotlin
private fun updateGameState(updatedScore: Int) {
if (usedWords.size == MAX_NO_OF_WORDS) {
_uiState.update { currentState ->
currentState.copy(
isGuessedWordWrong = false,
score = updatedScore,
isGameOver = true
)
}
} else {
_uiState.update { currentState ->
currentState.copy(
isGuessedWordWrong = false,
currentScrambledWord = pickRandomWordAndShuffle(),
score = updatedScore,
currentWordCount = currentState.currentWordCount.inc()
)
}
}
}
```
4. Perbarui fungsi `checkUserGuess` untuk memperbarui status game dan skor pengguna jika tebakan benar.
```kotlin
fun checkUserGuess() {
if (userGuess.equals(currentWord, ignoreCase = true)) {
val updatedScore = _uiState.value.score.plus(SCORE_INCREASE)
updateGameState(updatedScore)
} else {
_uiState.update { currentState ->
currentState.copy(isGuessedWordWrong = true)
}
}
updateUserGuess("")
}
```
5. Perbarui fungsi `GameLayout` untuk menyertakan skor saat ini.
```kotlin
@Composable
fun GameLayout(
currentScrambledWord: String,
userGuess: String,
onUserGuessChanged: (String) -> Unit,
onKeyboardDone: () -> Unit,
score: Int,
modifier: Modifier = Modifier
) {
//...
Text(
text = stringResource(R.string.word_count, score),
// ...
)
}
```
6. Perbarui panggilan fungsi `GameLayout` di `GameScreen`.
```kotlin
GameLayout(
currentScrambledWord = gameUiState.currentScrambledWord,
userGuess = gameViewModel.userGuess,
onUserGuessChanged = { gameViewModel.updateUserGuess(it) },
onKeyboardDone = { gameViewModel.checkUserGuess() },
score = gameUiState.score
)
```
7. Bangun dan jalankan aplikasi untuk melihat skor yang diperbarui saat kata ditebak dengan benar.