Tugas PPB 11 Membuat Aplikasi Unscramble

 TUGAS PPB 11

Membuat Aplikasi Unscramble
Nama: Fayyadh Hafizh
NRP : 5025201164
Kelas: PPB I
Link Github: Tugas 11

Halo temen-temen semuanya! Pada kesempatan kali ini, kita akan mencoba membuat sebuah aplikasi yang bernama Unscramble. Aplikasi ini merupakan sebuah permainan sederhana dimana pengguna akan menebak kata dari huruf yang telah diacak sedemikian rupa. Setiap kata yang ditebak benar, pengguna mendapatkan skor 20 dengan maksimal skor 200 untuk total 10 kata yang dapat ditebak. Kode dan hasil implementasi dapat dilihat dibawah ini.
  • Kode Implementasi
     
  • /*
    * Copyright (C) 2023 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package com.example.unscramble
    import android.os.Bundle
    import androidx.activity.ComponentActivity
    import androidx.activity.compose.setContent
    import androidx.activity.enableEdgeToEdge
    import androidx.compose.foundation.layout.fillMaxSize
    import androidx.compose.material3.Surface
    import androidx.compose.ui.Modifier
    import com.example.unscramble.ui.GameScreen
    import com.example.unscramble.ui.theme.UnscrambleTheme
    class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
    enableEdgeToEdge()
    super.onCreate(savedInstanceState)
    setContent {
    UnscrambleTheme {
    Surface(
    modifier = Modifier.fillMaxSize(),
    ) {
    GameScreen()
    }
    }
    }
    }
    }
    view raw MainActivity.kt hosted with ❤ by GitHub
    /*
    * Copyright (C) 2023 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package com.example.unscramble.ui
    import android.app.Activity
    import androidx.compose.foundation.background
    import androidx.compose.foundation.layout.Arrangement
    import androidx.compose.foundation.layout.Column
    import androidx.compose.foundation.layout.fillMaxWidth
    import androidx.compose.foundation.layout.padding
    import androidx.compose.foundation.layout.safeDrawingPadding
    import androidx.compose.foundation.layout.statusBarsPadding
    import androidx.compose.foundation.layout.wrapContentHeight
    import androidx.compose.foundation.rememberScrollState
    import androidx.compose.foundation.text.KeyboardActions
    import androidx.compose.foundation.text.KeyboardOptions
    import androidx.compose.foundation.verticalScroll
    import androidx.compose.material3.AlertDialog
    import androidx.compose.material3.Button
    import androidx.compose.material3.Card
    import androidx.compose.material3.CardDefaults
    import androidx.compose.material3.MaterialTheme.colorScheme
    import androidx.compose.material3.MaterialTheme.shapes
    import androidx.compose.material3.MaterialTheme.typography
    import androidx.compose.material3.OutlinedButton
    import androidx.compose.material3.OutlinedTextField
    import androidx.compose.material3.Text
    import androidx.compose.material3.TextButton
    import androidx.compose.material3.TextFieldDefaults
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.collectAsState
    import androidx.compose.runtime.getValue
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    import androidx.compose.ui.draw.clip
    import androidx.compose.ui.platform.LocalContext
    import androidx.compose.ui.res.dimensionResource
    import androidx.compose.ui.res.stringResource
    import androidx.compose.ui.text.input.ImeAction
    import androidx.compose.ui.text.style.TextAlign
    import androidx.compose.ui.tooling.preview.Preview
    import androidx.compose.ui.unit.dp
    import androidx.compose.ui.unit.sp
    import androidx.lifecycle.viewmodel.compose.viewModel
    import com.example.unscramble.R
    import com.example.unscramble.ui.theme.UnscrambleTheme
    @Composable
    fun GameScreen(gameViewModel: GameViewModel = viewModel()) {
    val gameUiState by gameViewModel.uiState.collectAsState()
    val mediumPadding = dimensionResource(R.dimen.padding_medium)
    Column(
    modifier = Modifier
    .statusBarsPadding()
    .verticalScroll(rememberScrollState())
    .safeDrawingPadding()
    .padding(mediumPadding),
    verticalArrangement = Arrangement.Center,
    horizontalAlignment = Alignment.CenterHorizontally
    ) {
    Text(
    text = stringResource(R.string.app_name),
    style = typography.titleLarge,
    )
    GameLayout(
    onUserGuessChanged = { gameViewModel.updateUserGuess(it) },
    wordCount = gameUiState.currentWordCount,
    userGuess = gameViewModel.userGuess,
    onKeyboardDone = { gameViewModel.checkUserGuess() },
    currentScrambledWord = gameUiState.currentScrambledWord,
    isGuessWrong = gameUiState.isGuessedWordWrong,
    modifier = Modifier
    .fillMaxWidth()
    .wrapContentHeight()
    .padding(mediumPadding)
    )
    Column(
    modifier = Modifier
    .fillMaxWidth()
    .padding(mediumPadding),
    verticalArrangement = Arrangement.spacedBy(mediumPadding),
    horizontalAlignment = Alignment.CenterHorizontally
    ) {
    Button(
    modifier = Modifier.fillMaxWidth(),
    onClick = { gameViewModel.checkUserGuess() }
    ) {
    Text(
    text = stringResource(R.string.submit),
    fontSize = 16.sp
    )
    }
    OutlinedButton(
    onClick = { gameViewModel.skipWord() },
    modifier = Modifier.fillMaxWidth()
    ) {
    Text(
    text = stringResource(R.string.skip),
    fontSize = 16.sp
    )
    }
    }
    GameStatus(score = gameUiState.score, modifier = Modifier.padding(20.dp))
    if (gameUiState.isGameOver) {
    FinalScoreDialog(
    score = gameUiState.score,
    onPlayAgain = { gameViewModel.resetGame() }
    )
    }
    }
    }
    @Composable
    fun GameStatus(score: Int, modifier: Modifier = Modifier) {
    Card(
    modifier = modifier
    ) {
    Text(
    text = stringResource(R.string.score, score),
    style = typography.headlineMedium,
    modifier = Modifier.padding(8.dp)
    )
    }
    }
    @Composable
    fun GameLayout(
    currentScrambledWord: String,
    wordCount: Int,
    isGuessWrong: Boolean,
    userGuess: String,
    onUserGuessChanged: (String) -> Unit,
    onKeyboardDone: () -> Unit,
    modifier: Modifier = Modifier
    ) {
    val mediumPadding = dimensionResource(R.dimen.padding_medium)
    Card(
    modifier = modifier,
    elevation = CardDefaults.cardElevation(defaultElevation = 5.dp)
    ) {
    Column(
    verticalArrangement = Arrangement.spacedBy(mediumPadding),
    horizontalAlignment = Alignment.CenterHorizontally,
    modifier = Modifier.padding(mediumPadding)
    ) {
    Text(
    modifier = Modifier
    .clip(shapes.medium)
    .background(colorScheme.surfaceTint)
    .padding(horizontal = 10.dp, vertical = 4.dp)
    .align(alignment = Alignment.End),
    text = stringResource(R.string.word_count, wordCount),
    style = typography.titleMedium,
    color = colorScheme.onPrimary
    )
    Text(
    text = currentScrambledWord,
    style = typography.displayMedium
    )
    Text(
    text = stringResource(R.string.instructions),
    textAlign = TextAlign.Center,
    style = typography.titleMedium
    )
    OutlinedTextField(
    value = userGuess,
    singleLine = true,
    shape = shapes.large,
    modifier = Modifier.fillMaxWidth(),
    colors = TextFieldDefaults.colors(
    focusedContainerColor = colorScheme.surface,
    unfocusedContainerColor = colorScheme.surface,
    disabledContainerColor = colorScheme.surface,
    ),
    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 = { onKeyboardDone() }
    )
    )
    }
    }
    }
    /*
    * Creates and shows an AlertDialog with final score.
    */
    @Composable
    private fun FinalScoreDialog(
    score: Int,
    onPlayAgain: () -> Unit,
    modifier: Modifier = Modifier
    ) {
    val activity = (LocalContext.current as Activity)
    AlertDialog(
    onDismissRequest = {
    // Dismiss the dialog when the user clicks outside the dialog or on the back
    // button. If you want to disable that functionality, simply use an empty
    // onCloseRequest.
    },
    title = { Text(text = stringResource(R.string.congratulations)) },
    text = { Text(text = stringResource(R.string.you_scored, score)) },
    modifier = modifier,
    dismissButton = {
    TextButton(
    onClick = {
    activity.finish()
    }
    ) {
    Text(text = stringResource(R.string.exit))
    }
    },
    confirmButton = {
    TextButton(onClick = onPlayAgain) {
    Text(text = stringResource(R.string.play_again))
    }
    }
    )
    }
    @Preview(showBackground = true)
    @Composable
    fun GameScreenPreview() {
    UnscrambleTheme {
    GameScreen()
    }
    }
    view raw GameScreen.kt hosted with ❤ by GitHub
    /*
    * Copyright (C) 2023 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package com.example.unscramble.ui
    /**
    * Data class that represents the game UI state
    */
    data class GameUiState(
    val currentScrambledWord: String = "",
    val currentWordCount: Int = 1,
    val score: Int = 0,
    val isGuessedWordWrong: Boolean = false,
    val isGameOver: Boolean = false
    )
    view raw GameUiState.kt hosted with ❤ by GitHub
    /*
    * Copyright (C) 2023 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package com.example.unscramble.ui
    import androidx.compose.runtime.getValue
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.runtime.setValue
    import androidx.lifecycle.ViewModel
    import com.example.unscramble.data.MAX_NO_OF_WORDS
    import com.example.unscramble.data.SCORE_INCREASE
    import com.example.unscramble.data.allWords
    import kotlinx.coroutines.flow.MutableStateFlow
    import kotlinx.coroutines.flow.StateFlow
    import kotlinx.coroutines.flow.asStateFlow
    import kotlinx.coroutines.flow.update
    /**
    * ViewModel containing the app data and methods to process the data
    */
    class GameViewModel : ViewModel() {
    // Game UI state
    private val _uiState = MutableStateFlow(GameUiState())
    val uiState: StateFlow<GameUiState> = _uiState.asStateFlow()
    var userGuess by mutableStateOf("")
    private set
    // Set of words used in the game
    private var usedWords: MutableSet<String> = mutableSetOf()
    private lateinit var currentWord: String
    init {
    resetGame()
    }
    /*
    * Re-initializes the game data to restart the game.
    */
    fun resetGame() {
    usedWords.clear()
    _uiState.value = GameUiState(currentScrambledWord = pickRandomWordAndShuffle())
    }
    /*
    * Update the user's guess
    */
    fun updateUserGuess(guessedWord: String){
    userGuess = guessedWord
    }
    /*
    * Checks if the user's guess is correct.
    * Increases the score accordingly.
    */
    fun checkUserGuess() {
    if (userGuess.equals(currentWord, ignoreCase = true)) {
    // User's guess is correct, increase the score
    // and call updateGameState() to prepare the game for next round
    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("")
    }
    /*
    * Skip to next word
    */
    fun skipWord() {
    updateGameState(_uiState.value.score)
    // Reset user guess
    updateUserGuess("")
    }
    /*
    * Picks a new currentWord and currentScrambledWord and updates UiState according to
    * current game state.
    */
    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
    )
    }
    }
    }
    private fun shuffleCurrentWord(word: String): String {
    val tempWord = word.toCharArray()
    // Scramble the word
    tempWord.shuffle()
    while (String(tempWord) == word) {
    tempWord.shuffle()
    }
    return String(tempWord)
    }
    private fun pickRandomWordAndShuffle(): String {
    // Continue picking up a new random word until you get one that hasn't been used before
    currentWord = allWords.random()
    return if (usedWords.contains(currentWord)) {
    pickRandomWordAndShuffle()
    } else {
    usedWords.add(currentWord)
    shuffleCurrentWord(currentWord)
    }
    }
    }
    /*
    * Copyright (C) 2023 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */
    package com.example.unscramble.data
    const val MAX_NO_OF_WORDS = 10
    const val SCORE_INCREASE = 20
    // Set with all the words for the Game
    val allWords: Set<String> =
    setOf(
    "animal",
    "auto",
    "anecdote",
    "alphabet",
    "all",
    "awesome",
    "arise",
    "balloon",
    "basket",
    "bench",
    "best",
    "birthday",
    "book",
    "briefcase",
    "camera",
    "camping",
    "candle",
    "cat",
    "cauliflower",
    "chat",
    "children",
    "class",
    "classic",
    "classroom",
    "coffee",
    "colorful",
    "cookie",
    "creative",
    "cruise",
    "dance",
    "daytime",
    "dinosaur",
    "doorknob",
    "dine",
    "dream",
    "dusk",
    "eating",
    "elephant",
    "emerald",
    "eerie",
    "electric",
    "finish",
    "flowers",
    "follow",
    "fox",
    "frame",
    "free",
    "frequent",
    "funnel",
    "green",
    "guitar",
    "grocery",
    "glass",
    "great",
    "giggle",
    "haircut",
    "half",
    "homemade",
    "happen",
    "honey",
    "hurry",
    "hundred",
    "ice",
    "igloo",
    "invest",
    "invite",
    "icon",
    "introduce",
    "joke",
    "jovial",
    "journal",
    "jump",
    "join",
    "kangaroo",
    "keyboard",
    "kitchen",
    "koala",
    "kind",
    "kaleidoscope",
    "landscape",
    "late",
    "laugh",
    "learning",
    "lemon",
    "letter",
    "lily",
    "magazine",
    "marine",
    "marshmallow",
    "maze",
    "meditate",
    "melody",
    "minute",
    "monument",
    "moon",
    "motorcycle",
    "mountain",
    "music",
    "north",
    "nose",
    "night",
    "name",
    "never",
    "negotiate",
    "number",
    "opposite",
    "octopus",
    "oak",
    "order",
    "open",
    "polar",
    "pack",
    "painting",
    "person",
    "picnic",
    "pillow",
    "pizza",
    "podcast",
    "presentation",
    "puppy",
    "puzzle",
    "recipe",
    "release",
    "restaurant",
    "revolve",
    "rewind",
    "room",
    "run",
    "secret",
    "seed",
    "ship",
    "shirt",
    "should",
    "small",
    "spaceship",
    "stargazing",
    "skill",
    "street",
    "style",
    "sunrise",
    "taxi",
    "tidy",
    "timer",
    "together",
    "tooth",
    "tourist",
    "travel",
    "truck",
    "under",
    "useful",
    "unicorn",
    "unique",
    "uplift",
    "uniform",
    "vase",
    "violin",
    "visitor",
    "vision",
    "volume",
    "view",
    "walrus",
    "wander",
    "world",
    "winter",
    "well",
    "whirlwind",
    "x-ray",
    "xylophone",
    "yoga",
    "yogurt",
    "yoyo",
    "you",
    "year",
    "yummy",
    "zebra",
    "zigzag",
    "zoology",
    "zone",
    "zeal"
    )
    view raw WordsData.kt hosted with ❤ by GitHub
  • Hasil Implementasi


Komentar

Postingan populer dari blog ini

Tugas PPB 8 Membuat Image Scroll dengan menggunakan Desain Material

Tugas PPB 13 Membuat Aplikasi Musik