Tải bản đầy đủ (.pptx) (54 trang)

Bài giảng Lập trình nâng cao: Tìm kiếm và đếm - Trần Quốc Long

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (165.59 KB, 54 trang )

Simple AI
9 - Tìm kiếm và đếm
/>

Nội dung





Máy chơi Hangman
Chương trình phức tạp → Mã giả + chia để trị
AI = Dữ liệu + Tìm kiếm + Đếm (thống kê)
Kỹ thuật:
○ Thư viện tập hợp <set>, thư viện ánh xạ <map>
○ Vòng lặp for trên vector, set, map
○ Tìm kiếm
■ Tìm kiếm thỏa mãn điều kiện
■ Tìm kiếm lớn nhất, nhỏ nhất
○ Đếm


Đặt vấn đề
Lập trình cho máy chơi trị Hangman:
● Người nghĩ từ
● Máy đoán các chữ cái
● Người trả lời các vị trí chữ cái đốn đúng

Người - chủ trị (host); Máy - người chơi (player)



Các thành phần
Giao diện tương
tác (UI)

Lõi trí tuệ nhân
tạo (AI core)

● Nhập số chữ cái của từ người
chơi nghĩ (dễ)
● Hiển thị phán đoán, lịch sử phán
đoán của máy và giá treo (đã làm)
● Nhập trả lời của người chơi

● Dựa vào các phán đoán đã
đưa ra và secretWord hiện
thời
○ Đưa ra phán đốn tiếp
theo
○ Liệu máy tính có thể chơi
Hangman giỏi hơn con
người ?


Nhập trả lời của người chơi
Khi máy đưa ra phán đoán, người chơi trả lời
bằng xâu mặt nạ (mask)
● Một xâu ký tự toàn dấu gạch ngang
● Chỉ hiển thị các vị trí đốn đúng
Ví dụ: người nghĩ từ “h an g m an ”
máy đoán p, người trả lời ------máy đoán tiếp a, người trả lời tiếp -a---amáy đoán tiếp g, người trả lời tiếp -a-g -a-



Tiện ích sinh xâu mặt nạ
// genm ask.cpp
// M ask generating toolfor H angm an gam e
# include < iostream >
# include < cctype>
u sin g n am esp ace std;
in t m ain (in t argc,ch ar* argv[])
{
if (argc < 3) {
cout < < "U sage: genm ask < w ord> < char> " < < endl;
retu rn 1;
}
string w ord = argv[1];
ch ar guess = tolow er(argv[2][0]);
for (u n sig n ed in t i= 0; i< w ord.length(); i+ + )
if (tolow er(w ord[i]) != guess) w ord[i] = '-';
else w ord[i] = guess;
cout < < w ord < < endl;
retu rn 0;
}

Chuyển word
sang mặt nạ,
các ký tự khác
guess biến
thành dấu
gạch ngang



Mã giả - chia để trị
w ordLength = getU serW ordLength();
secretW ord = string(w ordLength, '-');
incorrectG uess = 0;
previousG uesses = em pty set of characters;
stop = false;
do {
guess = getN extG uess(previousG uesses, secretW ord);

Trí tuệ nhân tạo (AI)

m ask = getU serAnsw er(guess);
update(guess, m ask, incorrectG uess, previousG uesses, secretW ord, stop);
render(incorrectG uess, previousG uesses, secretW ord);
} w hile (!stop);
playAnim ation(incorrectG uess = = M AX_G U ESSES, secretW ord);


Lập trình nhóm
● Dự án phức tạp nhiều người
○ Mỗi người làm một phần

● Dự án này
○ Một người làm giao diện
○ Một người làm phần lõi AI (getNextGuess)
■ Đây là phần khó, chưa biết làm thế nào
● Nếu đợi → làm chậm dự án

■ Cần một hàm getNextGuess() đơn giản để bên

làm giao diện có thể phát triển độc lập
■ Đồng thời, bên làm AI có thể tìm cách cải tiến


Tạo Project
● Trong CodeBlocks tạo Project SimpleAI
● Tạo tệp guesser.h, guesser.cpp thêm vào
Project
○ Thêm hàm char getNextGuess(string, string) vào
guesser.*
○ #include "guesser.h" trong main.cpp
# pragm a once

guesser.h

# include < string>
# include < set>
ch ar g etN extG u ess(con st std::set< ch ar> & previousG uesses, con st std::string& secretW ord);


Giới thiệu thư viện <set>
● previousGuesses cần lưu tập hợp các chữ
cái đã đoán
● <set>: tập hợp các giá trị cùng kiểu
○ set<int>: tập hợp (con) các số nguyên
○ set<char>: tập hợp các ký tự
○ set<string>: tập hợp các xâu ký tự

● Các phần tử trong tập hợp đảm bảo luôn
khác nhau (!=)



Giới thiệu thư viện <set>
● Các phép toán tập hợp:







s.insert('a'): thêm phần tử 'a' vào tập s
s.erase('a'): xóa phần tử 'a' khỏi tập s
s.find('a') != s.end(): phần tử 'a' thuộc tập s
s.find('a') == s.end(): phần tử 'a' không thuộc tập s
for (char c : s): duyệt các phần tử trong tập s
/>

getNextGuess đơn giản
Chọn ngẫu nhiên 1 ký
tự chưa đoán bao giờ
● Thêm util.* vào
Project
● #include "util.h"
trong guesser.cpp

guesser.cpp
# include < string>
# include "guesses.h"
# include "util.h"

u sin g n am esp ace std;
ch ar g etN extG u ess(con st set< ch ar> &
previousG uesses,
con st string& secretW ord)
{
set< ch ar> rem ainingChars =
getRem ainingChars(previousG uesses);
if (rem ainingChars.size() = = 0)
retu rn 0;
else
retu rn selectRandom Char(rem ainingChars);
}


getRemainingChars()
Bắt đầu, remainChars = tập chữ cái từ a → z
sau đó xóa các chữ cái trong previousGuesses
set< ch ar> getRem ainingChars(con st set< ch ar> &
previousG uesses)
{
set< ch ar> rem ainingC hars;
for (ch ar c = 'a'; c < = 'z'; c+ + )
rem ainingC hars.insert(c);
for (ch ar c: previousG uesses)
rem ainingC hars.erase(c);
retu rn rem ainingChars;
}


selectRandomChar()

Google “c++ select random element from set”
/>ement-in-stdset
ch ar selectR an d om C h ar(con st set< ch ar> & s)
{
in t r = rand() % s.size();
for (char c : s) {
if (r-- = = 0) return c;
}
retu rn 0;
}


Lập trình giao diện
● Đã có lõi AI đơn giản
● Có thể phát triển giao diện riêng rẽ
○ Phát triển thêm từ code Hangman cũ

● Người làm AI tiếp tục tìm hiểu để cải tiến
cách phán đốn (thuật tốn)


main(): chuyển từ mã giả sang
Chia để trị
Viết mã
lần lượt
cho các
hàm

in t m ain ()
{

in t w ordLength;
string secretW ord;
in t incorrectG uess;
set< ch ar> previousG uesses;
b ool stop;
initialize(w ordLength, secretW ord,incorrectG uess,previousG uesses,stop);
render(incorrectG uess, previousG uesses,secretW ord);
do {
ch ar guess = getN extG uess(previousG uesses,secretW ord);
string m ask = getU serAnsw er(guess);
u p d ate(g u ess, m ask, in correctG u ess, p reviou sG u esses, secretW ord ,
stop );
render(incorrectG uess,previousG uesses,secretW ord);
} w h ile (!stop);
playAnim ation(incorrectG uess = = M AX_G U ESSES,secretW ord);
retu rn 0;
}


getUserWordLength()
Nhập độ dài từ người chơi nghĩ
in t g etU serW ord Len g th ()
{
in t w ordLength;
cout < < endl< < "Enter your w ord length: ";
cin > > w ordLength;
retu rn w ordLength;
}



getUserAnswer()
Nhập (mặt nạ) trả lời của người chơi, chuyển
qua chữ thường
string g etU serA nsw er(char guess)
{
string answ er;
cout < < endl< < "Iguess " < < guess < < ", please enter your m ask: ";
cin > > answ er;
transform (answ er.begin(),answ er.end(),answ er.begin(),::tolow er);
return answ er;
}


initialize()
Khởi tạo các trạng thái của trò chơi
void in itialize(in t& w ordLength, string& secretW ord,
in t& incorrectG uess, set< ch ar> & previousG uesses,
b ool& stop)
{
w ordLength = getU serW ordLength();
secretW ord = string(w ordLength, '-');
incorrectG uess = 0;
previousG uesses = set< ch ar> ();
stop = false;
}


render()
Sử dụng lại các hàm trong draw.* (nhớ include)
for (char c: previousGuesses) in các phần tử

void ren d er(in t incorrectG uess, con st set< ch ar> &
previousG uesses,
con st string& secretW ord)
{
clearScreen();
cout < < endl< < "Incorrect guess = " < < incorrectG uess
< < " previous guesses = ";
for (ch ar c : previousG uesses)
cout < < c;
cout < < " secretW ord = " < < secretW ord < < endl;
cout < < getD raw ing(incorrectG uess) < < endl;
}


playAnimation()
Sửa playAnimation() một ít cho phù hợp
void p layA n im ation (b ool isLosing, con st string& w ord)
{
clearScreen();
w h ile (true) {
if (isLosing)
cout < < endl< < "Ilost :(. M y best w ord is: " < < w ord < < endl;
else
cout < < endl< < "H aha, Iw in :D . The w ord is: " < < w ord < < endl;
cout < < (isLosing ? getN extH angm an() : getN extStandingm an());
this_thread::sleep_for(chrono::m illiseconds(50 0 ));
clearScreen();
}
}



update(): viết như kể chuyện
void u p d ate(char guess, con st string& m ask,
in t& incorrectG uess, set< ch ar> & previousG uesses,
string& secretW ord, b ool& stop)
{
N ếế
u m ặt nạ không hợp lệ, báo lôỗ
i(ném ngoạilệ)
Thếm guess vào previousG uesses (các ký tự đã đoán)
N ếế
u m ặt nạ toàn dấế
u gạch ngang
tăng incorrectG uess
nếế
u incorrectG uess = = M AX_G U ESSES (7), stop = true
N gược lại
cập nhật secretW ord dựa vào m ặt nạ
nếế
u secretW ord khơng cịn dấế
u gạch ngang, stop = true
}


update(): viết như kể chuyện
void u p d ate(char guess, con st string& m ask,
in t& incorrectG uess, set< ch ar> & previousG uesses,
string& secretW ord, b ool& stop)
{
if (!isG oodM ask(guess,m ask, secretW ord))

th row invalid_argum ent("m istake entering answ er");
previousG uesses.insert(guess);
if (isAllD ash(m ask)) {
incorrectG uess + + ;
if (incorrectG uess = = M AX_G U ESSES) stop = true;
} else {
updateSecretW ord(m ask, secretW ord);
if (isAllN otD ash(secretW ord)) stop = true;
}
}


isAllDash(): trong util.*
Kiểm tra toàn bộ chữ cái là dấu gạch ngang
b ool isA llD ash (con st string& s)
{
for (u n sig n ed in t i= 0; i< s.length(); i+ + )
if (s[i] != '-') retu rn false;
retu rn true;
}


isAllDash(): trong util.*
Kiểm tra toàn bộ chữ cái là dấu gạch ngang
b ool isA llD ash (con st string& s)
{
for (ch ar c : s)
if (c != '-') retu rn false;
retu rn true;
}



×