Praktik: Dasar-Dasar Kotlin

1. Sebelum memulai

Setelah Anda bekerja keras untuk mempelajari dasar-dasar pemrograman Kotlin, kini saatnya untuk mempraktikkan materi yang telah Anda pelajari.

Latihan ini akan menguji pemahaman Anda terkait konsep yang telah dipelajari. Latihan ini didasarkan pada kasus penggunaan di dunia nyata, yang sebagian di antaranya mungkin pernah Anda temui sebagai pengguna.

Ikuti petunjuk guna menemukan solusi untuk setiap latihan di Kotlin Playground. Jika mengalami kesulitan, beberapa latihan memiliki petunjuk yang dapat membantu Anda mengatasinya. Kode solusi untuk setiap latihan tersedia di bagian akhir, namun sebaiknya Anda menyelesaikan latihan ini sebelum memeriksa jawaban.

Lakukan latihan dengan kecepatan yang sesuai untuk Anda. Ada perkiraan durasi untuk latihan tersebut, tetapi itu hanya perkiraan, jadi Anda tidak harus mematuhinya. Luangkan waktu sebanyak yang Anda butuhkan untuk menyelesaikan setiap soal dengan cermat. Solusi hanyalah satu cara untuk menyelesaikan latihan ini, jadi silakan bereksperimen sesuai keinginan Anda.

Prasyarat

Yang akan Anda butuhkan

  • Playground Kotlin

2. Notifikasi seluler

Biasanya, ponsel memberikan ringkasan notifikasi.

Pada kode awal yang diberikan dalam cuplikan kode berikut, tulis program yang mencetak pesan ringkasan berdasarkan jumlah notifikasi yang Anda terima. Pesan harus menyertakan:

  • Jumlah notifikasi yang tepat jika notifikasinya kurang dari 100.
  • 99+ sebagai jumlah notifikasi jika ada 100 notifikasi atau lebih.
fun main() {
    val morningNotification = 51
    val eveningNotification = 135

    printNotificationSummary(morningNotification)
    printNotificationSummary(eveningNotification)
}

fun printNotificationSummary(numberOfMessages: Int) {
    // Fill in the code.
}

Lengkapi fungsi printNotificationSummary() agar program dapat mencetak baris berikut:

You have 51 notifications.
Your phone is blowing up! You have 99+ notifications.

3. Harga tiket film

Harga tiket film biasanya berbeda-beda berdasarkan usia penonton bioskop.

Pada kode awal yang diberikan dalam cuplikan kode berikut, tulis program yang menghitung harga tiket berdasarkan usia ini:

  • Harga tiket anak sebesar $15 untuk anak berusia 12 tahun ke bawah.
  • Harga tiket standar sebesar $30 untuk orang-orang berusia antara 13 dan 60 tahun. Pada hari Senin, diskon harga tiket standar menjadi $25 untuk kelompok usia yang sama.
  • Harga tiket senior sebesar $20 untuk orang-orang berusia 61 tahun ke atas. Anggaplah usia maksimum penonton bioskop adalah 100 tahun.
  • Nilai -1 untuk menunjukkan bahwa harga tidak valid saat pengguna memasukkan usia di luar spesifikasi usia.
fun main() {
    val child = 5
    val adult = 28
    val senior = 87

    val isMonday = true

    println("The movie ticket price for a person aged $child is \$${ticketPrice(child, isMonday)}.")
    println("The movie ticket price for a person aged $adult is \$${ticketPrice(adult, isMonday)}.")
    println("The movie ticket price for a person aged $senior is \$${ticketPrice(senior, isMonday)}.")
}

fun ticketPrice(age: Int, isMonday: Boolean): Int {
    // Fill in the code.
}

Lengkapi fungsi ticketPrice() agar program dapat mencetak baris berikut:

The movie ticket price for a person aged 5 is $15.
The movie ticket price for a person aged 28 is $25.
The movie ticket price for a person aged 87 is $20.

4. Pengonversi suhu

Ada tiga skala suhu utama yang digunakan di dunia: Celsius, Fahrenheit, dan Kelvin.

Pada kode awal yang diberikan dalam cuplikan kode berikut, tulis program yang mengonversi suhu dari satu skala ke skala lain dengan rumus ini:

  • Celsius ke Fahrenheit: ° F = 9/5 (° C) + 32
  • Kelvin ke Celsius: ° C = K - 273,15
  • Fahrenheit ke Kelvin: K = 5/9 (° F - 32) + 273,15

Perhatikan bahwa metode String.format("%.2f", /* measurement */ ) digunakan untuk mengonversi angka menjadi jenis String dengan 2 angka di belakang koma.

fun main() {
    // Fill in the code.
}

fun printFinalTemperature(
    initialMeasurement: Double,
    initialUnit: String,
    finalUnit: String,
    conversionFormula: (Double) -> Double
) {
    val finalMeasurement = String.format("%.2f", conversionFormula(initialMeasurement)) // two decimal places
    println("$initialMeasurement degrees $initialUnit is $finalMeasurement degrees $finalUnit.")
}

Lengkapi fungsi main() agar memanggil fungsi printFinalTemperature() dan mencetak baris berikut. Anda harus meneruskan argumen untuk suhu dan rumus konversi. Petunjuk: Anda dapat menggunakan nilai Double untuk menghindari pemotongan Integer selama operasi pembagian.

27.0 degrees Celsius is 80.60 degrees Fahrenheit.
350.0 degrees Kelvin is 76.85 degrees Celsius.
10.0 degrees Fahrenheit is 260.93 degrees Kelvin.

5. Katalog lagu

Bayangkan Anda perlu membuat aplikasi pemutar musik.

Buat class yang dapat merepresentasikan struktur lagu. Class Song harus menyertakan elemen kode berikut:

  • Properti untuk judul, artis, tahun publikasi, dan jumlah pemutaran
  • Properti yang menunjukkan apakah lagu tersebut populer. Jika jumlah pemutaran kurang dari 1.000, anggap lagu itu tidak populer.
  • Metode yang mencetak deskripsi lagu dalam format ini:

"[Judul], dibawakan oleh [artis], dirilis pada tahun [tahun dipublikasikan]."

6. Profil internet

Sering kali, Anda harus melengkapi profil untuk situs web online yang berisi kolom wajib dan tidak wajib. Misalnya, Anda dapat menambahkan informasi pribadi dan menautkan ke orang lain yang merujuk Anda untuk mendaftarkan profil.

Pada kode awal yang diberikan dalam cuplikan kode berikut, tulis program yang mencetak detail profil seseorang.

fun main() {
    val amanda = Person("Amanda", 33, "play tennis", null)
    val atiqah = Person("Atiqah", 28, "climb", amanda)

    amanda.showProfile()
    atiqah.showProfile()
}

class Person(val name: String, val age: Int, val hobby: String?, val referrer: Person?) {
    fun showProfile() {
       // Fill in code
    }
}

Lengkapi fungsi showProfile() agar program dapat mencetak baris berikut:

Name: Amanda
Age: 33
Likes to play tennis. Doesn't have a referrer.

Name: Atiqah
Age: 28
Likes to climb. Has a referrer named Amanda, who likes to play tennis.

7. Ponsel foldable

Biasanya, layar ponsel menyala dan mati saat tombol daya ditekan. Sebaliknya, jika ponsel foldable akan dilipat, layar utama bagian dalam pada ponsel foldable tidak akan aktif saat tombol daya ditekan.

Pada kode awal yang diberikan dalam cuplikan kode berikut, tulis class FoldablePhone yang diwarisi dari class Phone. Class harus berisi hal berikut:

  • Properti yang menunjukkan apakah ponsel dilipat.
  • Perilaku fungsi switchOn() yang berbeda dengan class Phone sehingga hanya mengaktifkan layar saat ponsel tidak dilipat.
  • Metode untuk mengubah status lipat.
class Phone(var isScreenLightOn: Boolean = false){
    fun switchOn() {
        isScreenLightOn = true
    }

    fun switchOff() {
        isScreenLightOn = false
    }

    fun checkPhoneScreenLight() {
        val phoneScreenLight = if (isScreenLightOn) "on" else "off"
        println("The phone screen's light is $phoneScreenLight.")
    }
}

8. Lelang khusus

Biasanya dalam lelang, bidder tertinggi menentukan harga sebuah item. Dalam lelang khusus ini, jika tidak ada bidder untuk sebuah item, item tersebut akan otomatis dijual ke rumah lelang dengan harga minimum.

Pada kode awal yang diberikan dalam cuplikan kode berikut, Anda diberi fungsi auctionPrice() yang menerima jenis Bid? nullable sebagai argumen:

fun main() {
    val winningBid = Bid(5000, "Private Collector")

    println("Item A is sold at ${auctionPrice(winningBid, 2000)}.")
    println("Item B is sold at ${auctionPrice(null, 3000)}.")
}

class Bid(val amount: Int, val bidder: String)

fun auctionPrice(bid: Bid?, minimumPrice: Int): Int {
   // Fill in the code.
}

Lengkapi fungsi auctionPrice() agar program dapat mencetak baris berikut:

Item A is sold at 5000.
Item B is sold at 3000.

9. Kode solusi

Notifikasi seluler

Solusi ini menggunakan pernyataan if/else untuk mencetak pesan ringkasan notifikasi yang sesuai berdasarkan jumlah pesan notifikasi yang diterima:

fun main() {
    val morningNotification = 51
    val eveningNotification = 135

    printNotificationSummary(morningNotification)
    printNotificationSummary(eveningNotification)
}

fun printNotificationSummary(numberOfMessages: Int) {
    if (numberOfMessages < 100) {
        println("You have ${numberOfMessages} notifications.")
    } else {
        println("Your phone is blowing up! You have 99+ notifications.")
    }
}

Harga tiket film

Solusi ini menggunakan ekspresi when untuk menampilkan harga tiket yang sesuai berdasarkan usia penonton bioskop. Solusi ini juga menggunakan ekspresi if/else sederhana untuk salah satu cabang ekspresi when guna menambahkan kondisi tambahan untuk harga tiket standar.

Harga tiket di cabang else menampilkan nilai -1, yang menunjukkan bahwa harga yang ditetapkan untuk cabang else tidak valid. Implementasi yang lebih baik adalah membuat cabang else menampilkan pengecualian. Anda akan mempelajari penanganan pengecualian di unit mendatang.

fun main() {
    val child = 5
    val adult = 28
    val senior = 87

    val isMonday = true

    println("The movie ticket price for a person aged $child is \$${ticketPrice(child, isMonday)}.")
    println("The movie ticket price for a person aged $adult is \$${ticketPrice(adult, isMonday)}.")
    println("The movie ticket price for a person aged $senior is \$${ticketPrice(senior, isMonday)}.")
}

fun ticketPrice(age: Int, isMonday: Boolean): Int {
    return when(age) {
        in 0..12 -> 15
        in 13..60 -> if (isMonday) 25 else 30
        in 61..100 -> 20
        else -> -1
    }
}

Pengonversi suhu

Solusi ini mengharuskan Anda meneruskan fungsi sebagai parameter ke fungsi printFinalTemperature(). Solusi yang paling ringkas meneruskan ekspresi lambda sebagai argumen, menggunakan referensi parameter it sebagai pengganti nama parameter, dan memanfaatkan sintaksis lambda akhir.

fun main() {
        printFinalTemperature(27.0, "Celsius", "Fahrenheit") { 9.0 / 5.0 * it + 32 }
        printFinalTemperature(350.0, "Kelvin", "Celsius") { it - 273.15 }
        printFinalTemperature(10.0, "Fahrenheit", "Kelvin") { 5.0 / 9.0 * (it - 32) + 273.15 }
}

fun printFinalTemperature(
    initialMeasurement: Double,
    initialUnit: String,
    finalUnit: String,
    conversionFormula: (Double) -> Double
) {
    val finalMeasurement = String.format("%.2f", conversionFormula(initialMeasurement)) // two decimal places
    println("$initialMeasurement degrees $initialUnit is $finalMeasurement degrees $finalUnit.")
}

Katalog lagu

Solusi ini berisi class Song dengan konstruktor default yang menerima semua parameter yang diperlukan. Class Song juga memiliki properti isPopular yang menggunakan fungsi pengambil khusus, dan metode yang mencetak deskripsinya sendiri. Anda dapat membuat instance class dalam fungsi main() dan memanggil metodenya untuk menguji apakah implementasinya sudah benar. Anda dapat menggunakan garis bawah saat menulis angka besar seperti nilai 1_000_000 agar lebih mudah dibaca.

fun main() {
    val brunoSong = Song("We Don't Talk About Bruno", "Encanto Cast", 2022, 1_000_000)
    brunoSong.printDescription()
    println(brunoSong.isPopular)
}

class Song(
    val title: String,
    val artist: String,
    val yearPublished: Int,
    val playCount: Int
){
    val isPopular: Boolean
        get() = playCount >= 1000

    fun printDescription() {
        println("$title, performed by $artist, was released in $yearPublished.")
    }
}

Saat Anda memanggil fungsi println() pada metode instance, program dapat mencetak output ini:

We Don't Talk About Bruno, performed by Encanto Cast, was released in 2022.
true

Profil internet

Solusi ini berisi pemeriksaan null di berbagai pernyataan if/else untuk mencetak teks yang berbeda berdasarkan apakah berbagai properti class adalah null:

fun main() {
    val amanda = Person("Amanda", 33, "play tennis", null)
    val atiqah = Person("Atiqah", 28, "climb", amanda)

    amanda.showProfile()
    atiqah.showProfile()
}

class Person(val name: String, val age: Int, val hobby: String?, val referrer: Person?) {
    fun showProfile() {
        println("Name: $name")
        println("Age: $age")
        if(hobby != null) {
            print("Likes to $hobby. ")
        }
        if(referrer != null) {
            print("Has a referrer named ${referrer.name}")
            if(referrer.hobby != null) {
                print(", who likes to ${referrer.hobby}.")
            } else {
                print(".")
            }
        } else {
            print("Doesn't have a referrer.")
        }
        print("\n\n")
    }
}

Ponsel foldable

Agar class Phone menjadi class induk, Anda perlu membuka class tersebut dengan menambahkan kata kunci open sebelum nama class. Untuk mengganti metode switchOn() di class FoldablePhone, Anda perlu membuka metode di class Phone dengan menambahkan kata kunci open sebelum metode.

Solusi ini berisi class FoldablePhone dengan konstruktor default yang berisi argumen default untuk parameter isFolded. Class FoldablePhone juga memiliki dua metode untuk mengubah properti isFolded menjadi nilai true atau false. Class ini juga mengganti metode switchOn() yang diwarisi dari class Phone.

Anda dapat membuat instance class dalam fungsi main() dan memanggil metodenya untuk menguji apakah implementasinya sudah benar.

open class Phone(var isScreenLightOn: Boolean = false){
    open fun switchOn() {
        isScreenLightOn = true
    }

    fun switchOff() {
        isScreenLightOn = false
    }

    fun checkPhoneScreenLight() {
        val phoneScreenLight = if (isScreenLightOn) "on" else "off"
        println("The phone screen's light is $phoneScreenLight.")
    }
}

class FoldablePhone(var isFolded: Boolean = true): Phone() {
    override fun switchOn() {
        if (!isFolded) {
            isScreenLightOn = true
        }
    }

    fun fold() {
        isFolded = true
    }

    fun unfold() {
        isFolded = false
    }
}

fun main() {
    val newFoldablePhone = FoldablePhone()

    newFoldablePhone.switchOn()
    newFoldablePhone.checkPhoneScreenLight()
    newFoldablePhone.unfold()
    newFoldablePhone.switchOn()
    newFoldablePhone.checkPhoneScreenLight()
}

Outputnya adalah sebagai berikut:

The phone screen's light is off.
The phone screen's light is on.

Lelang khusus

Solusi ini menggunakan operator panggilan aman ?. dan operator Elvis ?: untuk menampilkan harga yang benar:

fun main() {
    val winningBid = Bid(5000, "Private Collector")

    println("Item A is sold at ${auctionPrice(winningBid, 2000)}.")
    println("Item B is sold at ${auctionPrice(null, 3000)}.")
}

class Bid(val amount: Int, val bidder: String)

fun auctionPrice(bid: Bid?, minimumPrice: Int): Int {
    return bid?.amount ?: minimumPrice
}

10. Latihan Tambahan

Untuk latihan lain terkait bahasa Kotlin, lihat jalur Dasar-Dasar Kotlin di JetBrains Academy. Untuk membuka topik tertentu, buka peta pengetahuan guna melihat daftar topik yang dibahas dalam jalur.