Tải bản đầy đủ (.docx) (29 trang)

báo cáo môn trí tuê nhân tạo áp dụng minmax và cắt tỉa alpha beta xây dựng trò chơi cờ caro trên ngôn ngữ java

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 (647.34 KB, 29 trang )

BÁO CÁO BÀI TẬP LỚN
Đề tài:
Chiến lược Minimax – Alpha-Beta Pruning
Game cờ Caro
Nhóm 8
• Lê Phương Nam 20093538
• Hoàng Mạnh Tiến 20092693
• Trịnh Văn Thắng 20202223
• Bùi Xuân Trường 20092906
• Lê Hồng Văn 20093231
• Lê Anh Vi 20093679
1
MỤC LỤC
I. Giới thiệu thuật toán minimax và cắt tỉa alpha-bêta
1. Thuật toán Minimax
Thuật toán Minmax hay còn gọi là Minimax là một thuật toán dùng trong tìm kiếm
có đối thủ. Cải tiến của thuật toán này là thuật toán cắt tỉa Alpha-Beta (Alpha -
Beta Pruning) rất hay được sử dụng làm chiến lược cho tìm kiếm nước đi trong
không gian tìm kiếm của trò chơi có tính chất đối kháng (vd cờ Tướng, cờ Vua, cờ
caro ). Nói một cách dễ hiểu, thì ý nghĩa của thuật toán này bạn có thể hiểu một
cách đơn giản như sau: Giả sử bạn đang đánh cờ với máy, thì cả bàn cờ sẽ được
biểu diễn trong một cái gọi là không gian trạng thái (KGTT) - bạn có thể hình dung
KGTT chính là cách mà máy tính biểu diễn bàn cờ thực lên bộ nhớ máy tính. Với
mỗi nước đi (mỗi thay đổi) sẽ làm cho KGTT của bàn cờ thay đổi thành một
KGTT mới. Như vậy, đến nước đi của máy. Chiến lược tìm kiếm nước đi Minimax
sẽ được sử dụng để làm sao tìm ra nước đi tốt nhất cho máy. Để có được nước đi
tốt thì cần có một sự lượng giá tốt - là kết quả từ một hàm lượng giá (tức là cách
đánh giá, như lúc mình tính ở trong đầu í == độ uyên thâm). Độ sâu (depth) là số
nước mà máy sẽ tính trước. Như vậy giả sử với độ sâu là 4 thì sẽ tìm với tầm nhìn
2
là 4 nước đi. Nút có kết quả lượng giá cao nhất ở mức gốc (mức 0) sẽ được chọn


để đi (trong hình ở mức 0 chỉ có 1nút thôi, nên bạn hình dung là như vậy).
Mức 0, 2, 4 là lượt đi của máy - mức MAX (kết quả lượng giá càng lớn càng tốt).
Mức 1, 3 là lượt đi của người - mức MIN (kết quả lượng giá càng nhỏ càng tốt).
a. Hàm Minimax
Quá trình chơi cờ là quá trình Trắng và Đen thay phiên nhau đưa ra quyết định,
thực hiện một trong số các nước đi hợp lệ. Trên cây trò chơi, quá trình đó sẽ tạo ra
đường đi từ gốc tới lá. Giả sử tới một thời điểm nào đó, đường đi đã dẫn tới đỉnh u.
Nếu u là đỉnh Trắng (Đen) thì Trắng (Đen) cần chọn đi tới một trong các đỉnh Đen
(Trắng) v là con của u. Tại đỉnh Đen (Trắng) v mà Trắng (Đen) vừa chọn, Đen
(Trắng) sẽ phải chọn đi tới một trong các đỉnh Trắng (Đen) w là con của v. Quá
trình trên sẽ dừng lại khi đạt tới một đỉnh là lá của cây.
Giả sử Trắng cần tìm nước đi tại đỉnh u. Nước đi tối ưu cho Trắng là nước đi dần
tới đỉnh con của v là đỉnh tốt nhất (cho Trắng) trong số các đỉnh con của u. Ta cần
giả thiết rằng, đến lượt đối thủ chọn nước đi từ v, Đen cũng sẽ chọn nước đi tốt
nhất cho anh ta. Như vậy, để chọn nước đi tối ưu cho Trắng tại đỉnh u, ta cần phải
xác định giá trị các đỉnh của cây trò chơi gốc u. Giá trị của các đỉnh lá (ứng với các
trạng thái kết thúc) là giá trị của hàm kết cuộc. Đỉnh có giá trị càng lớn càng tốt
cho Trắng, đỉnh có giá trị càng nhỏ càng tốt cho Đen. Để xác định giá trị các đỉnh
3
của cây trò chơi gốc u, ta đi từ mức thấp nhất lên gốc u. Giả sử v là đỉnh trong của
cây và giá trị các đỉnh con của nó đã được xác định. Khi đó nếu v là đỉnh Trắng thì
giá trị của nó được xác định là giá trị lớn nhất trong các giá trị của các đỉnh con.
Còn nếu v là đỉnh Đen thì giá trị của nó là giá trị nhỏ nhất trong các giá trị của các
đỉnh con.
Ví[i] dụ:[/i] Xét cây trò chơi trong hình trên, gốc a là đỉnh Trắng. Giá trị của các
đỉnh là số ghi cạnh mỗi đỉnh. Đỉnh i là Trắng, nên giá trị của nó là max(3,-2) = 3,
đỉnh d là đỉnh Đen, nên giá trị của nó là min(2, 3, 4) = 2. Việc gán giá trị cho các
đỉnh được thực hiện bởi các hàm đệ qui MaxVal và MinVal. Hàm MaxVal xác
định giá trị cho các đỉnh Trắng, hàm MinVal xác định giá trị cho các đỉnh Đen.
function MaxVal(u);

begin
if u là đỉnh kết thúc then MaxVal(u) ¬ f(u)
else MaxVal(u) ¬ max{MinVal(v) | v là đỉnh con của u}
end;
function MinVal(u);
begin
if u là đỉnh kết thúc then MinVal(u) ¬ f(u)
else MinVal(u) ¬ min{MaxVal(v) | v là đỉnh con của u}
end;
Trong các hàm đệ quy trên, f(u) là giá trị của hàm kết cuộc tại đỉnh kết thúc u. Sau
đây là thủ tục chọn nước đi cho trắng tại đỉnh u. Trong thủ tục Minimax(u,v), v là
biến lưu lại trạng thái mà Trắng đã chọn đi tới từ u.
procedure Minimax(u, v);
begin
val ¬ -¥;
for mỗi w là đỉnh con của u do
if val <= MinVal(w) then
{val¬ MinVal(w);
v ¬ w}
end;
4
Thủ tục chọn nước đi như trên gọi là chiến lược Minimax, bởi vì Trắng đã chọ
được nước đi dẫn tới đỉnh con có giá trị là max của các giá trị các đỉnh con, và Đen
đáp lại bằng nước đi tới đỉnh có giá trị là min của các giá trị các đỉnh con.
Thuật toán Minimax là thuật toán tìm kiếm theo độ sâu, ở đây ta đã cài đặt thuật
toán Minimax bởi các hàm đệ quy. Bạn đọc hãy viết thủ tục không đệ quy thực
hiện thuật toán này.
Về mặt lí thuyết, chiến lược Minimax cho phép ta tìm được nước đi tối ưu cho
Trắng. Song nó không thực tế, chúng ta sẽ không có đủ thời gian để tính được
nước đi tối ưu. Bởi vì thuật toán Minimax đòi hỏi ta phải xem xét toàn bộ các đỉnh

của cây trò chơi. Trong các trò chơi hay, cây trò chơi là cực kỳ lớn. Chẳng hạn, đối
với cờ vua, chỉ tính đến độ sâu 40, thì cây trò chơi đã có khoảng 10120 đỉnh! Nếu
cây có độ cao m, và tại mỗi đỉnh có b nước đi thì độ phức tạp về thời gian của thuật
toán Minimax là O(bm).
Để có thể tìm ra nhanh nước đi tốt (không phải là tối ưu) thay cho việc sử dụng
hàm kết cuộc và xem xét tất cả các khả năng dẫn tới các trạng thái kết thúc, chúng
ta sẽ sử dụng hàm đánh giá và chỉ xem xét một bộ phận của cây trò chơi.
b. Hàm lượng giá
Hàm đánh giá eval ứng với mỗi trạng thái u của trò chơi với một giá trị số eval(u),
giá trị này là sự đánh giá “độ lợi thế” của trạng thái u. Trạng thái u càng thuận lợi
cho Trắng thì eval(u) là số dương càng lớn; u càng thuận lợi cho Đen thì eval(u) là
số âm càng nhỏ; eval(u) » 0 đối với trạng thái không lợi thế cho ai cả.
Chất lượng của chương trình chơi cờ phụ thuộc rất nhiều vào hàm đánh giá. Nếu
hàm đánh giá cho ta sự đánh giá không chính xác về các trạng thái, nó có thể
hướng dẫn ta đi tới trạng thái được xem là tốt, nhưng thực tế lại rất bất lợi cho ta.
Thiết kế một hàm đánh giá tốt là một việc khó, đòi hỏi ta phải quan tâm đến nhiều
nhân tố: các quân còn lại của hai bên, sự bố trí của các quân đó, ở đây có sự mâu
thuẫn giữa độ chính xác của hàm đánh giá và thời gian tính của nó. Hàm đánh giá
chính xác sẽ đòi hỏi rất nhiều thời gian tính toán, mà người chơi lại bị giới hạn bởi
thời gian phải đưa ra nước đi.
5
[i]Ví dụ 1:[/i] Sau đây ta đưa ra một cách xây dựng hàm đánh giá đơn giản cho cờ
vua. Mỗi loại quân được gán một giá trị số phù hợp với “sức mạnh” của nó. Chẳng
hạn, mỗi tốt Trắng (Đen) được cho 1 (-1), mã hoặc tượng Trắng (Đen) được cho 3
(-3), xe Trắng (Đen) được cho 5 (-5) và hoàng hậu Trắng (Đen) được cho 9 (-9).
Lấy tổng giá trị của tất cả các quân trong một trạng thái, ta sẽ được giá trị đánh giá
của trạng thái đó. Hàm đánh giá như thế được gọi là hàm tuyến tính có trọng số, vì
nó có thể biểu diễn dưới
dạng:
s1w1

+s2w2+. . .
+snwn.
Trong đó, wi là giá trị mỗi loại quân, còn si là số quân loại đó. Trong cách đánh giá
này, ta đã không tính đến sự bố trí của các quân, các mối tương quan giữa chúng.
Thuật giải:
6
2. Cắt tỉa Alpha-Beta
Minimax yêu cầu phải có sự phân tích qua hai bước đối với không gian tìm kiếm:
Bước đầu truyền xuống đến độ sâu của lớp áp dụng heuristic và bước sau để truyền
ngược các giá trị trên cây. Minimax lần theo tất cả các nhánh trong không gian bao
gồm cả những nhánh mà một thuật toán thông minh hơn có thể bỏ qua hay tỉa bớt.
Các nhà nghiên cứu trong lĩnh vực chơi game đã xây dựng một kỹ thuật tìm kiếm
gọi là cắt tỉa alpha –beta nhằm nâng cao hiệu quả tìm kiếm trong các bài toán trò
chơi hai đối thủ.
Ý tưởng của tìm kiếm alpha – beta rất đơn giản: Thay vì nếu như tìm kiếm toàn bộ
không gian đến một độ sâu lớp cố định, tìm kiếm alpha – beta thực hiện theo kiểu
tìm kiếm sâu. Có hai giá trị, gọi là alpha và beta được tạo ra trong quá trình tìm
kiếm. Giá trị alpha liên quan với các nút MAX và có khuynh hướng không bao giờ
7
giảm. Ngược lại giá trị beta liên quan đến các nút MIN và có khuynh hướng không
bao giờ tăng. Giả sử có giá trị alpha của một nút MAX là 6, MAX không cần phải
xem xét giá trị truyền ngược nào nhỏ hơn hoặc bằng 6 có liên quan với một nút
MIN nào đó bên dưới. Alpha là giá trị thấp nhất mà MAX có thể nhận được sau
khi cho rằng MIN cũng sẽ nhận giá trị tốt nhất của nó. Tương tự nếu MIN có giá trị
beta là 6 nó cũng không cần xem xét các nút nằm dưới nó có giá trị lớn hơn hoặc
bằng 6.
Để bắt đầu thuật toán tìm kiếm alpha – beta, ta đi xuống hết độ sâu lớp theo kiểu
tìm kiếm sâu, đồng thời áp dụng đánh giá heuristic cho một trạng thái và tất cả các
trạng thái anh em của nó. Giả thuyết tất cả đều là nút MIN. Giá trị tối đa của các
nút MIN này sẽ được truyền ngược lên cho nút cha mẹ (là một nút MAX). Sau đó

giá trị này được gán cho ông bà của các nút MIN như là một giá trị beta kết thúc
tốt nhất. Tiếp theo thuật toán này sẽ đi xuống các nút cháu khác và kết thúc việc
tìm kiếm đối với nút cha mẹ của chúng nếu gặp bất kỳ một giá trị nào lớn hơn hoặc
bằng giá trị beta này. Quá trình này gọi là cắt tỉa beta (β cut). Cách làm tương tự
cũng được thực hiện cho việc cắt tỉa alpha (α cut) đối với các nút cháu của một nút
MAX.
Hai luật cắt tỉa dựa trên các giá trị alpha và beta là:
1. Quá trình tìm kiếm có thể kết thúc bên dưới một nút MIN nào có giá trị beta nhỏ
hơn hoặc bằng giá trị alpha của một nút cha MAX bất kỳ của nó.
2. Quá trình tìm kiếm có thể kết thúc bên dưới một nút MAX nào có giá trị alpha
lớn hơn hoặc bằng giá trị beta của một nút cha MIN bất kỳ của nó.
Việc cắt tỉa alpha – beta như vậy thể hiện quan hệ giữa các nút ở lớp n và các nút ở
lớp n+2 và do quan hệ đó toàn bộ các cây con bắt nguồn ở lớp n+1 đều có thể loại
khỏi việc xem xét. Chú ý rằng giá trị truyền ngược thu được hoàn toàn giống như
kết quả Minimax, đồng thời tiết kiệm được các bước tìm kiếm một cách đáng kể.
8
Thuật giải :
9
II. Xây dựng chương trình chơi cờ caro
1. Các vấn đề khi xây dựng chương trình
Chương trình có hai phần:
10
• Phần dữ liệu
• Phần giao diện
Dữ liệu chỉ gồm một mảng b[size][size] mỗi phần tử của mảng ứng với một giá trị
0,1,2, các trường trạng thái, và các hàm AI.
Tương ứng bên giao diện là một mảng các Label có khả năng thay đổi Icon hiển thị
khi Click chuột. Mỗi lần thay đổi bên giao diện thì dữ liệu được cập nhật ngay lập
tức. Ngược lại, khi phần dữ liệu có thay đổi chính thức thì cũng lập tức cập nhật
lên giao diện.

2. Áp dụng thuật toán min–max và cắt tỉa alpha-bêta
Sử dụng hàm minimax như sau:
Xây dựng các hàm chính:
score(): Hàm lượng giá một trạng thái bàn cờ.
min(int n): Trả về giá trị score() thấp nhất cho bên Min (bên X) sau n nước cờ.
max(int n): Trả về giá trị score() cao nhất cho bên Max (bên O) sau n nước cờ.
a. Hàm lượng giá eval():
Sau đây là quy ước hàm lượng giá đối với bên Max, bên Min cũng vậy nhưng thêm
dấu “-” cho mỗi giá trị đạt được.
Trả về 100000 nếu bên Max thắng;
Trả về 10000 đối với:
Trạng thái dãy 4 mở hai đầu (openFour):
11
Hai dãy 4 mở 1 đầu (halfOpenFour):

Trả về 5000 đối với 1 dãy 3 mở hai đầu + 1 dãy 4 mở 1 đầu:
Trả về 3000 đối với Hai dãy 3 mở hai đầu:
Trả về 1000 điểm đối với 1 dãy 3 mở hai đầu + 1 dãy ba mở một đầu:
12
Trả về 500 điểm đối với 1 dãy 4 mở 1 đầu:
200 điểm cho trạng thái có 1 dãy 3 mở hai đầu
100 điểm cho trạng thái có 1 cặp dãy 2 mở hai đầu:
13
50 điểm nếu trạng thái chỉ có 1 dãy 3 mở một đầu:
10 điểm cho trạng thái có 1 cặp dãy 2 mỗi dãy chỉ mở 1 đầu:
5 điểm cho trạng thái có 1 dãy 2 mở hai đầu:
3 điểm cho 1 dãy 2 mở một đầu:
0 điểm Các trạng thái còn lại và trạng thái hòa
b. Xây dụng hàm minimax và cắt tỉa alpha-beta
Minimax:

14
Ban đầu chỉ mục tiêu xây dựng hàm min(n) và hàm max(n) chứ chưa chú ý đến cắt
tỉa anpha-betha:
max(n):
Hàm này tính giá trị cho trạng thái sau khi bên Min vừa đánh xong.
Vì bên Max sẽ đánh tiếp theo nên Max nhất định sẽ chọn nước đánh đưa đến trạng
thái có giá trị cao nhất có thể. Vậy hàm max(n) được xây dụng như sau:
Xét tất cả các trạng thái tiếp theo, tính giá trị min(n-1) đối với mỗi trạng thái, trả
về giá trị lớn nhất.
min(n):
Hàm này tính giá trị cho trạng thái sau khi bên Max vừa đánh xong.
Vì bên Min sẽ đánh tiếp theo nên Min nhất định sẽ chọn nước đánh đưa đến trạng
thái có giá trị thấp nhất có thể. Vậy hàm min(n) được xây dụng như sau:
Xét tất cả các trạng thái tiếp theo, tính giá trị max(n-1) đối với mỗi trạng thái, trả
về giá trị nhỏ nhất.
max(n) và min(n) là hai hàm đệ quy lồng nhau.
Code: Hàm min(n)
public int min(int n){

updateArea(); //Cập nhật lại trạng thái
if(n==0){ //Nếu n=0 thì trả về giá trị của hàm lượng
giá
return eval();
}
int i,j,k,top,min,temp;
top = openArea.top;
15
if(top==-1) {
return 0;
}

min = 100000;
for(k=0;k<=openArea.top;k++){ //Vòng lặp duyệt các trạng thái tiếp
theo
i = openArea.a[0][k];
j = openArea.a[1][k];
b[i][j] = 1; //Đánh nước đi giả thiết
closeArea.push(i, j);
updateArea();
temp = max(n-1);
b[i][j] = 0;
closeArea.pop();
updateArea();
if(temp<min){ //Chọn nước đi có giá trị max(n-1) thấp nhất.
min = temp;
}
}
return min; //Trả về giá trị thấp nhất
}
Tuy nhiên max(n) và min(n) mới chỉ là hai hàm tính giá trị, chưa phải hàm ra quyết
định, vậy xây dựng hàm ra quyết định cho bên Max và Min:
16
Hàm đưa ra quyết định cho bên Max:
public void maxPlay(int n){
updateArea();
int i,j,im,jm,k,top,max,temp;
top = openArea.top;
if(top==-1) {
b[11][11] = 2;
u[11][11].setNO();
updateArea();

return;
}
max = -100000;
im = 0;
jm = 0;
for(k=0;k<=openArea.top;k++){
i = openArea.a[0][k];
j = openArea.a[1][k];
b[i][j] = 2; //Thử các nước đi.
closeArea.push(i, j);
updateArea();
temp = min(n,max);
b[i][j] = 0;
closeArea.pop();
updateArea();
if(temp>max){ //Chọn nước đi có giá trị m in(n-1) cao nhất.
17
max = temp;
im = i;
jm = j;
}
}
closeArea.push(im, jm);
b[im][jm] = 2;
u[im][jm].setNO();
if(im==12-size/2||jm==12-size/2||im==11+size/2||jm==11+size/2){
resize(size+2);
}
updateArea();
System.out.println("Max("+n+"): "+max);

}
Cắt tỉa alpha-beta
Xét hàm maxPlay(n) :
Trong khi xét các trạng thái tiếp theo, giả sử trạng thái đầu tiên cho giá trị max(n)
= x;
Như vậy trong các trạng thái tiếp theo ta chỉ quan tâm đến các trạng thái cho giá trị
max(n) < x; nếu biết trước một trạng thái nào đó có max(n) >x, ta có thể bỏ qua
trạng thái này.
Bởi vì nguyên tắc hoạt động trong hàm max(n) là chọn ra giá trị lớn nhất trong các
trạng thái kế tiếp, nên chỉ cần tồn tại 1 trạng thái kế tiếp cho giá trị > x thì ta có thể
bỏ qua không cần tính tiếp hàm này nữa và quy cho kết quả max(n) = x+1, bởi ta
18
không cần quan tâm kết quả chính xác của hàm này, chỉ cần nó > x ta không chọn
phương án đó.
Từ đây ta có thể xây dựng hàm minimax kết hợp cắt tỉa alpha-betha hoàn chỉnh
như sau:
min( n, prunValue) // Tham số đầu vào là độ sâu n và giá trị cắt prunValue
{
m = 100000; //Khởi tạo m vô cùng lớn
for each: Các trạng thái tiếp theo
if(max(n-1,m)<prunValue) //Nếu giá trị < prunValue thì cắt tỉa
{
return max(n-1,m);
}
if(max(n-1,Min)<m)
{
Min = max(n-1,m);
}
return m; //Nếu không có giá trị nào < prunValue thì chọn ra GTNN.
}

3. Các chiến lược phụ trợ
Để tăng tốc độ chương trình, ngoài áp dụng cắt tỉa alpha-beta chúng tôi còn áp
dụng một số chiến lược mới đó là khoanh vùng xét duyệt và nhận định trạng thái
sơ lược.
a. Khoanh vùng xét duyệt tính toán.
19
Để khoanh vùng xét duyệt, máy lưu vị trí các nước đi sau đó chỉ duyệt các
nước đi lân cận các nước đi đã đánh trước đó.
Stack lưu vị trí đã đánh: closeArea
Stack lưu miền xét duyệt: openArea
Hàm cập nhật trạng thái:
public void updateArea(){
int i,j,k,top;
if(!openArea.isEmpty()){
top = openArea.top;
for(k=0;k<=top;k++){
i = openArea.a[0][k];
j = openArea.a[1][k];
u[i][j].area = 0;
}
openArea.empty(); //Làm rỗng vùng xét duyệt.
}
if(closeArea.isEmpty()){ //Nếu vùng chơi rỗng tạo vùng xét
openArea.push(11, 11); // duyệt gồm 1 ô giữa bàn cờ.
u[11][11].area = 1;
return;
}

top = closeArea.top; //Tạo vùng xét duyệt mới bằng cách lần lượt
for(k=0;k<=top;k++){ // xét các ô xung quanh những ô đã đánh.

i = closeArea.a[0][k];
20
j = closeArea.a[1][k];
if(i>0){
if(b[i-1][j]==0&&u[i-1][j].area==0){
openArea.push(i-1, j);
u[i-1][j].area = 1;
}
}
if(i>0&&j<23){
if(b[i-1][j+1]==0&&u[i-1][j+1].area==0){
openArea.push(i-1, j+1);
u[i-1][j+1].area = 1;
}
}
if(j<23){
if(b[i][j+1]==0&&u[i][j+1].area==0){
openArea.push(i, j+1);
u[i][j+1].area = 1;
}
}
if(i<23&&j<23){
if(b[i+1][j+1]==0&&u[i+1][j+1].area==0){
openArea.push(i+1, j+1);
u[i+1][j+1].area = 1;
}
}
if(i<23){
21
if(b[i+1][j]==0&&u[i+1][j].area==0){

openArea.push(i+1, j);
u[i+1][j].area = 1;
}
}
if(i<23&&j>0){
if(b[i+1][j-1]==0&&u[i+1][j-1].area==0){
openArea.push(i+1, j-1);
u[i+1][j-1].area = 1;
}
}
if(j>0){
if(b[i][j-1]==0&&u[i][j-1].area==0){
openArea.push(i, j-1);
u[i][j-1].area = 1;
}
}
if(i>0&&j>0){
if(b[i-1][j-1]==0&&u[i-1][j-1].area==0){
openArea.push(i-1, j-1);
u[i-1][j-1].area = 1;
}
}
}
}
22
b. Thủ tục nhận định trạng thái
Trong tại một trạng thái, ngoài việc thu hẹp vùng xét duyệt thành một vùng
lân cận các ô đã đánh còn dùng một phương thức rất hiệu quả để thu hẹp vùng xét
duyệt đó là nhận định trạng thái bằng tri thức bổ sung.
Ví dụ trong trường hợp khi đối thủ là MIN đã tạo được một hàng 4 mở 1

đầu, thì hiển nhiên MAX cần phải chặn, lúc này có thể bỏ qua không cần xét duyệt
bằng MIMAX. Hoặc trường hợp MIN tạo được một hàng 3 mở hai đầu thì hoặc
MAX phải chặn một đầu ngay, hoặc MAX phải tạo được một hàng 4 ngay, lúc này
hàm MIMAX chỉ cần xét duyệt trong các trường hợp này xem trường hợp nào cho
giá trị cao nhất chứ không cần phải duyệt hết tất cả các trạng thái.
Từ ý tưởng trên chúng ta xây dựng hàm một số hàm đánh giá trạng thái, thu
nhỏ vùng xét duyệt openArea thành vùng xét duyệt thu nhỏ miniArea:
Định nghĩa:
Trạng thái thắng: Là trạng thái hình thành 1 hàng 5 ô liên tiếp.
Trạng thái thắng sau 1 nước: Là trạng thái tồn tại ít nhất 1 dãy 4 mở hai đầu hoặc
2 dãy 4 mở một đầu. Bởi vì thời gian tồn tại của đối thủ tối đa chỉ là 1 nước chặn,
sau đó phía mình sẽ đat đến trạng thái thắng.

Trạng thái thắng sau 2 nước: Là trạng thái tồn tại ít nhất 2 dãy ba mở hai đầu
hoặc 1 dãy 3 mở hai đầu và 1 dãy 4 mở 1 đầu. Vì từ trạng thái này đối thủ không
thể ngăn cản phía mình đạt đến Trạng thái thắng sau 1 nước.
23
Từ đó ta hình thành thứ tự ưu tiên cho các nước đi như sau:
Giả sử đến lượt MAX đi, thủ tục xét duyệt như sau:
Cho trước:
openArea: vùng xét duyệt ban đầu.
miniArea: là vùng xét duyệt rút gọn, khi bắt đầu thủ tục khởi tạo A rỗng.
1) IF(MAX Tồn tại nước đi để đạt đến Trạng thái thắng) THEN <Đi nước đi
này; return;>
ELSE <Chuyển qua bước 2>
2) IF(MIN Tồn tại nước đi để đạt đến Trạng thái thắng) THEN <Chặn nước
đi này; return;>
ELSE <Chuyển qua bước 3>
3) IF(MAX Tồn tại nước đi để đạt đến Trạng thái thắng sau 1 nước) THEN
<Đi nước đi này; return;>

ELSE <Chuyển qua bước 4>
4) WHILE(MIN Tồn tại nước đi (I,J) để đạt đến Trạng thái thắng sau 1
nước) THEN < miniArea  (I,J) >
ELSE <Chuyển qua bước 6>
5) FOR ( (I,J)∈ miniArea) < Max thử đánh vào (I,J) Tính Min(n); Chọn
(I,J) cho giá trị Min(I,J) lớn nhất rồi cuối cùng Max đánh vào
(I,J);return;>
6) IF(MAX Tồn tại nước đi để đạt đến Trạng thái thắng sau 2 nước) THEN
<Đi nước đi này> ELSE <Chuyển qua bước 7>
7) WHILE(MIN Tồn tại nước đi (I,J) để đạt đến Trạng thái thắng sau 2
nước) THEN < miniArea  (I,J) >ELSE <Chuyển qua bước 9>
24
8) FOR ( (I,J)∈ miniArea ) < Max thử đánh vào (I,J) Tính Min(n); Chọn
(I,J) cho giá trị Min(I,J) lớn nhất rồi cuối cùng Max đánh vào (I,J)>
9) Thực hiện hàm maxPlay(). (Lúc này thủ tục đánh giá trạng thái không
thành công, thực hiện maxPlay() duyệt hết các nước đi trong openArea)
III. Hoạt động của game cờ CARO
1. Các tùy chọn.
Chức năng tùy chọn kích thước:
Có thể chọn kích thước bàn cờ theo các kích thước cho sẵn hoặc khi đánh đến các
ô ở giới hạn, bàn cờ sẽ tự động mở rộng thêm:

Các cấp độ khó: Có 4 level để người chơi tùy chọn, mỗi level ứng với một độ sâu
trong giải thuật MiniMax:
25

×