[Game Maker Adventure] Chương 011: Method – Phương Thức

Method giống như những cỗ máy chuyên làm những việc lặp đi lặp lại.

Tóm tắt chương trước

Bạn và Kurobo tiến sâu vào phế tích nhưng bất ngờ bị chặn lại bởi một cánh cửa to lớn.

Thật may, nhờ tài trí của mình, bạn đã vượt qua thử thách.

Bạn không biết có thứ gì đang chờ đợi sắp tới.

Những nguy hiểm, bóng tối và phần thưởng đang chờ đợi.

Kiến thức chương này

  • method (phương thức) giúp chúng ta sử dụng lại code một cách dễ dàng.
  • method có thể return lại dữ liệu hoặc không.
  • Việc khi nào dùng return, khi nào dùng input, khi nào không dùng gì cả, tất cả tuỳ vào sự sáng tạo của bạn.
  • method có thể được đặt ở bất kì đâu nhưng ưu tiên đặt ở vị trí khiến code dễ đọc nhất có thể.
  • method gọi lại chính nó được gọi là recursion (đệ qui).

 

Cốt truyện

“Cánh cửa đó khá thú vị nhỉ.”

“Thời của Kurobo gọi đó là Games đó.”

“G… Games? Trên cái cửa á?”

“Chủ nhân nghĩ đó là cái cửa á?”

“…”

Method (Phương Thức/Cách Thức)

Ở những chương trước, ta đã sớm được làm quen với khái niệm method, chẳng hạn: WriteLine(), ReadLine(), ToInt32()…, bây giờ hãy quay lại nghiên cứu chúng sâu hơn một chút nhé.

Hãy tưởng tượng ta cần giải bài toán tính tổng của căn bậc hai của hai số

Trước hết, ta cần viết chương trình tính căn bậc hai của một số X bất kì. Ý tưởng của chương trình như sau:

  1. Khởi tạo một số Y = X/2.
  2. Sau đó so sánh Y*Y với X.
  3. Nếu kết quả nhỏ hơn thì Y += Y/2.
  4. Nếu kết quả lớn hơn thì Y -= Y/2.
  5. Sau đó lại so sánh Y*Y với X và tiếp tục vòng lặp cho tới khi Y*Y xấp xỉ X.

Viết lại đoạn code:

Console.WriteLine("Square Root Machine");
Console.WriteLine("Please Input Your Number:");

double x = Convert.ToDouble(Console.ReadLine());
double y = x/2;
double precision = x/1000;

while (y * y - x > precision || x - y * y > precision)
{
    if (y * y > x)
    {
        y -= y / 2;
    }
    else
    {
        y += y / 2;
    }
    Console.WriteLine(y);
}
Console.WriteLine("-----------------");
Console.WriteLine("Square Root of " + x + " is: " + y);

Đoạn code tham khảo về cách tính căn bậc 2 của một số. Cách tính thực tế phức tạp hơn rất nhiều nhưng đây là ý tưởng chính của nó.

Nhưng đoạn code trên mới chỉ tính được căn bậc hai của 1 số. Bài toán yêu cầu ta tính cho hai số, vậy là phải viết lại đoạn code trên 2 lần cho 2 input? Nghe có vẻ không hợp lí cho lắm nhỉ.

Giờ bài toán sửa yêu cầu tính cho 5 số thì… càng có vẻ không ổn cho lắm!?

Đây là lúc mà method (Phương Thức) toả sáng.

Trong C#, Method (Phương Thức) thỉnh thoảng còn được gọi là Function (Hàm).

Kurobo

Thay vì phải mất công viết lại, hãy tạo ra một cỗ máy và khiến nó thực hiện điều đó cho chúng ta, mỗi lần cần tính toán thì ta chỉ việc lấy nó ra sử dụng.

Method có bản chất tương tự như vậy.

Method là một phương pháp thực hiện một thứ gì đó, giống như một cỗ máy. Máy móc được tạo ra để thay thế con người làm những công việc lặp đi lặp lại.

Công thức để tạo ra một method là:

<kiểu return> + <tên method> + (<parameters>) + {block statement}

<kiểu return>

Giống như các operator kiểm tra điều kiện (==, !=, <, >…) return lại bool, các method cũng có thể return lại các kiểu dữ liệu riêng biệt.

Giống như cách khởi tạo một biến (VD: int number = 1;). Bạn sẽ phải xác định trước kiểu return của một method.

Có thể hiểu đơn giản kiểu return giống như đầu ra (output) của method vậy.

Ngoài các kiểu return dữ liệu thông thường như int, string, float, double… thì method có thể không cần return cái gì cả. Lúc này sẽ dùng từ khoá void.

Ta có một vài thí dụ về cách return như sau:

  • void + <tên method> + (<parameters>) + {block statement}
  • int + <tên method> + (<parameters>) + {block statement}
  • string + <tên method> + (<parameters>) + {block statement}

<tên method>

Trong C#, cách đặt tên cho method cũng theo qui chuẩn giống cách đặt tên biến, chỉ khác một điều chữ cái đầu tiên viết hoa.

VD: TinhCanBacHai, SquareRootOf, DrinkMana,…

Mặc dù các bạn có thể đặt tên tuỳ thích nhưng nhằm tối ưu cho việc đọc và học code về sau hãy cố gắng viết theo qui chuẩn.

Ta có một vài thí dụ về cách viết tên method như sau:

  • void SquareRootOf + (<parameters>) + {block statement}
  • float DrinkMana + (<parameters>) + {block statement}

(<parameters>)

Parameters là các thông số đầu vào.

Để nhận input từ bàn phím và chuột thì trên case máy tính sẽ phải có các cổng kết nối.

Các parameters cũng hoạt động tương tự như các cổng kết nối vậy. VD đầu vào là kiểu int thì parameters sẽ được viết là (int numberInput) .

numberInput là tên của parameter, đặt tên giống như cách đặt tên biến thông thường. Các parameter bản chất là các biến nhưng parameters chỉ có thể sử dụng bên trong method của nó.

Trong trường hợp có nhiều parameter, mỗi parameter sẽ cách nhau bằng một dấu phẩy ,

Nếu không cần đầu vào thì để trống (VD: ())

Ta có một vài thí dụ về parameters như sau:

  • void SquareRootOf (double x) + {block statement}
  • void SquareRootOf (double x, double y, double precision) + {block statement}
  • float DrinkMana () + {block statement}

{block statement}

Phần này chính là lõi của một method, quyết định xem nó làm những gì.

Khi method không phải void thì cuối method phải ghi return + <tên biến> + ;

Ta có một số thí dụ sau:

method không return: void IsOddOrEven(int number): kiểm tra một số là số chẵn hay lẻ và in ra màn hình.

void IsOddOrEven(int number)
{
    if (number % 2 == 0) Console.WriteLine(number + " is even.");
    else Console.WriteLine(number + " is odd");
}

method có return: float DoubleIt(float number): trả về một float lớn hơn nó gấp đôi.

float DoubleIt(float number)
{
    number *= 2;
    return number;
}

Từ khoá return để cho máy tính biết bạn muốn return chính xác giá trị nào. Giá trị được return phải cùng kiểu với return của method.

VD: method float DoubleIt(float number) có kiểu return là float thì bạn phải return chính xác một float để method hoạt động.

Đoạn code dưới đây hoàn toàn hợp lệ:

float JustReturnNumber()
{
    return 2.4f;
}

 

Việc khi nào dùng return, khi nào dùng input, khi nào không dùng gì cả, tất cả tuỳ vào sự sáng tạo của bạn.

Dưới đây là 3 cách khác nhau về viết một method để tính căn bậc hai (đoạn code ở đầu bài)

Cách 1: Dùng return double và 1 parameter

double SquareRootOfX(double x)
{
    double y = x / 2;
    double precision = x / 1000;
    while (y * y - x > precision || x - y * y > precision)
    {
        if (y * y > x)
        {
            y -= y / 2;
        }
        else
        {
            y += y / 2;
        }
    }
    return y;
}

Do method return double nên cuối method phải return lại một biến có kiểu double.

Cách 2: Dùng return double và 3 parameters

double SquareRootOfX(double x, double y, double precision)
{
    while (y * y - x > precision || x - y * y > precision)
    {
        if (y * y > x)
        {
            y -= y / 2;
        }
        else
        {
            y += y / 2;
        }
    }
    return x;
}

Trong trường hợp này, ta lại phải tính yprecision riêng ở bên ngoài mới có thể sử dụng method được.

Cách 3: Dùng void và 3 parameters

void SquareRootOfX(double x, double y, double precision)
{
    while (y * y - x > precision || x - y * y > precision)
    {
        if (y * y > x)
        {
            y -= y / 2;
        }
        else
        {
            y += y / 2;
        }
    }
    Console.WriteLine("Square Root of " + x + " is: " + y);
}

Như vậy, chúng ta đã hoàn thành bước tạo ra method. Phần còn lại là cách sử dụng chúng.

Sử dụng Method

Giống như cách sử dụng Console.WriteLine(); việc sử dụng method cũng tương tự như vậy. Ta chỉ cần gọi tên của method và điền các parameters (nếu có).

Ta có thể sử dụng bao nhiêu lần method tuỳ thích. Thí dụ:

IsOddOrEven(50);
IsOddOrEven(40);
IsOddOrEven(21); 
IsOddOrEven(25);

void IsOddOrEven(int number)
{
    if (number % 2 == 0) Console.WriteLine(number + " is even.");
    else Console.WriteLine(number + " is odd.");
}

Màn hình sẽ in ra một loạt kết quả như sau:

50 is even.
40 is even.
21 is odd.
25 is odd.

Khá tiện lợi phải không?

 

Ngoài ra, ta có thể dùng các method return như một biến.

Trở lại bài toán đầu bài. Giả sử ta phải tính tổng của căn bậc hai của 5 số A, B, C, D, E lần lượt là 24, 78, 923, 12, 33.

Áp dụng method để giải như sau:

double finalNumber;

finalNumber = SquareRootOfX(24) + SquareRootOfX(78) + SquareRootOfX(923) + SquareRootOfX(12) + SquareRootOfX(33);
Console.WriteLine(finalNumber);

double SquareRootOfX(double x)
{
    double y = x / 2;
    double precision = x / 1000;
    while (y * y - x > precision || x - y * y > precision)
    {
        if (y * y > x)
        {
            y -= y / 2;
        }
        else
        {
            y += y / 2;
        }
    }
    return y;
}

Kết quả cho ra là:

53.32629370125361

 

Vị trí của Method

Khác với các loại code cho shader (HLSL, GLSL…) method trong C# có thể đứng ở bất kì đâu trong đoạn code.

Nó có thể được đặt ở cuối cùng của đoạn code, có thể đặt ở đầu tiên mà việc sử dụng nó sẽ không bị ảnh hưởng. Hãy tận dụng điều này để đặt method ở những khu vực khiến code dễ đọc nhất có thể nhé.

Method copy value chứ không dùng chính value đó khi input

Đặc biệt chú ý trường hợp sau

int x = 2;
Console.WriteLine("Before: " + x);
PlusOne(x);
Console.WriteLine("After: " + x);

void PlusOne(int number)
{
    number++;
}

Đoạn code sử dụng một method void PlusOne(int number) có tác dụng cộng thêm 1 khi input được đưa vào.

Kết quả như sau:

Before: 2
After: 2

Lẽ ra after sẽ phải là 3 nhưng vì method copy value của x sau đó cộng thêm 1 vào giá trị copy đó nên bản thân x vẫn không thay đổi.

Ta có thể sửa đoạn code bằng nhiều cách, nhưng đơn giản nhất là sử dụng method return.

int x = 2;
Console.WriteLine("Before: " + x);
Console.WriteLine("After: " + PlusOne(x));

int PlusOne(int number)
{
    number++;
    return number;
}

Kết quả như sau:

Before: 2
After: 3

Recursion – Đệ qui

Là khi một method gọi lại chính nó.

void MethodRecursion()
{
    void MethodRecursion();
}

Giống như while loop, bạn cũng phải rất cẩn thận khi sử dụng recursion để tránh infinite loop.

Chẳng hạn, viết chương trình tính tổng các số từ 1 -> đến N:

int CalculateSum(int n)
{
    if (n == 0) return n;
    return n + CalculateSum(n - 1);
}

 

Giả sử, ta tính tổng các số từ 1 tới 3 bằng cách gọi method CalculateSum(3); method này chạy như sau:

Ta cũng có thể viết lại đoạn code tính căn bậc 2 của một số bằng cách dùng đệ qui như sau:

SquareRootOfX(25, 12.5);

double SquareRootOfX(double x, double y)
{
    double precision = x / 100;
    if ((y * y - x) * (y * y - x) < precision)
    {
        Console.WriteLine(y);
        return y;
    }
    if (y * y > x)
    {
        y -= y / 2;
    }
    else
    {
        y += y / 2;
    }
    Console.WriteLine(y);
    return SquareRootOfX(x, y);
}

 

Kết quả

6.25
3.125
4.6875
7.03125
3.515625
5.2734375
2.63671875
3.955078125
5.9326171875
2.96630859375
4.449462890625
6.6741943359375
3.33709716796875
5.005645751953125
5.005645751953125

Bonus*

*Phần này không yêu cầu bạn phải hiểu ngay trong bài này, đừng lo lắng nếu thấy khó hiểu.

Thực chất Method sẽ nằm trong Class. Một method nằm trong method được gọi là local function.

Tất cả các chương trình chúng ta viết đều nằm trong một method được gọi là Main(). Method Main() nằm trong Class Program.

Nếu tích vào Do not use top-level statements khi tạo mới chương trình ta sẽ thấy cấu trúc đầy đủ của một chương trình

namespace Chapter11
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

Trong namespace sẽ có các class, trong class có method, trong method có các local function.

Chúng ta sẽ review lại các khái niệm này trong các chương tới.

Quest: Lại – Đối đầu với Goblin

Phía sau “cánh cửa” dù tối tăm nhưng Kurobo bất ngờ phát sáng rất mạnh.

Có vẻ bạn không cần lo lắng về nguồn sáng rồi.

*bíp bíp*

“Chủ nhân có muốn nâng cao lực chiến không?”

“Làm như thế nào?”

“Đi theo Kurobo nào”

“Nhưng ta phát hiện có kẻ địch xung quanh đây”

“Chủ nhân yên tâm, Kurobo đã tính toán rất kĩ càng, sẽ không sao đâu”

Nghe lời, bạn liền đi theo Kurobo. Băng qua những khu vực đầy bụi bẩn…

Bạn tìm thấy một chiếc hòm!

Thật giống game!

+1 Rusty Sword.
+10 Small HP Potion (+100 HP).
+1 hộp bí ẩn

Quest I: Chiếc hộp trí tuệ ✦✦✧✧✧

Bạn nhận được một chiếc hộp bí ẩn từ trong hòm. Chiếc hộp này dường như đang nhìn thấu tâm can bạn.

Bạn hãy nghĩ tới một con số có 2 chữ số trong đầu (số tự nhiên). Chiếc hộp sẽ đoán con số đó trong đầu bạn.

Hãy viết chương trình thoả mãn:

  1. Chiếc hộp sẽ đoán tối đa 6 lần, sau đó nó sẽ đưa ra câu trả lời.
  2. Sau mỗi lần đoán, bạn sẽ phải xác nhận với chiếc hộp con số đó thấp hơn hay cao hơn số bạn chọn.

Quest II: Goblin xuất hiện ✦✦✦✧✧

Hãy hoàn thành đề bài dưới đây:

Bạn bất ngờ đụng độ với 2 con Goblin gồm 1 Goblin Mage và 1 Goblin Sword. Các thông số của Goblin và của bạn xem trong hình dưới đây:

Nhân vật Máu (HP) Công (ATK)
Goblin Mage 100 50
Goblin Sword 200 30
Bạn 450 35

Trận đấu sẽ diễn ra theo từng lượt, phe Goblin đi trước và tấn công thường bằng chỉ số ATK của chúng sau đó mới tới bạn.

Bạn đi sau có 3 lựa chọn:

  1. Tấn công lại. Gây sát thương cho 1 kẻ địch bằng chỉ số ATK của bạn.
  2. Uống máu: +100 HP.
  3. Không làm gì cả.

 

Hãy viết chương trình thoả mãn:

  1. Mỗi khi bắt đầu turn, ghi ra số turn hiện tại và lượng máu còn lại của các Goblin còn sống.
  2. Ở lượt Goblin: sau khi chúng tấn công, hiển thị lượng HP còn lại của bạn.
  3. Ở lượt của bạn: có 3 lựa chọn.
  4. Nếu tấn công, hiển thị muốn chọn ai để tấn công, đối tượng lựa chọn phải còn sống.
  5. Nếu uống máu, cộng máu nhưng không được quá số máu khởi tạo ban đầu.
  6. Nếu không làm gì, không có chuyện gì xảy ra cả.
  7. Khi HP của bạn về 0, ngay lập tức hiển thị ra thông báo thua trận.
  8. Khi HP của tất cả các Goblin về 0, hiển thị thông báo thắng trận.
  9. Trận chiến sẽ kết thúc khi 1 trong 2 phe chết hết.

 

Kết quả tham khảo hình dưới đây

Xem đáp án Goblin xuất hiện ✦✦✦✧✧

Premium Content

Kể từ phần này, bạn cần đăng nhập và một lượng Point để tiếp tục xem 🙁

Chương Trước | Tổng quan | Chương Kế

 

Kurrwo

Công nhân👷gõ 💬 văn bản ⌨️ trò chơi 🎮 điện tử 📱 👏👏👏

Post navigation

Subscribe
Notify of
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments