Bài giảng Lập trình nâng cao: Phát triển chương trình cung cấp cho người học các kiến thức: Trò chơi Hangman; sơ đồ khối, mã giả và tư tưởng chia để trị; thao tác với xâu ký tự trong C++; bắt đầu với hàm đơn giản, dần dần biến đổi và luôn có chương trình chạy được.
Trang 1Game: Hangman
3 - Phát triển chương trình
https://github.com/tqlong/advprogram
Trang 2Nội dung
○ Hình dung các thành phần của chương trình
○ Thao tác với xâu ký tự trong C++
○ Bắt đầu với hàm đơn giản, dần dần biến đổi và luôn có chương trình chạy được
Trang 3Cùng chơi Hangman
○ http://www.manythings.org/hmf/
Đối với người mới lập trình
Trang 4Hangman: Luật chơi
○ secretWord: Số vạch = số chữ cái trong từ
○ Mỗi lần B đoán 1 chữ cái đúng, A ghi chữ cái đó lên các vạch tương ứng
○ Nếu B đoán sai, B mất 1 lượt đoán
Trang 5Hangman: Luật chơi
Đủ thân người → thua cuộc
Trang 6| | | O | | | -
| | | O | | | | - - | | | O | /|\
| | -
| | | O | /|\ | / | - -
| | | O | /|\
| / \ | -
secretWord
−AN−−AN
| | | O | /| | | -
-secretWord
HAN−−AN
secretWord
HANG−AN
Trang 7Lập trình trò chơi Hangman
Hãy lập trình trò chơi Hangman với máy là chủ trò
Cần hình dung các tác vụ của chương trình trước khi lập trình cụ thể
● Khởi tạo: máy nghĩ từ tiếng Anh, số đếm lần đoán sai, đúng
● Cập nhật: xử lý phán đoán và thay đổi trạng thái trò chơi
● Hiển thị trạng thái trò chơi: người trên giá treo và secretWord
Trang 8Đọc thêm: http://gameprogrammingpatterns.com/game-loop.html
Hiển thị (render)
- Giá treo cổ
- Từ đã đoán được
Sơ đồ khối - quan hệ giữa các tác vụ
Khởi tạo (initialize)
Trang 9char g uess = readA G uess;
if (w ord contains guess) upd ate g uessed W ord;
else badG u essC oun t+ + ;
} w h ile (gam e not over);
true
Trang 10string w ord = chooseW ord();
string guessedW ord = string(w ord.length(), '-');
int badG uessCount = 0;
do {
renderG am e(guessedW ord, badG uessCount);
char guess = readAG uess();
if (contains(w ord, guess))
guessedW ord = update(guessedW ord, w ord, guess); else badG uessCount+ + ;
} w hile (badG uessCount < 7 & & w ord != guessedW ord);
renderG am e(guessedW ord, badG uessCount);
if (badG uessCount < 7) cout < < "Congratulations! You w in!"; else cout < < "You lost The correct w ord is " < < w ord;
Trang 11string w ord = chooseW ord();
string guessedW ord = string(w ord.length(), '-');
int badG uessCount = 0;
do {
renderG am e(guessedW ord, badG uessCount);
char guess = readAG uess();
if (contain s(w ord , g uess))
g uessed W ord = upd ate(g uessedW ord , w ord , g uess);
else b ad G uessC ou nt+ + ;
} w hile ( bad G uessC ou nt < 7 & & w ord != gu essed W ord );
renderG am e(guessedW ord, badG uessCount);
if (badG u essC oun t < 7) cout < < "C ongratulations! You w in !";
else cou t < < "You lost Th e correct w ord is " < < w ord ;
Các logic đủ đơn giản để đặt tại câu chuyện chính
Trang 12Chia để trị
○ Cấu trúc chung của chương trình cơ bản đã rõ
Trang 13Các vấn đề kĩ thuật tồn đọng
○ file? Cần học về ra vào dữ liệu với file
● Quyết định thế nào?
Trang 14Làm gì trước?
Hai cách tiếp cận:
1 Thử các kĩ thuật trước khi lắp ghép vào chương trình chính
2 Chạy chương trình với phiên bản tối thiểu để test logic trước khi nâng cấp về giao diện, hiệu năng
● Thử nghiệm các kỹ thuật
● Kiểm tra, chạy thử
● Ráp nối
Trang 150.2 ChooseWord chọn ngẫu nhiên trong một danh sách hardcode
1.0 RenderGame vẽ được giá treo cổ
2.0 ChooseWord chọn từ trong file (để các bài sau)
3.0 RenderGame dùng thư viện đồ họa (để tự làm sau)
Trang 16Phiên bản 0.1
Giao diện tối thiểu
Từ được chọn cố định
Tập trung vào logic chính của game
string chooseW ord()
cout < < guessedW ord < < endl;
cout < < "N um ber of w rong guesses: " < < badG uessCount < < endl;
}
Number of wrong guesses: 0
Your guess: a
Number of wrong guesses: 1
Your guess: b
Number of wrong guesses: 1
b -Your guess: e
Number of wrong guesses: 2
b -Your guess: o
Number of wrong guesses: 2
boo-Your guess: k
book Number of wrong guesses: 2 Congratulations! You win!
Trang 17Thao tác với từ
○ Cần kiểm tra xem “book” có chứa kí tự ‘o’
○ Update(“ ”, “book”, ‘o’) cần biến “ ” thành “-oo-”
Trang 18string greeting = "hello"
string nam e = "w orld!";
cout < < greeting < < " " < < nam e < < endl; cout < < "First char: " < < greeting[0];
greeting[ 0 ] = 'H ' ; cout < < greeting + " " + nam e < < endl;
cout < < nam e.size() < < endl; // 6
size_t pos = nam e.fi nd("or"); // 1
//sub string starting at pos
string found = nam e.substr(pos);
cout < < found < < endl; // orld!
Trang 19Xử lý luật chơi (game logic)
Trạng thái trò chơi tại mỗi lượt chơi (lượt đoán):
Trang 20● Kiểm tra thắng thua - dễ
○ Thua: badG uessCount = = 7
○ Đã đoán xong: w ord = = guessedW ord
○ Chưa đoán xong: w ord != guessedW ord
(ở kiểu string, các phép so sánh = = và != kiểm tra nội dung hai chuỗi kí tự nằm trong hai biến string)
Xử lý luật chơi (game logic)
Trang 21● Cập nhật guessedWord, badGuessCount theo luật chơi Tiếp tục cách tiếp cận down
top-if (contains(w ord, guess))
U pdate //sửửa guessedW ord
else badG uessCount+ + ;
● Hàm update sửa guessedWord để hiện các kí tự đã đoán được
‘ ’ (‘book’) thành ‘-oo-’ nếu vừa đoán ‘o’
‘-oo-’ (‘book’) thành ‘-ook’ nếu vừa đoán ‘k’
Trang 22update(guessedWord, word, guess)
Đầu vào (tham số):
● char guess : phán đoán của người chơi
● string guessedWord : các vạch (chữ cái chưa đoán được) và các chữ cái đã đoán được
● string word : từ máy chọn từ đầu
Đầu ra: Xâu guessedWord mới, hiển thị các vị trí guess xuất hiện trong word
update(" -", "H AN G M AN ", 'A' ) trả về "-A -A-"
update("-A -A-", "H AN G M AN ", 'P' ) trả về "-A -A-"
update("-A -A-", "H AN G M AN ", 'H ' ) trả về "H A -A-"
Trang 23string update(string guessedW ord, string w ord, char guess)
update(guessedWord, word, guess)
Duyệt lần lượt các ký tự của word : Nếu ký tự đó bằng guess thì thay thế vào vị trí tương ứng (cùng chỉ số) trong guessedWord
Trang 24string update(string guessedW ord, string w ord, char guess)
update(guessedWord, word, guess)
Chú ý hàm length() lấy độ dài của string,
cách đọc và ghi giá trị của một ký tự trong string
Trang 25Hàm contains(word, guess)
Đầu vào (tham số):
● char guess : phán đoán của người dùng
● string word : từ máy chọn từ đầu
Đầu ra: giá trị kiểu bool : true nếu ch xuất hiện trong word , là false nếu ngược lại
contains("H AN G M AN ", 'A' ) trả về true
contains("H AN G M AN ", 'P' ) trả về false
Gợi ý: hàm s.f i nd_f i rst_of(c) trả về chỉ số của vị trí đầu tiên của c trong string s, trả về hằng số
string::npos nếu không tìm thấy
Trang 26Hoàn thành phiên bản 0.1
- dễ dàng tạo các trường hợp đoán sai/đúng để test badGuessCount và renderGame
Trang 28Phiên bản 0.2
Có thể chọn từ ngẫu nhiên từ một danh sách cố định trong code (hardcode)
Trang 29string chooseWord()
● Danh sách từ vựng lưu trong mảng
Trang 30string chooseWord()
const string W O R D _LIS T[] = {"dog", "cat", "hum an"};
string chooseW ord()
{
int random Index = rand() % 3;
return W O R D _LIS T[random Index];
}
Trang 31string chooseWord()
số từ)
○ Kĩ thuật tìm số phần tử của mảng
const string W O RD _LIST[] = {"dog", "cat", "hum an"};
const int W O R D _C O U N T = sizeof(W O R D _LIS T) / sizeof(string) ;
string chooseW ord()
{
int random Index = rand() % W O R D _C O U N T;
return W O RD _LIST[random Index];
}
Kích thước mảng / kích thước một phần tử
Trang 32"dog", "door", "drain", "draw er", "dress", "drop", "ear", "egg", "engine", "eye", "face", "farm ", "feather", "finger", "fish", "flag", "floor", "fly",
"foot", "fork", "fow l", "fram e", "garden", "girl", "glove", "goat", "gun", "hair", "ham m er", "hand", "hat", "head", "heart", "hook", "horn", "horse", "hospital", "house", "island", "jew el", "kettle", "key", "knee", "knife", "knot", "leaf", "leg", "library", "line", "lip", "lock",
"m ap", "m atch", "m onkey", "m oon", "m outh", "m uscle", "nail", "neck", "needle", "nerve", "net", "nose", "nut", "of fice", "orange", "oven", "parcel", "pen", "pencil", "picture", "pig", "pin", "pipe", "plane", "plate", "plow ", "pocket", "pot", "potato", "prison", "pum p", "rail", "rat", "receipt", "ring", "rod", "roof", "root",
"sail", "school", "scissors", "screw ", "seed", "sheep", "shelf", "ship", "shirt", "shoe", "skin", "skirt", "snake", "sock", "spade", "sponge", "spoon", "spring", "square", "stam p", "star", "station", "stem ", "stick", "stocking", "stom ach", "store", "street", "sun", "table", "tail", "thread", "throat", "thum b", "ticket", "toe", "tongue", "tooth", "tow n", "train", "tray", "tree", "trousers", "um brella", "w all", "w atch", "w heel", "w hip", "w histle", "w indow ", "w ire", "w ing", "w orm ",
Trang 33Phiên bản 1.0
Vẽ giá treo cổ bằng text
| | | O | /|\ | / \ |
-
Trang 34-Hiển thị giá treo cổ
○ 1 Hình vẽ 1 ⇔ string (xuống dòng bằng ký tự \n )
7 6
5 4
| | | | | -
| | | | | | -
| | | O | | | -
| | | O | | | | -
| | | O | /|
| | -
| | | O | /|\
| | -
| | | O | /|\
| / | -
| | | O | /|\
| / \ | -
Trang 35const strin g FIG U R E[] = {
"f i g0", "f i g1", "f i g 2", "f i g 3", "f i g 4", "f i g5", "f i g 6", "f i g 7"
};
void renderG am e(string guessedW ord, int badG uessCount)
{
cout < < FIG U R E[bad G uessC ou nt] < < endl;
cout < < guessedW ord < < endl;
cout < < "N um ber of w rong guesses: " < < badG uessCount < < endl; }
Trang 36const string FIG U R E [] = {
Trang 37Ta đã hoàn thành phiên bản 1.0
Trang 38Tổng kết
○ Khởi tạo xâu, duyệt ký tự, nối/cộng xâu
○ cho các giá trị không đổi