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.
Game: Hangman - Phát triển chương trình https://github.com/tqlong/advprogram Nội dung ● ● Trò chơi Hangman Sơ đồ khối, mã giả tư tưởng chia để trị ○ ● Hình dung thành phần chương trình Kỹ thuật: ○ ○ Thao tác với xâu ký tự C++ Bắt đầu với hàm đơn giản, biến đổi ln có chương trình chạy Cùng chơi Hangman ● Trò chơi bạn bè tiếng ○ ● http://www.manythings.org/hmf/ Luyện từ vựng tiếng Anh Đối với người lập trình ● ● ● ● Mơ-đun hóa chương trình Thao tác với xâu ký tự Xử lý logic trò chơi (game logic) Vẽ hình đơn giản (text) Hangman: Luật chơi ● ● Trò chơi A (chủ trò) B (người chơi) A nghĩ từ tiếng Anh giấu ○ ● B tìm cách đốn từ A ○ ○ ● secretWord: Số vạch = số chữ từ Mỗi lần B đoán chữ đúng, A ghi chữ lên vạch tương ứng Nếu B đoán sai, B lượt đoán Số lượt ≈ số nét vẽ giá treo thân người B (so fun :-D) Hangman: Luật chơi ● ● ● ● ● ● ● Sai lần đầu: Vẽ chữ L ngược (giá treo cổ) Sai lần 2: Vẽ vòng tròn (đầu) Sai lần 3: Vẽ vạch (thân người) Sai lần 4: Vẽ vạch (tay trái) Sai lần 5: Vẽ vạch (tay phải) Sai lần 6: Vẽ vạch (chân trái) Sai lần 7: Vẽ vạch (chân phải) Đủ thân người → thua Ví dụ ván chơi E | | A | HANGMAN | | | F | | secretWord | O −A−−−A− | | | - C - - N P | | | O | O | | | /| secretWord | - - | | - | O | | /|\ | | | | | - H I secretWord HAN−−AN - - G V secretWord HANG−AN | | | | O | /|\ | /\ | - | | O | /|\ | / | - | −−−−−−− | | −AN−−AN | secretWord - | | V - Lập trình trị chơi Hangman Hãy lập trình trị chơi Hangman với máy chủ trị Cần hình dung tác vụ chương trình trước lập trình cụ thể ● ● ● ● ● Khởi tạo: máy nghĩ từ tiếng Anh, số đếm lần đoán sai, Nhập liệu: phán đoán người chơi Cập nhật: xử lý phán đoán thay đổi trạng thái trò chơi Hiển thị trạng thái trò chơi: người giá treo secretWord Thơng báo kết trị chơi Sơ đồ khối - quan hệ tác vụ Khởi tạo (initialize) - Chọn từ tiếng Anh - Số đếm lần đoán sai - Từ đoán Nhập liệu (input) Hiển thị (render) ● - Giá treo cổ Phán đoán người chơi - Từ đoán Game loop false Cập nhật trạng thái (update) điều kiện dừng ● ● từ đoán số lần đoán sai true Thông báo kết Đọc thêm: http://gameprogrammingpatterns.com/game-loop.html Mã giả Initialize Render Input ch oose w ord ; in itialize g u essed W ord w ith ‘-’; b ad G u essC ou n t = 0; false Game Over true { ren d er g am e; ch ar g u ess = read A G u ess; if (w ord tain s g u ess) u p d ate g u essed W ord ; else b ad G u essC ou n t+ + ; } w h ile (g am e n ot over); d isp lay g am e resu lt; End game Update game string w ord = chooseW ord(); Code string guessedW ord = string(w ord.length(), '-'); int badG uessC ount = 0; { renderG am e(guessedW ord, badG uessC ount); char guess = readAG uess(); if (contains(w ord, guess)) guessedW ord = update(guessedW ord, w ord, guess); else badG uessC ount+ + ; } w hile (badG uessCount < & & w ord != guessedW ord); renderG am e(guessedW ord, badG uessC ount); if (badG uessCount < 7) cout < < "Congratulations! You w in!"; else cout < < "You lost.The correct w ord is " < < w ord; update(guessedWord, word, guess) Chú ý hàm length() lấy độ dài string, cách đọc ghi giá trị ký tự string string update(string guessedW ord, string w ord,char guess) { for (int i= w ord len g th () - ; i> = 0; i ) { if (w ord [i] = = g u ess) { g u essed W ord [i] = g u ess; } } return guessedW ord; } Hàm contains(word, guess) Đầu vào (tham số): ● ● char guess: phán đoán người dùng string word: từ máy chọn từ đầu Đầu ra: giá trị kiểu bool: true ch xuất word, false ngược lại contains("H AN G M AN ",'A') trả true contains("H AN G M AN ",'P') trả false Gợi ý: hàm s.f i n d _f i rst_of(c) trả số vị trí c string s, trả số string::npos khơng tìm thấy Hồn thành phiên 0.1 - Test luật chơi Do chooseWord cố định nên chạy ta biết đoán từ - - dễ dàng tạo trường hợp đoán sai/đúng để test badGuessCount renderGame Nên refactor (cải tiến, làm code) trước tiếp Dùng để tránh magic number { } w hile (b ad G u essC ou n t < & & w ord != guessedW ord); Magic number: vậy? if (b ad G u essC ou n t < 7) cout < < "C ongratulations! You w in!"; st in t M A X _B A D _G U ESS ES = 7; } w hile (b ad G u essC ou n t < M A X _B A D _G U ESS ES & & w ord != guessedW ord); if (b ad G u essC ou n t < M A X _B A D _G U ESS ES ) - Dễ hiểu Dễ dàng sửa giá trị cần Phiên 0.2 Có thể chọn từ ngẫu nhiên từ danh sách cố định code (hardcode) string chooseWord() ● ● ● Danh sách từ vựng lưu mảng Chọn từ ngẫu nhiên ⇔ Chọn số ngẫu nhiên mảng Các kỹ thuật cần thiết ○ Dữ liệu từ vựng http://www.manythings.org/vocabulary/lists/l/ http://www.manythings.org/vocabulary/lists/l/words.php?f=ogden-picturable (200 từ) ○ Mảng string (array of string) http://stackoverflow.com/questions/9626722/c-string-array-initialization string chooseWord() ● Thử với số từ nhỏ st strin g W O R D _LIS T[] = { "d og ", "cat", "h u m an "} ; string chooseW ord() { in t ran d om In d ex = ran d () % 3; retu rn W O R D _LIS T[ran d om In d ex]; } string chooseWord() ● Tổng qt hóa số lượng từ (khơng thể lần sửa danh sách lại phải sửa số từ) ○ Kĩ thuật tìm số phần tử mảng const string W O RD _LIST[] = {"dog","cat","hum an"}; st in t W O R D _C O U N T = sizeof(W O R D _LIS T) / sizeof(strin g ); string chooseW ord() { int random Index = rand() % W O R D _C O U N T; return W O R D _LIST[random Index]; } Kích thước mảng / kích thước phần tử string chooseWord() : 200 từ ● ● ● Thay danh sách từ Đã có srand()? string W O R D _LIST[] = { "angle","ant","apple","arch","arm ","arm y", "baby","bag","ball","band","basin","basket","bath","bed","bee","bell","berry", Đến ta cho "bird","blade","board","boat","bone","book","boot","bottle","box","boy", "brain","brake","branch","brick","bridge","brush","bucket","bulb","button", "cake","cam era","card", "cart","carriage","cat","chain","cheese","chest", chương trình "chin","church","circle","clock","cloud","coat","collar","com b","cord", "cow ","cup","curtain","cushion", chọn ngẫu nhiên "dog","door","drain","draw er","dress","drop","ear","egg","engine","eye", "face","farm ","feather","fi n ger","fi sh","fl ag","fl oor","fl y", "foot","fork","fow l","fram e","garden","girl","glove","goat","gun", từ "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 f ce","orange","oven","parcel","pen","pencil","picture","pig","pin", i "pipe","plane","plate","plow ","pocket","pot","potato","prison","pum p", Hoàn thành "rail","rat","receipt","ring","rod","roof","root", "sail","school","scissors","screw ","seed","sheep","shelf","ship","shirt", phiên 0.2 "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 ", }; Phiên 1.0 Vẽ giá treo cổ text | | | O | /|\ | /\ | - Hiển thị giá treo cổ ● Bản chất đoạn văn có nhiều dịng ○ ● Hình vẽ ⇔ string (xuống dòng ký tự \n) Nếu lưu hình vẽ mảng string ○ badGuessCount tương ứng với số mảng - - - - | | | | | | | | | O | O | | | | | | | | | | | | | | - - - - - - - - | | | | | | | | O | O | O | O | /| | /|\ | /|\ | /|\ / | /\ | | | | | | - - - | | - renderGame() ● Luôn đơn giản để chạy thử st strin g FIG U R E[] = { "f g i 0", "f i g 1", "f i g 2", "f i g 3", "f i g 4", "f i g 5", "f i g 6", "f i g 7" }; void renderG am e(string guessedW ord, int badG uessCount) { cou t < < FIG U R E[b ad G u essC ou n t] < < en d l; cout < < guessedW ord < < endl; cout < < "N um ber of w rong guesses: " < < badG uessCount < < endl; } renderGame ● Sau đưa hình vẽ thật vào biến figure const string FIG U R E [] = { " - \n " " - " | \n " " | | " | \n " " | O " | \n " " | | \n " " | " | " | \n " " | " - \n ", " " | | \n " " | \n " " | " - \n ", \n " " - " | \n " " | O " | \n " " | /| \n " " | \n " " | " - \n ", | " | \n " " | O " | " | " | \n " " - \n ", \n " \n " \n " | " | \n " " | \n " " | " | O " | \n " " | \n " \n " \n " \n " " - \n ", \n " O \n " \n " \n " /|\\ \n " / \\ \n " \n " " - \n ", /|\\ \n " \n " | " | \n " " | " - / \n " " | \n " " | \n " /|\\ \n " " - \n " " - \n ", \n " O \n " \n " " - \n ", }; " | | " | \n " " | " | " | " " | \n " \n " " | \n " \n " Ta hoàn thành phiên 1.0 Tổng kết ● Viết chương trình ○ ○ ○ ● ● Dần dần thay đổi theo u cầu Ln có chương trình chạy Sơ đồ khối, mã giả, tư tưởng chia để trị string, thao tác với xâu kí tự ○ ● Bắt đầu đơn giản Khởi tạo xâu, duyệt ký tự, nối/cộng xâu Dùng ○ ○ thay magic number cho giá trị không đổi ... guess xuất word update(" -" ,"H AN G M AN ", 'A') trả "-A -A-" update("-A -A-","H AN G M AN ", 'P') trả "-A -A-" update("-A -A-","H AN G M AN ", 'H ') trả "H A -A-" update(guessedWord, word,... - | | | | | | | | | O | O | | | | | | | | | | | | | | - - - - - - - - | | | | | | | | O | O | O | O | /| | /| | /| | /| / | / | | | | | | - - - |... | - | | O | /| | / | - | −−−−−−− | | −AN−−AN | secretWord - | | V - Lập trình trị chơi Hangman Hãy lập trình trị chơi Hangman với máy chủ trị Cần hình dung tác vụ chương trình