Chương trình dùng một mảng hai chiều để lưu một trạng thái của trò chơi. Mỗi trạng thái đó còn có các thuộc tính khác như:
- Chi phí đi từ trạng thái khởi đầu đến trạng thái hiện tại.
- Chỉ số ước lượng Heuristic, là chi phí để đi đến đích từ trạng thái đó. - Chỉ số f là tổng hai chi phí bên trên.
- Và trạng thái cha của trạng thái hiện tại.
Khi một trạng thái được tạo ra thì các chỉ số phía trên cũng được tính toán là gán vào cho trạng thái. Bên cạnh đó khi trạng thái thay đổi thì các chỉ số cũng được tính toán hoặc xử lý lại cho phù hợp.
Chương trình xây dựng lớp PuzzleGame để xử lý trò chơi và đưa ra một danh sách chứa các trạng thái để trò chơi có thể đi đến đích.
Thuật toán A*
public void solveAstar() { //Giải quyết A* KQ.clear();
long startTime = System.currentTimeMillis();
initialnode.f = initialnode.h = initialnode.estimate(goalnode); initialnode.g = 0;
FRINGE.add(0, initialnode); // cho nút đầu đầu tiên vào FRINGE total_nodes = 0;
count = 0; while (true) {
if (FRINGE.isEmpty() || !(Main.window.issolu)) //điều kiện dừng { FRINGE.clear(); M.clear(); Stop = "stop"; return; }
if (System.currentTimeMillis()- startTime > 180000) //điều kiện dừng { FRINGE.clear(); M.clear(); Stop = ":D \n"; return; } lowIndex = 0; fmin = FRINGE.elementAt(0).f;
for (int i = 0; i < FRINGE.size(); i++) // tìm nút có f nhỏ nhất trong FRINGE { number = FRINGE.elementAt(i).f; if (number < fmin) {
lowIndex = i; //vị trí nút có fmin trong FRINGE fmin = number;
} }
n = FRINGE.elementAt(lowIndex); //xét nút n có fmin
FRINGE.removeElement(n); //xóa nút đã xét trong FRINGE
if(n.h == 0) //if (n.equals(goalnode)) //kiểm tra nút đang xét có phải là đích
{
long endTime = System.currentTimeMillis(); time_solve = endTime - startTime;
total_nodes = count + FRINGE.size(); AddKQ(n); //đưa kết quả vào trong KQ FRINGE.clear();
M.clear(); return; }
M = n.successors(); // sinh tâp trạng thái con của n if(n.Parent != null)
{
{
if(isKT(n.Parent,M.elementAt(i))) // xóa trạng thái con của n trùng với trạng thái Cha(n)
M.remove(i); }
}
for (int i = 0; i < M.size(); i++) // tính thông số của các trạng thái con { Node s = M.elementAt(i); s.g = n.g + s.cost; s.h = s.estimate(goalnode); s.f = s.g + s.h; tempNode = (Node)M.elementAt(i);
tempNode.Parent = n; // đặt n là cha các trạng thái con
FRINGE.add(0, M.elementAt(i)); // thêm các trạng thái con vào FRINGE
}
count++; //tăng số nút đã duyệt }
}
Thuật toán IDA*
public void solveIDAstar() { //giải quyết IDA* KQ.clear();
long startTime = System.currentTimeMillis();
initialnode.f = initialnode.h = initialnode.estimate(goalnode); initialnode.g = 0;
cutOff = 0; total_nodes = 0; count = 0; while (true) {
while (FRINGE.size() != 0) //quá trình tìm kiếm sâu dần { if (FRINGE.isEmpty() || !(Main.window.issolu)) { FRINGE.clear(); M.clear(); VISIT.clear(); Stop = "stop"; return; }
if (System.currentTimeMillis()- startTime > 180000) //điều kiện dừng { FRINGE.clear(); M.clear(); Stop = ":D \n"; return; }
n = FRINGE.elementAt(0); //lấy nút đầu tiên trong FRINGE
if(n.f <= cutOff) count++; //nếu nút n có f ko vượt ngưỡng cutOff thì n là nút đã được xét
FRINGE.removeElement(n); //xóa nút n
{
long endTime = System.currentTimeMillis(); time_solve = endTime - startTime;
total_nodes = count + FRINGE.size() + VISIT.size(); AddKQ(n); FRINGE.clear(); VISIT.clear(); M.clear(); return; }
if (n.f <= cutOff) //nếu nút n có f ko vượt ngưỡng cutOff thì xét n {
M = n.successors(); // sinh các trạng thái con của n if(n.Parent!=null)
{
for(int i = 0; i < M.size(); i++) {
if(isKT(n.Parent,M.elementAt(i))) // xóa trạng thái con của n trùng với trạng thái Cha(n)
M.remove(i); }
}
for (int i = 0; i < M.size(); i++) {
Node s = M.elementAt(i); s.g = n.g + s.cost;
s.f = s.g + s.h; tempNode = (Node)M.elementAt(i); tempNode.Parent = n; FRINGE.add(0, M.elementAt(i)); } }
else VISIT.add(0, n); // nếu n.f vượt ngưỡng cutOff thì thêm n vào VISIT
}//end while
if (VISIT.size() == 0) {
System.out.println("Failure! Can't solve problem, exiting..."); return;
}
fmin = VISIT.elementAt(0).f; for (int i = 0; i < VISIT.size(); i++) {
number = VISIT.elementAt(i).f;
if (number < fmin) fmin = number; //tìm nút có f nhỏ nhất trong VISIT }
cutOff = fmin;// đặt ngưỡng cutOff là fmin for (int i = 0; i < VISIT.size(); i++)
FRINGE.add(0, VISIT.elementAt(i)); VISIT.clear();
} }
Xây dựng các hàm heuristic:
- Heuristic 1: Dựa vào việc tính khoảng cách Manhattan là tính tổng số ô sai lệch của các ô so với vị trí đúng của nó.
//tổng khoảng cách dịch chuyển ngắn nhất để dịch chuyển các ô sai về vị trí đúng của nó: Manhattan
public int heuristic1(State goalstate) {
int[] goal = goalstate.Value; int distance = 0;
for (int i = 0; i < Length; i++) {
int c = Value[i]; int v = 0;
for (int j = 0; j < Length; j++) if (c == goal[j]) { v = j; break; } if (c != 0) {
int xd = Math.abs((i % Size) - (v % Size)); int yd = Math.abs((i / Size) - (v / Size)); distance += xd + yd;
} }
- Heuristic 2: Heuristic 1 + chỉ số phạt cặp ô hàng xóm với nhau nằm ngược vị trí của nhau.
//hàm h2 = heuristic1 + chỉ số phạt cặp ô hàng xóm với nhau đang nằm ngược vị trí của nhau
public int heuristic2(State goalstate) {
int[] goal = goalstate.Value; int distance = 0;
int a = 0;
for (int i = 0; i < Length; i++) {
int c = Value[i]; int v = 0;
for (int j = 0; j < Length; j++) if (c == goal[j]) { v = j; break; } if (c != 0) {
int xd = Math.abs((i % Size) - (v % Size)); int yd = Math.abs((i / Size) - (v / Size)); distance += xd + yd;
//Tính chỉ số phạt
if((i != 0) && (i % Size != Size-1) && (Value[i] == i+1) && (Value[i+1] == i)) a += 2;
if((i != 0) && (i < Length - Size) && (Value[i] == i+Size)&& (Value[i+Size] == i)) a += 2;
}
return distance + a; }
- Heuristic 3: Dùng hàm ước lượng đề xuất.
public int heuristic3(State goalstate) //Hàm ước lượng đề xuất: thống kê nhiều trạng thái thấy hàm này tốt hơn 2 hàm kia
{
int[] goal = goalstate.Value; int distance = 0;
int a = 0;
for (int i = 0; i < Length; i++) {
int c = Value[i]; int v = 0;
for (int j = 0; j < Length; j++) if (c == goal[j]) { v = j; break; } if (c != 0) {
int xd = (i % Size) - (v % Size); int yd = (i / Size) - (v / Size); distance += xd*xd + yd*yd; }
//Tính chỉ số phạt
if((i != 0) && (i % Size != Size-1) && (Value[i] == i+1) && (Value[i+1] == i)) a += 2;
if((i != 0) && (i < Length - Size) && (Value[i] == i+Size)&& (Value[i+Size] == i)) a += 2;
}
distance = distance - (int)(0.15*distance) + a; return distance;
}
Một số giao diện chương trình
Hình 3.6: Sắp xếp 25 ô (5×5)
Ngoài việc sắp xếp các ô số chúng ta có thể ghép một bức tranh hoàn chỉnh (hình 3.7)
Máy có thể tự động sắp xếp các miếng ghép để đưa ra kết quả cuối cùng khi chúng ta kích vào “Solve” chương trình sẽ hiển thị hộp thoại như trong hình 3.8.
KẾT LUẬN VÀ HƯỚNG PHÁT TRIỂN 1. Kết luận
Khóa luận đã trình bày được tổng quan về trí tuệ nhân tạo, giới thiệu về lý thuyết trò chơi và giới thiệu ngôn ngữ lập trình Java. Tìm hiểu một số thuật toán được ứng dụng trong trò chơi trí tuệ như cờ vua, cờ ca – rô, trò chơi xếp hình… Trên cơ sở đó xây dựng chương trình thử nghiệm trên trò chơi xếp hình.
- Kết quả đạt được
Tìm hiểu một số thuật toán như tìm kiếm theo chiều sâu, chiều rộng, thuật toán AT, AKT, A*
Vận dụng thuật toán A* , IDA* (giải thuật A* lặp sâu dần) trong trí tuệ nhân tạo để xây dựng thành công trò chơi xếp hình.
Chương trình được viết bằng Java một ngôn ngữ hướng đối tượng, cung cấp cho người dùng một giao diện đơn giản, dễ tiếp cận.
- Hạn chế
Chưa thiết kế trò chơi trên môi trường mạng.
Số lượng các hình chưa phong phú
Trong trò chơi xếp hình di chuyển giữa các ô chưa được linh hoạt. 2. Hướng phát triển
Hiện nay, thị trường game tại Việt Nam vẫn đang phát triển khá sôi động. Tuy nhiên các game đang thịnh hành đều là của nước ngoài và được đầu tư để Việt hóa. Liệu rằng có thể phát triển một thị trường game với các trò chơi thuần Việt được sản xuất trong nước?
Trước thực thực trạng đó em sẽ tiếp tục tìm hiểu sâu hơn nữa để cho ra đời trò chơi xếp hình mang tính chuyên nghiệp hơn:
Thiết kế chương trình để phát triển trên môi trường mạng, nâng cao khả năng tương tác giữa các người chơi.
Giao diện thân thiện với người dùng.
Xây dựng chương trình với nhiều chức năng hơn.
Trò chơi sẽ phù hợp cho cả đối tượng trẻ nhỏ lẫn người lớn, số lượng tranh ảnh sẽ phong phú hơn.
TÀI LIỆU THAM KHẢO Tiếng Việt
1. Đinh Mạnh Tường (2002), Giáo trình trí tuệ nhân tạo, nhà xuất bản khoa
học kỹ thuật.
2. Bạch Hưng Khang, Hoàng Kiếm (1989), Trí tuệ nhân tạo: Các phương pháp và ứng dụng, nhà xuất bản Khoa học và kỹ thuật.
3. Nguyễn Thanh Thuỷ (1995-1999), Trí tuệ nhân tạo: Các phương pháp giải quyết vấn đề và xử lý tri thức, nhà xuất bản Giáo dục.
4. Đoàn Văn Ban (2005), Lập trình hướng đối tượng với Java, nhà xuất bản
kỹ thuật. Tiếng Anh
5. Stuart Russell, Peter Norvig (1995), Artificial Intelligence: A modern Approach, Prentice- Hall.