Ứng dụng cỏc chiến lược tỡm kiếm Heuristic cho trũ chơi cờ caro

Một phần của tài liệu CÁC PHƯƠNG PHÁP BIỂU DIỄN TRI THỨC và ỨNG DỤNG vào TRÒ CHƠI cờ CARO (Trang 26 - 37)

5.3.1. Giới thiệu khụng gian trạng thỏi

Như đó biết, trong trũ chơi caro, cứ sau mỗi nước cờ, mỗi đối thủ sẽ chọn ra từ những ụ trống (empty - not occupied) để đi, do đú, sau mỗi nước đi thỡ số ụ trống cũn lại sẽ giảm. Như vậy, việc tỡm nước đi tiếp theo cho trạng thỏi cú sẵn chỉ là việc tỡm kiếm những ụ trống cũn lại, đồng thời, khụng gian tỡm kiếm sẽ thu hẹp theo số nước đi đó tạo. Như vậy, để chọn một nước đi kế tiếp từ một trạng thỏi bàn cờ cú sẵn, ta phải tỡm kiếm nước đi.

Khụng gian chọn nước đi từ mỗi trạng thỏi ban đầu là hữu hạn, nhưng khụng gian tỡm kiếm (searching space) một nước đi dẫn đến chiến thắng là hữu hạn luụn. Nhưng rừ ràng số lượng phần tử của hai khụng gian này đuợc so sỏnh giống như hạt cỏt và sa mạc. Do đú ta khụng thể vột sạch khụng gian tỡm kiếm nước đi này mà ta phải giới hạn khụng gian tỡm kiếm.

Một khụng gian tỡm kiếm cú thể hiện thực theo dạng một cỏi cõy đa phõn bỡnh thường như trong Data Struct định nghĩa, lỳc này nú đuợc gọi là cõy tỡm kiếm, cõy trũ chơi... (Searching Tree, Game Tree), mỗi nỳt (Node) cựng mức của cõy này thể hiện một lựa chọn cỏc nước đi cú sẵn, mức (Ply) này sẽ thể hiện cho việc đỏnh giỏ khoảng cỏch từ nỳt gốc đến những nỳt con này. Nếu số nỳt ở mỗi mức càng nhiều, tức là cú nhiều khả năng chọn lựa một nước đi từ một trạng thỏi trước, do đú độ phõn nhỏnh (Branching factor) của cõy này càng lớn.

Dựa vào cõy trũ chơi đó định nghĩa ở trờn, việc tỡm kiếm nước đi là chọn một nỳt trờn cõy (ở mức một) sao cho nước đú là tốt. Theo thụng thường khi chơi, một nước đi tốt hay khụng là phụ thuộc vào khả năng dành chiến thắng là cao hay thấp sau khi nước đi này đuợc đi. Do đú, muốn chọn một nước đi tốt thỡ nếu chỉ dựa vào thế cờ hiện tại là chưa đủ, mà phải biết thụng tin của những thế cờ sau khi chọn nước này để đi... Vớ dụ như khi chơi trũ caro, chỳng ta chọn nước đi vào một ụ nào đú để chặn đuờng ba hở hai đầu của đối thủ (Opponent, Enemy) vỡ chỳng ta biết là nếu khụng đi nuớc này thỡ sẽ thua ở hai nước đi tiếp theo, tức là trạng thỏi thua cũn chưa biết đuợc nếu ngay sau khi chọn đi một ụ khỏc để đi xuất phỏt trạng thỏi này. Khỏi niệm độ sõu cung nảy sinh từ đõy, đơn giản thỡ độ sõu (Depth) là khả năng “nhỡn thấy trước” (looking ahead) một nước đi tốt sau một loạt nước đi xuất phỏt từ hiện tại, vớ dụ như nếu từ trạng thỏi này, chỳng ta nhận biết đuợc là sau 6

con nữa là mỡnh sẽ thắng (tức là mỗi bờn đi 3 con), khi đú độ sõu tớnh toỏn của chỳng ta là >= 6 [not 3].

Khi viết chương trỡnh cho mỏy tớnh chơi cờ, tức là mỏy tớnh phải tự tỡm nước đi khi chỳng ta đưa vào một trạng thỏi bàn cờ bất kỡ, do khụng gian tỡm kiếm là quỏ lớn (coi như là vụ hạn) nờn chỳng ta chỉ giới hạn cho mỏy tớnh tỡm kiếm đến một độ sõu nhất định. Đú là độ sõu tỡm kiếm lớn nhất.

Hỡnh 5.2: Một phần khụng gian trạng thỏi bài toỏn Tic – tac – toe (cờ caro 3x3)

5.3.2. Tớnh điểm kinh nghiệm cho cỏc nước đi

Từ trạng thỏi hiện tại của bàn cờ, mỏy tớnh sẽ xõy dựng cỏc trạng thỏi khả năng tiếp theo. Sau đú, mỏy tớnh tiến hành tớnh điểm kinh nghiệm cho từng trạng thỏi để chọn ra trạng thỏi tối ưu nhất (trạng thỏi cú lợi nhất cho ta và hạn chế tối đa dẫn đến chiến thắng của địch).

Chỳng ta tớnh điểm kinh nghiệm cho cỏc nước đi dựa trờn cỏc thế cờ kinh nghiệm. Mỗi thế cờ sẽ ứng với một số điểm cụ thể cho ta và cho địch. Sau mỗi nước đi của người chơi, mỏy tớnh sẽ tiến hành phõn tớch trạng thỏi hiện tại của bàn cờ, sau đú sẽ tiến hành so sỏnh thế cỏc thế cờ hiện tại của mỡnh với cỏc thế cờ kinh nghiệm để tớnh điểm kinh nghiệm cho nước đi tiếp theo. Cuối cựng, mỏy tớnh sẽ thực hiện nước đi tốt nhất dựa trờn điểm kinh nghiệm vừa tớnh được.

Điểm kinh nghiệm của mỗi trạng thỏi là tổng điểm cho ta của tất cả cỏc thế cờ trờn bàn cờ trừ cho tổng điểm cho địch.

Số điểm kinh nghiệm được gỏn cho mỗi nước đi kinh nghiệm với đ1 là điểm cho ta (mỏy), đ2 là điểm cho địch (người chơi):

- Trường hợp chắc thắng ở nước đi tiếp theo sau (-011110-,-1011101-,-010111010-, -10111010-): đ1 = 6000; đ2 = 3000.

- Trường hợp cú thể dẫn tới thắng ở cỏc nước đi sau (-11101-, -11110-, -01111-, -101110-, -011101-, -110110-, -011011-, -111010-, -010111-, -0101110-, -0111010-, -0110110-): đ1 = 4000; đ2 = 55.

- Trường hợp tối ưu cú thể dẫn tới chiến thắng sau 2 nước đi (-01110-, -010110-, -011010-, -01011010-): đ1 = 1000; đ2 = 50.

- Trường hợp khú cú thể dẫn tới chiến thắng: -1110-, -0111-, -10110-, -01101-, -11010-, -01011-: đ1 = 30; đ2 = 25.

-0110-, -01010-: đ1 = 20; đ2 = 15.

Nếu thế cờ trờn bàn cờ khụng trựng khớp với cỏc thế cờ kinh nghiệm thỡ đ1 = 0; đ2 = 0.

5.3.3. Cỏc chiến lược tỡm kiếm Heuristic ỏp dụng cho trũ chơi cờ caro

Như chỳng ta đó biết thỡ trũ chơi cờ caro là một trũ chơi cú đối thủ. Tức là yờu cầu phải cú tối thiểu hai người chơi để cú thể tiến hành trũ chơi. Hai người thay phiờn nhau đi nước đi của mỡnh. Áp dụng vào chương trỡnh trũ chơi cờ caro thỡ một người chơi chớnh là chương trỡnh mỏy tớnh. Mỏy tớnh dựa vào cỏc giải thuật tỡm kiếm nước đi đó được lập trỡnh mà tỡm ra nước đi thớch hợp cho mỡnh.

Để thực hiện bài toỏn trũ xõy dựng chương trỡnh trũ chơi cờ caro chỳng ta cú thể sử dụng cỏc chiến lược tỡm kiếm cú đối thủ đó được trỡnh bày ở chương 1 như:

- Chiến lược minimax

- Chiến lược cắt tỉa alpha – beta - Chiến lược negascout

- Chiến lược negamax - Chiến lược MTD(f).

Chương 6

í TƯỞNG VÀ CHƯƠNG TRèNH TRề CHƠI CỜ CARO 6.1. í tưởng cho chương trỡnh trũ chơi cờ caro

6.1.1. Xõy dựng cấu trỳc dữ liệu cho bài toỏn

Chỳng ta xõy dựng chương trỡnh trũ chơi cờ caro này bằng ngụn ngữ C++ với hỗ trợ về giao diện window của phần mềm Microsoft Visual Studio 2005.

Cấu trỳc dữ liệu cho bài toỏn cơ bản như sau:

- int m_box[m][n]: là một mảng biểu diễn bàn cờ, đầu tiên các phần tử của nó đợc khởi tạo = 0 sau đó trong quỏ trỡnh chơi nó sẽ đợc cập nhật (0: chưa đi; 1: người đi; -1: mỏy đi). (adsbygoogle = window.adsbygoogle || []).push({});

- int val[m][n]: là một mảng nháp nó đợc sử dụng để tính các nớc đi tiếp theo. Các phần tử của mảng cho biết điểm các ô trên bàn cờ.

- int Computer, Human: hai biến chỉ rõ nớc đi của ngời hay máy.

- int m_xNext, m_yNext: vị trớ mà mỏy sẽ đi quõn cờ, cho toạ độ của ô có lợi nhất mà máy tính đợc (nếu độ sâu là 0 thì m_xNext, m_yNext là toạ độ ô có điểm lớn nhất trong mảng val).

- BYTE m_nSide: m_nSide = 1 nếu quõn cờ này do mỏy đi

m_nSide=2 nếu quõn cờ này do người đi.

6.1.2. Cỏch tớnh điểm kinh nhiệm

Để tính điểm cho nước đi ở vị trí (i, j) ta tớnh điểm kimh nghiệm theo theo 4 trục như hỡnh sau:

Hỡnh 6.1: Cỏc hướng tớnh điểm kinh nghiệm cho một nước đi

* Các vị trí cần xét khi tính điểm cho một ô

Trớc hết các ô lân cận trên một trục đợc lấy vào một mảng nh hình vẽ, trong đó ô cần xét nằm giữa mảng (vị trí N0 = 4).

Giá trị ô N0 ban đầu là val = 0 ;

- Nếu hai ô lân cận N0 (xét theo một trục) cha đợc đánh thì val = 0 kết thúc xét; - Nếu một trong các ô lân cận đã đợc đánh. Ta giả sử đó là ô bên phải. Có hai trờng hợp xảy ra: ô đó do ngời đánh hay do máy đánh. Vì việc xét hai tờng hợp này là tơng đ- ơng nên ta xét trong trờng hợp máy đã đánh vào ô phải.

Hỡnh 6.2: Mụ phỏng tớnh điểm kinh nghiệm cho cỏc ụ lõn cận

Xuất phát từ ô đang xét: vt[N0] ta tiến sang phải đến khi gặp quân của đối phơng hay gặp quân trống thì dừng lại và đánh dấu ô đó là i0. Nếu cha gặp thì thì tăng điểm của ô N0 lên một lợng là m = i * w trong đó i = 1, 2, 3, 4 và w là trọng số.

Nh vậy nếu cả 4 ô phải đều là quân máy đi thì ô N0 sẽ có điểm là:

Val = (1+ 2 + 3+ 4) * w (Cụ thể w = 13, khi tính cho ngời w=12). Điểm số này ứng với mức u tiên cao nhất nên ta dừng việc xét.

Nếu nh gặp quân đối phơng thì chuyển sang xét 4 ô trái.

Việc xét 4 ô trái tiến hành tơng tự chỉ khác là nếu nh gặp ô trống thì ta sẽ giảm trọng số đi một lợng để điều chỉnh cho phù hợp.

Việc tiến hành xét bên phải còn kiểm tra xem có bị chặn hai đầu. Ví dụ nếu i0 = 3 và đồng thời một trong các vị trí 1, 2 bên trái là O thì điểm ô đang xét bằng 0.

6.1.3. Cỏc hàm dựng trong quỏ trỡnh tớnh điểm kinh nghiệm

Hỡnh 6.3: Sơ đồ hoạt động cho quỏ trỡnh tớnh điểm kinh nghiệm cho một thế cờ

a. Hàm Setbit(unsigned int &x,int i)

í tưởng: trước tiờn, ta sẽ dịch trỏi 1 (…000001) i bit, sau đú thực hiện phộp or (|)

từng bit với giỏ trị x ban đầu. x=(1<<i)|x; VD: x=3, bật bit thứ 5 của x ta thực hiờn.

3=…00000011 1=…00000001.

1<<5=…00100000. (1<<5)|3=…00100011.

b. Hàm Egal(unsigned int x, int len1, unsigned int y, int len2)

- x: Chuỗi bit theo lý thuyết.

- len1: độ dài chuỗi bit theo lý thuyết. - y: chuỗi bit trờn thực tế.

- len2: độ dài chuỗi bit trờn thực tế. (adsbygoogle = window.adsbygoogle || []).push({});

Chức năng: so sỏnh một phần hoặc toàn bộ chuỗi bit của y với x nếu tất cả hoặc một

phần cỏc bit giống nhau thỡ trả về 1 ngược lại trả về 0.

í tưởng: Nếu độ dài thực tế lớn hơn độ dài lý thuyết thỡ chuỗi chắc khụng giống nờn

Egal=0. Ngược lại, tiến hành thực hiện (x & y) ==x. Nếu x hội cỏc bit với y mà giỏ trị vẫn cũn là x thỡ đoạn len2 của x chứa cỏc bit hoàn toàn giống với y. Cũn ngược lại thỡ dịch phải tất cả cỏc bit của x, và trừ len2 cho 1, làm thế trong khi len1 vẫn cũn bộ hơn len2.

Vớ dụ: x = …00100101 y = …01001010 => x &y = ...00000000

Tiến hành dịch phải y 1 bit.

x = …00100101 y = …00100101

=> x &y = ...00100101

c. Hàm Evaluetepiece(Point p,int k, int t, int &diemt, int &diems )

- p: điểm phải xột. - k: hướng phải xột.

- t: điểm cần xột thuộc phớa người chơi nào.

- diemt: Điểm sẽ đạt được nếu thực hiện nước đi tại vị trớ p tại nước đi đang xột (Điểm của ta).

- diems: Điểm sẽ đạt được nếu thực hiện nước đi tại vị trớ p tại nước đi sau (Điểm của địch).

Chức năng: tớnh điểm cho con cờ tại vị trớ p.

- Đặt bit thứ 7 bằng 1, tiến hành đi về phớa k, nếu gặp quõn cờ của địch hoặc biờn thỡ ngưng tỡm kiếm theo hướng k. Nếu trong quỏ trỡnh tỡm kiếm, nhận thấy 2 bit 0, cỏc giỏ trị bit tương ứng sẽ được lưu từ bit 6  0 (ụ trống liờn tiếp) thỡ ngưng. Tiếp tục đi theo hướng ngược lại, và lưu chuỗi bit từ 8 trở lờn.

- Sau đú ta cú được chuỗi x, độ dài chuỗi x là len.

- Tiến hành so sỏnh chuỗi x với cỏc trường hợp (Kinh nghiệm): + Trường hợp chắc thắng ở nước đi hiện tại.

if (Egal(31,5,x,len)) {diemt=10000;diems =10000; return;} //11111 + Trường hợp chắc thắng ở nước đi tiếp theo sau.

if (Egal(30,6,x,len)) {diemt=6000;diems =3000; return;} //011110 if (Egal(93,7,x,len)) {diemt=6000;diems =3000; return;} //1011101 if (Egal(186,9,x,len)) {diemt=6000;diems =3000; return;} //010111010 if (Egal(186,8,x,len)) {diemt=6000;diems =3000; return;} // 10111010 + Trường hợp cú thể dẫn tới thắng ở cỏc nước đi sau.

if (Egal(29,5,x,len)) {diemt=4000;diems =55; return;} //11101 if (Egal(30,5,x,len)) {diemt=4000;diems =55; return;} //11110 if (Egal(15,5,x,len)) {diemt=4000;diems =55; return;} //01111 if (Egal(46,6,x,len)) {diemt=4000;diems =55; return;} //101110 if (Egal(29,6,x,len)) {diemt=4000;diems =55; return;} //011101 if (Egal(54,6,x,len)) {diemt=4000;diems =55; return;} //110110 if (Egal(27,6,x,len)) {diemt=4000;diems =55; return;} //011011 if (Egal(48,6,x,len)) {diemt=4000;diems =55; return;} //111010 if (Egal(23,6,x,len)) {diemt=4000;diems =55; return;} //010111 if (Egal(46,7,x,len)) {diemt=4000;diems =55; return;} //0101110 if (Egal(48,7,x,len)) {diemt=4000;diems =55; return;} //0111010 if (Egal(54,7,x,len)) {diemt=4000;diems =55; return;} //0110110 + Trường hợp tối ưu cú thể dẫn tới chiến thắng sau 2 nước đi. if (Egal(14,5,x,len)) {diemt=1000;diems =50; return;} //01110 if (Egal(22,6,x,len)) {diemt=1000;diems =50; return;} //010110 if (Egal(26,6,x,len)) {diemt=1000;diems =50; return;} //011010 if (Egal(70,8,x,len)) {diemt=1000;diems =50; return;} //01011010 + Trường hợp khú cú thể dẫn tới chiến thắng.

if (Egal(14,4,x,len)) {diemt=30;diems =25; return;} //1110 if (Egal( 7,4,x,len)) {diemt=30;diems =25; return;} //0111 if (Egal(22,5,x,len)) {diemt=30;diems =25; return;} //10110 if (Egal(13,5,x,len)) {diemt=30;diems =25; return;} //01101 if (Egal(26,5,x,len)) {diemt=30;diems =25; return;} //11010 if (Egal(11,5,x,len)) {diemt=30;diems =25; return;} //01011 if (Egal( 6,4,x,len)) {diemt=20;diems =15; return;} //0110 if (Egal(10,5,x,len)) {diemt=20;diems =15; return;} //01010 - Sau khi so sỏnh, hàm trả về diemt và diems cho chương trỡnh.

d. Hàm Eval()

Chức năng: Tớnh điểm cho bàn cờ ở trạng thỏi hiện tại (lỳc đang xột).

í tưởng: tớnh tổng điểm của ta và tổng điểm của đối thủ ở trạng thỏi hiện tại của bàn

cờ, trừ tổng điểm của ta cho tổng điểm của địch sẽ là điểm của thế cờ hiện tại.

Tại một thời điểm, chương trỡnh sẽ hoạt động như sau: Duyệt qua tất cả cỏc phần tử của bàn cờ, nếu quõn cờ tại đú P là quõn cờ của người đang cú lược (ở đõy là mỏy) thỡ sẽ xột theo 4 hướng. Nếu hướng k của quõn cờ tại vị trớ P chưa xột thỡ sẽ tiến hành gọi hàm value(P, k, <người chơi>, diemt, diems). Khi đú điểm của người đang cú lược (Mỏy) ở đõy sẽ là tổng diem += diemt của tất cả cỏc thế cờ trong bàn cờ hiện tại.

Đồng thời nếu quõn cờ tại vị trớ P khụng là quõn cờ của người đang cú lược thỡ cũng tiến hành xột theo 4 hướng. Nếu hướng k của quõn cờ tại vị trớ P chưa xột thỡ sẽ tiến hành gọi hàm value(P, k, <người chơi>, diemt, diems). Khi đú điểm của người đang cú lược (Mỏy) ở đõy sẽ là tổng diem -= diems của tất cả cỏc thế cờ trong bàn cờ hiện tại.

6.1.4. Hoạt động của chương trỡnh

Sự kiện đợc xử lý là sự kiện On_Click xảy ra khi ngời chơi nhấn chuột trên bàn cờ. void CCaro2Dlg::OnLButtonDown(UINT nFlags, CPoint point) {

int x=point.x/20, y=point.y/20; if (!m_box[x][y]&&x<20&&y<20) if (m_who) { m_num++; fillBox(x,y); if(m_num<4) ABeta(x,y,0); else ABeta(x,y,8); (adsbygoogle = window.adsbygoogle || []).push({});

for(int k=1;k<5;k++) displayWinner(x,y,k); fillBox(m_xNext, m_yNext);

updateBox(m_xNext, m_yNext);

for(k=1;k<5;k++) displayWinner(m_xNext, m_yNext,k); }

CDialog::OnLButtonDown(nFlags, point); }

Khi sự kiện này xảy ra chơng trình sẽ tính toạ độ (x,y) ô đợc chọn trên bàn cờ, kiểm tra tính hợp lệ của ô này và gọi hàm fillbox(x,y) để hiển thị nớc đi trên màn hình. Sau đó một vòng lặp sẽ thực hiện để thông báo kết quả (mỗi bớc lặp sẽ tính kết quả theo một h- ớng).

Tiếp theo hàm Abeta (x,y,k) sẽ đợc gọi để xác định nớc đi tiếp theo cho máy; các tham số truyền cho hàm này là toạ độ ô ngời vừa đánh vào, và độ sâu tìm kiếm. Hàm sẽ tính nớc đi tiếp theo và cập nhật vào hai thuộc tính m_xNext, m_yNext đã nói ở trên. Tiếp theo là các công việc hiển thị nớc đi của máy lên màn hình (hàm fillbox (m_xNext, m_yNext)) và cập nhật lại mảng lu trữ bàn cờ bằng hàm updateBox() và cuối cùng là gọi hàm thông báo thắng.

6.2. Giới thiệu về chương trỡnh trũ chơi cờ caro

6.2.1. Mụ hỡnh tổng thể

Hỡnh 6.4: Mụ hỡnh tổng thể của chương trỡnh

Hỡnh 6.5: Giao diện chớnh chương trỡnh

TÀI LIỆU THAM KHẢO

1. Bạch Hưng Khang – Hoàng Kiếm (1989), Trớ tuệ nhõn tạo, cỏc phương phỏp và ứng

Một phần của tài liệu CÁC PHƯƠNG PHÁP BIỂU DIỄN TRI THỨC và ỨNG DỤNG vào TRÒ CHƠI cờ CARO (Trang 26 - 37)