Membuat Aplikasi Pengubah Angka ke Kata dengan Kotlin

Kali ini kita akan membuat aplikasi sederhana yang saya sebut dengan Pengubah Angka Ke Kata. Aplikasi ini akan mengubah sebuah angka menjadi kata berbahasa Indonesia. Misalnya kita memasukkan angka 235 maka aplikasi akan mengeluarkan “Dua Ratus Tiga Puluh Lima”.

Sebelum kalian memulai tutorial ini saya sarankan kalian mempelajari konsep berikut:

Membuat Project

Pada tutorial ini saya menggunakan IntelliJ IDEA 2022.1 (Community Edition). Sebelum menulis kode kalian buat proyek baru di IDEA dengan opsi seperti ini:

InputIsi
Nameangka_ke_kata
LanguagesPilih Kotlin
Build SystemPilih IntelliJ

Untuk JDK kalian pilih JDK yang ada di system kalian. Saya menggunakan JDK 17. Kemudian klik Create.

Ilustrasi Membuat Project

Kemudian klik kanan pada src > main > kotlin kemudian pilih New > Kotlin Class/File

Ilustrasi Folder

Isi nama file dengan AngkaKeKata dan kemudian pada pilihan di bawahnya pilih File. Lalu tekan Enter.

Ilustrasi Membuat File

Maka akan file bernama AngkaKeKata.kt akan terbuat.

Meminta Input Pengguna

Program kita pertama-pertama harus meminta input ke pengguna. Proses yang kita lakukan seperti ini:

  1. Mencetak kalimat perintah
  2. Meminta input dari pengguna menggunakan readln
  3. Mengubah input pengguna menjadi Int
  4. Mengubah Int/angka menjadi kata
  5. Mencetak kata hasil

Isi AngkaKeKata.kt dengan kode berikut:

fun main() {
   println("Tolong masukkan angka yang akan diubah menjadi kata!")
   val teks = readln()
   val angka = teks.toInt()
   val kata = angkaKeKata(angka)
   println(kata)
}

fun angkaKeKata(angka: Int): String {
   return "Tidak bisa"
}

Kemudian kalian bisa menjalankan kode dengan mengeklik tombol Run di sebelah kiri fungsi main.

Menjalankan Kode Pertama Kali

Angka apa pun yang kita masukkan aplikasi pasti akan mencetak Tidak Bisa.

Tolong masukkan angka yang akan diubah menjadi kata!
12
Tidak bisa

Selanjutnya kalian bisa menjalankan aplikasi dengan mengeklik tombol Run yang berada di Toolbar.

Menjalankan Kode Kedua dan Seterusnya

Angka Dasar (0-11)

Pertama kita mulai dengan kasus yang paling sederhana, kita hanya perlu menggunakan kondisional. Ubah fungsi angkaKeKata menjadi seperti ini:

fun angkaKeKata(angka: Int): String {
   return when (angka) {
      0 -> "Nol"
      1 -> "Satu"
      2 -> "Dua"
      3 -> "Tiga"
      4 -> "Empat"
      5 -> "Lima"
      6 -> "Enam"
      7 -> "Tujuh"
      8 -> "Delapan"
      9 -> "Sembilan"
      10 -> "Sepuluh"
      11 -> "Sebelas"
      else -> "Tidak bisa diubah"
   }
}

Sederhana sekali bukan?. Lalu kenapa kita menambahkan cabang Else?. Pada kode di atas kita menggunakan When sebagai ekspresi untuk menghasilkan nilai, maka Kotlin memaksa kita menambahkan klausa Else agar When bisa menghasilkan nilai pada kondisi apa pun.

Kita coba lagi menjalankan kodenya. Kita coba dengan angka 7.

Tolong masukkan angka yang akan diubah menjadi kata!
7
Tujuh

Angka Belasan (12-19)

Pada kasus ini kita perlu melakukan proses seperti berikut:

  1. Mencari satuan dari angka, caranya dengan mengurangi angka dengan 10
  2. Mengubah satuan menjadi kata
  3. Menambah “Belas” ke hasil

Tambahkan kode berikut tepat sebelum cabang Else pada When:

1
2
3
4
in 12 until 20 -> {
   val satuan = angka - 10
   "${angkaKeKata(satuan)} Belas"
}

Nilai String pada akhir blok kode menjadi nilai yang dihasilkan When yaitu kode baris ke 3.

Kita coba untuk mengubah angka 19. Hasilnya:

Tolong masukkan angka yang akan diubah menjadi kata!
19
Sembilan Belas

Angka Puluhan (20-99)

Pada kasus ini kita perlu melakukan proses seperti berikut:

  1. Mencari puluhan dari angka, dengan cara membagi angka dengan 10 kemudian membulatkannya ke bawah
  2. Mencari satuan dari angka, dengan cara mencari sisa pembagian (modulus) angka dengan 10.
    Misalkan angka 23. Maka puluhannya 2 dan satuannya 3.
  3. Hasilnya adalah puluhan + " Puluh " + satuan
  4. Jika satuannya 0, maka satuan tidak perlu ditambahkan ke hasil

Tambahkan kode berikut tepat sebelum cabang When Else:

in 20 until 100 -> {
   val puluhan = floor(angka / 10.0).toInt()
   val satuan = angka % 10
   var result = "${angkaKeKata(puluhan)} Puluh"
   if (satuan > 0)
      result += " ${angkaKeKata(satuan)}"

   result
}

Jika terjadi error pada floor maka arahkan cursor ke floor kemudian klik Import.

Visualisasi Import Floor

Lalu pilih pilihan paling atas sendiri.

Fungsi floor digunakan untuk membulatkan angka ke bawah dan menghasilkan angka bertipe Double. Fungsi floor membutuhkan angka Double sehingga pada pembagian salah satu operannya adalah Double (10.0). Fungsi toInt digunakan untuk mengubah Double menjadi Int agar bisa digunakan sebagai argumen fungsi angkaKeKata.

Kita coba angka 57. Hasilnya seperti ini:

Tolong masukkan angka yang akan diubah menjadi kata!
57
Lima Puluh Tujuh

Angka Ratusan (100-999)

Pada kasus ini kita perlu melakukan proses seperti berikut:

  1. Mencari ratusan dari angka, dengan cara membagi angka dengan 100 kemudian membulatkannya ke bawah
  2. Mencari sisa dari angka, dengan cara mencari sisa pembagian angka dengan 100.
    Misalkan angka 235. Maka ratusannya 2 dan sisanya 35.
  3. Jika ratusannya 1 maka hasilnya adalah “Seratus”, selain itu hasilnya adalah ratusan + " Ratus"
  4. Jika sisa lebih dari 0, maka hasilnya ditambah sisa yang diubah menjadi kata

Tambahkan kode berikut tepat sebelum cabang When Else:

in 100 until 1_000 -> {
   val ratusan = floor(angka / 100.0).toInt()
   val sisa = angka % 100
   var result = if (ratusan == 1) "Seratus" else "${angkaKeKata(ratusan)} Ratus"
   if (sisa > 0 )
      result += " ${angkaKeKata(sisa)}"

   result
}

Kita coba dengan angka 734. Hasilnya:

Tolong masukkan angka yang akan diubah menjadi kata!
734
Tujuh Ratus Tiga Puluh Empat

Angka Ribuan (1.000-999.999)

Pada kasus ini kita perlu melakukan proses seperti berikut:

  1. Mencari ribuan dari angka, dengan cara membagi angka dengan 1.000 kemudian membulatkannya ke bawah
  2. Mencari sisa dari angka, dengan cara mencari sisa pembagian angka dengan 1.000.
    Misalkan angka 23.578. 23 adalah ribuan dan 578 adalah sisanya.
  3. Jika ribuannya adalah 1, hasilnya adalah “Seribu”. Selain itu hasilnya adalah ribuan + " Ribu"
  4. Jika sisa lebih dari 0, maka hasilnya ditambah sisa yang diubah menjadi kata

Tambahkan kode berikut tepat sebelum cabang When Else:

in 1_000 until 1_000_000 -> {
   val ribuan = floor(angka / 1_000.0).toInt()
   val sisa = angka % 1_000
   var result = if (ribuan == 1) "Seribu" else "${angkaKeKata(ribuan)} Ribu"
   if (sisa > 0)
      result += " ${angkaKeKata(sisa)}"

   result
}

Kita coba dengan angka 5194. Hasilnya:

Tolong masukkan angka yang akan diubah menjadi kata!
5194
Lima Ribu Seratus Sembilan Puluh Empa

Merefractor Kode

Aplikasi yang kita buat sudah berjalan lancar dan sudah sesuai dengan keinginan kita. Sekarang kodenya seperti ini:

import kotlin.math.floor

fun main() {
    println("Tolong masukkan angka yang akan diubah menjadi kata!")
    val teks = readln()
    val angka = teks.toInt()
    val kata = angkaKeKata(angka)
    println(kata)
}

fun angkaKeKata(angka: Int): String {
    return when (angka) {
        0 -> "Nol"
        1 -> "Satu"
        2 -> "Dua"
        3 -> "Tiga"
        4 -> "Empat"
        5 -> "Lima"
        6 -> "Enam"
        7 -> "Tujuh"
        8 -> "Delapan"
        9 -> "Sembilan"
        10 -> "Sepuluh"
        11 -> "Sebelas"
        in 12 until 20 -> {
            val satuan = angka - 10
            "${angkaKeKata(satuan)} Belas"
        }
        in 20 until 100 -> {
            val puluhan = floor(angka / 10.0).toInt()
            val satuan = angka % 10
            var result = "${angkaKeKata(puluhan)} Puluh"
            if (satuan > 0)
                result += " ${angkaKeKata(satuan)}"

            result
        }
        in 100 until 1_000 -> {
            val ratusan = floor(angka / 100.0).toInt()
            val sisa = angka % 100
            var result = if (ratusan == 1) "Seratus" else "${angkaKeKata(ratusan)} Ratus"
            if (sisa > 0)
                result += " ${angkaKeKata(sisa)}"

            result
        }
        in 1_000 until 1_000_000 -> {
            val ribuan = floor(angka / 1_000.0).toInt()
            val sisa = angka % 1_000
            var result = if (ribuan == 1) "Seribu" else "${angkaKeKata(ribuan)} Ribu"
            if (sisa > 0)
                result += " ${angkaKeKata(sisa)}"

            result
        }
        else -> "Tidak bisa diubah"
    }
}

Namun, perhatikan kode secara seksama maka akan terlihat beberapa kode yang terlihat sangat mirip. Kode untuk mengubah angka ratusan dan ribuan terlihat mirip.

Agar kode lebih ringkas, kita dapat membuat fungsi baru bernama ubahAngkaKelipatan. Fungsi ini akan kita taruh di dalam fungsi angkaKeKata.

fun angkaKeKata(angka: Int): String {
   fun ubahAngkaKelipatan(pembagi: Int, kataKelipatan1: String, suffiks: String): String {
      val kelipatan = floor(angka / pembagi.toDouble()).toInt()
      val sisa = angka % pembagi
      var result = if (kelipatan == 1) kataKelipatan1 else "${angkaKeKata(kelipatan)} $suffiks"
      if (sisa > 0)
         result += " ${angkaKeKata(sisa)}"

      return result
   }
   // ...
}

Angka 100, 1000 kita representasikan dengan parameter pembagi. Teks Seratus dan Seribu kita representasikan dengan parameter kataKelipatan1. Ratus dan Ribu kita representasikan dengan parameter suffiks. Variabel ratusan dan ribuan kita representasikan dengan variabel kelipatan.

Mengapa fungsi ubahAngkaKelipatan kita masukkan ke dalam fungsi angkaKeKata?. Karena pada fungsi ubahAngkaKelipatan kita perlu mengakses variabel angka dan agar fungsi ini tidak bisa dipanggil dari luar fungsi angkaKeKata.

Kode untuk kasus puluhan, ratusan dan ribuan perlu kita ubah menjadi seperti ini:

in 20 until 100 -> ubahAngkaKelipatan(10, "", "Puluh")
in 100 until 1_000 -> ubahAngkaKelipatan(100, "Seratus", "Ratus")
in 1_000 until 1_000_000 -> ubahAngkaKelipatan(1_000, "Seribu", "Ribu")

Pada kasus puluhan, kita juga menggunakan menggunakan ubahAngkaKelipatan karena proses pada kasus puluhan sama dengan proses pada kasus ratusan dan ribuan. Bedanya pada kasus puluhan, puluhan/kelipatannya tidak mungkin bernilai 1 karena kasus puluhan hanya terjadi pada angka 20 sampai 99. Oleh karena itu, pada kasus puluhan kataKelipatan1 kita kosongkan.

Kode bisa kalian coba lagi dan hasilnya akan tetap sama seperti tadi.

Angka Jutaan dan Milyaran

Pada kasus ini, proses yang kita lakukan mirip dengan kasus pada angka ribuan. Kita bisa gunakan fungsi ubahAngkaKelipatan pada kasus ini. Namun, pada terdapat sedikit perbedaan. 1.000.000 dibaca Satu Juta bukan Sejuta.

Jadi, bagaimana kita mengatasi ini?. Jadi kita membuat kataKelipatan1 menjadi Nullable dan hanya digunakan saat tidak null. Kita perlu mengubah fungsi ubahAngkaKelipatan menjadi seperti ini:

fun ubahAngkaKelipatan(pembagi: Int, kataKelipatan1: String?, suffiks: String): String {
   val kelipatan = floor(angka / pembagi.toDouble()).toInt()
   val sisa = angka % pembagi
   var result = if (kelipatan == 1 && kataKelipatan1 != null) kataKelipatan1
      else "${angkaKeKata(kelipatan)} $suffiks"
   if (sisa > 0)
      result += " ${angkaKeKata(sisa)}"

   return result
}

Ubah cabang Else pada When menjadi seperti berikut:

in 1_000_000 until 1_000_000_000 -> ubahAngkaKelipatan(1_000_000, null, "Juta")
else -> ubahAngkaKelipatan(1_000_000_000, null, "Milyar")

Untuk kode Else kita gunakan untuk Milyar karena Int hanya bisa menampung angka sampai 2 milyar.

Kita bisa coba 2147483647. Hasilnya:

Tolong masukkan angka yang akan diubah menjadi kata!
2147483647
Dua Milyar Seratus Empat Puluh Tujuh Juta Empat Ratus Delapan Puluh Tiga Ribu Enam Ratus Empat Puluh Tujuh

Angka tersebut merupakan angka maksimal yang bisa ditampung oleh Int.

Kode Akhir

Kode akhirnya seperti ini:

import kotlin.math.floor

fun main() {
    println("Tolong masukkan angka yang akan diubah menjadi kata!")
    val teks = readln()
    val angka = teks.toInt()
    val kata = angkaKeKata(angka)
    println(kata)
}

fun angkaKeKata(angka: Int): String {
    fun ubahAngkaKelipatan(pembagi: Int, kataKelipatan1: String?, suffiks: String): String {
        val kelipatan = floor(angka / pembagi.toDouble()).toInt()
        val sisa = angka % pembagi
        var result = if (kelipatan == 1 && kataKelipatan1 != null) kataKelipatan1
        else "${angkaKeKata(kelipatan)} $suffiks"
        if (sisa > 0)
            result += " ${angkaKeKata(sisa)}"

        return result
    }
    return when (angka) {
        0 -> "Nol"
        1 -> "Satu"
        2 -> "Dua"
        3 -> "Tiga"
        4 -> "Empat"
        5 -> "Lima"
        6 -> "Enam"
        7 -> "Tujuh"
        8 -> "Delapan"
        9 -> "Sembilan"
        10 -> "Sepuluh"
        11 -> "Sebelas"
        in 12 until 20 -> {
            val satuan = angka - 10
            "${angkaKeKata(satuan)} Belas"
        }
        in 20 until 100 -> ubahAngkaKelipatan(10, "", "Puluh")
        in 100 until 1_000 -> ubahAngkaKelipatan(100, "Seratus", "Ratus")
        in 1_000 until 1_000_000 -> ubahAngkaKelipatan(1_000, "Seribu", "Ribu")
        in 1_000_000 until 1_000_000_000 -> ubahAngkaKelipatan(1_000_000, null, "Juta")
        else -> ubahAngkaKelipatan(1_000_000_000, null, "Milyar")
    }
}

Akhir Kata

Pada tutorial ini kalian telah belajar banyak sekali konsep dalam bahasa Kotlin.