Thêm hành vi có điều kiện trong Kotlin

1. Trước khi bắt đầu

Trong lớp học lập trình Kotlin này, bạn sẽ tạo một trò chơi xúc xắc khác tên là Lucky Dice Roll (Xúc xắc may mắn) để cố gắng tung ra một con số may mắn. Chương trình của bạn sẽ thiết lập một con số may mắn và tung xúc xắc. Sau đó, bạn đối chiếu kết quả tung xúc xắc với con số may mắn và xuất ra thông báo thích hợp. Để thực hiện điều này, bạn sẽ tìm hiểu cách so sánh các giá trị và đưa ra quyết định trong chương trình Kotlin.

Để giúp bạn tập trung vào các khái niệm lập trình mà không phải lo lắng về giao diện người dùng của ứng dụng, bạn sẽ sử dụng công cụ lập trình Kotlin dựa trên trình duyệt và xuất kết quả sang bảng điều khiển.

Điều kiện tiên quyết

  • Biết cách mở, chỉnh sửa và chạy mã trong https://developer.android.com/training/kotlinplayground
  • Có thể tạo và chạy một chương trình Kotlin sử dụng các biến, hàm có đối số, lớp có phương thức và xuất kết quả ra bảng điều khiển.

Kiến thức bạn sẽ học được

  • Cách sử dụng câu lệnh ifelse.
  • Cách so sánh các giá trị bằng các toán tử như lớn hơn (>), nhỏ hơn (<) và bằng (==).
  • Cách sử dụng câu lệnh when để chọn một tuỳ chọn dựa trên giá trị đã cho.
  • Loại dữ liệu Boolean là gì, cách sử dụng giá trị truefalse để đưa ra quyết định.

Sản phẩm bạn sẽ tạo ra

  • Trò chơi xúc xắc may mắn Lucky Dice Roll được lập trình bằng Kotlin, cho phép bạn chỉ định một con số may mắn. Người chơi sẽ chiến thắng nếu họ tung ra được con số may mắn.

Bạn cần có

  • Một máy tính có kết nối Internet.

2. Đưa ra quyết định trong mã

Chương trình Lucky Dice Roller cần xác định xem người dùng có tung ra con số may mắn hay không và có nhận được lời chúc mừng hay không, nếu không thì họ sẽ nhận thông báo mời thử lại.

Là nhà phát triển ứng dụng, bạn sẽ cần đưa ra quyết định về cách ứng dụng hoạt động và tạo ra các kết quả khác nhau cho người dùng.

Nếu đang tạo ứng dụng mua sắm, bạn có thể cho hiện màn hình dựa trên chế độ giao hàng mà người dùng chọn. Đối với trò chơi giải đố, bạn sẽ cho hiện màn hình tuỳ thuộc vào việc câu trả lời của người chơi có chính xác hay không. Tuỳ thuộc vào ứng dụng, có thể có nhiều kết quả mà bạn cần đưa vào trong mã.

Trong chương trình Lucky Dice Roller, ứng dụng sẽ xử lý những trường hợp như:

  • If: Nếu kết quả tung xúc xắc là con số may mắn thì cho hiện lời chúc mừng!
  • Else if: Nếu kết quả tung xúc xắc không phải là con số may mắn thì cho hiện thông báo mời thử lại.

Để thêm logic này vào mã của bạn, hãy sử dụng các từ khoá Kotlin đặc biệt như ifelsewhen.

Hãy cùng xem xét một số ví dụ.

Sử dụng câu lệnh if để thiết lập một điều kiện được thoả mãn

  1. Hãy xem xét mã dưới đây. Bạn có thể đoán được kết quả xuất ra là gì không?
fun main() {
   val num = 5
   if (num > 4) {
       println("The variable is greater than 4")
   }
}
  1. Sao chép rồi dán mã vào trình chỉnh sửa chương trình Kotlin, chạy chương trình này để quan sát kết quả.
The variable is greater than 4

Quá trình đưa ra quyết định cho chương trình này là:

  1. Tạo biến num rồi thiết lập biến đó thành 5.
  2. Nếu đúng là num lớn hơn 4 thì xuất "The variable is greater than 4".
  3. Trong tất cả các trường hợp khác thì không cần làm gì cả.

Trong ví dụ trên, num được thiết lập thành 5. Câu lệnh if so sánh xem biến này có lớn hơn 4 hay không. Vì đúng là biến này lớn hơn 4 nên hệ thống sẽ thực thi lệnh trong dấu ngoặc nhọn và xuất ra thông báo đó.

Bạn sẽ nhận thấy định dạng chung cho câu lệnh if:

  • Bắt đầu bằng từ khoá if.
  • Theo sau là hai dấu ngoặc đơn (). Bên trong ngoặc đơn sẽ có điều kiện. Điều kiện là bất cứ tuyên bố nào có thể là true (đúng) hoặc false (sai). Ví dụ: số này có lớn hơn số kia hay không.
  • Theo sau là hai dấu ngoặc nhọn {}. Bên trong dấu ngoặc nhọn, bạn đặt mã để thực thi nếu điều kiện là true.
if (condition-is-true) {
    execute-this-code
}

Sử dụng câu lệnh if để thiết lập một điều kiện không được thoả mãn

  1. Thay đổi giá trị của num thành 3, như minh hoạ dưới đây. Bạn mong đợi điều gì xảy ra khi chạy đoạn mã này?
fun main() {
    val num = 3
    if (num > 4) {
        println("The variable is greater than 4")
    }
}
  1. Sao chép rồi dán mã vào trình chỉnh sửa chương trình Kotlin và chạy chương trình để quan sát kết quả trống.

Với num được thiết lập thành 3, không có kết quả nào xuất ra vì giá trị của num nhỏ hơn 4. Vì vậy, điều kiện num lớn hơn 4 là false và mã trong dấu ngoặc nhọn không được thực thi và không có kết quả nào xuất ra.

Sử dụng else để tạo phương án thay thế cho các điều kiện không đạt

Thay vì không làm gì cả, bạn có thể cung cấp cho người dùng một phương án thay thế khi không thoả mãn một điều kiện. Tương tự như với ngôn ngữ thông thường, bạn có thể thực hiện việc đó bằng cách sử dụng câu lệnh else.

  1. Thêm câu lệnh else để xuất thông báo khi num không lớn hơn 4, như minh hoạ dưới đây. Bạn mong đợi điều gì xảy ra khi chạy đoạn mã này?
fun main() {
    val num = 3
    if (num > 4) {
        println("The variable is greater than 4")
    } else {
        println("The variable is less than 4")
    }
}
  1. Sao chép rồi dán mã vào trình chỉnh sửa chương trình Kotlin, chạy chương trình này để quan sát kết quả.
The variable is less than 4
  1. Xin lưu ý khi num có giá trị là 3, chương trình sẽ xuất thông báo "The variable is less than 4" liên kết với câu lệnh elsenum không lớn hơn 4.
  2. Thay đổi num thành 5 và chạy lại chương trình. Bây giờ, đúng là num lớn hơn 4 và chương trình xuất ra "The variable is greater than 4".
  3. Thay đổi num thành 4 và chạy chương trình. Bây giờ, 4 không lớn hơn 4 và chương trình xuất ra "The variable is less than 4".

Mặc dù "The variable is less than 4" là kết quả đầu ra chính xác cho các điều kiện mà bạn thiết lập trong mã, nhưng câu lệnh được xuất ra đó không chính xác vì 4 không nhỏ hơn 4. Việc bạn có thể làm là thêm một điều kiện khác để kiểm tra khả năng thứ ba, liệu num có phải là 4 không và xuất câu lệnh chính xác khi điều kiện đó đúng.

Sử dụng tổ hợp else if để thêm các điều kiện thay thế

Bạn có thể có nhiều điều kiện. Ví dụ: sau đây là cách bạn có thể giải quyết mọi tình huống có thể xảy ra cho num:

  • If : Nếu num lớn hơn 4, hãy xuất "The variable is greater than 4".
  • Else if: Nếu num bằng 4, hãy xuất "The variable is equal to 4".
  • Else: Ngược lại, hãy xuất "The variable is less than 4".

Đây được gọi là các trường hợp trong câu lệnh if-else. Có 3 trường hợp được liệt kê.

Đoạn mã mới có dạng như sau:

fun main() {
    val num = 4
    if (num > 4) {
        println("The variable is greater than 4")
    } else if (num == 4) {
        println("The variable is equal to 4")
    } else {
        println("The variable is less than 4")
    }
}

Hãy lưu ý những thay đổi sau:

  • Giá trị của num hiện được thiết lập thành 4 để bạn có thể kiểm thử điều kiện mới.
  • Giữa câu lệnh ifelse ban đầu là câu lệnh else if mới cho trường hợp num bằng 4.
  1. Sao chép và dán mã trên vào trình chỉnh sửa chương trình Kotlin, chạy chương trình này để quan sát kết quả.
The variable is equal to 4
  1. Bạn có thể thử thay đổi giá trị của num và xem giá trị này ảnh hưởng đến kết quả xuất ra như thế nào. Thay đổi num thành 2 và 6 để bạn có thể thấy mỗi điều kiện đạt giá trị true.

Luồng điều khiển

Khi bạn xem các câu lệnh if-else ở trên, mã sẽ thực thi, hay nói cách khác là tiến vào luồng (flow), do các điều kiện kiểm soát. Vì vậy, cách bạn hướng dẫn quá trình thực thi thông qua các điều kiện này được gọi là "luồng kiểm soát" ("control flow") của chương trình.

  • Giả sử kết quả tung xúc xắc num là 3. Chương trình kiểm tra điều kiện đầu tiên (num > 4). Điều kiện này sai, vì vậy chương trình kiểm tra điều kiện tiếp theo (num == 4) và điều kiện này cũng sai. Sau đó, chương trình sẽ thực thi mã của câu lệnh khác. Đây là phương án cuối cùng.
  • Nếu kết quả tung xúc xắc là 6, điều kiện đầu tiên (num > 4) là đúng. Chương trình sẽ in thông báo "The variable is greater than 4". Vì điều kiện này đúng nên chương trình không cần kiểm tra các điều kiện còn lại và hoàn thành câu lệnh if-else (nếu-còn không).
  • Sử dụng tổ hợp else + if để thêm các điều kiện thay thế

3. Tạo trò chơi Lucky Dice Roll (Xúc xắc may mắn)

Trong phần này, bằng cách áp dụng kiến thức học được trong nhiệm vụ trước, bạn sẽ cập nhật chương trình tung xúc xắc để kiểm tra xem liệu bạn có tung ra con số may mắn được thiết lập trước hay không. Nếu tung ra đúng số đó, bạn sẽ thắng!

Thiết lập mã khởi động

Bạn bắt đầu tạo ứng dụng Lucky Dice Roller (Xúc xắc may mắn) bằng mã tương tự với mã giải pháp của chương trình Dice Roller (Tung xúc xắc) dùng Kotlin trước đó. Bạn có thể chỉnh sửa hàm main() trong mã trước đó cho phù hợp hoặc bạn có thể sao chép và dán mã bên dưới để bắt đầu.

fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    println("Your ${myFirstDice.numSides} sided dice rolled ${rollResult}!")
}

class Dice (val numSides: Int) {

    fun roll(): Int {
        return (1..numSides).random()
    }
}

Kiểm tra xem xúc xắc có lăn ra con số may mắn hay không

Trước tiên, hãy tạo một số may mắn, sau đó so sánh kết quả tung xúc xắc với số đó.

  1. Trong main(), hãy xoá câu lệnh println().
  2. Trong main(), hãy thêm val tên là luckyNumber rồi thiết lập thành 4. Mã của bạn sẽ có dạng như thế này.
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4
}
  1. Bên dưới, hãy thêm câu lệnh if có điều kiện bên trong dấu ngoặc đơn () để kiểm tra xem rollResult có bằng (==) với luckyNumber hay không. Hãy chừa ra chỗ trống giữa dấu ngoặc nhọn {} để bạn có thể thêm mã.
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4
    if (rollResult == luckyNumber) {

    }
}
  1. Bên trong dấu ngoặc nhọn {}, hãy thêm câu lệnh println để xuất "You win!"
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    if (rollResult == luckyNumber) {
        println("You win!")
    }
}
  1. Chạy chương trình. Có thể bạn sẽ phải chạy thử vài lần mới ra được số may mắn và nhìn thấy thông báo chiến thắng trong kết quả!
You win!

Phản hồi khi không tung được số may mắn

Nếu chương trình không phản hồi gì khi người dùng không thắng, có thể họ sẽ cho rằng chương trình bị hỏng. Chương trình nên có phản hồi cho mọi thao tác của người dùng. Đối với chương trình Lucky Dice Roller, bạn có thể cho người dùng biết họ không giành chiến thắng bằng cách sử dụng câu lệnh else.

  1. Thêm câu lệnh else để xuất "You didn't win, try again!".
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    if (rollResult == luckyNumber) {
        println("You win!")
    } else {
        println("You didn't win, try again!")
    }
}
  1. Chạy chương trình và bất kể kết quả thế nào, người dùng sẽ luôn nhận được thông báo.

Đến đây, người dùng biết mình có thắng hay không nhưng không biết lý do. Hãy luôn cung cấp cho người dùng thông tin để họ hiểu được kết quả của hành động! Hãy tưởng tượng chương trình của bạn là hồ sơ vay vốn. "Bạn không được phê duyệt vì có điểm xếp hạng tín dụng thấp", đồng thời cung cấp thêm thông tin thay vì chỉ nói "Rất tiếc, bạn không thể vay tiền, hãy thử lại!" Đối với chương trình Lucky Dice Roller, bạn có thể cung cấp cho người dùng một thông báo riêng cho mỗi lần tung xúc xắc nếu họ thua. Hãy dùng nhiều câu lệnh else if để thực hiện.

  1. Thêm câu lệnh else if để xuất một thông báo riêng cho mỗi lần tung. Hãy tham khảo định dạng bạn đã tìm hiểu trong nhiệm vụ trước (nếu cần).
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    if (rollResult == luckyNumber) {
        println("You win!")
    } else if (rollResult == 1) {
        println("So sorry! You rolled a 1. Try again!")
    } else if (rollResult == 2) {
        println("Sadly, you rolled a 2. Try again!")
    } else if (rollResult == 3) {
        println("Unfortunately, you rolled a 3. Try again!")
    } else if (rollResult == 5) {
        println("Don't cry! You rolled a 5. Try again!")
    } else {
        println("Apologies! You rolled a 6. Try again!")
    }
}

Trong mã trên, bạn

  • Kiểm tra xem rollResult có phải là luckyNumber hay không.
  • Nếu rollResultluckyNumber, xuất thông báo chiến thắng.
  • Nếu không, kiểm tra xem rollResult có phải là 1 hay không. Nếu phải, xuất thông báo mời người dùng thử lại.
  • Nếu không, kiểm tra xem rollResult có phải là 2 hay không. Nếu phải, xuất một thông báo khác cũng mời người dùng thử lại.
  • Nếu không, tiếp tục kiểm tra đến số 5.
  • Nếu số đó không nằm trong khoảng từ 1 đến 5, thì khả năng duy nhất còn lại là 6, do đó, bạn không cần phải thử nghiệm với else if, bạn có thể chọn khả năng cuối cùng bằng câu lệnh else.

Việc có nhiều trường hợp else if là rất phổ biến nên Kotlin có cách viết khác đơn giản hơn.

4. Sử dụng câu lệnh when

Việc thử nghiệm nhiều khả năng (hoặc nhiều trường hợp) là rất phổ biến trong lập trình. Đôi khi, danh sách khả năng có thể sẽ rất dài. Ví dụ: nếu bạn tung xúc xắc có 12 mặt, thì bạn sẽ có 11 câu lệnh else if giữa trường hợp thành công và else cuối cùng. Để dễ dàng viết và đọc các loại câu lệnh này cũng như tránh được lỗi, Kotlin cung cấp câu lệnh when.

Bạn sẽ thay đổi chương trình để sử dụng câu lệnh when. Câu lệnh when bắt đầu bằng từ khoá when, theo sau là dấu ngoặc đơn (). Bên trong dấu ngoặc đơn sẽ có giá trị cần kiểm tra. Theo sau là dấu ngoặc nhọn {} để mã thực thi cho nhiều điều kiện.

  1. Trong main() của chương trình, hãy chọn mã từ câu lệnh if đầu tiên đến dấu ngoặc nhọn } đóng câu lệnh else cuối cùng rồi xoá phần mã đó.
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4
}
  1. Trong main(), bên dưới phần khai báo luckyNumber, hãy tạo một câu lệnh when. Vì when của bạn cần đối chiếu với kết quả tung xúc xắc nên hãy đặt rollResult ở giữa dấu ngoặc đơn (). Thêm dấu ngoặc nhọn {} và để chừa một ít khoảng trống, như minh hoạ dưới đây.
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {

    }
}

Như đã làm lúc trước, đầu tiên, hãy kiểm tra xem rollResult có giống với luckyNumber hay không.

  1. Bên trong dấu ngoặc nhọn {} của câu lệnh when, hãy thêm một câu lệnh để đối chiếu rollResult với luckyNumber và nếu hai giá trị giống nhau thì xuất thông báo chiến thắng. Câu lệnh có dạng như sau:
luckyNumber -> println("You win!")

Mã này có nghĩa là:

  • Trước tiên, bạn cần thiết lập giá trị cần so sánh với rollResult. Đó là luckyNumber.
  • Thêm một mũi tên (->) ở phía sau.
  • Sau đó, hãy thêm hành động để thực hiện nếu có kết quả trùng khớp.

Hãy đọc nội dung này là "Nếu rollResultluckyNumber, xuất thông báo "You win!"".

main() của bạn có dạng như thế này.

fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {
        luckyNumber -> println("You win!")
    }
}
  1. Sử dụng cùng một mẫu để thêm dòng mã và thông báo cho các khả năng từ 1 đến 6, ngoại trừ 4, như minh hoạ bên dưới. Hàm main() hoàn chỉnh có dạng như sau.
fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {
        luckyNumber -> println("You won!")
        1 -> println("So sorry! You rolled a 1. Try again!")
        2 -> println("Sadly, you rolled a 2. Try again!")
        3 -> println("Unfortunately, you rolled a 3. Try again!")
        5 -> println("Don't cry! You rolled a 5. Try again!")
        6 -> println("Apologies! You rolled a 6. Try again!")
    }
}
  1. Chạy chương trình. Kết quả xuất ra vẫn như vậy nhưng mã của bạn nay gọn gàng và dễ đọc hơn nhiều.

Xin chúc mừng! Bạn đã học được hai cách xuất thông báo theo điều kiện. Đây là một công cụ mạnh mẽ để viết các chương trình thú vị!

5. Mã giải pháp

fun main() {
    val myFirstDice = Dice(6)
    val rollResult = myFirstDice.roll()
    val luckyNumber = 4

    when (rollResult) {
        luckyNumber -> println("You won!")
        1 -> println("So sorry! You rolled a 1. Try again!")
        2 -> println("Sadly, you rolled a 2. Try again!")
        3 -> println("Unfortunately, you rolled a 3. Try again!")
        5 -> println("Don't cry! You rolled a 5. Try again!")
        6 -> println("Apologies! You rolled a 6. Try again!")
   }
}

class Dice(val numSides: Int) {
    fun roll(): Int {
        return (1..numSides).random()
    }
}

6. Tóm tắt

  • Sử dụng câu lệnh if để thiết lập điều kiện thực thi một số lệnh. Ví dụ: nếu người dùng tung được con số may mắn, hãy xuất thông điệp chiến thắng.
  • Loại dữ liệu Boolean có giá trị truefalse, và có thể dùng để đưa ra quyết định.
  • So sánh các giá trị bằng cách sử dụng các toán tử như lớn hơn (>), nhỏ hơn (<) và bằng (==).
  • Sử dụng một chuỗi câu lệnh else if để thiết lập nhiều điều kiện. Ví dụ: xuất thông báo riêng cho mỗi lần tung xúc xắc.
  • Sử dụng câu lệnh else ở cuối chuỗi điều kiện để phát hiện mọi trường hợp chưa có mã rõ ràng. Nếu bạn viết mã cho các trường hợp của xúc xắc 6 mặt, câu lệnh else sẽ tìm ra số 7 và số 8 cho xúc xắc 8 mặt.
  • Sử dụng câu lệnh when như một hình thức ngắn gọn để thực thi mã dựa trên việc so sánh một giá trị.

Hình thức chung của câu lệnh if-else:

if (condition-is-true) {
    execute-this-code
} else if (condition-is-true) {
    execute-this-code
} else {
    execute-this-code
}

Câu lệnh when:

when (variable) {
    matches-value -> execute-this-code
    matches-value -> execute-this-code
    ...
}

7. Tìm hiểu thêm

8. Tự thực hành

Thực hiện những việc sau:

  1. Thay đổi myFirstDice để có 8 mặt rồi chạy mã. Điều gì sẽ xảy ra?

Gợi ý: Khi bạn tăng số mặt xúc xắc, câu lệnh when của bạn không bao gồm mọi trường hợp nữa. Do đó, đối với các trường hợp chưa được phát hiện, sẽ không có kết quả nào xuất ra.

  1. Chỉnh sửa câu lệnh when để tính đến cả 8 mặt. Bạn có thể thực hiện việc này bằng cách thêm trường hợp cho các số mới. Thử thách: Thay vì thêm trường hợp mới cho từng số, hãy sử dụng câu lệnh else để tìm ra mọi trường hợp chưa được nêu rõ ràng.

Gợi ý: Bạn có thể thêm các trường hợp khác để tính đến nhiều mặt hơn. Đó là một cách hữu ích để thực hiện việc này nếu bạn muốn xuất thông điệp riêng cho mỗi số mà người dùng có thể tung trúng. Bạn cũng có thể sử dụng câu lệnh else và xuất ra cùng một thông báo cho các mặt lớn hơn 6 bên trong mã hiện tại.

  1. Thay đổi myFirstDice để chỉ có 4 mặt. Điều gì sẽ xảy ra?

Gợi ý: Việc thay đổi số cạnh của xúc xắc thành số lượng ít hơn phạm vi mà câu lệnh when đề cập không gây ảnh hưởng đáng kể, vì tất cả trường hợp đều đã được đề cập.