1. Trang chủ
  2. » Công Nghệ Thông Tin

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

54 17 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 54
Dung lượng 193,44 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Bài giảng Lập trình nâng cao: Tìm kiếm và đếm cung cấp cho người học các kiến thức: Máy chơi Hangman, chương trình phức tạp, thư viện tập hợp, thư viện ánh xạ, vòng lặp for trên vector,... Mời các bạn cùng tham khảo nội dung chi tiết.

Trang 1

Simple AI

9 - Tìm kiếm và đếm

https://github.com/tqlong/advprogram

Trang 2

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

Trang 3

Đặ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 đoán đúng

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

Trang 4

đoán của máy và giá treo (đã làm)

đưa ra và secretWord hiện

thời

theo

Hangman giỏi hơn con người ?

Trang 5

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í đoán đúng

Ví dụ: người nghĩ từ “ hangm 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 -a-máy đoán tiếp g, người trả lời tiếp

Trang 6

-a-g-a-Tiện ích sinh xâu mặt nạ

// genm ask.cpp

// M ask generating tool for H angm an gam e

# include < iostream >

# include < cctype>

using nam espace std;

int m ain(in t argc, char* argv[])

string w ord = argv[1];

char guess = tolow er(argv[2][0]);

for (un sign 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;

return ;

}

Chuyển word

sang mặt nạ, các ký tự khác

guess biến

thành dấu gạch ngang

Trang 7

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);

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);

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

Trang 8

Lập trình nhóm

● Dự án phức tạp nhiều người

● Dự án này

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

Trang 9

Tạo Project

● Trong CodeBlocks tạo Project SimpleAI

● Tạo tệp guesser.h, guesser.cpp thêm vào Project

Trang 10

Giới thiệu thư viện <set>

cái đã đoán

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

Trang 11

Giới thiệu thư viện <set>

● Các phép toán tập hợp:

Trang 12

getNextGuess đơn giản

Chọn ngẫu nhiên 1 ký

tự chưa đoán bao giờ

● Thêm util.* vào

using nam espace std;

char getN extG u ess(const set<char> &

previousG uesses, const string& secretW ord){

set<char> rem ainingChars = getRem ainingChars(previousG uesses);

if (rem ainingChars.size() = = 0) return ;

else

return selectRandom Char(rem ainingChars);

}

guesser.cpp

Trang 13

set< ch ar > rem ainingChars;

for ( ch ar c = 'a' ; c < = 'z' ; c+ + ) rem ainingChars.insert(c);

for ( ch ar c: previousG uesses) rem ainingChars.erase(c);

return rem ainingChars;

}

Trang 14

Google “c++ select random element from set”

http://stackoverflow.com/questions/3052788/how-to-select-a-random-el ement-in-stdset

ch ar selectR and 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;

} return 0;

}

Trang 15

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ẽ

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

Trang 16

main(): chuyển từ mã giả sang

initialize(w ordLength, secretW ord, incorrectG uess, previousG uesses, stop);

render(incorrectG uess, previousG uesses, secretW ord);

do { char guess = getN extG uess(previousG uesses, secretW ord);

string m ask = getU serAnsw er(guess);

up date(guess, m ask, incorrectG u ess, p reviousG 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);

retu rn ;}

Trang 17

Nhập độ dài từ người chơi nghĩ

in t g etU serW ordLen g th () {

Trang 18

string answ er;

cout < < endl < < "I guess " < < guess < < ", please enter your m ask: ";

cin > > answ er;

transform (answ er.begin(), answ er.end(), answ er.begin(), ::tolow er);

return answ er;

}

Trang 19

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 ;

}

Trang 20

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 der ( in t incorrectG uess, const set< ch ar > &

cout < < " secretW ord = " < < secretW ord < < endl;

cout < < getD raw ing(incorrectG uess) < < endl;

}

Trang 21

void p layA n im ation ( b ool isLosing, const string& w ord)

Trang 22

update(): viết như kể chuyện

void update ( char guess, const string& m ask,

int & incorrectG uess, set< char > & previousG uesses,

string& secretW ord, bool & stop)

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

}

Trang 23

update(): viết như kể chuyện

void update ( char guess, const string& m ask,

int & incorrectG uess, set< char > & previousG uesses,

string& secretW ord, bool & stop)

{

if (!isG oodM ask(guess, m ask, secretW ord))

throw invalid_argum ent("m istake entering answ er");

updateSecretW ord(m ask, secretW ord);

if (isAllN otD ash(secretW ord)) stop = true ;

}

}

Trang 24

isAllDash(): trong util.*

Kiểm tra toàn bộ chữ cái là dấu gạch ngang

b ool isA llD ash ( const string& s) {

for ( unsign ed in t i = 0 ; i < s.length(); i+ + )

if (s[i] != '-' ) return false ; return true ;

}

Trang 25

isAllDash(): trong util.*

Kiểm tra toàn bộ chữ cái là dấu gạch ngang

b ool isA llD ash ( const string& s) {

for ( ch ar c : s)

if (c != '-' ) return false ; return true ;

}

Trang 26

isAllNotDash(): trong util.*

Kiểm tra toàn bộ chữ cái không là dấu gạch ngang

b ool isA llN otD ash ( con st string& s) {

for ( unsign ed in t i = 0 ; i < s.length(); i+ + )

if (s[i] = = '-' ) return false ; return true ;

}

Trang 27

isAllNotDash(): trong util.*

Kiểm tra toàn bộ chữ cái không là dấu gạch ngang

b ool isA llN otD ash ( con st string& s) {

for ( ch ar c : s)

if (c = = '-' ) return false ; return true ;

}

Trang 28

Hiển thị các chữ cái trong mặt nạ (mask)

void up d ateS ecretW ord ( con st string& m ask, string& secretW ord) {

for ( un sig n ed in t i = 0 ; i < secretW ord.length(); i+ + )

if (m ask[i] != '-' )

secretW ord[i] = m ask[i];

}

Trang 29

b ool isG oodM ask ( char guess, const string& m ask,

const string& secretW ord)

{

if (m ask.length() != secretW ord.length()) return false ;

for ( unsigned int i = 0 ; i < secretW ord.length(); i+ + )

độ dài phải bằng nhau

nếu mask[i] là chữ cái thì mask[i] phải bằng

guess và secretWord[i]

phải là dấu gạch hoặc

phải bằng mask[i]

Trang 30

Sửa hàm main() bắt ngoại lệ

Đến đây, mỗi người có thể làm phần của mình độc lập

string m ask = getU serAnsw er(guess);

update(guess, m ask, incorrectG uess, previousG uesses, secretW ord, stop);

break;

} catch (invalid_argum ent e) {

cout < < "Invalid m ask, try again" < < endl;

}

} w hile (true);

render(incorrectG uess, previousG uesses, secretW ord);

} w hile (!stop);

Trang 31

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> , ánh xạ <map>

○ Vòng lặp for trên vector, set, map

Trang 32

Simple AI

● may rủi, có tỉ lệ thua cao

● đơn giản, dễ cài đặt

→ dùng làm thuật toán tạm thời để phát triển

độc lập các thành phần của chương trình

Trang 33

Simple AI

Cải tiến getNextGuess() như con người chơi

● B0: Chuẩn bị vốn từ vựng tiếng Anh

● B1: Thử đoán các nguyên âm a, e, i, o, u

● B2: Sau khi đoán đúng một số vị trí

Trang 34

B0: Chuẩn bị vốn từ vựng tiếng Anh

char getN extG uess(const set<char> & previousG uesses,

const string& secretW ord){

static vector< string> w ordList = readW ordListFrom File("data/O gden_Picturable_200.txt");

set<char> rem ainingChars = getRem ainingChars(previousG uesses);

// TO D O : m ake a guess (B 1, B 2)

}

guesser.cpp

Trang 35

B1: ban đầu đoán nguyên âm

âm chưa đoán trong a, e, i, o, u để đoán

set< ch ar > rem ainingChars = getRem ainingChars(previousG uesses);

if (rem ainingChars.size() = = 0 )

return ;

if (isAllD ash(secretW ord))

return getVow elG uess(rem ainingChars);

Trang 36

getVowelGuess(): tìm nguyên âm

Trả về 0 nếu không tìm thấy nguyên âm

char getVow elG uess(const set<ch ar> & rem ainingChars)

{

char vow el[] = {'a', 'e', 'i', 'o', 'u'};

for (int i = 0; i < 5; i+ + ) {

if (rem ainingChars.find(vow el[i]) != rem ainingChars.end())

retu rn vow el[i];

Trang 37

getVowelGuess(): tìm nguyên âm

Vòng lặp for trên vector

char getVow elG uess(const set<ch ar> & rem ainingChars)

{

char vow el[] = {'a', 'e', 'i', 'o', 'u'};

for (char c : vow el) {

if (rem ainingChars.find(c) != rem ainingChars.end())

Trang 38

getVowelGuess(): thứ tự tìm

Đoán nguyên âm có tần suất xuất hiện cao trước

● Google: letter frequency

Thứ tự: e, a, o, i, u

● Cũng có thể tính tần suất các ký tự trong từ vựng của mình (sẽ làm)

ch ar vow el[] = {'e', 'a', 'o', 'i', 'u'};

Trang 39

B2: lọc từ và chọn chữ cái

● Lọc từ trong từ vựng

○ Có các chữ cái ở vị trí giống secretWord

(trừ dấu gạch ngang)

vector< string> fi lteredW ordList =

getSuitableW ords(w ordList, secretW ord, rem ainingChars);

Trang 40

Duyệt mảng wordList để tìm các từ phù hợp

vector< string> getSuitableW ords( const vector< string> & w ordList,

const string& secretW ord,

const set< ch ar > & rem ainingChars)

{

vector< string> result;

for ( un sign ed in t i = 0 ; i < w ordList.size(); i+ + )

if (isSuitableW ord(w ordList[i], secretW ord, rem ainingChars))

result.push_back(w ordList[i]);

return result;

}

thỏa mãn điều kiện thì đưa vào kết quả

Trang 41

vector< string> result;

for ( con st string& w ord : w ordList)

if (isSuitableW ord(w ord, secretW ord, rem ainingChars))

result.push_back(w ord);

return result;

}

thỏa mãn điều kiện thì đưa vào kết quả

Trang 42

● Có độ dài bằng secretWord

● Các chữ cái ở secretWord hiện đúng vị trí trong word

● Các chữ cái còn lại nằm trong remainingChars

bool isS uitableW ord ( const string& w ord, const string& secretW ord,

const set< char > & rem ainingChars)

{

if (w ord.length() != secretW ord.length()) return false ;

for ( unsigned int i = 0 ; i < w ord.length(); i+ + ) {

Trang 43

Bài tập: tách các bộ lọc riêng

vector< string> getSuitableW ords( const vector< string> & w ordList,

con st string& secretW ord,

con st set< ch ar > & rem ainingChars)

{

vector< string> result;

result = fi lterW ordListByLen(secretW ord.length(), w ordList);

result = fi lterW ordListByM ask(secretW ord, result);

result = fi lterW ordListByRem ainingChars(

rem ainingChars, secretW ord, result);

return result;

}

làm các hàm này

Trang 44

B2: lọc từ và chọn chữ cái

● Chọn chữ cái

Chức năng auto-complete của Google

occurenceCount = getO ccurenceCount(rem ainingChars, fi lteredW ordList);

return g etM axO ccuren ceC h ar (rem ainingChars, occurenceCount);

Trang 45

Thư viện <map>

● Mỗi chữ cái cần lưu số lần xuất hiện

○ Ánh xạ từ ký tự (char) ra số nguyên (int)

○ Trong C++: map<char, int>

○ Thư viện <map>:

http://www.cplusplus.com/reference/map/map/

Trang 46

Thư viện <map>

● Các thao tác với map:

■ 'a' gọi là key , 1 là value

Trang 47

Duyệt các phần tử của map

● Mỗi phần tử của map có dạng

● Duyệt qua map

for (auto p: my_map)

cout << p.first << p.second << endl;

Trang 48

● Khởi tạo count là map<char, int>

remainingChars

● Duyệt qua các từ, với mỗi từ

○ Duyệt qua từng chữ cái

○ Tăng số đếm tương ứng trong count thêm 1

Trang 49

Tăng số đếm các ký tự trong danh sách từ

m ap<char, int> getO ccurenceCount(const set<char> & rem ainingChars,

const vector< string> & w ordList)

{

m ap<char, int> count;

for (char c: rem ainingChars) count[c] = 0;

for (unsig ned int i = 0; i < w ordList.size(); i+ + ) {

const string& w ord = w ordList[i];

for (unsigned int j = 0; j < w ord.length(); j+ + )

if (count.find(w ord[j]) != count.end())

count[w ord[j]]+ + ;

}

retu rn count;

}

Trang 50

Chuyển hết qua lệnh for mới

m ap<char, int> getO ccurenceCount(const set<char> & rem ainingChars, const vector< string> & w ordList)

{

m ap<char, int> count;

for (char c: rem ainingChars) count[c] = 0;

for (con st string& w ord : w ordList) {

for (char c : w ord)

Trang 51

Duyệt các cặp (key, value) trong count

Nếu value > best_count thì gán best bằng c

char getM axO ccurenceC har(const set<char> & rem ainingChars, const m ap<char, in t> & count)

{ char best = 0; int best_count = 0; for (au to p : count)

if (p.second > best_count) { best = p.first;

best_count = p.second;

} return best;

}

Trang 52

Simple AI 1.0

char g etN extG u ess(const set<char> & previousG uesses, const string& secretW ord)

{

static vector< string> w ordList = readW ordListFrom File("data/O gden_Picturable_200.txt");

set<char> rem ainingChars = getRem ainingChars(previousG uesses);

if (rem ainingChars.size() = = 0)

return ;

if (isAllD ash(secretW ord))

return getVow elG uess(rem ainingChars);

vector< string> filteredW ordList = getSuitableW ords(w ordList, secretW ord, rem ainingChars);

m ap<ch ar, int> occurenceCount = getO ccurenceCount(rem ainingChars, filteredW ordList);

retu rn getM axO ccurenceChar(rem ainingChars, occurenceCount);

} // chỉỉ có hàm này được khai báo ởỉ guesser.h, các hàm khác chỉỉ nằm trong guesser.cp p

https://github.com/tqlong/advprogram/archive/9bc66 14903304407ddee771d30cad02cf5051ecb.zip

Ngày đăng: 08/05/2021, 12:19

🧩 Sản phẩm bạn có thể quan tâm