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

Bài tập lớn AI: hành trình quân mã

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 (166.66 KB, 13 trang )

TRƯỜNG ĐẠI HỌC THỦY LỢI
KHOA CÔNG NGHỆ THÔNG TIN

BÀI TẬP LỚN
HỌC PHẦN: TRÍ TUỆ NHÂN TẠO

ĐỀ TÀI: Hành trình qn mã

Giáo viên hướng dẫn: Nguyễn Thị Kim Ngân
Sinh viên/nhóm sinh viên thực hiện:
1. Ngô Thị Hồng Nhung, lớp 62CNTT03
2. Đỗ Ngọc Minh, lớp 62CNTT03
3. Nguyễn Huy Mạnh, lớp 62CNTT03

Hà Nội, năm 2021


Phần 1: Tổng quan
I.
Phương pháp
1. Phương pháp duyệt theo chiều rộng: Tìm kiếm theo chiều rộng (BFS) là một thuật
tốn tìm kiếm trong đồ thị trong đó việc tìm kiếm chỉ bao gồm 2 thao tác: Cho
trước một đỉnh của đồ thị và thêm các đỉnh kề với đỉnh vừa cho vào danh sách có
thể hướng tới tiếp theo.
- Mục đích : Có thể sử dụng thuật tốn tìm kiếm theo chiều rộng cho hai mục
đích: tìm kiếm đường đi từ một đỉnh gốc cho trước tới một đỉnh đích, và tìm
kiếm đường đi từ đỉnh gốc tới tất cả các đỉnh khác.
- Trong đồ thị khơng có trọng số, thuật tốn tìm kiếm theo chiều rộng ln tìm ra
đường đi ngắn nhất có thể. Thuật tốn BFS bắt đầu từ đỉnh gốc và lần lượt nhìn
các đỉnh kề với đỉnh gốc. Sau đó, với mỗi đỉnh trong số đó, thuật tốn lại lần
lượt nhìn trước các đỉnh kề với nó mà chưa được quan sát trước đó và lặp lại.


- Thuật toán sử dụng một cấu trúc dữ liệu hàng đợi để lưu trữ thông tin trung gian
thu được trong quá trình tìm kiếm:
 Chèn đỉnh gốc vào hàng đợi (đang hướng tới)
 Lấy ra đỉnh đầu tiên trong hàng đợi và quan sát nó
 Nếu đỉnh này chính là đỉnh đích, dừng q trình tìm kiếm và trả về kết
quả.
 Nếu khơng phải thì chèn tất cả các đỉnh kề với đỉnh vừa thăm nhưng
chưa được quan sát trước đó vào hàng đợi.
 Nếu hàng đợi là rỗng, thì tất cả các đỉnh có thể đến được đều đã được
quan sát – dừng việc tìm kiếm và trả về "khơng thấy".
 Nếu hàng đợi khơng rỗng thì quay về bước 2.
2. Phương pháp duyệt theo chiều sâu:
- Giải thuật tìm kiếm theo chiều sâu (Depth First Search – viết tắt là DFS), cịn
được gọi là giải thuật tìm kiếm ưu tiên chiều sâu, là giải thuật duyệt hoặc tìm
kiếm trên một cây hoặc một đồ thị và sử dụng stack (ngăn xếp) để ghi nhớ đỉnh
liền kề để bắt đầu việc tìm kiếm khi khơng gặp được đỉnh liền kề trong bất kỳ
vòng lặp nào. Giải thuật tiếp tục cho tới khi gặp được đỉnh cần tìm hoặc tới một
nút khơng có con. Khi đó giải thuật quay lui về đỉnh vừa mới tìm kiếm ở bước
trước.
- Việc triển khai DFS tiêu chuẩn chia mỗi đỉnh của biểu đồ thành một trong hai
loại:
 Đã được duyệt.
 Chưa được duyệt.
- Mục đích của thuật tốn là đánh dấu mỗi đỉnh là đã duyệt trong khi tránh việc
duyệt theo vòng trịn chu kỳ.
- Thuật tốn DFS hoạt động như sau:
 Bắt đầu bằng cách đặt bất kỳ một trong các đỉnh của biểu đồ lên trên
một ngăn xếp.
 Lấy ra phần tử trên cùng của ngăn xếp và thêm nó vào danh sách đã truy
cập.

 Tạo danh sách các nút liền kề của đỉnh đó. Thêm những nút mà khơng
có trong danh sách đã được duyệt vào đầu ngăn xếp.
 Tiếp tục lặp lại các bước 2 và 3 cho đến khi ngăn xếp trống rỗng.


Phần 2: Thực nghiệm (code)
1.Mơ tả bài tốn
-

Tính tốn số bước và cách đi của quân mã từ vị trí gốc tới vị trí đích
Input: Trạng thái gốc và trạng thái đích
Ouput: Cách di chuyển, số bước
Method (phương pháp thực hiện):
+ Mô tả cách xây dựng trạng thái:

class data:
def __init__(self, state, parent, move, depth, cost):
self.state = state
self.parent = parent
self.move = move
self.depth = depth
self.cost = cost

 Biến state để lưu trữ tọa độ của trạng thái hiện tại của quân mã
 Biến parent dùng để chỉ nút cha hay trạng thái cha của nút hiện tại
 Biến move dùng để chỉ cách di chuyển của nút cha để tới nút hiện tại
 Biến depth dùng để lưu độ sâu của nút
 Biến cost dùng để lưu các bước biến đổi
+ Mô tả các quy luật chuyển trạng thái:






Quân mã có thể có tối đã là 8 khả năng di chuyển (như trên hình)
Mỗi khả năng di chuyển ta sẽ có thể tính được tọa độ của quân mã
Nếu như quân mã của ta đang tại vị trí (x;y) thì ta sẽ có 8 khả năng di
chuyển như sau:


Các khả năng : (x-2;y-1), (x-2;y+1), (x-1;y-2), (x-1;y+2), (x+1;y-2),
(x+1;y+2), (x+2:y-1), (x+2;y+1)
 Ta sẽ di chuyển sao cho tọa độ không được quá pham vi của bàn cờ
+ Mô tả trạng thái đầu, trạng thái đích:
 Trạng thái đầu: [3,5] tức là quân mã sẽ đứng tại vị trí x = 3 và y = 5
 Trạng thái đích: [2,2] là vị trí mà qn mã sẽ đi tới
+ Mơ tả cách thực hiện để tìm ra đường đi từ trạng thái đầu đến trạng thái đích
 BFS(Thuật tốn tìm kiếm theo chiều rộng)


Số bước
0
1

U

Kề(U)

(3,5) (1,4) (1,6) (2,3) (2,7) (4,3) (4,7) (5,4) (5,6)


2

(1,4) (2,2) (2,6) (3,3)

3

(1,6) (2,4) (2,8) (3,7)

4

(2,3) (1,1) (1,5) (3,1) (4,2) (4,5)

5

(2,7) (1,5) (4,6) (4,8)

6

(4,3) (2,2) (2,4) (3,1) (5,1) (5,5) (6,2) (6,4)

7

(4,7) (2,6) (2,8) (5,5) (6,6) (6,8)

8

(5,4) (3,3) (4,2) (4,6) (6,2) (6,6) (7,3) (7,5)

9


(5,6) (3,7) (4,4) (4,8) (6,4) (6,8) (7,5) (7,7)

10

(2,2)



DFS(Thuật tốn tìm kiếm theo chiều sâu)

OPEN
(3,5)
(1,4) (1,6) (2,3) (2,7) (4,3) (4,7) (5,4)
(5,6)
(1,6) (2,3) (2,7) (4,3) (4,7) (5,4) (5,6)
(2,2) (2,6) (3,3)
(2,3) (2,7) (4,3) (4,7) (5,4) (5,6) (2,2)
(2,6) (3,3) (2,4) (2,8) (3,7)
(2,7) (4,3) (4,7) (5,4) (5,6) (2,2) (2,6)
(3,3) (2,4) (2,8) (3,7) (1,1) (1,5) (3,1)
(4,2) (4,5)
(4,3) (4,7) (5,4) (5,6) (2,2) (2,6) (3,3)
(2,4) (2,8) (3,7) (1,1) (1,5) (3,1) (4,2)
(4,5) (4,6) (4,8)
(4,7) (5,4) (5,6) (2,2) (2,6) (3,3) (2,4)
(2,8) (3,7) (1,1) (1,5) (3,1) (4,2) (4,5)
(4,6) (4,8) (5,1) (5,5) (6,2) (6,4)
(5,4) (5,6) (2,2) (2,6) (3,3) (2,4) (2,8)
(3,7) (1,1) (1,5) (3,1) (4,2) (4,5) (4,6)
(4,8) (5,1) (5,5) (6,2) (6,4) (6,6) (6,8)

(5,6) (2,2) (2,6) (3,3) (2,4) (2,8) (3,7)
(1,1) (1,5) (3,1) (4,2) (4,5) (4,6) (4,8)
(5,1) (5,5) (6,2) (6,4) (6,6) (6,8) (7,3)
(7,5)
(2,2) (2,6) (3,3) (2,4) (2,8) (3,7) (1,1)
(1,5) (3,1) (4,2) (4,5) (4,6) (4,8) (5,1)
(5,5) (6,2) (6,4) (6,6) (6,8) (7,3) (7,5)
(4,4) (7,7)
(2,6) (3,3) (2,4) (2,8) (3,7) (1,1) (1,5)
(3,1) (4,2) (4,5) (4,6) (4,8) (5,1) (5,5)
(6,2) (6,4) (6,6) (6,8) (7,3) (7,5) (4,4)
(7,7)


Số bước
0
1

U

Kề(U)

(3,5) (1,4) (1,6) (2,3) (2,7) (4,3) (4,7) (5,4) (5,6)

2

(1,4) (2,2) (2,6) (3,3)

3


(2,2)

OPEN
(3,5)
(1,4) (1,6) (2,3) (2,7) (4,3) (4,7) (5,4)
(5,6)
(2,2) (2,6) (3,3) (1,6) (2,3) (2,7) (4,3)
(4,7) (5,4) (5,6)
(1,3) (2,4) (4,1) (4,3) (2,6) (3,3) (1,6)
(2,3) (2,7) (4,3) (4,7) (5,4) (5,6)

2. Đánh giá kết quả tìm được:
- Số các bước chuyển trạng thái từ trạng thái đầu đến trạng thái đích của mỗi phương pháp
duyệt. So sánh kết quả của 2 phương pháp.
+ BFS: Số bước chuyển trạng thái từ trạng thái đầu đến trạng thái đích là: 10 bước
+ DFS: Số bước chuyển trạng thái từ trạng thái đầu đến trạng thái đích là: 3 bước
Số bước thực hiện của phương pháp BFS nhiều hơn số bước thực hiện của DFS
- So sánh thời gian thực hiện của 2 phương pháp.
Do số bước của BFS nhiều hơn của DFS Thời gian thực hiện của BFS lâu hơn DFS
Kết luận
o
o
o

Tóm lược các nội dung chính mà bài tập lớn làm được
Hiểu được cách hoạt động của thuật tốn tìm kiếm chiều rộng và chiều sâu
Biết cách xây dựng trạng thái của 1 nút
Biết cách di chuyển của quân mã trong bàn cờ vua

Tài liệu tham khảo

- Các tài liệu được tham khảo trong báo cáo.
o />-

Ứng dụng BFS để giải quyết bài tập đường đi của quân mã trong đồ thị

o />-

Giải thuật tìm kiếm theo chiều rộng (Breadth First Search)


import timeit
from collections import deque
cl1 = [-2,-1]
cl2 = [-2, 1]
cl3 = [-1,-2]
cl4 = [-1, 2]
cl5 = [1,-2]
cl6 = [1,2]
cl7 = [2,-1]
cl8 = [2, 1]
m,n = 8,8
goalPoint = [2,2]
goalNode = None
MaxSearchDeep = 0
NodeExpand = 0
path = ''
class data:
def __init__(self, state, parent, move, depth, cost):
self.state = state
self.parent = parent

self.move = move
self.depth = depth
self.cost = cost


if self.state:
self.map = ''.join(str(e) for e in self.state)
def __eq__(self, other):
return self.map == other.map
def __lt__(self, other):
return self.map < other.map
def __str__(self):
return str(self.map)

def bfs(startPoint):
global MaxSearchDeep, goalNode
Queue = deque([data(startPoint,None,None, 0, 0)])
boardVisited = set()
while Queue:
node = Queue.popleft()
boardVisited.add(node.map)
if node.state == goalPoint:
goalNode = node
return Queue
possiblePath = subNode(node)
for path in possiblePath:
if path.map not in boardVisited:
Queue.append(path)
boardVisited.add(path.map)
if path.depth > MaxSearchDeep:



MaxSearchDeep = MaxSearchDeep + 1

def dfs(startPoint):
global MaxSearchDeep, goalNode
boardVisited = set()
stack = list([data(startPoint, None, None, 0, 0)])
while stack:
node = stack.pop()
boardVisited.add(node.map)
if node.state == goalPoint:
goalNode = node
return stack
possiblePath = reversed(subNode(node))
for path in possiblePath:
if path.map not in boardVisited:
stack.append(path)
boardVisited.add(path.map)
if path.depth > MaxSearchDeep:
MaxSearchDeep = MaxSearchDeep + 1

def subNode(node):
global NodeExpand
NodeExpand = NodeExpand + 1
nextPath = []
nextPath.append(data(move(node.state, 1), node, 1, node.depth + 1, node.cost +
1))



nextPath.append(data(move(node.state, 2), node,2, node.depth + 1, node.cost +
1))
nextPath.append(data(move(node.state, 3),node, 3, node.depth + 1, node.cost +
1))
nextPath.append(data(move(node.state, 4),node, 4, node.depth + 1, node.cost +
1))
nextPath.append(data(move(node.state, 5),node, 5, node.depth + 1, node.cost +
1))
nextPath.append(data(move(node.state, 6),node, 6, node.depth + 1, node.cost +
1))
nextPath.append(data(move(node.state, 7), node,7, node.depth + 1, node.cost +
1))
nextPath.append(data(move(node.state, 8), node,8, node.depth + 1, node.cost +
1))
nodes = []
for proc in nextPath:
if proc.state != None:
nodes.append(proc)
return nodes

def move(state, direction):
new_state = state[:]
if direction == 1:
new_state[0] = cl1[0] + new_state[0]
new_state[1] = cl1[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:
return new_state
else:



return None
if direction == 2:
new_state[0] = cl2[0] + new_state[0]
new_state[1] = cl2[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:
return new_state
else:
return None
if direction == 3:
new_state[0] = cl3[0] + new_state[0]
new_state[1] = cl3[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:
return new_state
else:
return None
if direction == 4:
new_state[0] = cl4[0] + new_state[0]
new_state[1] = cl4[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:
return new_state
else:
return None
if direction == 5:
new_state[0] = cl5[0] + new_state[0]



new_state[1] = cl5[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:
return new_state
else:
return None
if direction == 6:
new_state[0] = cl6[0] + new_state[0]
new_state[1] = cl6[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:
return new_state
else:
return None
if direction == 7:
new_state[0] = cl7[0] + new_state[0]
new_state[1] = cl7[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:
return new_state
else:
return None
if direction == 8:
new_state[0] = cl8[0] + new_state[0]
new_state[1] = cl8[1] + new_state[1]
if new_state[0]>=1 and new_state[0]<=m and new_state[1]>=1 and
new_state[1]<=n:


return new_state

else:
return None

def main():
global goalNode, path
initialState = [3,5]
start = timeit.default_timer()
bfs(initialState)
stop = timeit.default_timer()
time = stop - start
move = []
deep = goalNode.depth
while initialState != goalNode.state:
if goalNode.move == 1:
path = 'x-2:y-1'
if goalNode.move == 2:
path = 'x-2:y+1'
if goalNode.move == 3:
path = 'x-1:y-2'
if goalNode.move == 4:
path = 'x-1:y+2'
if goalNode.move == 5:
path = 'x+1:y-2'
if goalNode.move == 6:


path = 'x+1:y+2'
if goalNode.move == 7:
path = 'x+2:y-1'
if goalNode.move == 8:

path = 'x+2:y+1'
move.insert(0,path)
goalNode = goalNode.parent
print("path: ",move)
print("cost: ",len(move))
print("nodes expanded: ",str(NodeExpand))
print("search_depth: ",str(deep))
print("running_time: ",format(time, '.8f'))

main()



×