Tạo lời chúc sinh nhật bằng Kotlin

1. Giới thiệu

Trong lớp học lập trình này, bạn sẽ tạo một chương trình Kotlin ngắn để in lời chúc sinh nhật cùng với một chiếc bánh và một biểu ngữ sinh nhật.

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

  • Nắm được cách mở và chỉnh sửa mã trong https://developer.android.com/training/kotlinplayground, một công cụ lập trình Kotlin dùng trên trình duyệt.
  • Hiểu chương trình "Hello world!" trong lớp học lập trình Viết chương trình Kotlin đầu tiên.
  • Biết cách sử dụng println() để ghi văn bản vào bảng điều khiển (console) của trình soạn thảo mã Kotlin trực tuyến.

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

  • Cách in văn bản phức tạp hơn trong chương trình của bạn.
  • Cách giải toán cơ bản trong Kotlin và lưu trữ kết quả trong các biến để sử dụng sau.
  • Cách tạo một hàm để in nhiều lần cùng một chuỗi.
  • Cách tạo vòng lặp để in đoạn trích văn bản nhiều lần.

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

  • Bạn sẽ tạo một chương trình ngắn mà bạn có thể sử dụng để in lời chúc sinh nhật, hình ảnh một chiếc bánh dựa trên văn bản và một biểu ngữ.

Bạn cần có

  • Một máy tính có kết nối Internet và một trình duyệt web hiện đại, chẳng hạn như trình duyệt Chrome phiên bản mới nhất.

2. Tạo lời chúc sinh nhật bằng Kotlin

Thiết lập mã bắt đầu

  1. Trên trình duyệt, hãy mở https://developer.android.com/training/kotlinplayground. Thao tác này sẽ mở ra một công cụ lập trình Kotlin dùng trên trình duyệt.
  2. Bên trong hàm fun main(), hãy thay thế văn bản "Hello, world!" bằng "Happy Birthday, Rover!".
  3. Bên dưới, vẫn ở trong các dấu ngoặc nhọn, hãy thêm hai dòng khác để in: "You are already 5!""5 is the very best age to celebrate!".

Mã hoàn thiện của bạn sẽ có dạng như sau.

fun main() {
    println("Happy Birthday, Rover!")
    println("You are already 5!")
    println("5 is the very best age to celebrate!")
}
  1. Chạy mã.
  2. Xác minh rằng ngăn đầu ra cho thấy Happy Birthday, Rover! (Chúc mừng sinh nhật Rover!) và phía dưới là You are already 5! (Rover lên 5 tuổi rồi!) và 5 is the very best age to celebrate! (5 là một tuổi thật đẹp để kỷ niệm!)
Happy Birthday, Rover!
You are already 5!
5 is the very best age to celebrate!

Thêm chiếc bánh sinh nhật

Lời chúc sinh nhật cần có một hình ảnh chủ đề sinh nhật. Chẳng hạn như, một chiếc bánh. Bạn có thể thêm một chiếc bánh vào lời chúc sinh nhật bằng cách in thêm các dòng sử dụng chữ cái và ký hiệu trên bàn phím và println().

Tiếp tục từ mã giải pháp ở trên.

  1. Trong mã của bạn, giữa hai câu lệnh println() cho Happy BirthdayYou are already 5, hãy thêm các dòng gồm những câu lệnh in sau đây, như trong đoạn mã dưới đây. Việc này tạo ra một chiếc bánh. Câu lệnh println() cuối cùng không có văn bản giữa các dấu ngoặc kép sẽ in ra một dòng trống.
    println("   ,,,,,   ")
    println("   |||||   ")
    println(" =========")
    println("@@@@@@@@@@@")
    println("{~@~@~@~@~}")
    println("@@@@@@@@@@@")
    println("")

Để giúp người khác hiểu mã của bạn, bạn có thể thêm nhận xét (comment) trước khi in chiếc bánh. Nếu bạn chạy mã, kết quả sẽ không có vẻ gì khác vì các nhận xét chỉ là thông tin dành riêng cho bạn và các nhà phát triển khác, không phải là lệnh cho hệ thống. Một nhận xét trong dòng bắt đầu bằng // rồi đến văn bản, như trong đoạn mã dưới đây.

// This is a comment line
// This is another comment
  1. Thêm một nhận xét trước khi in chiếc bánh: // Let's print a cake!.
  2. Thêm một nhận xét trước khi in dòng trống: // This prints an empty line.

Mã của bạn phải trông giống như đoạn mã dưới đây.

fun main() {
    println("Happy Birthday, Rover!")

    // Let's print a cake!
    println("   ,,,,,   ")
    println("   |||||   ")
    println(" =========")
    println("@@@@@@@@@@@")
    println("{~@~@~@~@~}")
    println("@@@@@@@@@@@")

    // This prints an empty line.
    println("")

    println("You are already 5!")
    println("5 is the very best age to celebrate!")
}
  1. Hãy chạy mã và đầu ra sẽ có dạng như sau.
Happy Birthday, Rover!
   ,,,,,
   |||||
 =========
@@@@@@@@@@@
{~@~@~@~@~}
@@@@@@@@@@@

You are already 5!
5 is the very best age to celebrate!

3. Tạo và sử dụng biến

Lưu trữ tuổi của Rover trong một biến

  1. Trong đoạn mã mà bạn vừa hoàn thành, hãy chú ý đến cách bạn lặp lại cùng một số tuổi hai lần.

Thay vì lặp lại, bạn có thể lưu trữ con số này ở một nơi, dưới dạng biến. Cách này giống như đặt con số của bạn vào hộp rồi đặt tên cho cái hộp chứa con số đó. Sau đó, bạn có thể sử dụng tên biến này mỗi khi bạn cần giá trị đó. Ngoài ra, nếu độ tuổi thay đổi, bạn chỉ cần thay đổi chương trình ở một chỗ. Bằng cách thay đổi biến, giá trị chính xác cho độ tuổi sẽ được in ở bất cứ nơi nào biến được sử dụng.

  1. Trong chương trình của bạn, ở dòng mã đầu tiên trong hàm main(), hãy thêm mã sau đây để tạo biến có tên là age với giá trị là 5, như minh hoạ dưới đây. (Bạn phải đặt dòng này trước các câu lệnh println()).
val age = 5

Dòng này có nghĩa là:

  • val là một từ đặc biệt mà Kotlin sử dụng, được gọi là keyword (từ khoá), cho biết rằng phần phía sau là tên của một biến.
  • age là tên của biến.
  • = làm cho giá trị của age (ở bên trái) trở nên giống với giá trị ở bên phải. Trong toán học, dấu bằng được dùng để xác nhận rằng các giá trị ở mỗi bên là giống nhau. Trong Kotlin, không giống như trong toán học, dấu bằng được dùng để gán giá trị ở bên phải cho biến có tên ở bên trái.

Nhà phát triển sẽ nói như thế này: Dòng này khai báo một biến có tên age mang giá trị được chỉ định là 5.

Để sử dụng một biến bên trong một câu lệnh in, bạn cần bao quanh biến đó bằng một số ký hiệu để hệ thống biết rằng nội dung tiếp theo không phải là văn bản, mà là biến. Thay vì in văn bản, hệ thống cần in giá trị của biến. Bạn thực hiện việc này bằng cách đặt biến bên trong các dấu ngoặc nhọn phía sau ký hiệu đô la, như trong ví dụ dưới đây.

${variable}
  1. Trong mã, hãy thay số 5 trong cả hai câu lệnh in bằng biến age như dưới đây.
println("You are already ${age}!")
println("${age} is the very best age to celebrate!")
  1. Chạy mã và cả hai thông điệp sẽ phải cho thấy cùng một độ tuổi.
  2. Thay đổi giá trị của biến thành giá trị khác. Ví dụ: bạn có thể hiện tuổi của Rover theo ngày thay vì năm. Để làm việc này, hãy nhân tuổi với 365, bỏ qua năm nhuận. Bạn có thể thực hiện phép tính này ngay khi tạo biến, như dưới đây.
val age = 5 * 365
  1. Chạy lại mã và để ý rằng cả hai lời chúc nay đã hiện độ tuổi tính theo ngày.
Happy Birthday, Rover!
   ,,,,,
   |||||
 =========
@@@@@@@@@@@
{~@~@~@~@~}
@@@@@@@@@@@

You are already 1825!
1825 is the very best age to celebrate!
  1. [Không bắt buộc] Thay đổi văn bản của thông điệp in để phù hợp hơn với cách tính độ tuổi theo ngày. Chẳng hạn như, thay đổi lời chúc thành:
You are already 1825 days old!
1825 days old is the very best age to celebrate!

Đặt văn bản vào một biến

Không chỉ con số, bạn còn có thể đưa cả văn bản vào biến.

  1. Bên dưới biến age, hãy thêm biến tên là name cho tên của người có sinh nhật rồi đặt giá trị cho biến đó thành "Rover".
val name = "Rover"
  1. Thay thế tên Rover trong lời chúc sinh nhật bằng biến, như dưới đây.
println("Happy Birthday, ${name}!")

Bạn cũng có thể có nhiều hơn một biến trong một câu lệnh in.

  1. Thêm Rover vào lời chúc độ tuổi bằng cách sử dụng biến name như dưới đây.
println("You are already ${age} days old, ${name}!")

Mã đã hoàn tất của bạn sẽ trông giống như thế này.

fun main() {

    val age = 5 * 365
    val name = "Rover"

    println("Happy Birthday, ${name}!")

    // Let's print a cake!
    println("   ,,,,,   ")
    println("   |||||   ")
    println(" =========")
    println("@@@@@@@@@@@")
    println("{~@~@~@~@~}")
    println("@@@@@@@@@@@")

    // This prints an empty line.
    println("")

    println("You are already ${age} days old, ${name}!")
    println("${age} days old is the very best age to celebrate!")
}

Xin chúc mừng! Giờ đây, bạn có thể tạo thông điệp bằng văn bản, hình ảnh tạo bằng ký hiệu, sử dụng biến để lưu trữ số và văn bản, cũng như sử dụng biến để in văn bản.

4. In biểu ngữ sinh nhật có đường viền

Trong nhiệm vụ này, bạn sẽ tạo một biểu ngữ sinh nhật, sau đó tìm hiểu cách đơn giản hoá mã bằng cách sử dụng các kỹ thuật để lặp lại và sử dụng lại mã, cũng như tìm hiểu tác dụng của việc này.

Tạo biểu ngữ sinh nhật ban đầu

  1. Trong https://developer.android.com/training/kotlinplayground, hãy đặt con trỏ vào vị trí bất kỳ bên trong mã.
  2. Nhấp chuột phải để mở trình đơn rồi chọn Select All (Chọn tất cả).
  3. Nhấn phím Backspace hoặc phím Delete để xoá tất cả mã.
  4. Sao chép và dán mã dưới đây vào trình chỉnh sửa.
fun main() {
    println("=======================")
    println("Happy Birthday, Jhansi!")
    println("=======================")
}
  1. Chạy chương trình của bạn để xem biểu ngữ in trên Console (Bảng điều khiển).
=======================
Happy Birthday, Jhansi!
=======================

Tạo một hàm để in đường viền

Mã bạn vừa dán và chạy là một hàm tên là main() chứa 3 câu lệnh in. Khi bạn nhấn nút Run (Chạy), hệ thống sẽ thực thi hàm và toàn bộ mã bên trong.

Chương trình Kotlin của bạn luôn phải có một hàm main(). Ngoài ra, bạn có thể tạo và sử dụng các hàm của riêng mình. Giống như các biến giúp bạn tránh được việc trùng lặp công việc, các hàm có thể giúp bạn tránh việc viết nhiều lần cùng một mã. Trong mã của bạn, các câu lệnh in dành cho phần đầu và cuối biểu ngữ giống hệt nhau. Hãy tạo và sử dụng một hàm để in các đường viền đó.

  1. Trong trình chỉnh sửa, bên dưới hàm main(), hãy chèn một dòng trống để bạn có thêm chỗ làm việc. Các dòng trống sẽ được hệ thống bỏ qua, cho nên bạn có thể chèn dòng trống vào bất cứ nơi nào có ích để sắp xếp mã.
  2. Tạo một hàm. Bắt đầu bằng từ khoá fun, theo sau là tên printBorder, một cặp dấu ngoặc đơn () và một cặp dấu ngoặc nhọn {}, như dưới đây.
fun printBorder() {}

Vài lời về việc đặt tên cho hàm.

  • Hãy để ý rằng tên hàm printBorder bắt đầu bằng một chữ viết thường và là một động từ. Tên hàm hầu như luôn bắt đầu bằng một chữ cái viết thường và là một động từ. Tên hàm cũng nên mô tả chức năng của hàm đó. Chẳng hạn như: print() hoặc printBorder().
  • Ngoài ra, hãy lưu ý rằng từ thứ hai trong tên hàm bắt đầu bằng chữ hoa. Kiểu tên này được gọi là "kiểu lạc đà" (camel-case) và giúp tên dễ đọc hơn. Ví dụ về một số tên khác drawReallyCoolFancyBorderprintBirthdayMessage.
  1. Đặt dấu đóng ngoặc nhọn } của hàm printBorder trên một dòng mới và thêm một dòng trống giữa hai dấu ngoặc nhọn, để có khoảng trống cho việc thêm mã. Việc đặt dấu đóng ngoặc nhọn } trên dòng riêng sẽ giúp bạn dễ dàng biết được hàm này kết thúc ở đâu.
  2. Bên trong hàm main(), hãy sao chép câu lệnh in của đường viền rồi dán vào giữa các dấu ngoặc nhọn của hàm printBorder().

Hàm printBorder() đã hoàn tất sẽ có dạng như sau.

fun printBorder() {
    println("=======================")
}

Để sử dụng hoặc gọi hàm, hãy sử dụng tên của hàm, với cặp dấu ngoặc đơn. Xin lưu ý rằng đây là cách bạn đã sử dụng println()! Do đó, để sử dụng hàm printBorder, hãy gọi printBorder() ở bất kỳ nơi nào trong mã khi cần đến.

  1. Trong hàm main(), hãy thay thế các dòng mã in đường viền bằng cách sử dụng println() với các lệnh gọi đến hàm printBorder(). Mã hoàn thiện của bạn sẽ có dạng như sau.
fun main() {
    printBorder()
    println("Happy Birthday, Jhansi!")
    printBorder()
}

fun printBorder() {
    println("=======================")
}
  1. Chạy mã của bạn để đảm bảo tất cả đều hoạt động như trước.

Lưu ý rằng việc thay đổi mã để chương trình làm việc tốt hơn hoặc dễ dàng hơn mà không thay đổi đầu ra được gọi là "refactoring" (tái cấu trúc).

Lặp lại mẫu hoa văn đường viền

Hãy nhìn vào đường viền, toàn bộ thực sự là cùng một ký hiệu. Vì vậy, thay vì nói:

"In chuỗi gồm 23 ký hiệu này"

bạn có thể nói:

"In 1 ký hiệu này 23 lần".

Trong phần mã, bạn thực hiện việc này bằng cách sử dụng câu lệnh repeat().

  1. Trong hàm printBorder(), hãy dùng câu lệnh repeat() để in dấu bằng 23 lần.
  2. Thay vì sử dụng println(), hãy sử dụng print() để bạn không chuyển sang dòng mới sau khi in từng "=".

Sau đây là mã. Bạn hiện có một lệnh đơn để in dấu bằng và để lặp lại 23 lần lệnh đó, hãy sử dụng câu lệnh repeat().

fun printBorder() {
    repeat(23) {
        print("=")
    }
}
  • Câu lệnh repeat() bắt đầu bằng từ repeat, theo sau là (). Loại câu lệnh này được gọi là "vòng lặp" ("loop") vì bạn lặp đi lặp lại hoặc lặp lại theo vòng nhiều lần cùng một mã. Sau này bạn sẽ tìm hiểu các cách tạo vòng lặp khác.
  • Trong ngoặc đơn, () là số lần lặp lại,
  • tiếp theo là các dấu ngoặc nhọn {},
  • và bên trong các dấu ngoặc nhọn {} là mã cần lặp lại.
  1. Trong hàm printBorder(), sau dấu đóng ngoặc nhọn } của câu lệnh repeat(), tức là sau khi bạn in xong đường viền, hãy thêm câu lệnh println() để in một dòng mới.

Mã của bạn bây giờ có dạng như sau.

fun printBorder() {
    repeat(23) {
        print("=")
    }
    println()
}

Mã trong hàm main() không thay đổi và toàn bộ chương trình sẽ có dạng như sau.

fun main() {
    printBorder()
    println("Happy Birthday, Jhansi!")
    printBorder()
}

fun printBorder() {
    repeat(23) {
        print("=")
    }
    println()
}
  1. Chạy mã. Nội dung xuất sẽ giống như trước, nhưng lần này, bạn đã có thể tạo đường viền bằng cách chỉ định ký hiệu "=" chỉ một lần!
=======================
Happy Birthday, Jhansi!
=======================

Dùng đối số để thay đổi đường viền

Nếu bạn muốn tạo đường viền sử dụng nhiều loại ký hiệu, chẳng hạn như các ký hiệu dưới đây thì sao?

%%%%%%%%%%%%%%%%%%%%%%%

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

Bạn có thể định nghĩa hàm cho từng ký hiệu riêng biệt. Tuy nhiên, có một cách hiệu quả hơn để làm việc này. Bạn có thể sử dụng lại hàm mà bạn vừa viết và tăng tính linh hoạt của hàm để dùng được nhiều loại ký hiệu.

Thú vị là bạn có thể cung cấp đầu vào cho các hàm bằng cách sử dụng đối số. Bạn từng gặp khái niệm này trong một lớp học lập trình trước đây, khi làm quen với main(). Ở bước này, bạn sẽ thêm một đối số vào hàm printBorder() để hàm này có thể in mọi mẫu đường viền mà bạn cung cấp.

  1. Trong main(), ở trên cùng, hãy tạo biến có tên border dành cho mẫu hoa văn đường viền. Biến này sẽ giữ văn bản cần lặp lại để tạo thành đường viền.
val border = "%"
  1. Bây giờ, hãy truyền biến border đó vào làm đối số cho cả hai lệnh gọi hàm printBorder(). Bạn thực hiện việc này bằng cách đặt border bên trong các dấu ngoặc đơn (), giống như khi bạn cung cấp văn bản để println() in.

Hàm main() của bạn phải trông giống như đoạn mã dưới đây.

fun main() {
    val border = "%"
    printBorder(border)
    println("Happy Birthday, Jhansi!")
    printBorder(border)
}

Hàm printBorder() sẽ nhận giá trị của border này làm dữ liệu đầu vào và tìm cách in ra đường viền đầy đủ.

  1. Chạy mã của bạn. Mã của bạn không thực thi, thay vào đó, bạn sẽ thấy các biểu tượng lỗi bên cạnh mã. f97a62ffa05c6291.png
  2. Hãy nhìn vào bảng điều khiển đầu ra, ở đó có một thông báo lỗi.

Như trước đó, thông báo chỉ ra vị trí của lỗi và gợi ý cho bạn về lỗi. Phần quan trọng là: Too many arguments for public fun printBorder(). Bạn đang gọi hàm printBorder() và truyền một đường viền dưới dạng giá trị nhập. Tuy nhiên, định nghĩa hàm printBorder() hiện không chấp nhận giá trị nhập nào.

  1. Hãy sửa lỗi này bằng cách thêm một đối số cho đường viền vào định nghĩa hàm printBorder(). Xem dòng mã đầu tiên như dưới đây.
fun printBorder(border: String) {
    repeat(23) {
        print("=")
    }
    println()
}
  • Hãy lưu ý rằng tên của đối số là border.
  • Theo sau tên đó là một dấu hai chấm :
  • và từ String, là nội dung mô tả về loại hoặc kiểu của đối số.

String là một đoạn văn bản được tạo thành từ các ký tự và nằm giữa các dấu ngoặc kép. Bạn có thể xem đó như những chiếc hạt xâu trên một chuỗi để tạo thành một chiếc vòng cổ, chẳng hạn như các ký tự xếp hàng để tạo thành từ và văn bản. Việc chỉ định đối số phải là String sẽ giúp hệ thống thực thi việc đối số phải là văn bản và không phải là loại khác, chẳng hạn như số.

  1. Chạy mã. Hàm printBorder() nay chấp nhận đường viền String làm giá trị đầu vào. Và mã trong main() gọi printBorder(border) với border là đối số. Mã của bạn sẽ chạy mà không có lỗi.
  2. Xem kết quả của chương trình trong Console(Bảng điều khiển) và kết quả đó vẫn cho thấy chính đường viền trước đây?
=======================
Happy Birthday, Jhansi!
=======================

Đây không phải là hành vi bạn mong muốn! Bạn đã cố tạo đường viền có ký hiệu "%" nhưng chương trình này vẫn in đường viền dùng ký hiệu "=". Trong các bước tiếp theo, bạn sẽ tìm hiểu nguyên nhân dẫn đến việc này.

  1. Trong trình chỉnh sửa, hãy chú ý dấu chấm than màu xám. Biểu tượng này biểu thị một cảnh báo (warning). Cảnh báo là về những vấn đề trong mã mà bạn cần chú ý đến nhưng không ngăn việc chạy mã. 5757cbe505f34d82.png
  2. Di chuột qua dấu chấm than và một thông báo sẽ xuất hiện. Nội dung là "Parameter 'border' is never used." Cảnh báo này giải thích sự cố xảy ra với đầu ra. Bạn đang chuyển một chuỗi mới dành cho đường viền đến hàm này, nhưng bạn hiện không sử dụng chuỗi này để in.
  3. Thay đổi hàm printBorder() để sử dụng giá trị đã truyền vào border thay vì in dấu "=". Việc này cũng giống hệt như khi border là một biến mà bạn đã xác định bên trong hàm!
fun printBorder(border: String) {
    repeat(23) {
        print(border)
    }
    println()
}
  1. Chạy lại mã. Kết quả đầu ra sẽ có dạng như sau.
%%%%%%%%%%%%%%%%%%%%%%%
Happy Birthday, Jhansi!
%%%%%%%%%%%%%%%%%%%%%%%

Tuyệt vời, bạn đã khắc phục được vấn đề! Sau đây là mã đã hoàn tất.

fun main() {
    val border = "%"
    printBorder(border)
    println("Happy Birthday, Jhansi!")
    printBorder(border)
}

fun printBorder(border: String) {
    repeat(23) {
        print(border)
    }
    println()
}

Bạn đã làm cho hàm printBorder() linh hoạt hơn rất nhiều mà không cần thêm nhiều mã khác. Giờ đây, bạn có thể in đường viền bằng nhiều loại ký hiệu, chỉ cần một lần thay đổi nhỏ.

  1. [Không bắt buộc] Bằng cách chỉ thay đổi một dòng mã trong hàm main(), bạn sẽ in biểu ngữ sinh nhật như này bằng cách nào?
***********************
Happy Birthday, Jhansi!
***********************
:::::::::::::::::::::::
Happy Birthday, Jhansi!
:::::::::::::::::::::::

Sửa đổi một hàm để có hai đối số

Nếu bạn muốn sử dụng một mẫu hoa văn khác dài hơn 1 ký tự thì sao, chẳng hạn "'-._,-'". Bạn sẽ không lặp lại mẫu hoa văn này 23 lần vì như vậy sẽ quá dài. Bạn có thể lặp lại thao tác này khoảng 4 lần. Để hoàn thành việc này, bạn có thể thay đổi số lần lặp lại trong câu lệnh repeat() của printBorder(). Tuy nhiên, bạn có thể làm tốt hơn!

Bạn có thể khai báo một đường viền bắt mắt hơn dựa trên hai điều sau:

  • Mẫu hoa văn để lặp lại (việc mà bạn đã thực hiện)
  • Số lần mà bạn muốn lặp lại mẫu hoa văn

Bạn có thể tạo các biến cho từng yếu tố, mẫu hoa văn và số lần lặp lại, sau đó truyền cả hai thông tin vào hàm printBorder().

  1. Trong main(), hãy thay đổi đường viền thành mẫu hoa văn "'-._,-'".
val border = "`-._,-'"
  1. Chạy mã và để ý thấy mẫu hoa văn hiện quá dài.
  2. Trong main(), bên dưới phần định nghĩa border, hãy tạo một biến mới tên là timesToRepeat cho số lần lặp lại. Đặt giá trị biến đó thành 4.
val timesToRepeat = 4
  1. Trong main(), khi gọi printBorder(), hãy thêm số lần lặp lại làm đối số thứ hai. Phân tách hai đối số bằng dấu phẩy.
printBorder(border, timesToRepeat)

Bây giờ, hàm main() sẽ có dạng như sau:

fun main() {
    val border = "`-._,-'"
    val timesToRepeat = 4
    printBorder(border, timesToRepeat)
    println("Happy Birthday, Jhansi!")
    printBorder(border, timesToRepeat)
}

Cũng như trước đây, mã này sẽ trả về một lỗi vì bạn có nhiều đối số gọi printBorder() hơn so với định nghĩa printBorder().

  1. Hãy sửa printBorder() để cũng chấp nhận cả số lần lặp lại làm đầu vào. Thêm dấu phẩy sau đối số, theo sau là đối số bổ sung: timesToRepeat: Int. Dòng đầu tiên trong định nghĩa hàm của bạn giờ đây sẽ có dạng như sau.
fun printBorder(border: String, timesToRepeat: Int) {

Lưu ý:

  • Dấu phẩy sẽ phân tách hai đối số.
  • timesToRepeat là tên của đối số,
  • theo sau là ký hiệu dấu hai chấm ":"
  • và kiểu: Int. timesToRepeat là một số, do đó, thay vì tạo kiểu String, bạn cần phải tạo kiểu Int (viết tắt của integer, tức là một số nguyên).
  1. Bên trong printBorder(), hãy thay đổi repeat để sử dụng đối số timesToRepeat (thay cho số 23). Mã printBorder() của bạn sẽ có dạng như sau.
fun printBorder(border: String, timesToRepeat: Int) {
    repeat(timesToRepeat) {
        print(border)
    }
    println()
}
  1. Chạy mã. Và kết quả đầu ra có dạng như sau.
`-._,-'`-._,-'`-._,-'`-._,-'
Happy Birthday, Jhansi!
`-._,-'`-._,-'`-._,-'`-._,-'
  1. Để hoàn thiện kết quả đầu ra này, hãy chèn hai dấu cách vào đầu thông điệp Happy Birthday (Chúc mừng sinh nhật). Khi đó, kết quả đầu ra của bạn sẽ có dạng như sau.
`-._,-'`-._,-'`-._,-'`-._,-'
  Happy Birthday, Jhansi!
`-._,-'`-._,-'`-._,-'`-._,-'

Đây là mã hoàn thiện dành cho biểu ngữ của bạn:

fun main() {
    val border = "`-._,-'"
    val timesToRepeat = 4
    printBorder(border, timesToRepeat)
    println("  Happy Birthday, Jhansi!")
    printBorder(border, timesToRepeat)
}

fun printBorder(border: String, timesToRepeat: Int) {
    repeat(timesToRepeat) {
        print(border)
    }
    println()
}

Xin chúc mừng! Với các hàm, đối số, biến và vòng lặp, bạn đã học được các khối xây dựng cơ bản sử dụng trong hầu hết chương trình.

Hãy nghỉ ngơi, sau đó xử lý công việc tiếp theo dưới đây để tạo thêm các hàm và vòng lặp. Bạn sẽ có đủ năng lực để xây dựng một chiếc bánh khổng lồ với số nến phù hợp chỉ bằng một vài dòng lập trình.

5. Tạo một chiếc bánh với nhiều lớp và nến

Trong nhiệm vụ này, bạn sẽ nâng cấp mã bánh sinh nhật để luôn có kích thước phù hợp với số lượng nến cho mọi độ tuổi.

  • Bạn sẽ tạo tổng cộng 3 hàm để vẽ một chiếc bánh nhiều lớp (layer) với nhiều nến (candle).
  • Bạn sẽ dùng repeat() bên trong một repeat() khác, tạo nên một khái niệm được gọi là "vòng lặp lồng nhau" (nested loop).
  • Cách xây dựng mã tăng dần này cũng là cách xây dựng mà bạn có thể áp dụng với mọi chương trình, bắt đầu bằng một bức tranh tổng thể rồi thêm các chi tiết vào. Phương pháp này được gọi là "phát triển từ trên xuống" (top-down development).
  • Hướng dẫn này sẽ không nêu rõ chi tiết về phương pháp này. Bạn có thể tham khảo mã hoàn thiện nếu gặp khó khăn.

Sau đây là hình ảnh của chiếc bánh mà bạn sẽ cho ra lò:

 ,,,,,,,,,,,,,,,,,,,,,,,,
 ||||||||||||||||||||||||
==========================
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@

Và sau đây là hướng dẫn.

Tạo hàm main()

  1. Đặt lại mã của bạn trong trình soạn thảo (editor) thành chương trình Hello, world!.
  2. Bạn có thể xoá đối số thành main() vì bạn sẽ không sử dụng đối số đó.
  3. Trong main(), hãy tạo biến age rồi đặt giá trị 24 cho biến đó.
  4. Trong main(), hãy tạo biến thứ hai layers rồi đặt giá trị 5 cho biến đó.
  5. Trong main(), hãy gọi một hàm printCakeCandles() rồi truyền age vào. Việc này sẽ khiến bạn gặp lỗi vì bạn chưa tạo hàm đó.
  6. Tương tự, hãy gọi một hàm printCakeTop() rồi cũng truyền age vào.
  7. Cuối cùng, hãy gọi một hàm printCakeBottom() rồi truyền age vào, cũng như số layers.
  8. Để loại bỏ các lỗi, hãy nhận xét về 3 lệnh gọi hàm này bằng cách thêm // vào đầu mỗi dòng, như dưới đây. Kỹ thuật này cho phép bạn tạo bản nháp mã mà không kích hoạt lỗi.
  9. Hãy chạy chương trình của bạn. Chương trình này sẽ không gặp lỗi nào và không làm gì cả.

Hàm main() của bạn phải trông giống như đoạn mã dưới đây.

fun main() {
    val age = 24
    val layers = 5
    // printCakeCandles(age)
    // printCakeTop(age)
    // printCakeBottom(age, layers)
}

Tạo printCakeTop()

Hàm printCakeTop() để in phần trên của chiếc bánh, một dòng dấu bằng, gần giống với hàm printBorder() mà bạn đã tạo trước đó trong lớp học lập trình này.

==========================
  1. Bên dưới hàm main(), hãy thêm một dòng trống, sau đó tạo một hàm, printCakeTop() có một đối số age là kiểu Int.
  2. Bên trong, hãy dùng câu lệnh repeat() để in một dấu bằng age lần cộng thêm 2. Hai dấu bằng là để nến không bị "rơi" khỏi cạnh chiếc bánh.
  3. Ở dưới cùng, khi repeat() hoàn tất, hãy in một dòng trống.
  4. Trong main(), hãy xoá hai ký hiệu // khỏi đầu dòng mã dành cho printCakeTop() vì hàm này nay đã tồn tại.
printCakeTop(age)

Sau đây là hàm của bạn khi hoàn tất.

fun printCakeTop(age: Int) {
    repeat(age + 2) {
        print("=")
    }
    println()
}
  1. Chạy mã để xem phần trên của chiếc bánh.

Tạo printCakeCandles()

Mỗi cây nến được tạo thành từ hai ký hiệu: dấu phẩy (,) tạo hình ngọn lửa và đường kẻ dọc (|) tạo hình thân nến.

,,,,,,,,,,,,,,,,,,,,,,,,

||||||||||||||||||||||||

Để hoàn thành việc này trong một hàm, hãy đặt hai câu lệnh repeat() (một câu lệnh cho ngọn lửa và một câu lệnh cho phần thân nến) vào hàm của bạn.

  1. Bên dưới hàm main() và hàm printCakeTop(), hãy tạo một hàm mới, printCakeCandles() có một đối số (age) kiểu Int.
  2. Bên trong, hãy sử dụng câu lệnh repeat() để in một dấu phẩy , tạo hình ngọn lửa.
  3. Lặp lại việc này age lần.
  4. Ở cuối, hãy in một dòng trống.
  5. Thêm câu lệnh in để in một khoảng trống để đặt nến.
  6. Bên dưới, hãy lặp lại các bước tạo câu lệnh repeat() thứ hai để in phần thân nến với đường kẻ dọc |
  7. Ở cuối, hãy in một dòng mới, sử dụng println().
  8. Trong main(), hãy xoá hai ký hiệu // khỏi đầu dòng mã dành cho printCakeCandles().
printCakeCandles(age)
  1. Chạy mã để xem phần trên của chiếc bánh và những cây nến

Giải pháp:

fun printCakeCandles(age: Int) {
    print(" ")
    repeat(age) {
        print(",")
    }
    println() // Print an empty line

    print(" ") // Print the inset of the candles on the cake
    repeat(age) {
        print("|")
    }
    println()
}

Tạo printCakeBottom()

Trong hàm này, bạn vẽ phần dưới cùng của chiếc bánh với chiều rộng bằng age + 2 và bạn vẽ phần đó theo chiều cao của một số lớp nhất định.

@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
  • Tức là hàm của bạn cần 2 đối số, một đối số cho chiều rộng (age) và một đối số cho chiều cao (layers).
  • Để in phần dưới cùng của chiếc bánh, trước tiên hãy lặp lại ký hiệu "at" @ age + 2 để in một lớp bánh. Sau đó, bạn lặp lại thao tác in một lớp bánh layers lần.

Vẽ ký hiệu at age+2 lần để tạo một lớp bánh

  1. Bên dưới các hàm hiện có, hãy tạo một hàm printCakeBottom() có hai đối số agelayers cùng thuộc kiểu Int.
  2. Bên trong hàm này, hãy sử dụng câu lệnh repeat() để in một lớp bánh gồm các ký hiệu "at" @ age + 2 lần. Hãy hoàn tất bằng cách in một dòng trống, như minh hoạ dưới đây.
fun printCakeBottom(age: Int, layers: Int) {
    repeat(age + 2) {
        print("@")
    }
    println()
}
  1. Chạy mã để xác minh rằng mã đó in một dòng dưới cùng của chiếc bánh.
 ,,,,,,,,,,,,,,,,,,,,,,,,
 ||||||||||||||||||||||||
==========================
@@@@@@@@@@@@@@@@@@@@@@@@@@

Các câu lệnh repeat() lồng nhau

Để in nhiều lớp giống hệt nhau của chiếc bánh, bạn có thể nói:

Đối với lớp 1, hãy lặp lại ký hiệu 12 lần: @@@@@@@@@@@

Đối với lớp 2, hãy lặp lại ký hiệu 12 lần: @@@@@@@@@@@

Đối với lớp 3, hãy lặp lại ký hiệu 12 lần: @@@@@@@@@@@

Hoặc bạn có thể nói ngắn gọn hơn như sau:

Lặp lại trong cả 3 lớp:

Repeat the symbol 12 times.

@@@@@@@@@@@@

@@@@@@@@@@@@

@@@@@@@@@@@@

Bây giờ, bạn có thể dễ dàng làm một số việc qua các câu lệnh repeat(). Bạn có thể đặt một câu lệnh repeat() bên trong một câu lệnh repeat() khác. Do đó, bạn có thể tạo câu lệnh repeat() bên trong câu lệnh repeat() để in ký hiệu ra theo một số lần nhất định cho một số lớp nhất định.

Sử dụng repeat() lồng nhau để in các lớp bánh

  1. Đặt câu lệnh repeat() thứ hai xung quanh toàn bộ mã bên trong hàm. Lặp lại vòng lặp này layers lần.
  2. Trong main(), chỉ xoá hai // khỏi dòng mã dành cho printCakeBottom().
printCakeBottom(age, layers)
  1. Chạy mã để xem toàn bộ chiếc bánh.

Giải pháp dành cho printCakeBottom().

fun printCakeBottom(age: Int, layers: Int) {
    repeat(layers) {
        repeat(age + 2) {
            print("@")
        }
        println()
    }
}

Xin chúc mừng! Bạn vừa hoàn thành một chương trình khá phức tạp, với một số hàm và một câu lệnh repeat lồng nhau. Chiếc bánh của bạn sẽ luôn có số lượng nến phù hợp!

Kết quả đầu ra hoàn thiện của chương trình của bạn sẽ như sau:

 ,,,,,,,,,,,,,,,,,,,,,,,,
 ||||||||||||||||||||||||
==========================
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@

6. Mã giải pháp

fun main() {
    val age = 24
    val layers = 5
    printCakeCandles(age)
    printCakeTop(age)
    printCakeBottom(age, layers)
}

fun printCakeCandles(age: Int) {
    print (" ")
    repeat(age) {
          print(",")
    }
    println() // Print an empty line

    print(" ") // Print the inset of the candles on the cake
    repeat(age) {
        print("|")
    }
    println()
}

fun printCakeTop(age: Int) {
    repeat(age + 2) {
        print("=")
    }
    println()
}

fun printCakeBottom(age: Int, layers: Int) {
    repeat(layers) {
        repeat(age + 2) {
            print("@")
        }
        println()
    }
}

7. Khắc phục sự cố

Nếu công cụ lập trình Kotlin trên trình duyệt không thực thi mã của bạn hoặc báo một lỗi ngoài dự kiến không liên quan đến mã của bạn, bạn có thể thử các cách sau:

  • Tải lại trang bằng cách sử dụng Shift+Reload (Shift+Tải lại).
  • Đợi một lát, sau đó thử lại.

8. Tóm tắt

  • Sử dụng ${} để bao quanh các biến và phép tính trong phần văn bản của các câu lệnh in. Ví dụ: ${age}, trong đó age là một biến.
  • Tạo một biến bằng từ khoá val và tên. Sau khi đặt, bạn không thể thay đổi giá trị này. Gán một giá trị cho biến bằng cách sử dụng dấu bằng. Ví dụ về các giá trị là văn bản và số.
  • String là văn bản có dấu ngoặc kép bao quanh, chẳng hạn như "Hello".
  • Int là một số nguyên dương hoặc âm, chẳng hạn như 0, 23 hoặc -1024.
  • Bạn có thể truyền một hoặc nhiều đối số vào một hàm để hàm đó dùng được, ví dụ: fun printCakeBottom(age:Int, layers:Int) {}
  • Sử dụng câu lệnh repeat() {} để lặp lại một tập hợp lệnh theo một số lần. Ví dụ: repeat (23) { print("%") } hoặc repeat (layers) { print("@@@@@@@@@@") }
  • Vòng lặp (loop) là một lệnh lặp lại nhiều lần. Câu lệnh repeat() là một ví dụ về vòng lặp.
  • Bạn có thể lồng các vòng lặp, tức là đặt vòng lặp trong vòng lặp. Ví dụ: bạn có thể tạo câu lệnh repeat() trong câu lệnh repeat() để in một ký hiệu một số lần cho một số hàng, giống như cách bạn làm đối với các lớp bánh.

Tóm tắt về việc sử dụng các đối số của hàm: Để sử dụng các đối số của hàm, bạn cần thực hiện 3 việc sau:

  • Thêm đối số và kiểu vào định nghĩa hàm: printBorder(border: String)
  • Sử dụng đối số bên trong hàm: println(border)
  • Cung cấp đối số khi bạn gọi hàm: printBorder(border)

9. Tìm hiểu thêm

Sau đây là tài liệu chính thức về các khái niệm Kotlin mà bạn đã học trong lớp học lập trình này.