Professional Documents
Culture Documents
ĐỀ TÀI:
1 Vũ Thế
Mạnh
2 Bùi Minh
Đức
3 Đào Văn
Triệu
PHẦN MỞ ĐẦU..................................................................................................1
Thuật toán A* là một trong những thuật toán tìm kiếm đường đi ngắn nhất
phổ biến trong lĩnh vực trí tuệ nhân tạo. Nó được sử dụng rộng rãi trong việc
giải quyết các vấn đề tìm đường đi trong không gian trạng thái. Trong đề tài này,
chúng em sẽ áp dụng thuật toán A* để giải quyết trò chơi Ghép tranh N-Puzzle,
một bài toán tối ưu hóa thú vị và có ứng dụng thực tế.
Báo cáo này sẽ giới thiệu về trò chơi Ghép tranh N-Puzzle, trình bày về
thuật toán A* và cách áp dụng nó vào việc giải quyết trò chơi này. Nhóm tác giả
cũng sẽ xem xét hiệu suất và độ phức tạp của thuật toán A* trong ngữ cảnh của
trò chơi Ghép tranh N-Puzzle.
Nhóm tác giả tin rằng báo cáo này sẽ cung cấp một cái nhìn sâu sắc về
cách trí tuệ nhân tạo có thể được áp dụng vào giải quyết các vấn đề thực tế thông
qua trò chơi và thuật toán tối ưu hóa. Nó cũng sẽ giúp độc giả hiểu rõ hơn về cơ
chế hoạt động của thuật toán A* và cách nó có thể được sử dụng để giải quyết
các bài toán tìm đường đi phức tạp.
Cuối cùng, xin gửi lời cảm ơn chân thành đến thầy Vũ Văn Định đã
hướng dẫn trong môn học Trí Tuệ Nhân Tạo. Không thể phủ nhận sự tận tâm,
kiên nhẫn và kiến thức sâu rộng mà thầy đã truyền đạt trong suốt khoá học nhất
là trong thời gian thực hiện đề tài, để đề tài có thể hoàn thành một cách thành
công nhất.
CHƯƠNG 1: TỔNG QUAN THUẬT TOÁN A*
1.1 Thuật toán A*
Thuật toán A* được mô tả lần đầu tiên vào năm 1986 bởi Peter Hart, Nils
Nilson và Bertram Raphael. Trong báo cáo của họ, thuật toán được gọi là thuật
toán A, khi sử dụng thuật toán này với một hàm đánh giá Heuristic thích hợp sẽ
thu được hoạt động tối ưu, do đó nó có tên là A*.
Trong khoa học máy tính, A* là một thuật toán tìm kiếm trong đồ thị. Thuật
toán này tìm một đường đi từ nút khởi đầu tới một nút đích cho trước(hoặc tới
một nút thỏa mãn điều kiện đích). Thuật toán này sử dụng một đánh giá Heuristic
để xếp loại từng nút theo ước lượng về tuyến đường tốt nhất đi qua nút đó. Thuật
toán này duyệt theo các nút theo thứ tự của đánh giá heuristic, do đó nó là một ví
dụ của tìm kiếm theo lựa chọn tốt nhất (Best-first search).
Xét bài toán tìm kiếm đường đi – bài toán mà thuật toán A* thường được
dùng để giải. Thuật toán xây dựng tăng dần các tuyến đường từ điểm xuất phát
cho tới khi nó tìm thấy một đường đi tới đích. Tuy nhiên, cũng giống các thuật
toán tìm kiếm có thông tin (như AT, AKT,…), nó chỉ xây dựng các tuyến đường
có vẻ dần về đích.
Để biết những tuyến đường nào có khả năng dẫn tới đích, A* sử dụng hàm
đánh giá heuristic về khoảng cách từ điểm bất kì cho tới đích. Trong trường hợp
tìm đường đi, đnash giá này có thể là khoảng cách đường chim bay – đánh giá
xấp xỉ thường dùng cho khoảng cách đường giao thông, cũng là cách tính thông
dụng nhất.
Điểm khác biệt của A* so với tìm kiếm theo lựa chọn tốt nhất như AT, AKT
là nó còn tính đến khoảng cách đã đi qua, điều này làm cho A* đầy đủ và tối ưu,
nghĩa là A* sẽ luôn tìm được đường đi ngắn nhất trong trường hợp bài toán có tồn
tại đường đi như thế. A* không đảm bảo rằng sẽ chạy nhanh hơn các thuật toán
khác. Ví dụ trong bài toán dạng mê cung, cách để đi đến đích có thể phải đi vòng
1
ra xa đích sau đó quay trở lại, trong trường hợp đó, việc thử các nút theo thứ tự
“gần đích hơn thì ưu tiên” có thể gây tốn thời gian hơn rất nhiều.
A* lưu giữ một tập các lời giải chưa hoàn chỉnh, nghĩa là các đường đi qua
đồ thị, bắt đầu từ nút xuất phát. Tập lời giải này được lưu trong một hàng đợi ưu
tiên (priority queue). Thứ tự ưu tiên gán cho một đường đi x được quyết định bởi
hàm: f(x) = g(x) + h(x)
Trong đó:
g(x): là chi phí của đường đi cho đến thời điểm hiện tại, nghĩa là tổng
trọng số của các cạnh đã đi qua.
h(x): là hàm đánh giá heuristic về chi phí nhỏ nhất để đến đích từ x. Ví
dụ, nếu "chi phí" được tính là khoảng cách đã đi qua, khoảng cách đường chim
bay giữa hai điểm trên một bản đồ là một đánh giá heuristic cho khoảng cách
còn phải đi tiếp.
Mã giả:
function A*(điểm_xuất_phát,đích)
var đóng:= tập rỗng
var q:= tạo_hàng_đợi(tạo_đường_đi(điểm_xuất_phát))
while q không phải tập rỗng
var p:= lấy_phần_tử_đầu_tiên(q)
var x:= nút cuối cùng của p
if x in đóng
continue
if x == đích
return p
bổ sung x vào tập đóng
foreach y in các_đường_đi_tiếp_theo(p)
2
đưa_vào_hàng_đợi(q, y)
return failure
1.3 Một số tính chất
A* là một thuật toán đầy đủ, nếu có một lời giải cho bài toán, thì A* sẽ
tìm thấy nó.
Tính chất tối ưu của A* liên quan đến hàm heuristic. Nếu hàm heuristic
đủ tốt thì A* sẽ cho ra lời giải tối ưu.
A* sử dụng ít tài nguyên hơn so với các thuật toán khác khi sử dụng cùng
một hàm heuristic, với điều kiện hàm heuristic đảm bảo tính đơn điệu hoặc tối
ưu.
1.4 Một số hàm heuristic
Hàm heuristic (hàm ước tính) có vai trò quan trọng trong việc xác định chi
phí dự kiến từ nút hiện tại đến mục tiêu. Nó giúp A* quyết định xem nên mở
rộng nút nào tiếp theo để tìm kiếm đường đi ngắn nhất.
Hiện nay có rất nhiều hàm heuristic đã được sử dụng trong A*, ví dụ có thể
kể tới như:
· Manhattan Distance: Ước tính khoảng cách bằng cách sử dụng độ lệch
theo chiều ngang và dọc trên lưới (hoặc trong không gian 2D).
3
· Chebyshev Distance: Đây là một loại heuristic khác dựa trên khoảng
cách theo đường chéo trên lưới (hoặc trong không gian 2D). Nó sử dụng lệch
tuyệt đối lớn nhất giữa các tọa độ x và y.
4
CHƯƠNG 2:TRÒ CHƠI GHÉP TRANH N-PUZZLE
Trò chơi N-PUZZLE được biết đến với nhiều phiên bản và tên gọi khác
nhau như 8-puzzle, 15-puzzle, Gem puzzle, Boss puzzle, Game of Fifteen,
Mystic Square,…, là một bài toán khá hay và trí tuệ. Bài toán này là vấn đề cổ
điển cho mô hình thuật toán liên quan đến trí tuệ nhân tạo.
Mục tiêu trò chơi đặt ra là tìm đường đi từ trạng thái bất kì tới trạng thái
đích. Và đương nhiên có thể trạng thái ban đầu sẽ không bao giờ đi tới trạng
thái đích được.
Để đơn giản trong cách tiếp cận giải bài toán, người ta giả định chỉ có ô
trống trong bảng là di chuyển đến những vị trí khác. Như vậy tại một trạng thái
thì chỉ có tối đa 4 cách đi để chuyển sang trạng thái khác (trái, phải, lên, xuống).
Trong N-Puzzle có một số heuristic phổ biến vì tính dễ cài đặt của nó. Trong đó
gồm có:
5
Misplaced tiles: Heuristic này đếm số lượng mảnh sai vị trí so với trạng thái
đích. Ví dụ như hình vẽ:
6
Euclidian Distance: Đối với N-PUZZLE là không gian 2D nên để tính
khoảng cách từ ô đang đứng tới ô đúng, ta sử dụng công thức tính khoản cách
7
2.3 Quy luật ước lượng lời giải
Đối với mỗi bài toán, không phải lúc nào chúng ta cũng tìm ra lời giải.
Trong những bài toán không tìm ra lời giải, ta nên ước tính xem bài toán đó có
lời giải không, nếu có ta mới thực hiện tìm kiếm lời giải để tránh mất thời gian.
Bài toán N-PUZZLE cũng có cách ước lượng để tìm kiếm xem ở một trạng thái
bất kì có thể đưa về trạng thái đích được không.
Cho trạng thái đầu tiên, ta duyệt qua từng ô theo thứ tự từ trái qua và từ trên
xuống, ở mỗi ô số duyệt đến, ta hãy đếm xem có bao nhiêu ô số có giá trị bé hơn
nó (không tính ô trống). Đây chính là phương pháp tính heuristic Misplaced
tiles(Haming distance).
Với n là kích thước của trò chơi, H là hàm heuristic tính theo Misplaced
tiles, dòng của ma trận tính từ 1, ta có thể ước lượng:
Với n lẻ:
o Nếu H chia hết cho 2, bài toán chắc chắn có lời giải, ngược lại
không thể tìm ra lời giải.
Với n chẵn xảy ra 2 trường hợp có lời giải:
o H chia hết cho 2 và ô trống nằm trên dòng chẵn tính từ trên xuống.
o H không chia hết cho 2 và ô trống nằm trên dòng lẻ tính từ trên
xuống.
8
Hình 2.6. Ví dụ ước lượng lời giải
Với trạng thái trên ta tính được heuristic của trạng thái này:
Vì n = 3 mà h chia hết cho 2, vậy trạng thái này có thể giải được.
Rất dễ thấy là mỗi trạng thái của bảng số là một hoán vị của n x n phần tử
(với n là cạnh), như vậy không gian trạng thái của nó là (n x n)!, với 8-puzzle là
9! = 362880 (n = 3) và 15-puzzle là 16! = 20922789888000 (n = 4). Khi n tăng
lên 1 đơn vị thì không gian trạng thái tăng lên rất nhanh, điều này khiến cho việc
giải quyết các phiên bản n>3 ít khi được áp dụng. Ước lượng lời giải rất hữu ích
trong việc ta cài đặt chạy trên bài toán n lớn. Ta có thể xử lý luôn được những
trạng thái không trả ra kết quả.
Lưu ý rằng đây chỉ là ước lượng bài toán có thể giải được, còn giải trong
bao lâu, giải bao nhiêu bước thì chưa thể xác định được.
9
CHƯƠNG 3: CÀI ĐẶT CHƯƠNG TRÌNH
Nhóm tác giả chọn sử dụng ngôn ngữ lập trình C# và Winforms để xây
dựng chương trình demo giải bài toán N-PUZZLE.
Do máy tính cá nhân không đủ mạnh và với mục đích học tập nên chỉ cài
đặt chạy trên ma trận 3*3, 2*2 có thể nhìn và giải được(nếu có lời giải). Nếu
chạy ở mức cao hơn cần phải sử dụng thuật toán khác, máy tính cấu hình khác,
cần tối ưu hơn.
Nhanh chóng xây dựng ứng dụng: C# là một ngôn ngữ lập trình mạnh
mẽ và dễ học, có nhiều thư viện và khung làm việc sẵn có. WinForms
cung cấp một cách nhanh chóng và đơn giản để xây dựng giao diện
người dùng. Điều này cho phép phát triển ứng dụng nhỏ một cách
nhanh chóng.
Hỗ trợ đa luồng: C# cung cấp hỗ trợ đa luồng mạnh mẽ. Trong bài
toán N-Puzzle cần thực hiện tính toán phức tạp trong thời gian dài.
Bằng cách sử dụng đa luồng, ta có thể tận dụng tối ưu CPU và ngăn
ứng dụng bị đứng trong quá trình chạy.
Dễ dàng chia sẻ và triển khai: Sử dụng C# và WinForms khiến việc
đóng gói và cài đặt ứng dụng lên nhiều máy tính dễ dàng trên nền
tảng Windows.
Giao diện chương trình được thiết kế với sự đơn giản và sử dụng các control
mặc định, tạo ra một trải nghiệm dễ nhìn và dễ sử dụng.
10
Hình 3.1. Giao diện ứng dụng
11
3.2.2 Lập trình
Do chương trình khá dài nên phần này nhóm tác giả chỉ trình bày những
phần cốt lõi liên quan tới thuật toán A*.
12
Heuristic Euclidean:
13
Hình 3.6. Class Node
o G: quãng đường đã đi được
o Heuristic: hàm heuristic tính toán so với trạng thái đích
o Index: chỉ số của node
o Matrix: trạng thái hiện tại đang nắm giữ
o Parent:Node cha sinh ra trạng thái hiện tại
AstarAlgorithm: class này đảm nhiệm việc giải, truy vết kết quả
14
Hình 3.7. Class AstarAlgorithm
o BestOpenIndex: trả về vị trí nút tốt nhất trong tập open.
o CompareBetter: so sánh node hiện tại với danh sách node trong tập
open hoặc close dựa vào ma trận.
o EqualMatrix: so sánh trạng thái hai ma trận có giống nhau hoàn toàn
hay không.
o GetDipdicateNodeInClose: tìm kiếm node trùng trong close, sử dụng
trong trường hợp trong close và open chung một node nhưng có nốt
tốt hơn.
o Solve:Sử dụng tất cả các method trên để tìm kết quả
o BacktrackingResult: quay lui tìm kết quả sau khi giải thành công.
Helper class
15
Hình 3.8. Helper class
o GameHelper: hỗ trợ việc ước lượng kết quả, tìm ra vị trí ô trống trên
ma trận.
o ImageHelper: giúp cắt ảnh, xử lý ảnh phù hợp với giao diện.
o TableLayoutHelper: giúp trực quan hóa ảnh, trực quan hóa các bước
di chuyển của thuật toán.
o MatrixHelper: giúp lấy ra ma trận hiện tại trên giao diện, lấy ma trận
đích, biến ma trận hai chiều thành 1 chiều.
o TaskHelper: Hỗ trợ đa luồng cho ứng dụng, giúp ứng dụng không bị
treo trong quá trình chạy kết quả thuật toán.
3.2.3 Chạy chương trình
Chương trình đã được kiểm thử một số lỗi cơ bản giúp trải nghiệm tốt hơn.
16
Hình 3.9. Khởi động chương trình và chọn ảnh
17
Hình 3.11. Đảo lại, ước lượng đã có lời giải
18
Hình 3.12. Lựa chọn chạy với heuristis Manhattan
19
Hình 3.14. Hoàn thành chạy
3.2.4 Kết quả thu được
Như vậy sau khi chạy và kiểm thử, chương trình đã có thể đáp ứng đủ các
yêu cầu cơ bản để giải quyết bài toán N-PUZZLE.
Dưới đây là bảng tính số bước chạy và thời gian chạy theo từng heuristic:
Kết quả
Misplaced Tiles Manhattan Euclidean Chebyshev
Lần chạy
1 28 | 5ms 28 | 2ms 28 | 5ms 58 | 154ms
20
Nhận xét tổng quan sau 5 lần chạy: cả 4 heuristic trung bình số bước chạy
tương đương nhau, thời gian có một chút biến động:
o Manhattan: Thời gian chạy tốt nhất.
o Euclidean: Thời gian chạy tương đối thấp.
o Misplaced Tiles: Thời gian chạy ở mức trung bình.
o Chebyshev: Chạy lâu hơn.
Dưới đây là mã nguồn của chương trình A* giải bài toán N-Puzzle đã được
triển khai và có sẵn cả bản cài đặt và mã nguồn đầy đủ. Dự án được lưu trữ
trên Github tại: https://github.com/D16IT6/AStarPuzzle.
Tóm lại, chương trình N-Puzzle đã thành công trong việc thử nghiệm và triển
khai thuật toán tìm kiếm A*.
21
PHẦN KẾT LUẬN
Bài báo cáo về bài toán N-Puzzle không chỉ là một sự giới thiệu sâu rộng
về thuật toán tìm kiếm và heuristics, mà còn là một hành trình khám phá thú vị
về ứng dụng của trí tuệ nhân tạo trong giải quyết vấn đề thực tế. Việc nghiên
cứu và cài đặt bài toán này không chỉ mang lại kiến thức vững về lý thuyết mà
còn mở rộng tầm nhìn về cách áp dụng chúng vào những thách thức phức tạp
hơn trong thế giới thực.
N-Puzzle đưa ra nhận thức về những thách thức khi áp dụng chúng vào
các trạng thái lớn hơn. Điều này đặt ra những cơ hội nghiên cứu tiềm năng về tối
ưu hóa thuật toán và phương pháp giải quyết bài toán trong các tình huống phức
tạp và thực tế.
Trong bài báo cáo, việc đánh giá sự hiệu quả của các heuristic như
Misplaced Tiles, Manhattan Distance, Euclidean Distance, Chebyshev Distance
là rất quan trọng. Điều này thúc đẩy sự nhận thức về tầm quan trọng của việc
chọn lựa và kết hợp các phương pháp khác nhau để đạt được hiệu suất tốt nhất
trong việc giải quyết bài toán N-Puzzle.
Mặc dù đã đạt được nhiều thành công, việc thừa nhận rằng vẫn còn những
thách thức và hướng nghiên cứu tiềm năng là một cách tiếp cận khôn ngoan.
Điều này thể hiện tinh thần tự học và không ngừng cải tiến trong lĩnh vực trí tuệ
nhân tạo. Việc chia sẻ những kiến thức và kinh nghiệm từ bài toán này thông
qua báo cáo cũng là một cách quan trọng để cộng đồng nghiên cứu có thể học
hỏi và phát triển.
Cuối cùng, việc mở cửa đón nhận sự đóng góp và phản hồi là một bước
quan trọng để nâng cao chất lượng của bài báo cáo. Bài báo cáo chắc chắn
không tránh khỏi những sai sót, mong các thầy cô, độc giả góp ý để hoàn thiện
hơn. Xin chân thành cảm ơn!
22
TÀI LIỆU THAM KHẢO
[1]. Từ Minh Phương, Nhập môn trí tuệ nhân tạo, Học viện công nghệ bưu
chính viễn thông; 2014
[2]. Đinh Mạnh Tường. Trí tuệ nhân tạo, Nhà xuất bản Khoa học kỹ thuật,
2002
23