So sánh giải thuật Minimax và giải thuật Alpha-beta

Một phần của tài liệu GIẢI THUẬT TÌM KIẾM MINIMAX VÀ ỨNG DỤNG TRONG CÁC TRÒ CHƠI CÓ TỔNG BẰNG KHÔNG (Trang 47)

Dưới đây là bảng so sánh số nút phải xét giữa hai giải thuật Minimax và Alpha-beta.

Độ sâu Minimax AlphaBeta Tỉ lệ số nút

Minimax/Alpha-beta Số nút Số lần tăng Số nút Số lần tăng

1 40 40 1

3 64000 40 1852 23.2 34 4 2560000 40 3199 1.7 800 5 102400000 40 74118 23.2 1381 6 4096000000 40 127999 1.7 32000 7 163840000000 40 2964770 23.2 55262 8 6553600000000 40 5120000 1.7 1280000

Với b = 40 và d = 4 ta có số nút phải xét là 2x402 - 1 = 3199. Như vậy trong điều kiện lí tưởng thì số nút phải xét nhờ Alpha-beta (chỉ khoảng 3 nghìn nút) ít hơn thuật toán Minimax (hơn 2,5 triệu nút) là 2560000/ 3199 khoảng 800 lần. Còn với b = 40 và d = 5 ta có số nút phải xét là 403 + 40(5/2) - 1 = 64000+10119-1 = 74118. Số nút phải xét nhờ Alpha-beta ít hơn thuật toán Minimax (hơn 102 triệu nút) là 102400000/74118 = 1382 lần.

Ta có thể nhận xét như sau:

- Số lần tăng số nút khi tăng độ sâu của Minimax luôn là hệ số phân nhánh b, trong trường hợp này là 40. Số lần tăng của Alpha-beta ít hơn nhiều: chỉ cỡ 1.7 lần khi tăng từ d lẻ sang d chẵn và 23.2 lần khi từ d chẵn sang lẻ, trung bình chỉ tăng khoảng hơn 6 lần khi tăng d.

- Số nút của Alpha-beta tăng chậm hơn rất nhiều lần so với Minimax. Tỉ số nút phải xét giữa hai giải thuật này càng cao khi d càng lớn.

Công thức tính số nút cho thấy số nút phải xét khi dùng Alpha-beta ít hơn nhiều so với Minimax nhưng vẫn là hàm số mũ và vẫn dẫn tới bùng nổ tổ hợp. Thuật toán Alpha-beta hoàn toàn không chống được bùng nổ tổ hợp mà chỉ làm giảm tốc độ bùng nổ tổ hợp. Tuy trong thực tế số nút phải xét (lượng giá) thường nhiều hơn trong điều kiện lí tưởng nhưng nó vẫn đủ để tiết kiệm khá nhiều thời gian. Trong cùng một khoảng thời gian, thuật toán Alpha-beta có thể tìm đến độ sâu gấp hai lần độ sâu tìm kiếm bằng Minimax. Hình sau đây là đồ thị so sánh giữa hai thuật toán này [5].

Hình 2.10 : Khảo sát sự bùng nổ tổ hợp, Thuật toán Alpha-beta chỉ làm giảm sự bùng nổ tổ hợp chứ không chống được nó. Hệ số phân nhánh trong các đồ thị trên là 40. Tóm lại : Do bùng nổ tổ hợp quá lớn của cây trò chơi mà cả hai người chơi không thể (và không bao giờ) có thể tìm kiếm vét cạn (hết mọi khả năng). Do đó phương pháp tìm kiếm duy nhất là chỉ tìm kiếm đến một độ sâu giới hạn nào đó và chọn nước đi dẫn đến một thế cờ có lợi nhất cho mình. Do phải tính cả khả năng chống trả của đối phương nên ta không dùng được các thuật toán tìm kiếm thông thường. Phải dùng một thuật toán tìm kiếm riêng cho cây trò chơi. Đó là thuật toán Minimax và cải tiến của nó là thuật toán Alpha-beta. Tuy cả hai thuật toán đều không tránh được bùng nổ tổ hợp nhưng thuật toán Alpha-beta làm chậm bùng nổ tổ hợp hơn nên được dùng nhiều trong các trò chơi cờ.

CHƯƠNG 3: ỨNG DỤNG 3.1 Phân tích bài toán

3.1.1 Trò chơi

Trò chơi N quân hậu bắt nguồn từ bài toán rất nổi tiếng là Bài toán 8 con hậu: đặt lần lượt 8 con hậu lên bàn cờ quốc tế (kích thước 8x8) sao cho không có 2 con hậu nào khống chế lẫn nhau. Do vậy, người ta có khá nhiều cách định nghĩa về trò chơi N quân hậu, điển hình là 3 cách sau:

1) Cho bàn cờ quốc tế có kích thước N x N, 2 người chơi lần lượt đặt từng quân hậu lên bàn cờ sao cho không có 2 quân hậu nào khống chế nhau. Người chơi nào không đặt được quân hậu lên bàn cờ nữa là người thua cuộc.

2) Cho bàn cờ quốc tế có kích thước N x N, 2 người chơi lần lượt đặt từng quân hậu lên bàn cờ sao cho không có 2 quân hậu nào khống chế nhau cho đến khi không đặt được nữa. Mỗi quân hậu đặt lên bàn cờ sẽ khống chế các ô nằm trong 8 hướng đi của nó nếu ô đó còn chưa bị khống chế. Ai khống chế được nhiều ô hơn là người thắng cuộc.

3) Cho bàn cờ quốc tế kích thước N x N. Người đi đầu tiên sẽ đặt a quân hậu lên bàn cờ. Người chơi thứ 2 tiếp tục đặt b con hậu lên bàn cờ (a > b và a + b ≤ N) sao cho không có 2 quân hậu nào khống chế lẫn nhau. Sau đó người chơi thứ nhất sẽ di chuyển các con hậu của mình để ăn các con hậu của đối phương, người chơi thứ 2 có nhiệm vụ phòng thủ, di chuyển các con hậu của mình để đối phương không bắt được. Sau k nước đi nếu người chơi thứ nhất ăn được hết b con hậu của đối phương thì người chơi thứ nhất thắng, ngược lại người chơi thứ 2 thắng.

Sau khi cân nhắc, cách phát biểu trò chơi thứ 2 được chọn để tiến hành viết ứng dụng cho luận văn. Tuy nhiên, để cho trò chơi hấp dẫn hơn và công bằng hơn chúng ta bổ sung thêm một số luật chơi.

Phát biểu trò chơi (bài toán) như sau:

Cho bàn cờ có kích thước N x N (3 ≤ N ≤ 15), trên đó có sẵn m ô đá ( hay có thể hiểu là chướng ngại vật) (0 ≤ m ≤ (N - 2)2) nằm ở các vị trí ngẫu nhiên, các ô còn lại là ô trống.

Hai người chơi lần lượt đặt từng con hậu lên bàn cờ sao cho không có 2 con hậu nào khống chế lẫn nhau. Hai con hậu khống chế nhau nếu chúng nằm trên đường đi của nhau và không có ô đá nào nằm trên đường đi ấy.

Mỗi con hậu đặt lên bàn cờ sẽ khống chế các ô nằm trên 8 đường đi của nó nếu ô đó còn trống, chưa bị khống chế bởi con hậu nào khác.

Trò chơi kết thúc khi không đối thủ nào đặt được quân hậu lên bàn cờ nữa. Người nào khống chế được nhiều ô hơn là người thắng cuộc.

Hình 3.1 dưới đây minh họa hai trường hợp: Hai con hậu không khống chế nhau và hai con hậu khống chế nhau:

Hình 3.1

(a) Hai con Hậu không khống chế nhau (b) Hai con Hậu khống chế nhau

Trong hình (a) Con Hậu xanh ở vị trí (2,3) đặt trước do đó nó khống chế được 5 ô, con Hậu màu vàng đặt sau nên chỉ khống chế được 3 ô.

3.1.2 Cơ sở lý thuyết

Theo như phát biểu trò chơi ở trên, ta có thể thấy trò chơi N quân hậu thuộc lớp các trò chơi đối kháng giữa hai người chơi. Cụ thể trò chơi này thuộc dạng trò chơi có tổng bằng không với hai người chơi (Two players, Zero-sum-game). Vì thế ta có thể áp dụng thuật toán tìm kiếm Minimax và thuật toán Alpha-beta trong trò chơi này.

Mặt khác nếu viết chương trình để người chơi với người thì chỉ cần xây dựng các tập luật chơi để người chơi không phạm quy và kết thúc khi có người thắng. Tuy nhiên như vậy lại không ứng dụng và kiểm tra được thuật toán trong luận văn này. Vì vậy chúng ta sẽ viết chương trình cho Người chơi với Máy, trong trường hợp này ta phải tính toán như thế nào để khả năng máy tính thắng cao hơn người.

Máy tính có lợi thế là khả năng tính toán nhanh, khả năng nhớ tốt gấp nhiều lần so với con người, vậy để máy tính thắng thì thật dễ, vấn đề là làm sao để máy có thể nghĩ được như người? Và có thể tính trước được ít nhất là 4 đến 5 nước. Vậy phải có thuật toán để máy có thể quét qua các phương án đi, và chọn phương án cuối cùng là tốt nhất sao cho máy tính có thể thắng. Trong ứng dụng này ta chọn thuật toán Minimax và thuật toán cải tiến Alpha-beta (chương 2) để cài đặt cho máy tính chơi.

3.2 Cài đặt chương trình

Chương trình được cài đặt bằng ngôn ngữ C# (.NET Framework 2.0). Ngoài ra còn sử dụng thêm một số phầm mềm như: PowerCHM, Photoshop và phần mềm tạo file icon.

3.2.1 Cấu trúc chương trình và mối quan hệ giữa các lớp chính

Chương trình được thiết kế theo mô hình Hướng đối tượng(Object-Oriented) để tiện cho việc cải tiến về sau. Do chương trình mới được phát triển nên cấu trúc còn đơn giản, chỉ có 3 lớp chính là các lớp Form1 (tên lớp mặc định do C# đặt cho

form), lớp CBoard và lớp gameAI. Trong đó lớp gameAI là lớp được áp dụng thuật toán trong chương 2 của chúng ta.

Mối quan hệ giữa 3 lớp thể hiện qua sơ đồ các lớp trong hình 3.2 như sau:

Hình 3.2: Sơ đồ thể hiện mối liên quan giữa 3 lớp chính. Trong đó:

- Lớp Form1 có thuộc tính mb thuộc lớp CBoard.

- Lớp CBoard có thuộc tính form thuộc lớp Form1.

- Lớp CBoard có thuộc tính machine thuộc lớp GameAI. - Lớp GameAI có thuộc tính ownBoard thuộc lớp CBoard.

Các lớp tương tác với nhau thông qua các bước sau:

1. Lớp Form1 truyền thông tin nhận được từ người chơi cho lớp CBoard, lớp

CBoard lấy được thông tin thông qua thuộc tính form.

2. Lớp Cboard xử lý dữ liệu thu được từ lớp Form1 và truyền cho lớp GameAI, lớp

GameAI thu được thông qua thuộc tính ownBoard .

3. Lớp GameAI sau khi nhận được thông tin sẽ xử lý và truyền lại cho lớp Cboard, lớp Cboard nhận được thông qua thuộc tính machine.

1

2

4. Lớp Cboard nhận được thông tin từ lớp GameAI, xử lý và truyền lại cho lớp

Form1 thông qua thuộc tính mb. Lớp form1 xử lý lại thông tin và điều chỉnh giao diện của form.

Sau đây chúng ta sẽ xem xét cấu trúc và nhiệm vụ của 3 lớp trên.

3.2.2 Lớp Form1

Lớp này thể hiện giao diện của trò chơi, làm nhiệm vụ giao tiếp với người chơi. Các thao tác chính của lớp này là:

- Nhận thông tin khởi tạo một ván chơi từ người sử dụng như: kích thước bàn cờ, trình độ của máy, số ô đá (hay vật cản) sử dụng, ai là người đi trước để cung cấp thông tin cho lớp CBoard khởi tạo một ván chơi mới.

- Ghi nhận thông tin về nước đi của người chơi mỗi khi người chơi nhấp chuột lên một ô trống rồi truyền cho lớp CBoard xử lý.

- Cập nhật nước đi của người và máy lên màn hình.

- Hiển thị các thông tin về trận đấu như điểm của các đối thủ, các nước đã đi, ai là người đang đi…

- Thể hiện 1 số hiệu ứng khi người dùng di chuyển chuột trên bàn cờ để tiện cho người chơi suy nghĩ, đánh giá.

- Ngoài ra còn thực hiện xuất các kết quả của các ván chơi ra một file Excel để tiện theo dõi lại sau nhiều ván chơi.

Trong mục 3.3 chúng ta sẽ thấy được các thành phần cụ thể của lớp Form1.

3.2.3 Lớp CBoard

Lớp CBoard đóng vai trò như một bàn cờ trong thực tế. Lớp này chứa các thông tin về bàn cờ:

- Một mảng 2 chiều lưu trữ trạng thái từng ô của bàn cờ.

- Kích thước bàn cờ, người đi trước, số ô đá trên bàn cờ, thời gian và trình độ suy nghĩ của máy, điểm của 2 đối thủ.

- Lưu trữ thông tin về nước đi hiện tại: ai đang đi, là nước đi thứ mấy… Các phương thức chính của lớp Cboard như sau:

- Khởi tạo một ván chơi mới.

- Kiểm tra một nước đi có hợp lệ hay không? - Ghi nhận một nước đi.

- Thực hiện nước đi của người chơi. - Yêu cầu máy thực hiện nước đi.

3.2.4 Lớp gameAI

Có thể nói lớp gameAI là lớp trung tâm của các chương trình trò chơi đối kháng. Lớp này chứa các phương thức phục vụ cho việc quyết định đi một nước của máy. Sau đây chúng ta sẽ xem xét chi tiết các thuộc tính và phương thức của lớp này.

Hình 3.3: Cấu trúc lớp gameAI Trong lớp gameAI có các thuộc tính đáng chú ý là:

- Mảng 2 chiều board[,] chứa trạng thái của bàn cờ hiện tại.

o board[i, j] = -100 nếu ô đó là ô đá.

o board[i, j] = -x tức là ô (i, j) chứa con hậu được đặt ở nước thứ x.

- Mảng listCell[] chứa danh sách các ô sẽ bị khống chế nếu ta đặt con hậu ở một ô nào đó

- 2 mảng dx, dy thể hiện 8 hướng đi có thể của quân hậu.

- ownBoard là một thể hiện( đối tượng) của lớp cBoard, chứa bàn cờ chúng ta đang chơi và các thông tin về nó như kích cỡ, trình độ máy v.v…..

- ownedCell: ghi nhận số ô đã bị khống chế trên bàn cờ

- totalCell: tổng số ô trống trên bàn cờ lúc đầu = tổng số ô – số ô đá. - startTime: ghi nhận thời gian bắt đầu suy nghĩ của máy.

- resX, resY: ghi lại nước đi máy sẽ đi.

- bestValue ghi nhận giá trị tốt nhất nếu thực hiện nước đi (resX, resY).

Các phương thức của lớp gameAI

- Lớp chỉ có một phương thức có thuộc tính public là phương thức requestMove(). Phương thức này có đầu vào là một trạng thái của bàn cờ, trả lại giá trị (resX, resY) là ô mà máy sẽ đặt quân hậu. Để tìm kiếm được nước đi tốt nhất, phương thức requestMove sử dụng các phương thức hỗ trợ là:

- AlphaBeta: thực hiện tìm kiếm theo thuật toán Alpha-beta. - Minimax: thực hiện tìm kiếm theo thuật toán Minimax. - Hàm eval: lượng giá thế cờ hiện tại.

- Phương thức heuristicGenerateMove: sinh heuristic các nước đi có thể.

- Phương thức doMove: thử thực hiện một nước đi được sinh bởi phương thức heuristicGenerateMove.

- Phương thức remove: bỏ thực hiện nước đi đã thử (như đã nói trong thuật toán ở chương 2).

Sau đây chúng ta sẽ xem xét các phương thức của lớp gameAI một cách chi tiết.

Function Minimax(depth): integer; Begin

If (đã quá thời gian suy nghĩ) then

return –INFINITY; {dừng không duyệt nữa}

if (depth=0) or (không thể đi được nước nào nữa) then

return eval(depth); {lượng giá ngay thế cờ hiện tại và kết thúc}

best = -INFINITY;

pMove = heuristicGenerateMove; {sinh các nước đi có thể} while (còn lấy được nước đi m trong pMove)do

begin

Thực hiện nước đi m;

value = -Minimax(depth - 1); Bỏ thực hiện nước đi m; if (value > best) then

begin

best := value;

if (đây là nước đi đầu tiên của máy) then

cập nhật nước đi resX, resY;

end;

end; return best; End;

Phương thức Alphabeta

Function AlphaBeta(Alpha, beta, depth): integer; Begin

If (đã quá thời gian suy nghĩ) then

return –INFINITY; {dừng không duyệt nữa}

if (depth=0) or (không thể đi được nước nào nữa) then

return eval(depth); {lượng giá ngay thế cờ hiện tại và kết thúc}

best = -INFINITY;

pMove = heuristicGenerateMove; {sinh các nước đi có thể} while (còn lấy được nước đi m trong pMove) and (best < beta) do begin

if (best > Alpha) then Alpha := best; Thực hiện nước đi m;

value = -AlphaBeta(-beta, -Alpha, depth - 1); Bỏ thực hiện nước đi m;

if (value > best) then

begin

best := value;

if (đây là nước đi đầu tiên của máy) then

cập nhật nước đi resX, resY;

end;

end; return best; End;

Phương thức sinh nước đi heuristicGenerateMove

Trong chương 2 khi đánh giá thuật toán Alpha-beta ta đã nhận xét: thuật toán hoạt động càng hiệu quả khi sự thu hẹp cửa sổ Alpha và Beta càng nhanh. Cửa sổ này được thu hẹp một bước khi gặp một giá trị mới tốt hơn giá trị cũ. Khi gặp giá trị tốt nhất thì cửa sổ này thu hẹp nhất. Do đó nếu càng sớm gặp giá trị tốt nhất thì cửa sổ càng chóng thu hẹp. Như vậy phải làm sao cho các nút ở lá được sắp xếp theo trật tự từ cao xuống thấp. Trật tự này càng tốt bao nhiêu thì thuật toán chạy càng nhanh bấy nhiêu.

Tuy vậy, do giới hạn về thời gian tính toán và sự bùng nổ tổ hợp, ta không thể liệt kê hết các nút lá để sắp xếp được. Do đó, ta chỉ áp dụng cách sinh các nước đi theo một tiêu chuẩn mà ta cho là tốt, phù hợp với đặc điểm trò chơi đang xét như sau:

- Ta thấy, nếu không có ô đá thì nước đi đầu tiên vào ô trung tâm bao giờ cũng chiếm được nhiều ô trống nhất. Do đó, ta sẽ ưu tiên xét các ô theo thứ tự từ ô trung tâm tỏa ra các ô xung quanh (tất nhiên là trừ ô đá!)

- Một cách cảm tính, ta có thể nhận thấy đi vào các ô có số ô trống trong 8 ô xung quanh nó lớn thì có vẻ có lợi hơn.

Như vậy ta có thể sinh các nước đi sắp tới theo hướng heuristic như sau: tìm tất cả các ô còn trống. với mỗi ô, đếm số ô trống xung quanh nó, cho tất cả vào một

Một phần của tài liệu GIẢI THUẬT TÌM KIẾM MINIMAX VÀ ỨNG DỤNG TRONG CÁC TRÒ CHƠI CÓ TỔNG BẰNG KHÔNG (Trang 47)

Tải bản đầy đủ (DOC)

(72 trang)
w