[Dịch] Beginning C++ Game Programming,dành cho những ai chưa học C++

Thảo luận trong 'Lập trình & Đồ hoạ' bắt đầu bởi Hyutars, 1/12/06.

  1. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Đang dịch, sẽ cố gắng 1,2 ngày/bài
    [​IMG]
    Tác giả:Michael Dawson
    Người dịch: hyutars
    Trang chủ: http://vnsharing.vnn.bz
    Mọi người có thể sử dụng nội dung của bài dịch này ở các nơi khác, nhưng xin yêu cấu ghi rõ nguồn.


    Chương 1: Kiểu, Biến, Chuẩn I/O và viết thử game căn bản: Lost Fortune

    Bài 1.1 Giới thiệu C++:

    C++ là một ngôn ngữ lập trình tiến tiến, mạnh trong các ngôn ngữ lập trình hiện nay, nó được sử dụng bởi hàng triệu lập trình viên trên thế giới. Nó là một trong những ngôn ngữ phổ biến để viết các ứng dụng máy tính – và ngôn ngữ thông dụng nhất để lập trình games.
    Được sáng tạo bởi Bjarne Stroustrup, C++ là thế hệ sau của ngôn ngữ C. Thực tế, C++ giữ lại hầu hết các đặc điểm của C. Như thế nào đi nữa, C++ đem đến cho chúng ta những thuận lợi hơn trong việc lập trình.

    Dùng C++ cho Games:
    C++ là ngôn ngữ được các lập trình viên (games) lựa chọn. Hầu hết các games được giới thiệu hiện nay đều được viết bởi C++. Có nhiều lí do khác nhau để giải thích vì sao những người lập trình games sử dụng C++. Đây là một vài lí do:
    Nó nhanh:Nếu bạn rành C++ thì bạn có thể lập trình nhanh như gió. Một trong những mục tiêu của C++ là khả năng thực thi. Và nếu bạn cần thêm các tính năng cho chương trình, C++ cho phép bạn dùng ngôn ngữ Assembly (Hợp ngữ) – Ngôn ngữ lập trình bậc thấp nhất – để liên lạc trực tiếp với phần cứng của máy tính.
    Nó dễ điều khiển: C++ là một ngôn ngữ biến hóa, nó hỗ trợ các phong cách lập trình khác nhau, bao gồm lập trình hướng đối tượng. Không giống các ngôn ngữ khác, C++ không ép buộc lập trình viên phải đi theo một phong cách nào cả.
    Nó được hỗ trợ nhiều: Vì nó là ngôn ngữ vượt trội các ngôn ngữ khác, có rất nhiều tài nguyên cho người lập trình bằng C++, bao gồm đồ họa API và 2D, 3D, vật lý, các thiết bị âm thanh – tất cả là một cái đòn bẩy cho phép lập trình viên tăng tốc độ lập trình games.

    Tạo File thực thi: (.exe)
    File mà bạn dùng để chạy chương trình – dù bạn đang nói đến game hay các ứng dụng windows – gọi là file thực thi (Executable File). Có rất nhiều bước để tạo một file thực thi từ mã nguồn của C++ (tập hợp các lệnh trong ngôn ngữ C++). Quá trình này được mô tả ở hình 1.1

    [​IMG]
    Hình 1.1: Quá trình tạo file thực thi trong mã nguồn C++
    1.Đầu tiên, người lập trình dùng editor (trình soạn thảo) để viết mã nguồn C++, file đó thường có đuôi .cpp. Trình soạn thảo giống như bộ xử lý ngôn ngữ cho chương trình, nó cho phép lập trình viên tạo, chỉnh sửa, và lưu trữ mã nguồn.

    2.Sau khi lập trình viên lưu lại mã nguồn, anh (chị) ta sẽ gọi compiler (trình biên dịch) – một ứng dụng có chức năng đọc mã nguồn và dịch nó sang file đối tượng (object file). Object files thường có đuôi mở rộng là .obj.

    3.Tiếp theo, bộ phận kết nối (Linker) sẽ kết nối file object đến những file ngoài nếu cần thiết, sau đó tạo file thực thi (executable file), thường có đuôi mở rộng là .exe. Đến lúc này, người dùng có thể chạy chương trình bằng cách chạy file thực thi.
    Lưu ý: Quá trình tôi miêu tả ở trên chỉ là một trường hợp đơn giản. Để tạo nên một ứng dụng phức tạp trong C++ thường liên quan đến rất nhiều file mã nguồn được viết bởi lập trình viên (hay một nhóm lập trình viên).

    Để tự động hóa quá trình này, lập trình viên dùng một công cụ tổng hợp, đó là IDE (Integrated Development Environment – môi trường tương thích khai triển). IDE thường bao gồm editor, compiler, linker và một số công cụ khác. Phiên bản thương mại IDE cho Windows bao gồm Visual Studio.NET và C++ Builder Studio. Dev-C++ là một ngôn ngữ mà nguồn mở miễn phí cho Windows (hyutar: strong CD ROM kèm quyển sách gốc có cái Dev-C++, nhưng sách này là đồ lậu nên hổng có :D, mọi người có thể tải cái này từ trên net về, hoặc dùng C++ 6.0 hay Visual C++ cũng được, mình nghĩ hầu hết mọi người đều có bản thương mại của C rồi).

    Xử lý lỗi: (error)
    Khi tôi (tác giả) miêu tả quá trình tạo file thực thi từ mã nguồn C++, tôi đã bỏ qua một chi tiết nhỏ: lỗi. Nếu mắc lỗi là một chuyện bình thường của con người, thì lập trình viên chính là người thường xuyên mắc lỗi nhất. Ngay cả lập trình viên giỏi nhất đều có thể mắc lỗi ở lần thứ 1 (hoặc nhiều hơn) chạy chương trình. Lập trình viên phải sửa lỗi và chạy lại quá trình tạo file thực thi. Sau đây là một vài loại lỗi cơ bản bạn thường mắc phải khi chạy chương trình:
    Lỗi biên dịch (Compile Errors): Nó xảy ra trong quá trình biên dịch. Kết quả, file object không được tạo ra. Lỗi này thường do lỗi cú pháp, có nghĩa là trình biên dịch không hiểu cái gì đó. Nó có thể đơn giản như gõ sai lệnh chẳng hạn, hay thiếu dấu “;”. Trình biên dịch còn đưa ra những cảnh báo (warning). Mặc dù bạn thường không cần phải chú ý đến warning, nhưng bạn nên giải quyết nó như là lỗi, sữa chửa, sau đó biên dịch lại, đây là một thói quen tốt đấy ^^.
    Lỗi liên kết (Link Errors): Nó xảy ra trong quá trình kết nối và có thể cho biết có vài thứ mà chương trình liên kết đến không thể tìm thấy. Lỗi này thường được giải quyết bằng cách đặt đúng vị trí các liên kết và bắt đầu quá trình biên dịch/kết nối lần nữa.
    Lỗi Run-time (Run-time errors): Nó xảy ra khi đang chạy file thực thi. Nếu chương trình làm một cái gì đó không hợp lý, nó có thể phá hủy hệ thống. Nhưng một dạng lỗi tinh vi, khó phát hiện hơn của lỗi run-time: logical error (lỗi logic), có thể làm chương trình làm những việc mà ta không định trước. Nếu bạn đã từng chơi game mà trong đó nhân vật có thể bước trên không khí (trong kịch bản nhân vật không thể bước trên không khí), khi đó bạn đã thấy lỗi logical trong hành động.

    Trong thực tế: Như các nhà tạo phần mềm, công ty game thường gặp rắc rối với các sản phẩm bị lỗi. Biện pháp khắc phục của họ là trước khi đem ra ngoài thị trường, họ thuê những người chơi game thử (game testers). Những người này chơi games để sống, nhưng công việc của họ không thú vị như bạn tưởng đâu. Họ phải chơi đi chơi lại một phần nào đó của game – có thể lên đến hàng trăm – cố gắng tìm xem có lỗi nào không. Và với công việc buồn tẻ này, lương của họ cũng bèo nhèo. Nhưng trở thành game testers là một nấc thang để bạn có thể vào làm việc tại công ty làm games.

    Hiểu chuẩn ISO:

    Chuẩn ISO cho C++ là sự xác định rõ trong đó miêu tả chính xác ngôn ngữ hoạt động như thế nào. Nó cũng xác định các nhóm file, gọi là thư viên chuẩn, bao gồm các khối chức năng cho việc lập trình thông dụng, chẳng hạn như I/O – lấy thông tin từ lối vào và hiển thị ở lối ra. Thư viện chuẩn làm cuộc sống có vẻ dễ thở hơn đối với các lập trình viên, giúp họ không phải viết lại các khối code rối rắm (hyutars: theo mình hiểu thì nó giống như các macro, chẳng hạn trong một số hàm đếm bạn học sau này, chúng ta có thể thay một đoạn mã bằng một từ strlen duy nhất). Tôi sẽ dùng thư viện chuẩn trong tất cả các chương trình trong cuốn sách này.
    Trong cuốn sách này, tôi dùng Dev-C++. Trình biên dịch của Dev-C++ khá trung thành với chuẩn ISO, bạn có thể biên dịch, liên kết, và chạy tất cả chương trình dùng các trình biên dịch Windows. Tóm lại, bạn có thể biên dịch, liên kết, và chạy tất cả chương trình dưới bất kì hệ điều hành nào nếu bạn dùng ISO.
    Lưu ý: Chuẩn ISO còn được gọi là chuẩn ANSI hay chuẩn ANSI/ISO. Tên đơn giản dễ hiểu nhất là Standard C++.
    Hyutars: Nếu bạn dùng các trình C++ khác ngoài Dev-C++ thì cứ yên tâm, nó cũng giống nhau cả thôi.
     
    DonovanD thích bài này.
  2. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài 1.2 Viết chương trình C++ đầu tiên:

    Okay, lí thuyết vậy là đủ rồi. Bây giờ là lúc đi đến thực chất của vấn đề và viết chương trình C++ đầu tiên của bạn. Mặc dù nó đơn giản, chương trình dưới đây sẽ chỉ cho bạn thấy cấu trúc căn bản của một chương trình. Nó còn cho bạn thấy chuỗi kí tự (text) được hiển thị trong cửa sổ console như thế nào (hyutars: Cửa sổ console là một cửa sổ giống DOS vậy).

    Giới thiệu chương trình Game Over:

    Hyutars: Nếu bạn đang dùng C++ 6.0, vào new->project, chọn Win32 Console Application, Empty Project sau đó chọn New->Source File, bạn sẽ viết mã trong source file này. Trong Visual C++ 2005 cũng tương tụ như vậy. Lưu ý phải add file vào đúng thư mục file trong thanh navigation.
    Chương trình đầu tiên mà lập trình viên được học thường là chương trình Hello World, nó sẽ hiển thị dòng “Hello World” trên màn hình. Chương trình Game Over cũng giống vậy thôi, chỉ khác là dòng text đổi thành Game Over!, hình 1.2 cho bạn thấy chương trình này đang hoạt động.

    [​IMG]
    Hình 1.2 Chương trình C++ đầu tiên của bạn hiển thị hai chữ quen thuộc trong games.

    Bạn có thể tự viết chương trình này, tôi cũng hỗ trợ các mã nguồn trong CD-ROM kèm sách (hyutars: sách lậu thì hổng có đâu).

    Mã:
    // Game Over
    // A first C++ program
    
    #include <iostream>
    
    int main()
    {
                    std::cout << "Game Over!" << std::endl;
                    return 0;
    }
    Code chú thích:

    Hai dòng đầu tiên của chương trình là lời chú thích

    Mã:
    // Game Over
    // A first C++ program

    Lời chú thích sẽ được trình biên dịch bỏ qua, có nghĩa nó chỉ dành cho con người. Nó giúp các lập trình viên khác hiểu ý định của bạn. Đừng khinh thường, lời chú thích có thể giúp bạn rất nhiều đấy. Nó có thể giúp bạn nhớ lại bạn có ý định làm gì khi nhìn vào một đoạn mã được viết lúc trước (hyutars: Đây là thói quen tốt, lập trình là công việc của một nhóm chứ không phải của cá nhân, chương trình càng rõ ràng thì người ta càng thích đọc chương trình của bạn, sau này việc nâng cấp và bảo trì cũng tiến hành thuận lợi hơn, nói vậy không có nghĩa là bạn ghi quá cụ thể cho những dòng lệnh đơn giản).
    Bạn có thể tạo ra chú thích bằng cách dùng hai dấu / ở đầu dòng (//). Tất cả những gì nằm sau hai kí tự này (trong dòng đó) được hiểu là chú thích. Nó có nghĩa là bạn cũng có thể chèn lời chú thích sau code trên cùng một dòng (hyutars: ví dụ, coding coding … // chú thích).
    Lưu ý: Bạn cũng có thể viết chú thích trên nhiều dòng bằng cách dùng /* để bắt đầu, khi viết xong chú thích (cho dù dài đến mấy chục dòng), bạn chỉ cần đóng nó lại bằng dấu */.

    Dùng khoảng trắng:

    Dòng tiếp theo của chương trình là một dòng trống. Trình biên dịch bỏ qua dòng trống, trên thực tế, trình biên dịch bỏ qua tất cả khoảng trắng – dấu cách, tab, xuống dòng. Giống như lời chú thích, khoảng trắng chỉ dùng cho con người.
    Dùng khoảng trắng hợp lý sẽ làm chương trình sáng tỏ, dễ đọc. Ví dụ, bạn có thể dùng dòng trống để chia khu vực cho các đoạn mã. Tôi cũng dùng khoảng trắng (tab) lúc viết đoạn mã dưới dấu { và khi kết thúc thì lùi lại để đóng dấu } (hyutars: Trong các chương trình C++ thì khi bạn enter nó sẽ làm chức năng này giùm bạn).

    Include (Bao gồm) file khác:

    Dòng tiếp theo là chỉ thị trước chương trình. Bạn có thể nhận ra nó bởi dấu # ở đầu dòng:

    Mã:
    #include <iostream>
    Tôi gọi file iostream, là một phần của thư viện chuẩn, vì nó chứa các đoạn mã cho phép tôi hiển thị kết quả ra ngoài. Tôi dùng dấu < và > để bao quanh tên file nhằm nói cho trình biên dịch tìm file này ở nơi lưu giữ tất cả các file đi cùng trình biên dịch. File mà bạn gọi trong chương trình giống như thế này được gọi là header file.

    Hàm main()

    Dòng tiếp theo là một hàm gọi là main().

    Mã:
    int main()
    Hàm là một nhóm các dòng code (mã) có thể làm một công việc nào đó và trả lại một giá trị. Trong trường hợp này, int có nghĩa là hàm này sẽ trả lại một giá trị kiểu nguyên. Tất cả các hàm đều phải có hai dấu ngoặc đơn sau tên hàm, chúng ta sẽ khai báo biến trong đó nếu cần.
    Tất cả chương trình C++ đều phải có một hàm gọi là main(), là điểm bắt đầu của chương trình. Các hành động sẽ bắt đầu từ đây.
    Dòng tiếp theo đánh dấu sự bắt đầu của hàm:
    {
    Và lúc kết thúc hàm, sẽ có dấu này:
    }

    Tất cả các hàm đều được giới hạn bới dấu { và }, và tất cả những thứ giữa chúng là nội dung của hàm. Mã giữa hai dấu { } gọi là khối và nó thường được lùi vào (tab) như là một bộ phận của hàm. Khối code tạo nên hàm gọi là body (thân) của hàm.

    Hiển thị text thông qua chuẩn Output:

    Dòng đầu tiên trong body hàm main():

    Mã:
    std::cout << "Game Over!" << std::endl;
    “Game Over!” là một chuỗi (string) – tập hợp của các kí tự có thể in ra ngoài. Đó là các kí tự nằm giữa hai dấu “ “.
    cout là một đối tượng được định nghĩa trong file iostream, nó dùng để gửi dữ liệu ra ngoài. Trong đa số các chương trình (bao gồm cả chương trình này), đầu ra đơn giản là một cửa sổ console trên màn hình máy tính.

    Tôi dùng toán tử output (<<) để gửi chuỗi đến cout. Bạn có tưởng tượng toán tử output như là một cái phễu, nó lấy tất cả những thứ bên nó mở (<< là bên phải) và hút tất cả vào điểm cuối (điểm cuối<<). Cho nên chuối được đưa đến chuẩn output – màn hình.

    Tôi dùng std như là một tiếp đầu ngữ trước cout để nói trình biên dịch rằng: cout này nằm trong thư viện chuẩn, std gọi là namespace. Bạn có thể nghĩa namespace như là một mã khu vực – Nó xác định nhóm của một một thứ gì đó. Bạn dùng hai dấu :: sau namespace, nó gọi là scope resolution operator (toán tử scope resolution – dịch được vậy thôi, hì hì).

    Sau cùng, tôi gửi std::endl đến chuẩn output (standard output). endl là một đối tượng được định nghĩa trong thư viện iostream và nó cũng là một đối tượng trong namespace std. Gửi endl đến chuẩn output cũng giống như hành động nhấn nút Enter trong của sổ console vậy. Thực tế, nếu ta gửi chuỗi khác đến cửa sổ console, nó sẽ hiển thị ở dòng tiếp theo.

    Tôi hiểu có thể những gì trên đây là hơi nhiều để các bạn tiếp thu, vậy thì hãy nhìn hình 1.3 để hiểu thêm nào:

    [​IMG]
    Hình 1.3 Bổ sung của Standard (chuẩn) C++ gồm một tập các file gọi là thư viện chuẩn, gồm file iostream – định nghĩa nhiều đối tượng – gồm cả cout.

    Giới hạn câu lệnh:

    Bạn sẽ chú ý đến dòng đầu tiên của hàm kết thúc bởi dấu “;”. Đó là vì dòng là một câu lệnh, và tất cả các câu lệnh phải kết thúc bởi dấu “;” , dấu này giúp trình biên dịch phân biệt các câu lệnh, biết điểm bẳt đầu và kết thúc, nếu bạn viết thiếu dấu này, lỗi sẽ xuất hiện và chương trình không được biên dịch.

    Trả về giá trị trong hàm main():

    Dòng cuối cùng của hàm là việc trả lại giá trị 0 cho hệ điều hành:

    Mã:
    return 0;
    Trả lại giá trị 0 từ hàm main() là cách để ra dấu chương trình kết thúc mà không gặp vấn đề gì. Hệ điều hành không cần phải làm gì với giá trị trả lại này, nhưng chuẩn C++ cần bạn phải trả lại giá trị kiểu nguyên trong gàm main(). (hyutars: cái return 0 trong hàm main bạn chỉ viết vậy thôi, không cần quan tâm nó lắm, nếu bạn không muốn viết dòng return 0 này cũng được, chỉ cần đổi int main() thành void main() ).
    Mẹo: Khi bạn chạy chương trình Game Over, bạn có thể chỉ thấy cửa sổ console xuất hiện và kết thúc một cách nhanh chóng. Đó là vì C++ rất nhanh, nó mở cửa sổ console, hiển thị “Game Over!”, và đóng cửa sổ trong một phần giây. Nếu bạn gặp vấn đề này, chỉ cần bỏ đoạn code đây phía trước dòng return 0 trong hàm main().

    Mã:
    std::cout << "Press the enter key to exit";
    std::cin.ignore(std::cin.rdbuf()->in_avail() + 1);
    Những dòng này có chức năng đợi người dùng gõ phím Enter. Bạn có thể dùng kĩ thuật này trong các chương trình khác. (hyutars: nếu bạn dùng C++ 6.0, chỉ cần include thêm thư viện conio.h , sau đó trước dòng return 0, thêm code

    Mã:
    getch();
    )
     
    kuty142 thích bài này.
  3. Powers_2004

    Powers_2004 Hàng VN xuất khẩu \m/ Moderator

    Tham gia ngày:
    13/7/04
    Bài viết:
    1,171
    Nơi ở:
    Hanoi
    Quá hay
    Kain Stick topic này lên đi
    Biz! cảm ơn anh Hyutars :D
     
  4. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Cám ơn bạn đã góp ý ^^, nếu ai thấy tui dịch sai chỗ nào thì góp ý với nhé, để làm bài dịch tốt hơn, hôm nay up 2 bài để có gì hum sau nghỉ anh em khỏi trách

    Bài 1.3 Làm việc với namespace std:

    Vì việc dùng các yếu tố từ namespace std là rất phổ biến, tôi sẽ chỉ cho bạn hai phương thức khác nhau để trực tiếp truy cập các yếu tố kia. Nó sẽ giúp bạn không phải dùng tiền tố std:: nhiều lần, và làm cho đoạn code rõ ràng hơn.

    Giới thiệu chương trình Game Over 2.0:

    Chương trình Game Over 2.0 cho ra kết quả giống y hệ chương trình Game Over, được mô tả ở hình 1.2. Nhưng điểm khác biệt giữa hai chương trình này là: cách thức truy cập đến các yếu tố từ namespace std.

    Mã:
    // Game Over 2.0
    // Demonstrates a using directive
    
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        cout << "Game Over!" << endl;
        return 0;
    }
    Dùng chỉ thị:

    Chương trình bắt đầu giống nhau. Tôi dùng hai dòng chú thích và sao đó include thư viện iostream cho truy xuất ra ngoài. Nhưng tiếp theo, tôi dùng loại khai báo mới:

    Mã:
    using namespace std;
    Bằng cách dùng chỉ thị, nó giúp tôi truy cập trực tiếp đến các yếu tố của namespace std. Một lần nữa, nếu namespace giống như một mã khu vực, thì dòng này nói tất cả các yếu tố trong namespace std giống như điện thoại trong cùng tỉnh đối với tôi vậy (hyutars: Ví dụ nhé, mình ở Đà Lạt, mã vùng là 063, nếu dùng điện thoại cố định gọi đến một số trong Đà Lạt thì mình chỉ cần nhấn số chứ không cần nhấn mã vùng, nhưng nếu mình gọi ra Đà Nẵng thì phải thêm mã vùng 0511, dùng namespace std giống như nó đã hiểu mình ở Đà Lạt và gọi trong Đà Lạt, không cần dùng mã vùng). Tôi không phải dùng mã khu vực (tiền tố std:: ) để truy cập vào chúng nữa.
    Tôi có thể dùng cout và endl mà không cần ghi tiền tố. Nó có thể không thành vấn đề với bạn lắm bây giờ, nhưng sau này khi bạn làm việc với hàng tá hay hàng trăm đối tượng, bạn sẽ phải cảm ơn tôi.

    Giới thiệu chương trình Game Over 3.0:

    Okay, chúng ta còn một cách nữa để làm những việc này, và đó chính xác là những gì tôi chuẩn bị chỉ cho bạn trong chương trình Game Over 3.0.

    Mã:
    // Game Over 3.0
    // Demonstrates using declarations
    
    #include <iostream>
    using std::cout;
    using std::endl;
    
    int main()
    {
         cout << "Game Over!" << endl;
    return 0;
    }
    Dùng khai báo:

    Trong chương trình này, tôi dùng hai khai báo:

    Mã:
    using std::cout;
    using std::endl;
    Bằng cách khai báo chính xác yếu tố từ namespace std tôi local (hyutars: local có thể dịch là địa phương hóa một cái gì đó, tức là bỏ tiền tố std:: í mà, mình không dịch chỗ này vì không thể dịch sát được) cho chương trình, tôi có thể truy cập đến chúng trực tiếp, y như chương trình Game Over 2.0. Mặc dù nó cần gõ nhiều hơn cách dùng chỉ thị, nhưng lợi thế của kĩ thuật này là nó giải thích rõ ràng tôi muốn dùng yếu tố nào. Thêm vào đó, nó không local các yếu tố mà tôi không có ý định xài.

    Hiểu khi nào thì dùng using:

    Okay, bạn đã thấy hai cách để làm yếu tố từ namespace local trong chương trình. Nhưng đâu là kĩ thuật tốt nhất?
    Những người lập trình thuần túy sẽ nói bạn không nên dùng cả hai cách trên và bạn nên dùng tiền tố. Theo quan điểm của tôi, nó giống như lúc nào cũng gọi họ và tên của người bạn tốt nhất. Nó có vẻ trang trọng hóa vấn đề.
    Nếu bạn ghét gõ phím, bạn có thể dùng chỉ thị. Hoặc bạn có thể dùng khai báo cũng chả sao. Trong cuốn sách này, tôi sẽ dùng chỉ thị cho code được ngắn gọn súc tích hơn.

    Trong thực tế: Tôi đã trình bày các hình thức khác nhau để làm việc với namespace. Tôi cũng cố gắng giải thích ưu điểm của từng loại cho bạn có thể quyết định dùng cái nào cho chương trình của mình. Nhưng sự quyết định có thể không nằm trong tay của bạn đâu. Khi bạn làm việc với đề án nào đó, dù đó là trong lớp học hay trong thế giới của những pro, bạn có thể phải viết code theo chuẩn mà người phụ trách (project manager) đưa ra. Dù bạn có viết theo phong cách gì, tốt nhất là bạn nên nghe theo người đưa cho chúng ta tiền lương mỗi tháng. (hyutars: nghe có vẻ đau lòng quá nhỉ :( ).
     
  5. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài 1.4 Dùng các toán tử số học:

    Dù bạn có viết một đoạn mã để tăng số lượng kẻ thù mà người chơi tiêu diệt hay giảm số lượng HP của người chơi, bạn cần chương trình làm một số phép tính. Như các ngôn ngữ khác, C++ cũng cài đặt sẵn một hệ thống các toán tử số học.

    Giới thiệu chương trình Expensive Calculator:

    Chương trình này sẽ cho ra kết quả như bạn thấy ở hình 1.4:


    [​IMG]
    Hình 1.4: C++ có thể cộng, trừ, nhân, chia và còn có thể tính số dư.

    Mã:
    // Expensive Calculator
    // Demonstrates built-in arithmetic operators
    
    #include <iostream>
    using namespace std;
    
    int main()
    {
        cout << "7 + 3 = " << 7 + 3 << endl;
        cout << "7 - 3 = " << 7 - 3 << endl;
        cout << "7 * 3 = " << 7 * 3 << endl;
    
        cout << "7 / 3 = " << 7 / 3 << endl;
        cout << "7.0 / 3.0 = " << 7.0 / 3.0 << endl;
    
        cout << "7 % 3 = " << 7 % 3 << endl;
        cout << "7 + 3 * 5 = " << 7 + 3 * 5 << endl;
    
        cout << "(7 + 3) * 5 = " << (7 + 3) * 5 << endl;
        return 0;
    }
    Cộng, trừ, và nhân:

    Tôi dùng các toán tử số học cho phép cộng (+), trừ (-), và nhân (*). Kết quả ở trong hình 1.4 chắc ai cũng biết được.
    Mỗi toán tử số học là một phần của một biểu thức – thứ mà kết quả là một giá trị. Trong ví dụ trên, biểu thức 7 + 3 trả lại giá trị 10, và sau đó nó được gửi đến cout.

    Hiểu kiếu nguyên (integer) và phép chia dấu chấm động:

    Kí hiệu của phép chia là dấu “/”, là thứ mà tôi dùng ở dòng tiếp theo. Như thế nào đi nữa, kết quả có thể làm bạn ngạc nhiên. Theo C++, 7 chia 3 bằng 2. Cái quái gì đang diễn ra vậy? Vâng, kết quả của một phép tính số học gồm các số nguyên (số mà không có phần thập phân, tức là không có dấu “.”) luôn luôn là một số nguyên khác. Và khi 7 và 3 là số nguyên, kết quả phải là số nguyên. Phần thập phân của kết quả bị bỏ đi.
    Để lấy kết quả gồm cả phần thập phân, ít nhất một trong các giá trị phải có dấu chấm động (số mà có phần thập phân). Tôi mô tả phép tính này ở dòng tiếp theo với biểu thức 7.0 / 3.0. Kết quả sẽ chính xác hơn: 2.33333.
    Bẫy: Bạn có thể để ý thấy khi kết quả của biểu thức 7.0 / 3.0 (2.33333) gồm cả phần thập phân, nó vẫn bị cắt xén bớt (Kết quả đúng phải trải dài một dãy số 3 không bao giờ kết thúc). Việc hiểu máy tính chỉ lưu trữ những số hữu hạn là rất quan trọng. Như thế nào đi nữa, C++ đem đến các loại dấu chấm động đủ để đáp ứng các yêu cầu khắt khe – cho dù nó là một game 3D.

    Dùng toán tử lấy dư:

    Trong câu lệnh tiếp theo, tôi dùng toán từ mà có thể bạn chưa bao giờ gặp, toán từ lấy dư (%). Toán tử này trả lại phần dư của phép chia kiểu nguyên. Trong ví dụ, 7 % 3 cho ra 1 – phần dư.

    Hiểu độ ưu tiên của các toán tử:

    hyutars: Lược bỏ một đoạn của tác giả, thay vào câu này: “Nhân chia trước cộng trừ sau”, ông tác giả này giảng có lúc kĩ quá đáng thật.
    Để phòng có một số bạn chưa hiểu, mình trích lược các ví dụ nhé, dòng 7 + 3 * 5, nhân có tính ưu tiên hơn phép cộng, làm phép nhân trước, thành ra 7 + 15 = 22.
    Nếu bạn muốn phép tính có độ ưu tiên thấp hơn được làm trước, bạn có thể dùng dấu ngoặc đơn – có độ ưu tiên hơn các toán tử số học. Trong câu lệnh tiếp theo, biểu thức ( 7 + 3 ) * 5 tương đương 10 * 5 = 50.

    Sau đây là bảng cho biết độ ưu tiên của các phép toán, mình để tiếng Anh bên cạnh luôn nhé, các bạn học tiếng Anh của mấy thứ này cũng tốt đó:
    [​IMG]
    [​IMG]
    [​IMG]
     
  6. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài này hơi dài, dịch mệt quá, hum qua dịch khuya nữa, nếu có sai sót thì anh em góp ý giùm
    Bài 1.5: Khai báo và khởi đầu biến:

    Biến là một phần của bộ nhớ máy tính cho phép bạn lưu trữ, gọi lại và điều khiển dữ liệu. Chẳng hạn nếu bạn muốn lưu điểm của người chơi, bạn có thể tạo một biến cho nó, và sau đó bạn có thể gọi lại biến đó để hiển thị điểm. Bạn cũng có thể cập nhật lại điểm khi người chơi bắn trúng kẻ địch ở trên trời.

    Giới thiệu chương trình Game Stats:

    Chương trình Game Stats hiển thị dữ liệu bạn muốn lưu trữ trong game bắn nhau, chẳng hạn như điểm số của người chơi, số lượng kẻ địch người chơi đã tiêu diệt, và Hp của người chơi tăng lên (trong chương trình là biến shieldsUp). Chương trình dùng một nhóm các biến để lo vụ này. Hình 1.5 mô tả chương trình đang chạy:


    [​IMG]
    Hình 1.5: Mỗi số liệu trạng thái của game được lưu giữ trong một biến

    Mã:
    // Game Stats
    // Demonstrates declaring and initializing variables
    
    #include <iostream>
    using namespace std;
    
    int main()
    {
        int score;
        double distance;
        char playAgain;
        bool shieldsUp;
    
        short lives, aliensKilled;
    
        score = 0;
        distance = 1200.76;
        playAgain = ‘y';
        shieldsUp = true;
        lives = 3;
    
        aliensKilled = 10;
    
        double engineTemp = 6572.89;
    
        cout << "\nscore: " << score << endl;
        cout << "distance: " << distance << endl;
        cout << "playAgain: " << playAgain << endl;
        //skipping shieldsUp since you don't generally print Boolean values
        cout << "lives: " << lives << endl;
        cout << "aliensKilled: "<< aliensKilled << endl;
        cout << "engineTemp: " << engineTemp << endl;
    
        int fuel;
        cout << "\nHow much fuel? ";
        cin >> fuel;
        cout << "fuel: " << fuel << endl;
    
        typedef unsigned short int ushort;
        ushort bonus = 10;
        cout << "\nbonus: " << bonus << endl;
    
        return 0;
    }
    Các loại dữ liệu cơ bản:

    Mọi biến mà bạn tạo ra đều có kiểu dữ liệu của nó – kiểu dữ liệu sẽ quyết định loại thông tin mà bạn lưu trữ trong biến. Nó sẽ cho trình biên dịch biết nên dành bao nhiêu bộ nhớ cho biến và nó định nghĩa chính xác bạn có thể làm gì đối với biến đó.
    bool là giá trị kiểu Boolean (true or false – đúng hoặc sai), char là kiểu text cho 1 kí tự, int là kiểu số nguyên, float là kiểu số thực (có dấu chấm động), double cũng là kiếu số thực nhưng có độ chính xác gấp đôi float (có thể chứa nhiều số hơn).

    Sửa đổi kiểu dữ liệu: (type modifiers)

    Bạn có thể dùng modifiers để sửa đổi kiểu dữ liệu. short là một modifier, nó có thể giảm số chữ số mà biến có thể lưu giữ. long là modifier có chức năng tăng số chữ số mà biến có thể giữ. short có thể giảm dung lượng cần cho biến trong khi long có thể tăng nó lên. short và long có thể đi kèm kiểu int. long cũng có thể đi kèm double.
    signed và unsigned là modifiers chỉ làm việc với kiểu số nguyên (int). signed có nghĩa là biến có thể lưu giữ cả giá trị âm và dương, trong khi unsigned nghĩa là biến chỉ có thể lưu giữ giá trị dương mà thôi. Cả signed và unsigned đều không thay đổi số chữ số mà biến có thể lưu trữ; nó chỉ thay đổi vùng của giá trị. signed là modifier mặc định cho kiểu nguyên.
    Okay, bạn cảm thấy hơi rối hả? Được rồi, đừng lo. Bảng 1.1 tóm tắt các kiểu dữ liệu thông dụng đi kèm modifiers. Bảng cung cấp vùng giá trị của từng loại.

    [​IMG]

    hyutars: Khuyến mãi thêm cái bảng tiếng Việt, cái này lấy trong cuốn “Kĩ thuật lập trình” của Th.S Trần Tuấn Minh – Đại học Đà Lạt.

    [​IMG]


    Bẫy: Phạm vi giá trị trong bảng 1.1 là căn cứ vào trình biên dịch của tôi. Của bạn có thể khác. Hãy kiểm tra tư liệu kèm theo trình biên dịch của bạn.
    Mẹo: Để nhanh chóng, short int chỉ cần viết là short và long int chỉ cần viết là long.

    Khai báo biến:

    Được rồi, bây giờ bạn đã có những kiến thức căn bản về kiểu dữ liệu, đã đến lúc trở lại chương trình. Một trong những điều đầu tiên tôi làm là khai báo biến trong dòng:

    Mã:
    int score;
    Với đoạn code này, tôi khai báo biến thuộc kiểu dữ liệu int, và tôi đặt tên nó là score (điểm). Bạn dùng tên của biến để truy cập đến biến đó.
    Từ dòng này, bạn có thể thấy để khai báo một biến đầu tiên bạn ghi kiểu dữ liệu, sau đó gõ space một cái, ghi tên biến. Vì việc khai báo là một câu lênh, nó phải kết thúc bằng dấu chấm phẩy.
    Tôi khai báo thêm 3 biến nữa thuộc 3 kiểu dữ liệu khác nhau trong 3 dòng tiếp theo. distance (khoảng cách) là biến thuộc kiểu double. playAgain (chơi lại) là biến thuộc kiểu char (kí tự). Và shieldsUp là biến thuộc kiểu bool.
    Games (cũng như các ứng dụng khác) cần rất nhiều biến. Thật may mắn, C++ cho phép bạn khai báo nhiều biến trong cùng một câu lệnh. Đó là những gì mà tôi làm ở dòng tiếp theo:

    Mã:
    short lives, aliensKilled;
    Dòng này thiết lập hai biến kiểu short – lives (mạng sống) và aliensKilled (số lượng quân địch bị tiêu diệt).
    Mặc dù tôi định nghĩa một nhóm biến ở phía trên hàm main(), bạn đừng khai báo tất cả các biển trong cùng một chỗ. Lát nữa bạn sẽ thấy trong chương trình này, tôi định nghĩa biến mới chỉ trước khi tôi dùng nó.

    Đặt tên cho biến:

    Để khai báo biến, bạn phải cho nó một cái tên, được gọi là định danh (identifier). Chỉ có một số luật đặt tên bạn phải tuân theo:
    - Định danh chỉ gồm chữ số, kí tự và dấu underscores ( _ ).
    - Định danh không được bắt đầu bằng chữ số.
    - Định danh không được là keyword (từ khóa) của C++.
    Từ khóa là từ đặc biệt mà C++ lưu giữ để dùng riêng cho nó. Không có nhiều từ khóa lắm, nếu bạn muốn biết, xem bảng sau:

    [​IMG]

    Ngoại trừ những điều luật để tạo ra một tên biến hợp lệ, các bạn nên làm theo một số hướng dẫn sau để tạo ra một tên biến tốt:
    - Tên biến nên sát với thứ mà nó đề cập – có tính diễn đạt cao (Choose descriptive names): Tên biến phải rõ ràng đối với lập trình viên khác. Ví dụ, dùng score thay cho s (Một ngoại lệ cho quy luật này là biến dùng trong một thời gian ngắn – tức là có tính chất lướt qua, không phải biến quan trọng. Trong trường hợp đó, tên biến có một kí tự, chẳng hạn như x, cũng tốt).
    - Tên biến nên có tính chất nhất quán: Có nhiều trường dạy làm cách nào để viết tên biến gồm nhiều từ. Là high_score hay highScore? Trong cuốn sách này, tôi dùng phong cách thứ hai, tức là chữ đầu tiên của từ thứ hai (hay các từ khác) được viết hoa. Nhưng các bạn chỉ cần nhất quán, lúc đó việc chọn cách nào là không quan trọng.
    - Nên tuân theo truyền thống của ngôn ngữ lập trình: Một số lệ đặt tên tuân theo truyền thống, thói quen. Ví dụ, hầu hết trong các ngôn ngữ lập trình (gồm C++) tên biến bắt đầu với chữ viết thường. Truyền thống khác là bạn nên tránh sử dụng dấu underscore ( _ ) để bắt đầu tên biến. Tên bắt đầu với dấu underscore có ý nghĩa đặc biệt (hyutars: sau này học lập trình C++ trong Windows bạn sẽ thấy).
    - Độ dài hợp lý: Mặc dù từ playerTwoBonusForRoundOne rất rõ ràng, có tính diễn đạt cao nhưng nó có thể làm đoạn code khó đọc. Thêm nữa, tên dài tức là chúng ta phải gõ nhiều. Bạn nên cố gắng hạn chế tên biến từ 15 kí tự trở xuống. Cuối cùng, trình biên dịch của bạn có thể làm việc tốt hơn.
    Lưu ý: Self-documenting code là một cách viết làm cho việc hiểu chuyện gì xảy ra trong chương trình dễ dàng hơn mà không cần dùng lời chú thích. Chọn tên biến tốt cũng là một cách hiệu quả tạo nên loại code này.

    Gán giá trị cho biến:

    Trong nhóm câu lệnh tiếp theo, tôi gán giá trị cho 6 biến tôi đã khai báo. Tôi sẽ đi vào vài phép gán và nói một ít về từng loại biến.

    Gán giá trị cho biến kiểu nguyên:
    Trong câu lệnh gán sau đây tôi gán giá trị 0 cho biến score.

    Mã:
    score = 0;
    Bây giờ biến score lưu giữ giá trị 0.
    Tôi gán giá trị cho biến bằng cách viết tên biến, sau đó ghi dấu =, tiếp theo là biểu thức (Vâng, 0 cũng là một biểu thức, kết quả của biểu thức là 0).

    Gán giá trị cho biến có dấu chấm động:
    Trong câu lệnh này tôi gán giá trị 1200.76 cho biến distance:

    Mã:
    distance = 1200.76;
    Vì distance là biến thuộc kiểu double, tôi có thể dùng nó để lưu số với phần thập phân, như những gì tôi đã làm.

    Gán giá trị cho biến kiểu kí tự (char):
    Trong câu lệnh tiếp theo, tôi gán kí tự “y” cho biến playAgain:

    Mã:
    playAgain = `y';
    Như tôi đã làm, bạn có thể gán kí tự cho biến có kiểu char bằng cách bao quanh kí tự bởi dấu ‘ ‘ (hyutars: hoặc “ “).
    Biến kiểu char có thể lưu giữ 128 kí tự trong bảng mã ASCII. ASCII là từ viết tắt của American Standard Code for Information Interchange, là các mã tương ứng với kí tự. Sau đây là bảng mã ASCII:

    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]
    [​IMG]

    Gán giá trị cho biến kiểu Boolean:
    Trong câu lệnh tiếp theo tôi gán giá trị true (đúng) cho biến shieldsUp:

    Mã:
    shieldsUp = true;
    Trong chương trình của tôi, nó có nghĩa là lượng Hp của người chơi được tăng lên.
    shieldsUp là biến kiểu bool, có nghĩa là biến kiểu Boolean. Nó có thể nhận giá trị true hoặc false. Hơi tò mò, muốn tìm hiểu thêm đúng không? Nhưng bạn nên chờ đến chương 2 “Truth, Branching, and the Game Loop: Guess My Number” (hyutars: mình hiểu nhưng mà bảo dịch ra thì khó quá >_<, truth có thể nói là đúng hay sai – true or false, Branching chẳng hạn như if else, switch, … đến chương 2 bạn sẽ hiểu hơn).

    Khởi tạo cho biến:

    Bạn có thể khai báo và gán giá trị cho biến chỉ trong một câu lệnh khởi tạo. Đó là chính xác những gì tôi làm tiếp theo đây:

    Mã:
    double engineTemp = 6572.89;
    Dòng này tạo ra một biến kiểu double và đặt tên nó là engineTemp, nó lưu giữ giá trị 6572.89.
    Cũng giống như việc khai báo nhiều biến trong một câu lệnh, bạn có thể khởi tạo nhiều hơn một biến trong cùng một câu lệnh. Bạn có thể vừa khai báo, vừa khởi tạo các biến khác nhau trong một câu lệnh duy nhất. Hãy viết theo kiểu mà bạn cảm thấy thoải mái!.
    Mẹo: Mặc dù bạn có thể khai báo mà không cần gán giá trị, nhưng bạn nên khởi tạo biến mới với một giá trị nào đó tùy vào bài toán. Nó sẽ làm cho đoạn mã của bạn rõ ràng hơn, thêm vào đó, nó loại trừ khả năng ta truy cập vào một biến chưa được khởi tạo – có thể gây ra lỗi.

    Hiển thị giá trị của biến:

    Để hiển thị giá trị của biến, bạn chỉ cần gửi nó đến cout. Đó là những gì tôi làm tiếp theo trong chương trình. Chú ý tôi không thử hiển thị biến shieldsUp vì bạn không thể hiển thị giá trị kiểu bool một cách bình thường.
    Lưu ý: Trong câu lệnh đầu tiên của phần này, tôi dùng thứ gọi là escape sequence – một cặp kí tự bắt đầu bằng dấu backslash (\) – có chức năng hiển thị các kí tự đặc biệt.

    Mã:
    cout << "\nscore:" << score << endl;
    Escape sequence tôi dùng là \n, nó có chức năng xuống dòng. Khi gửi đến cout như một phần của chuỗi, nó giống như chúng ta nhấn phím Enter trong cửa sổ console. Một escape sequence nữa cũng rất hữu dụng là \t, nó đóng vai trò như là phím tab.
    Còn một số escape sequence nữa, nếu bạn quan tâm thì hãy xem thêm bảng sau:

    [​IMG]

    Lấy giá trị nhập từ bàn phím:

    Cách khác để gán giá trị cho biến là thông qua thao tác nhập vào của người dùng. Tiếp theo, tôi gán giá trị cho biến mới: fuel dựa trên những gì mà người dùng nhập vào. Để làm việc này tôi dùng câu lệnh:

    Mã:
    cin >> fuel;
    Cũng như cout, cin là một đối tượng được định nghĩa trong thư viện iostream và dùng namespace std. Để lưu giữ giá trị cho biến, tôi dùng cin và dấu >>, tiếp theo là tên biến. Bạn cũng có thể dùng mẫu này để lấy giá trị người dùng nhập vào cho biến thuộc các kiểu dữ liệu cơ bản khác. Để chứng minh mọi thứ đều hoạt động bình thường, tôi hiển thị biến fuel cho người dùng.

    Đặt tên mới cho kiểu dữ liệu:

    Bạn có thể đặt tên mới cho kiểu dữ liệu. Chẳng hạn như tôi viết thế này:

    Mã:
    typedef unsigned short int ushort;
    Đoạn mã này đặt tên mới cho kiểu unsigned short int thành “ushort”. Để đặt tên mới cho kiểu dữ liệu, bạn dùng typedef, sau đó là tên kiểu dữ liệu, cuối cùng là tên mới của kiểu dữ liệu. typedef được dùng rất thường xuyên để tạo nên tên các tên ngắn cho kiểu dữ liệu có tên dài.
    Bạn có thể dùng tên mới của kiểu dữ liệu y như tên cũ của nó vậy. Tôi khởi tạo biến kiểu ushort (tức là kiểu unsigned short int) tên bonus và hiển thị giá trị của nó.

    Cách chọn kiểu dữ liệu:

    Bạn có rất nhiều lựa chọn khi lựa chọn kiểu dữ liệu cho biến. Vậy bạn nên chọn kiểu dữ liệu nào? Ừm, nếu bạn cần kiểu nguyên, bạn có thể dùng int. Vì nó đủ dùng cho đa số trường hợp, lượng bộ nhớ mà nó chiếm dụng cũng không nhiều và máy tính có thể sử dụng nó một cách hiệu quả. Nếu bạn cần một giá trị kiểu nguyên lớn hơn max của kiểu int hoặc giá trị của bạn không âm, bạn có thể dùng kiều unsigned int.
    Nếu bạn có bộ nhớ không được phong phú lắm, bạn có thể dùng các kiểu dữ liệu yêu cầu ít bộ nhớ hơn. Như thế nào đi nữa, hầu hết các máy tính, bộ nhớ không phải là một vấn đề quan trọng lắm (Lập trình game trong hệ console – chẳng hạn như game boy hay game di động là một chuyện hoàn toàn khác).
    Cuối cùng, nếu bạn cần một số dạng dấu chấm động – số thực, bạn có thể dùng kiểu float, ưu điểm của nó giống như kiểu int khi cần biến nguyên.
     
  7. red_strike

    red_strike C O N T R A

    Tham gia ngày:
    13/10/04
    Bài viết:
    1,722
    Nơi ở:
    Onikage Clone :)
    Anh Hyutars dịch hay lắm !

    Anh lưu lại phiên bản Word sau này gom thành cái ebook dạng PDF để các anh em khác tiện việc học hỏi tại nhà ^_^ !
     
  8. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Cám ơn, mình còn dịch dở lắm, đang tập tành mà :'>
    Cái này mình sẽ cho ra bản pdf complete khi mình hoàn thành cuốn sách, hiện giờ mới có mấy bài à
    Sau đây là bài tiếp theo, dạo này bận học thi, có lẽ dịch không nhanh được, anh em thông cảm nhé, hết ngày 7/1 là tui thi xong rồi ^^

    Bài 1.6 Sử dụng các toán tử số học với biến

    Một khi bạn có biến với giá trị, bạn sẽ muốn thay đổi nó trong quá trình hoạt động của game. Bạn có thể muốn cộng thêm bonus cho điểm của player vì tiêu diệt được boss chẳng hạn. Hay bạn muốn giảm mức oxy trong bình dưỡng khí. Bằng cách dùng các toán tử bạn đã được học (cộng thêm một số cái mới), bạn có thể giải quyết các vấn đề này.

    Giới thiệu chương trình Game Stats 2.0:

    Chương trình Game Stats 2.0 điều khiển các biến tái hiện game stats và hiển thị kết quả, hình 1.6 cho thấy chương trình đang hoạt động:


    [​IMG]
    Hình 1.6: Mỗi biến được thay đổi bởi một cách khác nhau.

    Thay đổi giá trị của biến:

    Sau khi tôi tạo ra biến lưu giữ số điểm của người chơi và hiển thị nó, tôi thay đổi điểm số bằng cách tăng nó lên 100.

    Câu lệnh gán này nói rằng nó lấy giá trị hiện tại của biến score, cộng 100, và gán kết quả ngược lại cho biến score. Vậy là, dòng lệnh này đã tăng giá trị của biến score thêm 100.

    Sử dụng toán tử gán kết hợp: (Using Combined Assignment Operators – hyutars: từ đây mình dùng từ combined assignment cho chuẩn nhé, hông biết dịch sao cho thỏa đáng, trong một số tài liệu ghi: cách viết khác của biểu thức gán, mình nghĩ dùng các thuật ngữ tiếng Anh cũng là một cách học để sau này đọc sách nước ngoài ta khỏi bỡ ngỡ)

    Đây là một cách viết ngắn hơn của dòng trên:

    Câu lệnh cho ra cùng một kết quả như score = score + 100. Toán tử += được gọi là toán tử combined assignment vì nó kết hợp giữa toán tử số học (trong trường hợp này là toán tử +) và assignment (gán ~ dấu =). Toán tử này là phương pháp tốc kí – “cho bất cứ cái gì ở bên phải vào bên trái và gán kết quả trở lại những gì ở bên trái”.
    Sau đây là bảng các combined assignment đối với các toán tử số học bạn đã gặp:

    [​IMG]

    Sử dụng toán tử tăng (Increment) và giảm (Decrement):

    Tiếp đến tôi dùng toán tử tăng (++), có tác dụng tăng giá trị của biển lên 1 đơn vị. Tôi dùng toán tử này để tăng giá trị của biến lives lên hai lần. Đầu tiên tôi dùng nó ở dòng này:

    Sau đó tôi dùng nó một lần nữa ở dòng này:

    Mỗi dòng đều có tác dụng cuối cùng như nhau, nó tăng giá trị của biến lives từ 3 lên 4.
    Như bạn có thể thấy, bạn có thể đặt toán tử trước và sau biến bạn muốn tăng. Khi bạn đặt toán tử trước biến, toán tử này được gọi là toán tử tăng tiền tố (prefix increment operator), khi bạn đặt nó sau biến, nó được gọi là toán tử tăng hậu tố (postfix increment operator).
    Đến đây, bạn có thể nghĩ rằng không có sự khác biệt nào giữa cách viết tiền tố và hậu tố, nhưng bạn đã sai. Trong tình huống mà bạn chỉ tăng giá trị của một biến (như bạn đã thấy), cả hai cách viết đều cho ra một kết quả cuối cùng như nhau. Nhưng trong các biểu thức phức tạp hơn, kết quả có thể khác.
    Để chỉ ra sự khác biệt quan trọng này, tôi cho ra một bộ tính sẽ thích hợp khi người chơi kết thúc màn (hầm – level). Tôi tính bonus (điểm thưởng) dựa vào số lives (mạng sống) mà người chơi có, và tôi cũng tăng số lives lên. Như thế nào đi nữa, tôi tổ chức bộ tính toán này theo hai cách. Đầu tiên, tôi dùng toán tử tăng tiền tố:

    Theo cách này, toán tử tăng giá trị của biến trước khi các yếu tổ khác của biểu thức ảnh hưởng đến biến. ++lives * 10 tương đương: đầu tiên tăng lives lên một đơn vị, và sau đó nhân kết quả với 10. Do đó, đoạn mã này tương đương 4 * 10 = 40. Nó có nghĩa là lives bây giờ là 4 và bonus là 40.
    Sau đó ta thiết đặt lại lives mang giá trị 3, tôi tính bonus lần nữa, lần này tôi dùng toán tử tăng hậu tố:

    Trong cách này, toán tử tăng giá trị của biến sau khi các yếu tố khác của biểu thức ảnh hưởng đến biến. lives ++ * 10 tương đương: nhân giá trị hiện tại của biến lives với 10. Tức là 3 * 10 = 30. Sau đó, giá trị của lives được tăng lên. Sau dòng lệnh này, lives có giá trị là 4 và bonus là 30.
    C++ cũng cung cấp toán tử giảm (--). Nó hoạt động giống như toán tử tăng, chỉ khác là nó giảm giá trị của biến đi 1 đơn vị. Nó cũng có hai cách viết là tiền tố và hậu tố.

    Xử lý tình huống biến kiểu nguyên xoay vòng (Dealing with Integer Wrap Around):

    Chuyện gì xảy ra nếu bạn tăng giá trị của biến kiểu nguyên lên cao hơn giá trị max của nó? Nó sẽ không phát sinh lỗi. Thay vào đó, giá trị “xoay vòng” đến giá trị nhỏ nhất của kiểu dữ liệu. Tiếp theo, tôi minh họa sự việc này. Đầu tiên tôi gán trị lớn nhất mà biến score có thể giữ:

    Sau đó tôi tăng giá trị của biến này lên:

    Như kết quả, score bây giờ mang giá trị 0 vì giá trị của nó đã được xoay vòng, giống như đồng hồ đo cây số của xe hơi khi nó vượt quá giá trị max của nó.

    [​IMG]
    Hình 1.7: Hình ảnh biểu tượng biến kiểu unsigned int “xoay vòng” từ giá trị max đến giá trị min của nó.

    Giảm biến kiểu nguyên xuống dưới mức min của nó thì nó sẽ “xoay vòng” đến giá trị max.
    Mẹo: Luôn chắc rằng chọn kiểu nguyên có kích thước đủ lớn phù hợp mục đích sử dụng.
     
  9. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài 1.7: Làm việc với hằng số (Constants)

    Hằng số là một giá trị không thay đổi mà tên của nó do bạn đặt. Hằng số rất hữu dụng nếu bạn có một giá trị không thay đổi và nó xuất hiện thường xuyên trong chương trình của bạn. Ví dụ, nếu bạn viết trò chơi bắn máy bay, mỗi kẻ địch có giá trị điểm là 150, bạn nên đặt một hằng số tên ALIEN_POINTS có giá trị là 150. Sau đó, bất cứ khi nào bạn cần giá trị đó, bạn có thể dùng ALIEN_POINTS thay cho giá trị 150.

    Hằng số có hai lợi ích. Thứ nhất, nó làm cho chương trình trong sáng dễ đọc hơn. Ngay khi bạn thấy ALIEN_POINTS, bạn đã biết nó có ý nghĩa gì. Nếu bạn bất chợt nhìn vào một đoạn mã và thấy số 150, bạn có thể sẽ không biết giá trị đó đề cập đến cái gì. Lợi ích thứ hai, dùng tên hằng như vậy sẽ rất thuận tiện khi bạn muốn thay đổi giá trị của nó. Ví dụ nhé, chẳng hạn bạn muốn thử nghiệm trò chơi của mình và bạn quyết định tăng giá trị của kẻ địch (hyutars: alien = người ngoài hành tinh, dịch kẻ địch cũng được ^^) lên 250. Với hằng số, tất cả những gì bạn phải làm chỉ là thay đổi dòng khởi tạo ALIEN_POINTS thành 250. Nếu không dùng hằng số, bạn sẽ phải tìm và thay đổi từng số 150 thành 250, nếu đoạn mã của bạn khoảng 1000 dòng thì … chậc chậc >_< …

    Giới thiệu chương trình Game Stats 3.0:

    Chương trình Game Stats 3.0 dùng hằng số thay cho giá trị. Đầu tiên chương trình tính điểm của người chơi, và sau đó nó tính mức phí cho việc nâng cấp bộ phận nào đó trong một game chiến thuật. Hình 1.8 cho thấy kết quả:


    [​IMG]
    Hình 1.8: Mỗi phép tính đều có sự tham gia của hằng số, nó làm cho đoạn code rõ ràng hơn.

    Mã:
    // Game Stats 3.0
    // Demonstrates constants
    
    #include <iostream>
    using namespace std;
    
    int main()
    {
        const int ALIEN_POINTS = 150;
        int aliensKilled = 10;
        int score = aliensKilled * ALIEN_POINTS;
        cout << "score: " << score << endl;
    
        enum difficulty {NOVICE, EASY, NORMAL, HARD, UNBEATABLE};
        difficulty myDifficulty = EASY;
    
        enum ship {FIGHTER = 25, BOMBER, CRUISER = 50, DESTROYER = 100};
        ship myShip = BOMBER;
        cout << "\nTo upgrade my ship to a Cruiser will cost "
             << (CRUISER - myShip) << " Resource Points.\n";
        return 0;
    
    }
    Dùng Hằng số:

    Tôi định nghĩa hằng số, ALIEN_POINTS, để nó nhận giá trị của một kẻ địch:

    Mã:
    const int ALIEN_POINTS = 150;
    Tôi dùng keyword const để định nghĩa hằng số. Bây giờ tôi có thể dùng ALIEN_POINTS như một số nguyên bình thường. Bạn có thể để ý thấy, tên tôi chọn cho hằng số toàn là chữ hoa. Đó là một thói quen, nhưng rất phổ biến. Tên được đặt toàn bằng kí tự hoa nói với lập trình viên khác rằng: nó là một hằng số.

    Tiếp theo tôi dùng hằng số trong dòng này:

    Mã:
    int score = aliensKilled * ALIEN_POINTS;
    Tôi tính điểm của người chơi bằng cách nhân số kẻ địch đã tiêu diệt với giá trị điểm của một kẻ địch. Dùng hằng số ở đây giúp cho dòng mã khá rõ ràng.

    Bẫy: Bạn không thể dùng phép gán một giá trị mới cho một hằng số. Nếu bạn thử, lỗi sẽ phát sinh.

    Dùng Enumerations (Bảng liệt kê):

    Enumeration là tập hợp của các hằng số kiểu unsigned int, gọi là enumerator (Phần tử liệt kê). Thường thì enumerator liên quan với nhau và có một thứ tự nhất định. Sau đây là một ví dụ của enumeration:

    Mã:
    enum difficulty {NOVICE, EASY, NORMAL, HARD, UNBEATABLE};
    Nó định nghĩa một enumeration tên difficulty. Mặc định, giá trị của enumerator đầu tiên là 0 và các giá trị sau tăng lên 1. Ở dòng code trên, NOVICE là 0, EASY là 1, NORMAL là 2, HARD là 3, và UNBEATABLE là 4. Để định nghĩa một enumeration, dùng keyword enum, sau đó là tên của nó, tiếp theo là danh sách các enumerator giữa hai dấu { }.

    Tiếp theo tôi tạo một biến, kiểu của nó là enumeration tôi đã tạo.

    Mã:
    difficulty myDifficulty = EASY;
    Biến myDifficulty được đặt là EASY (có giá trị = 1). myDifficulty thuộc kiểu difficulty, cho nên nó chỉ có thể giữ một trong các giá trị mà bạn đã định nghĩa trong enumeration. Nó có nghĩa là, myDifficulty chỉ có thể được gán các giá trị NOVICE, EASY, NORMAL, HARD, UNBEATABLE, 0, 1, 2, 3, hay 4.

    Tiếp theo tôi định nghĩa một enumeration khác:

    Mã:
    enum ship {FIGHTER = 25, BOMBER, CRUISER = 50, DESTROYER = 100};
    Dòng code này định nghĩa enumeration ship, nó đề cập đến 4 loại ship (tàu) trong game chiến thuật. Trong nó, tôi gán các giá trị kiểu nguyên cho một số enumerator. Các chữ số là giá trị Resource Point (tài nguyên) của mỗi ship. Bạn có thể gán giá trị cho enumerator nếu bạn muốn. Bất kì enumerator nào không được gán giá trị sẽ nhận giá trị của enumerator đứng trước nó cộng thêm 1. Vì tôi không gán giá trị cho BOMBER, nó sẽ mang giá trị 26.

    Tiếp theo tôi định nghĩa một biến kiểu enumeration:

    Mã:
    ship myShip = BOMBER;
    Sau đó tôi mô tả cách thức dùng enumerator trong tính toán số học:

    Mã:
    (CRUISER - myShip)
    Code trên có chức năng tính mức phí để nâng cấp từ BOMBER lên CRUISE. Phép tính này tương đương 50 – 26 = 24.
     
  10. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài 1.8: Giới thiệu chương trình LOST FORTUNE

    Project cuối cùng trong chương này, Lost Fortune (Kho báu bị mất), là một đoạn mã nhận dạng người chơi thường thấy trong các game nhập vai, người chơi sẽ nhập vào thông tin của mình (gồm cả tên), sau đó máy tính sẽ dùng nó in ra màn hình một cốt truyện. Hình 1.9 cho thấy kết quả:


    [​IMG]
    Hình 1.9: Câu chuyện được xâu dựng dựa trên thông tin người chơi cung cấp.

    Thay vì giới thiệu cả đoạn code một lần, tôi sẽ đi vào từng phần nhỏ.

    Cài đặt chương trình:

    Đầu tiên tôi viết vài câu chú thích, sau đó include hai file thư viện, và viết vài chỉ thị:

    Mã:
    // Lost Fortune
    // A personalized adventure
    
    #include <iostream>
    #include <string>
    
    using std::cout;
    using std::cin;
    using std::endl;
    using std::string;
    Tôi include file string, một phần của thư viện chuẩn, để tôi có thể dùng các đối tượng trong string (chuỗi) để truy cập đến chuỗi thông qua biến (hơi rối nhưng đọc đoạn mã dưới bạn sẽ hiểu). Có rất nhiều đối tượng trong string, nhưng các bạn đừng vội. Bạn sẽ học kĩ về chúng trong chương 3: “Vòng lặp For, Chuỗi, và mảng: Word Jumble.”.

    Tôi dùng chỉ thị để giải thích các đối tượng trong namespace std mà tôi định truy cập. Bạn có thể thấy string trong namespace std.

    Lấy thông tin từ người chơi:

    Tiếp theo tôi lấy một số thông tin từ người chơi:

    Mã:
    int main()
    {
        const int GOLD_PIECES = 900;
        int adventurers, killed, survivors;
        string leader;
    
        //get the information
        cout << "Welcome to Lost Fortune\n\n";
        cout << "Please enter the following for your personalized adventure\n";
        cout << "Enter a number: ";
        cin >> adventurers;
    
        cout << "Enter a number, smaller than the first: ";
        cin >> killed;
    
        survivors = adventurers - killed;
    
        cout << "Enter your name: ";
        cin >> leader;
    GOLD_PIECES là một hằng số có chức năng lưu giữ số vàng mà người chơi tìm ra. Biến adventurers lưu giữ số người phiểu lưu trong câu chuyện. Biến killed lưu giữ số người chết trong chuyến phiêu lưu. Tôi tính biến survivors cho số người còn sống sót. Cuối cùng, tôi lấy thông tin về tên của người chơi, người mà tôi truy xuất thông qua biến leader.

    Bẫy: Nếu bạn dùng cin để lấy chuỗi từ người chơi, bạn chỉ có thể lấy chuỗi không có kí tự trắng (như phím space hoặc tab). Có cách để giải quyết vấn đề này, nhưng nó cần phải bàn tới một thứ gọi là streams, có lẽ nó vượt quá tầm kiến thức của chương này. Cho nên, tạm thời bạn cứ dùng cin, và nhớ phạm vi hoạt động của nó trong việc lấy chuỗi.

    Kể chuyện:

    Tiếp theo tôi chèn các biến để kể câu chuyện này:

    Mã:
    //tell the story
       cout << "\nA brave group of " << adventurers << " set out on a quest ";
       cout << "-- in search of the lost treasure of the Ancient Dwarves. ";
       cout << "The group was led by that legendary rogue, " << leader << ".\n";
    
       cout << "\nAlong the way, a band of marauding ogres ambushed the party. ";
       cout << "All fought bravely under the command of " << leader;
       cout << ", and the ogres were defeated, but at a cost. ";
    
       cout << "Of the adventurers, " << killed << " were vanquished, ";
       cout << "leaving just " << survivors << " in the group.\n";
    
       cout << "\nThe party was about to give up all hope. ";
       cout << "But while laying the deceased to rest, ";
       cout << "they stumbled upon the buried fortune. ";
       cout << "So the adventurers split " << GOLD_PIECES << " gold pieces.";
       cout << leader << " held on to the extra " << (GOLD_PIECES % survivors);
       cout << " pieces to keep things fair of course.\n";
    
       return 0;
    }
    Đoạn code khá rõ ràng. Tôi tính số lượng vàng mà người đứng đầu (leader) giữ, tôi dùng toán tử chia lấy dư trong biểu thức GOLD_PIECES % survivors. Biểu thức này tương đương với số dư của phép tính GOLD_PIECES / survivors. Người đứng đầu sẽ nhận thêm số dư này sau khi đã chia đều cho số người sống sót (kể cả người đứng đầu).
    (hyutars: Tới đây là xong rồi, có cần dịch câu chuyện không nhỉ … thôi dịch thoáng qua nhé, thực ra nó không quan trọng lắm. Đầu tiên nó bắt bạn nhập số người tham gia chuyến phiêu lưu, sau đó nhập một số bé hơn số vừa rồi (tức là số người chết), số còn sống sót là hiệu số của hai số trên. Câu chuyện thế này, một nhóm người tổ chức đi tìm kho báu bị mất, với dự dẫn đầu của leader – tên mà bạn nhập, sau đó họ gặp một toán ogre – quỷ nên giao chiến, chết một mớ, đúng lúc họ chán nản, nghỉ ngơi thì gặp kho báu, sau khi chia đều còn dư chút ít, thôi tui (leader) chịu khó nhận luôn :D ).
     
  11. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Tóm tắt:

    Trong chương 1, bạn đã học được các khái niệm sau đây:
    - C++ là ngôn ngữ lập trình bậc cao, nhanh, mạnh, được sử dụng phổ biến để lập trình games.
    - Chương trình là một dãy các câu lệnh trong C++.
    - Các yếu tố của ngôn ngữ C++ là ý tưởng, kế hoạch, mã nguồn, file object, thực thi.
    - Lỗi chương trình thường rơi vào các trường hợp: lỗi compile (biên dịch), lỗi link (liên kết), và lỗi run-time.
    - Chỉ thị #include ra lệnh bộ chọn trước include (bao gồm) một file vào file hiện hành.
    - Thư viện chuẩn là một tập hợp các file mà bạn include vào file chương trình để làm một số chức năng (hàm) gì đó.
    - Hàm (function) là một nhóm code có chức năng thực hiện công việc nào đó và sau đó trả về (return) một giá trị.
    - Mọi chương trình phải có hàm main(), đây là điểm bắt đầu của chương trình.
    - iostream - một phần của thư viện chuẩn, là một file chứa code giúp cho việc nhập xuất.
    - Namespace std chứa các công cụ từ thư viện chuẩn. Để truy cập đến các yếu tố từ namespace, bạn cần đặt tiền tố std:: ở phía trước hoặc dùng using.
    - cout là một object, định nghĩa trong file iostream, nó dùng để gửi dữ liệu đến lối ra (thường là màn hình máy tính).
    - cin là một object, định nghĩa trong file iostream, nó dùng để lấy dữ liệu từ lối vào (thường là bàn phím).
    - C++ được cài đặt sẵn các toán tử số học, như phép cộng, trừ, nhân, chia – và các toán tử không quen thuộc lắm nếu bạn chưa học lập trình (%).
    - C++ có các kiểu dữ liệu cơ bản là Boolean, char, integer, và double, float.
    - Thư viện chuẩn của C++ cung cấp object string dùng cho các chuỗi.
    - Bạn có thể dùng typedef để tạo tên mới cho kiểu dữ liệu đã có.
    - Hằng số là tên đại diện của một giá trị không đổi.
    - Enumeration là một chuỗi các hằng số kiểu unsigned int.
     
  12. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Hỏi Đáp:

    Hỏi:
    1. Tại sao các công ty games dùng C++?
    2. C++ khác C chỗ nào?
    3. Tại sao tôi nên dùng chú thích (comments)?
    4. Khối chương trình là gì? (Programming block)
    5. Cảnh báo của trình biên dịch là gì? (compiler warning)
    6. Tôi có thể bỏ qua compiler warnings được không?
    7. Khoảng trắng (white space) là gì?
    8. Tại sao hàm main() của chương trình trả lại giá trị kiểu int?
    9. Literals là gì?
    10. Tại sao tôi luôn nên khởi tạo một biến mới với một giá trị?
    11. Tại sao lập trình viên nhiều khi dùng tên biến như myInt hay myFloat?
    12. Biến kiểu bool dùng làm cái gì?
    13. Tên “bool” bắt nguồn từ đâu?
    14. Có phải bắt buộc đặt tên bằng chữ hoa cho các hằng số không?
    15. Làm thế nào để tôi có thể lưu giữ nhiều hơn 1 kí tự trong một biến?
    Đáp:
    1. C++ có tốc độ cao, truy cập được đến các phần cứng bậc thấp, nó hữu dụng hơn các ngôn ngữ khác. Thêm nữa, đa số các công ty games có rất nhiều resources (tài nguyên) của C++ (chẳng hạn như code có thể dùng lại được và kinh nghiệm của lập trình viên).
    2. C++ là bản cải tiến của C. C++ có tất cả những gì mà C có. Như thế nào đi nữa, C++ cung cấp cho chúng ta những phương pháp mới để làm một công việc nào đó, thay thế các phương pháp cổ điển máy móc trong C. Thêm nữa, C++ cung cấp thêm khả năng viết chương trình theo hướng đối tượng.
    3. Để giải thích cho các đoạn code khó hiểu. Bạn không nên chú thích những thứ đã quá rõ ràng.
    4. Là một hay nhiều câu lệnh được bao gộp bởi hai dấu { } tạo thành một khối thống nhất.
    5. Là một thông báo từ trình biên dịch của bạn về lỗi tiềm tàng. Warning sẽ không dừng quá trình biên dịch.
    6. Bạn có thể, nhưng bạn không nên. Bạn nên tìm những warning và sửa nó.
    7. Một tập hợp các kí tự không in ra được tạo nên các khoảng cách trong source file của bạn, bao gồm tabs, spaces, và xuống dòng.
    8. Vì đó là cái chuẩn ISO khuyên làm. Trên thực tế, bạn có thể trả về một giá trị khác 0 để chương trình kết thúc, nhưng nó rất hiếm.
    9. Yếu tố tái hiện lại các giá trị đã rõ ràng. “Game Over!” là literal string, trong khi 32 và 98.6 là literal số học.
    10. Vì nội dung của các biến chưa được khởi tạo có thể là một giá trị nào đó – nó có thể ảnh hưởng đến chương trình của bạn.
    11. Để cho thấy rõ ràng kiểu của biến. Thường thì cái này dùng thường xuyên trong các chương trình hướng dẫn.
    12. Chúng tái hiện điều kiện đúng hoặc sai, như kho báu đã được mở hay chưa, card được úp hay mở.
    13. Tên kiểu dữ liệu này được lấy từ tên của nhà toán học người Anh George Boole.
    14. Không. Dùng chữ hoa chỉ là một thông lệ, nhưng bạn nên dùng vì đó là điều những lập trình viên khác mong đợi.
    15. Dùng object string.
     
  13. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Câu hỏi thảo luận:

    1. Những đặc điểm hữu ích của C++ giúp cho các lập trình viên?
    2. Ưu điểm và khuyết điểm của việc dùng chỉ thị using?
    3. Ưu điểm của việc định nghĩa một tên mới cho kiểu dữ liệu có sẵn?
    4. Có hai cách viết (trước, sau) của toán từ tăng/giảm (++/--), sự khác biệt giữa chúng là gì?
    5. Hằng số giúp ích cho chương trình của bạn như thế nào?
     
  14. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài tập:

    1. Hãy tạo một list 6 tên biến hợp lệ - 3 tốt và 3 xấu. Giải thích vì sao tên đó xấu/tốt.
    2. Kết quả xuất ra ở mỗi dòng của đoạn code sau đây là gì? Giải thích?

    cout << "Seven divided by three is " << cout 7 / 3 << endl;
    cout << "Seven divided by three is " << cout 7.0 / 3 << endl;
    cout << "Seven divided by three is " << cout 7.0 / 3.0 << endl;


    3. Viết một chương trình có chức năng lấy điểm số của 3 người chơi (nhập từ bàn phím), sau đó xuất ra màn hình số trung bình của nó.

    Kết thúc chương I
     
  15. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Trùi ui bị hư USB, mới mua cái mới để đem bài lên đây, dạo này học thi bị stress, còn một môn vào ngày 7 tháng 1 nữa ... tới lúc đó sẽ dịch thường xuyên hơn
    Chương 2: Truth (true & false), Nhánh, và Game Loop(vòng lặp) – Guess My Number

    Tổng quan:

    Cho đến bây giờ, các chương trình mà bạn đã thấy đều thuộc dạng tuyến tính – mỗi câu lệnh được thực hiện theo thứ tự từ trên xuống dưới. Nhưng, để tạo nên một game hấp dẫn, bạn cần phải viết được chương trình có khả năng thi hành (hoặc bỏ qua) một đoạn code căn cứ vào điều kiện nào đó. Đó chính là chủ đề chính của chương này. Cụ thể, bạn sẽ học:
    - Hiểu truth.
    - Dùng câu lệnh if để phân nhánh các đoạn code.
    - Dùng câu lệnh switch để chọn đoạn code cần thi hành.
    - Dùng vòng lặp while và do để lặp lại một đoạn code nào đó.
    - Tạo nên một số ngẫu nhiên.
     
  16. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài 2.1 Hiểu Truth

    Truth là trắng và đen. Bạn có thể tái hiện lại giá trị đúng và sai với từ khóa tương ứng với chúng, true và false. Bạn có thể lưu giá trị kiểu Boolean vào một biến kiểu bool, như bạn đã thấy ở chương 1. Ví dụ nè:

    Mã:
    bool fact = true, fiction = false;
    Đoạn code tạo nên hai biến kiểu bool, fact và fiction. fact là true (đúng) và fiction là false (sai). Bên cạnh từ khóa true và false dễ sử dụng, các biểu thức và giá trị cũng có thể thể hiện giá trị true và false. Các giá trị khác 0 sẽ thể hiện giá trị true, trong khi 0 sẽ thể hiện giá trị false.
    Biểu thức thể hiện lại giá trị true và false thường là biểu thức so sánh thứ gì đó. Sự so sánh được sử dụng khá thường xuyên với các toán tử liên quan. Bảng 2.1 sẽ cho chúng ta thấy vài toán tử và ví dụ của chúng.

    [​IMG]

    hyutars: Chốt lại, Truth là true or false, đúng hoặc sai. 0 là false, các giá trị khác 0 là true, biểu thức so sánh là rất thường dùng để rút ra giá trị true or false.

    Bài 2.2 Dùng câu lệnh if:

    Okay, bây giờ là lúc đem khái niệm true và false ra ứng dụng. Bạn có thể dùng câu lệnh if để kiểm tra xem biểu thức trả về giá trị true hay false và thi hành một đoạn code dựa vào đó. Sau đây là cú pháp đơn giản của câu lệnh if:

    Nếu biểu thức là true, sau đó câu lệnh sẽ được thi hành. Ngược lại, câu lệnh sẽ bị bỏ qua và chương trình rẽ nhánh đến câu lệnh phía sau khối lệnh if. (hyutars: Nếu đúng thì làm, nếu sai thì bỏ qua không làm)

    Lưu ý: Bất cứ khi nào bạn thấy từ “câu lệnh;” như trong cú pháp trên, bạn có thể thay nó bằng một câu lệnh đơn hoặc một khối lệnh (các câu lệnh ở giữa hai dấu { }).

    Giới thiệu chương trình Score Rater:

    Chương trình Score Rater đưa ra những lời bình luận về số điểm của người chơi – dùng câu lệnh if. Hình 2.1 cho thấy chương trình đang chạy.

    [​IMG]
    Hình 2.1 – Lời bình luận xuất hiện (hay không xuất hiện) dựa trên các câu lệnh if khác nhau.

    Mã:
    // Score Rater
    // Demonstrates the if statement
    
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        if (true)
            cout << "This is always displayed.\n\n";
    
        if (false)
            cout << "This is never displayed.\n\n";
    
        int score = 1000;
    
        if (score)
            cout << "Okay, at least you didn't score zero.\n\n";
    
        if (score > 500)
            cout << "You scored over 500. Nice.\n\n";
    
        if (score == 1000)
        {
            cout << "You scored a perfect 1000!\n";
            cout << "Now that's impressive.\n";
        }
    
        if (score > 500)
        {
            cout << "You scored at least 500.\n";
            if (score >= 1000)
               cout << "You scored 1000 or more!\n";
        }
        return 0;
    }
    Thử nghiệm true và false:

    Trong câu lệnh if đầu tiên tôi thử nghiệm giá trị true. Vì trong điều kiện (biểu thức) của câu lệnh if trả về giá trị true, chương trình sẽ hiển thị lời bình luận, This is always displayed (Dòng này luôn được hiển thị).

    Mã:
    if (true)
        cout << "This is always displayed.\n\n";
    Trong câu lệnh if tiếp theo tôi thử giá trị false. Tất nhiên, do điều kiện của câu lệnh if trả về giá trị false, dòng bình luận sẽ không báo giờ xuất hiện, This is never displayed.

    Mã:
    if (false)
        cout << "This is never displayed.\n\n";
    Bẫy: Chú ý bạn không dùng dấu chấm phẩy phía sau dòng if (…). Nếu bạn đặt dấu chấm phẩy phía sau nó, bạn sẽ tạo một câu lệnh if trống, nó sẽ không làm gì cả. Sau đây là ví dụ:

    Mã:
    if (false);
        cout << "This is never displayed.\n\n";
    Khi bạn thêm dấu chấm phẩy phía sau if (false), câu lệnh phía trên sẽ tương đương:

    Mã:
    if (false)
           ; // tạo nên một câu lệnh trống, không làm gì cả
    cout << "This is never displayed.\n\n";
    Tất cả những gì phía sau câu lệnh if (phần được thực thi nếu điều kiện đúng) chỉ là khoảng trắng. Vấn đề đã được làm rõ. Câu lệnh if có điều kiện false bỏ qua khối lệnh phía sau (khối lệnh chỉ có khoảng trắng). Sau đó chương trình tiếp tục con đường của nó, thực hiện code phía sau if, tức là nó sẽ hiển thị dòng This is never displayed.

    Hãy cẩn trọng với lỗi này. Nó rất khó phát hiện vì chương trình sẽ chẳng báo lỗi gì cả.

    Phiên dịch giá trị thành true hay false:

    Bạn có thể phiên dịch mọi giá trị thành true hay false. Tất cả các giá trị khác 0 được hiểu là true, trong khi 0 được hiểu là false. Tôi thử nghiệm lại trong câu lệnh if tiếp theo:

    Mã:
    if (score)
        cout << "Okay, at least you didn't score zero.\n\n";
    score có giá trị 1000, vì nó khác 0 nên nó được hiểu là true. Kết quả, nó sẽ hiện thị lời thông báo Okay, at least you didn't score zero.

    Dùng các toán từ quan hệ:

    Có thể biểu thức mà bạn thường dùng nhất với câu lệnh if là biểu thức so sánh (dùng các toán tử quan hệ). Đó là những gì tôi minh họa tiếp theo. Đầu tiên, tôi thử nghiệm xem score có lớn hơn 500 không.

    Mã:
    if (score > 500)
        cout << "You scored over 500. Nice.\n\n";
    Vì score lớn hơn 500, chương trình sẽ hiện thị lời bình luận, You scored over 500. Nice.
    Tiếp theo, tôi thử xem score có bằng 1000 không.

    Mã:
    if (score == 1000)
    {
        cout << "You scored a perfect 1000!\n";
        cout << "Now that's impressive.\n";
    }
    Vì score có giá trị bằng 1000, khối lệnh sẽ được thực hiện và cả hai chuỗi đều được hiển thị. Nếu score không phải 1000 thì không có dòng bình luận nào được hiển thị cả, và chương trình sẽ tiếp tục với các câu lệnh phía dưới khối lệnh.

    Bẫy: Toán từ quan hệ “bằng” là = = (hai dấu bằng trong một hàng). Đừng có nhầm nó với dấu = (toán từ gán). (hyutars: mình từng sai nhiều chỗ bởi cái lỗi này >_<).
    Chương trình sẽ không báo lỗi, vì nó chẳng làm gì sai cả, và kết quả có thể không phải là những gì bạn mong đợi. Hãy xem code này:

    Mã:
    int score = 500;
    if (score = 1000)
        cout << "You scored a perfect 1000!\n";
    Ở kết quả của code này, score được gán thành 1000 và dòng bình luận, You scored a perfect 1000! sẽ được hiển thị. Sau đây là những gì đã xảy ra: Mặc dù score có giá trị 500 trước câu lệnh if, nhưng nó đã bị thay đổi. Chỗ (score = 1000) đã làm cho biến score được gán giá trị 1000. Biểu thức điều kiện của câu lệnh if lúc này trả về giá trị 1000, tức là giá trị khác 0, do đó nó tương ứng giá trị true. Kết quả, dòng bình luận được hiển thị.
    Cẩn thận với lỗi này, nó sẽ làm bạn đau đầu khi check lỗi đó. (hyutars <-- kinh nghiệm đau thương T_T).

    Lồng các câu lệnh if vào nhau:

    Câu lệnh if có thể làm chương trình thực thi câu lệnh hay một khối lệnh, trong đó gồm các câu lệnh if khác. Khi bạn viết một câu lệnh if bên trong câu lệnh if khác, nó gọi là “Lồng vào nhau”(nesting). Trong đoạn code tiếp theo, câu lệnh if bắt đầu với if (score >= 1000) được lồng bên trong câu lệnh if bắt đầu với (score > 500).

    Mã:
    if (score > 500)
    {
        cout << "You scored at least 500.\n";
        if (score >= 1000)
        cout << "You scored 1000 or more!\n";
    }
    Vì score lớn hơn 500, chương trình đi vào thực hiện khối lệnh bên trong câu lệnh if đầu tiên, và nó hiện thị lời bình luận You scored at least 500. Sau đó, ở câu lệnh if bên trong, chương trình so sánh score với 1000. Vì score “lớn hơn hoặc bằng” với 1000 (trường hợp này nó rơi vào “bằng”), chương trình hiển thị lời bình luận, You scored 1000 or more! Sau đó chương trình tiếp tục các câu lệnh phía sau khối lệnh.

    Lưu ý: Bạn có thể lồng vào bao nhiều câu lệnh if tùy ý. Nhưng, nếu bạn lồng quá nhiều, code sẽ rất khó đọc. Tóm lại, bạn nên lồng các câu lệnh vào nhau ở một mức độ vừa phải.
     
  17. Nguyen_Kain

    Nguyen_Kain Quậy hết mình Moderator

    Tham gia ngày:
    28/5/04
    Bài viết:
    1,299
    Sau 1 quá trình theo dõi và nhận xét , thì topic này rất hữu ích , cảm ơn bạn đã đóng góp , mình sẽ stick topic này lên để bạn có thể tiếp tục đóng góp thuận tiện , và nếu như bạn cố gắng , chắc chắn nó sẽ được đưa vào hộp lưu trữ ! ;)
     
  18. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Cám ơn đã động viên ::)
    Chiều nay mới thi xong môn cuối cùng, từ nay sẽ up thường xuyên cho anh em hơn ^^.

    Bài 2.3: Dùng mệnh đề else

    Bạn có thể thêm mệnh đề else vào sau câu lệnh if, chức năng của else là cho câu lệnh (hay khối lệnh) trong nó được thực hiện nếu biểu thức kiểm tra trong if là false. Sau đây là dạng tổng quát:

    Mã:
    if (biểu thức)
        câu lệnh 1; // hoặc khối lệnh
    else
        câu lệnh 2; // hoặc khối lệnh
    Nếu biểu thức là true, câu lệnh 1 sẽ được thực hiện. Sau đó chương trình sẽ bỏ qua câu lệnh 2 và thực hiện các câu lệnh sau khối if. Nếu biểu thức là false, câu lệnh 1 sẽ bị bỏ qua và câu lệnh 2 sẽ được thi hành. Sau khi câu lệnh 2 được thực thi xong, chương trình sẽ xử lý các câu lệnh sau khối if.

    Giới thiệu chương trình Score Rater 2.0:

    Chương trình Score Rater cũng làm chức năng bình chọn điểm, do người dùng nhập vào. Nhưng lần này, chương trình dùng câu lệnh if kết hợp với else. Hình 2.2 và 2.3 cho thấy hai thông điệp khác nhau được chương trình cho hiển thị tùy vào số điểm mà người dùng nhập vào.

    [​IMG]
    Hình 2.2 – Nếu người dùng nhập vào điểm số nhiều hơn 500, người đó sẽ được chúc mừng.

    [​IMG]
    Hình 2.3 – Nếu người dùng nhập vào số điểm nhỏ hơn hoặc bằng 500, người đó sẽ được thông báo: chẳng có gì đáng để tự hào cả.

    Mã:
    // Score Rater 2.0
    // Demonstrates the else clause
    
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        int score;
        cout << "Enter your score:";
        cin >> score;
    
        if (score > 500)
            cout << "\nYou got over 500. Nice score.\n";
        else
            cout << "\nYou got 500 or less. Nothing to brag about.\n";
        return 0;
    }
    Tạo hai đường rẽ nhánh:

    Bạn đã thấy phần đầu tiên của câu lệnh if, và nó hoạt động cũng giống như trước thôi. Nếu score (điểm số) lớn hơn 500, thông điệp You got over 500. Nice score, được hiển thị.

    Mã:
    if (score > 500)
        cout << "\nYou got over 500. Nice score.\n";
    Và đây là cái mới. Mệnh đề else cho phép chương trình rẽ nhánh vào nếu điều kiện của câu lệnh if là false. Cho nên if (score > 500) là false, chương trình bỏ qua thông điệp đầu tiên và thay vào đó, thông điệp You got 500 or less. Nothing to brag about. được hiển thị.

    Mã:
    else
        cout << "\nYou got 500 or less. Nothing to brag about.\n";
    Kết hợp mệnh đề else cho đúng với câu lệnh if:

    Cẩn thận, vì else sẽ kết hợp với câu lệnh if ở gần nó nhất. Nếu bạn không cẩn thận, nó có thể dẫn đến lỗi logic và kết quả không như ý. Sau đây là đoạn code ví dụ (không thuộc chương trình Score Rater) :

    Mã:
    if (false)
        if (true)
            cout << "This will never be displayed.";
    else
        cout << "This will always be displayed.";

    Nếu bạn nhìn thoáng qua, bạn có thể tưởng thông điệp This will always be displayed sẽ luôn được hiển thị. Nhưng thực tế, chuyện đó sẽ không bao giờ xảy ra vì else không kết hợp với if (false), nó kết hơp với if (true). Bằng cách thêm một khoảng trắng, bạn có thể thấy rõ đoạn code này hoạt động thế nào:

    Mã:
    if (false)
        if (true)
            cout << "This will never be displayed.";
        else
            cout << "This will always be displayed.";

    Tôi không hề thay đổi ý nghĩa của đoạn code (nên nhớ, khoảng trắng chỉ có ý nghĩa với con người), tôi chỉ làm cho đoạn code rõ ràng hơn. Vì điều kiện câu lệnh if bên ngoài là false, khối lệnh bên trong nó không bao giờ được thi hành, không có thông điệp nào được hiển thị cả.
    Tôi có thể giải quyết vấn đề này bằng cách thêm hai dấu ngoặc móc.

    Mã:
    if (false)
    {
        if (true)
            cout << "This will never be displayed.";
    }
    else
        cout << "This will always be displayed.";
    Kết quả, câu lệnh if thứ hai được đặt vào một thế giới nhỏ hơn (gọi là phạm vi - scope) bên trong khối lệnh, và mệnh đề else kết hợp với if (false). Bây giờ đoạn code sẽ luôn hiển thị thông điệp This will always be displayed.

    Lưu ý: Khái niêm scope khá quan trọng, nhưng tôi sẽ dành nó cho Chương 5. Bây giờ, các bạn cứ nghĩ scope là một thế giới nhỏ hơn.
     
  19. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài 2.4 : Dùng câu lệnh switch:

    Bạn có thể dùng câu lệnh switch để tạo nên nhiều điểm rẽ nhánh trong đoạn code. Sau đây là cú pháp:

    Mã:
    switch (choice)
    {
    case value1: statement1;
                   break;
    case value2: statement2;
                   break;
    
    case value3: statement3;
                   break;
               .
               .
               .
    case valueN: statementN;
                   break;
    default:  statementN + 1;
    }
    hyutars: choice: lựa chọn, value: giá trị, statement: câu lệnh (hoặc khối lệnh, lưu ý phải có dấu {}), default: mặc nhiên, mặc định.

    Câu lệnh kiểm tra lần lượt giá trị của choice với value1, value2, và value3. Nếu choice tương đương với giá trị nào, chương trình sẽ thực hiện câu lệnh (khối lệnh) tương ứng. Khi chương trình gặp câu lệnh break, nó sẽ thoát khỏi cấu trúc switch. Nếu choice không tương đương value nào cả thì câu lệnh ở chỗ default sẽ được thực hiện.
    Dùng break và default là tùy ý, không bắt buộc. Nếu bạn không dùng break, chương trình sẽ tiếp tục thực hiện các câu lệnh tiếp theo cho đến khi nó gặp break hoặc default hoặc cho đến khi câu lệnh switch kết thúc. Thường thì bạn dùng một câu lệnh break cho mỗi case. Và mặc dù default là tùy ý, nhưng bạn nên dùng nó, có nó thì chương trình của bạn sẽ bao quát được tất cả các trường hợp.
    Sau đây là ví dụ. Giả sử choice có giá trị bằng value2. Đầu tiên chương trình sẽ thử so sánh choice với value1. Vì chúng không bằng nhau, chương trình sẽ tiếp tục. Tiếp theo, chương trình sẽ so sánh choice với value2. Vì chúng bằng nhau nên chương trình sẽ thực hiện statement2. Sau đó chương trình gặp câu lệnh break và thoát khỏi khối switch.

    Bẫy: Bạn chỉ được dùng câu lệnh switch để kiểm tra giá trị thuộc kiểu int (hoặc giá trị có thể xem như là int, như char hay enumerator). Câu lệnh switch không hoạt động với các kiểu dữ liệu khác.

    Giới thiệu chương trình Menu Chooser:

    Chương trình Menu Chooser tái hiện lại một menu các mức độ khó của trò chơi và yêu cầu người chơi chọn. Nếu người chơi nhập vào số tương ứng với các lựa chọn (choice) trong menu, anh ta sẽ nhận được thông điệp xác nhận lại lựa chọn. Nếu người chơi nhập vào số khác, anh ta sẽ được thông báo rằng đã nhập sai. Hình 2.4 cho thấy chương trình đang hoạt động:

    [​IMG]
    Hình 2.4 – Người chơi chọn mức độ Easy.

    Mã:
    // Menu Chooser
    // Demonstrates the switch statement
    
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        cout << "Difficulty Levels\n\n";
        cout << "1 - Easy\n";
        cout << "2 - Normal\n";
        cout << "3 - Hard\n\n";
    
        int choice;
        cout << "Choice:";
        cin >> choice;
    
        switch (choice)
        {
        case 1:
                cout << "You picked Easy.\n";
                break;
        case 2:
                cout << "You picked Normal.\n";
                break;
        case 3:
    
                cout << "You picked Hard.\n";
                break;
        default:
                cout << "You made an illegal choice.\n";
        }
        return 0;
    }
    Tạo nên nhiều đường rẽ nhánh:

    Câu lệnh switch tạo nên bốn điểm rẽ nhánh. Nếu người chơi nhập vào số 1, đoạn code ở case 1 sẽ được thực hiện và You picked Easy sẽ được hiển thị. Nếu người chơi nhập vào số 2, đoạn code ở case 2 được thực hiện và You picked Normal được hiển thị. Nếu nhập vào số 3, đoạn code ở case 3 được thực hiện và You picked Hard được hiển thị. Nếu người chơi nhập vào các giá trị khác, đoạn code ở default được thực hiện và thông điệp You made an illegal choice được hiển thị.
    Bẫy: Thường thì hầu như kết thúc mỗi case đều dùng câu lệnh break. Đừng quên nó, nếu không, chương trình của bạn có thể làm những điều mà bạn không mong muốn.
     
  20. Hyutars

    Hyutars Mario & Luigi

    Tham gia ngày:
    26/11/05
    Bài viết:
    713
    Nơi ở:
    Ragnarok World
    Bài 2.5: Dùng vòng lặp while

    Vòng lặp while cho phép bạn lặp đi lặp lại một đoạn code trong khi biểu thức kiểm tra là true. Sau đây là cú pháp:

    Mã:
    while (expression)
        statement; // hoặc khối lệnh
    Nếu expression là false, chương trình đi đến các câu lệnh phía sau vòng lặp. Nếu expression là true, chương trình thực thi statement, sau đó vòng lặp tiếp tục kiểm tra expression. Vòng lặp cứ thực thi cho đến khi nào expression là false, lúc đó vòng lặp kết thúc.

    Giới thiệu chương trình Play Again:

    Chương trình Play Again tái hiện lại một trò chơi hấp dẫn (ta rút gọn quá trình chơi lại thành **Played an exciting game**). Sau đó (tức là chơi xong), chương trình hỏi người chơi có muốn chơi tiếp hay không. Nếu anh ta nhập y, anh ta sẽ được chơi lại (nên nhớ ta chỉ mô phỏng quá trình chơi thành hiển thị thông điệp **Played an exciting game**). Chương trình dùng vòng lặp while để giải quyết bài toán này. Hình 2.5 cho thấy chương trình đang hoạt động.


    [​IMG]
    Hình 2.5 – Tạo nên một vòng lặp nhờ while.


    Mã:
    // Play Again
    // Demonstrates while loops
    
    #include <iostream>
    using namespace std;
    
    int main()
    {
        char again = ‘y';
        while (again == ‘y')
        {
             cout << "\n**Played an exciting game**";
             cout << "\nDo you want to play again? (y/n):";
             cin >> again;
        }
    
        cout << "\nOkay, bye.";
    
        return 0;
    }
    Tạo vòng lặp với while:

    Việc đầu tiên chương trình làm trong hàm main() là khai báo một biến kiểu char tên là again, và khởi tạo nó là ‘y’. Sau đó chương trình bắt đầu vòng lặp while bằng cách kiểm tra again có bằng ‘y’ hay không. Vì nó là true, chương trình hiển thị thông điệp **Played an exciting game**, sau đó hỏi người chơi có muốn chơi tiếp hay không, và lưu giữ câu trả lời ở biến again. Vòng lặp tiếp tục nếu người chơi nhập vào y, ngược lại sẽ thoát khỏi vòng lặp.
    Bạn hãy chú ý, tôi phải khởi tạo biến again ở trước vòng lặp vì nó được dùng trong biểu thức kiểm tra của vòng lặp. Vì vòng lặp while kiểm tra biểu thức của nó trước khi đi vào thân vòng lặp (loop body - tức khối lệnh được lặp lại), cho nên bạn phải chắc rằng bất cứ biến nào tham gia biểu thức kiểm tra phải có giá trị trước khi vòng lặp bắt đầu (hyutars: ví dụ trong bài này nếu again không được khởi tạo là ‘y’ thì lúc đầu làm sao nó thực hiện phép so sánh (again == ‘y’) được, đúng không nào ^^).
     

Chia sẻ trang này