Đó là những ứng dụng lớn lao của trí tuệ nhân tạo vào của sống của con người.Trong bài tập lớn này chúng em sử dụng những thuật toán đã học cùng với giao diện trực quan mô tả cách thức h
CƠ SỞ LÝ THUYẾT
Môi trường lập trình
Với bài tập lớn này chúng em sử dụng Python làm ngôn ngữ chính để viết code với trình soạn thảo code Visual Studio Code và trình biên dịch spyder (anaconda3)
Thư viện chính sử dụng
Thư viện chính được nhóm chúng em sử dụng là pygame Đây là thư viện mã nguồn mở trên ngôn ngữ Python dùng để lập trình video game Pygame chứa đầy đủ các công cụ hỗ trợ lập trình game như đồ họa, hoạt hình, âm thanh, và sự kiện điều khiển. Pygame cũng đồng thời cung cấp các công cụ tích hợp hiệu ứng âm thanh cũng như nhạc nền cho game Cuối cùng, các sự kiện điều khiển từ bàn phím, chuột cũng được Pygame hỗ trợ một cách hiệu quả.
Trong đề tài này, nhóm chúng em sử dụng Pygame để xây dựng giao diện và mô phỏng chuyển động thuật toán. Đầu mỗi file, khai báo thư viện pygame qua câu lệnh ‘import pygame’.
Giải thuật BFS
Thuật toán duyệt đồ thị ưu tiên chiều rộng là thuật toán tìm kiếm mù mà những đỉnh gần với đỉnh gốc sẽ được duyệt trước.
Với đồ thị không trọng số và đỉnh nguồn Đồ thị này có thể là đồ thị có hướng hoặcs vô hướng, điều đó không quan trọng đối với thuật toán. Đầu tiên ta thăm đỉnh nguồn s
Việc thăm đỉnh sẽ phát sinh thứ tự thăm các đỉnh (u1 , u2 ,…up) kề với s s (những đỉnh gần nhất) Tiếp theo, ta thăm đỉnh u1, khi thăm đỉnh u1 sẽ lại phát sinh yêu cầus thăm những đỉnh (v1, v2, …, vp) kề với u1 Nhưng rõ ràng những đỉnh này “xa” v s hơn những đỉnh uu nên chúng chỉ được thăm khi tất cả những đỉnh uu đều đã được thăm Tức là thứ tự thăm các đỉnh sẽ là: , u1 , u2, …, up , v1, v2, …, vp.s
2.3.2 Mô tả trong code def bfs(GUI Grid start end , , , ):
Grid.generateNeighbors() count = 0 states = [] states append(( count, start )) states_history = { start } came_from = {} while len(states) != 0: if abortCatch(): return ( , ) 0 0 current = states pop(0)[ ] 1 if current == end: came_from pop(start) return came_from, count for nei in Grid neighbors[flat( current , Grid size)]: if (nei in came_from): if ( came_from[nei ] not in came_from): came_from[nei] = current else: came_from[nei] = current if nei not in states_history: count += 1 states append(( count, nei )) states_history add(nei) if nei != end: simulate(GUI, nei ) return 0, 0
Hình 1 Code cho thuật toán BFS
Giải thuật DFS
Thuật toán tìm kiếm theo chiều sâu là một thuật toán duyệt hoặc tìm kiếm trên một cây hoặc một đồ thị Thuật toán khởi đầu tại gốc (hoặc chọn một đỉnh nào đó coi như gốc) và phát triển xa nhất có thể theo mỗi nhánh.
2.4.1 Ý tưởng Đây là thuật toán tìm các đỉnh bằng cách duyệt theo chiều sâu Đầu tiên ta thăm đỉnh nguồn s
Xuất phát từ 1 đỉnh và đi cho đến khi không thể đi tiếp, sau đó đi về lại đỉnh đầu. Trong quá trình quay lại:
Nếu gặp đường đi khác thì đi cho đến khi không đi tiếp được nữa Nếu không tìm ra đường đi nào khác thì ngừng việc tìm kiếm.
Trong quá trình đi đến đỉnh khác, thuật toán sẽ lưu lại đỉnh cha vừa đi qua để khi đi ngược lại từ đỉnh Kết thúc đến đỉnh Xuất phát, ta có thể xem được đường đi từ đỉnh Kết thúc đến đỉnh Bắt Đầu (có thể số lần đi không ít nhất, các bạn có thể tham khảo thuật toán BFS).
2.4.2 Mô tả trong code def dfs(GUI Grid start end , , , ):
Grid.generateNeighbors() count = 0 states = [] states append(( count, start )) states_history = { start } came_from = {} while len(states) != 0: if abortCatch(): return ( , ) 0 0 current = states pop()[ ] 1 if current == end: came_from pop(start)
5 return came_from, count neis = Grid neighbors[flat( current , Grid.size)]
np random shuffle(neis) for nei in neis: if (nei in came_from): if ( came_from[nei ] not in came_from): came_from[nei] = current else: came_from[nei] = current if nei not in states_history: count += 1 states append(( count, nei )) states_history add(nei) if nei != end: simulate(GUI, nei ) return 0, 0
Hình 2 Code cho thuật toán DFS
Giải thuật UCS
Thuật toán tìm kiếm chi phí đều là một biến thể của thuật toán Dijkstra, được sử dụng hiệu quả trong những đồ thị vô hạn hoặc những đồ thị quá lớn để biểu diễn trong bộ nhớ Thuật toán UCS được sử dụng chính trong ngành Trí tuệ Nhân tạo.
Việc tìm kiếm sẽ bắt đầu tại nút gốc và tiếp tục tìm bằng cách duyệt các nút tiếp theo với trọng số (chi phí) thấp nhất tính từ nút gốc Các nút được duyệt tiếp tục cho đến khi đến được nút đích.
Thuật toán tìm kiếm với chi phí cực tiểu
2.5.2 Mô tả trong code def ucs(GUI Grid start end , , , ):
Grid.generateNeighbors() count = 0 states = PriorityQueue() states put(( 0, count, start )) states_history = { start } came_from = {} g_score = [ float("inf" ) for row in Grid.data for _ in row] g_score[ flat ( start, Grid size)] = 0 while not states empty(): if abortCatch(): return ( , ) 0 0 current = states get()[2] # start point if current == end: return came_from, count for nei in Grid neighbors[flat( current , Grid size)]: temp_g_score = g_score[ flat ( current, Grid size)] + 1 if temp_g_score < g_score[ flat ( nei, Grid.size)]: came_from[nei] = current
7 g_score[ flat ( nei, Grid size)] = temp_g_score if nei in states_history: continue count += 1 states put ((g_score[ flat (nei, Grid size)], count nei , )) states_history add(nei) if nei != end: simulate(GUI, nei ) return 0, 0
Hình 3 Code cho thuật toán UCS
Giải thuật Greedy Search
Thuật toán tìm kiếm tham lam (Greedy Search) là một thuật toán giải quyết một bài toán theo kiểu metaheuristic để tìm kiếm lựa chọn tối ưu địa phương ở mỗi bước đi với hy vọng tìm được tối ưu toàn cục
Nói chung, giải thuật tham lam có năm thành phần:
● Một tập hợp các ứng viên (candidate), để từ đó tạo ra lời giải
● Một hàm lựa chọn, để theo đó lựa chọn ứng viên tốt nhất để bổ sung vào lời giải
● Một hàm khả thi (feasibility), dùng để quyết định nếu một ứng viên có thể được dùng để xây dựng lời giải
● Một hàm mục tiêu, ấn định giá trị của lời giải hoặc một lời giải chưa hoàn chỉnh
● Một hàm đánh giá, chỉ ra khi nào ta tìm ra một lời giải hoàn chình
2.6.2 Mô tả trong code def greedy(GUI Grid start end , , , ):
Grid.generateNeighbors() count = 0 states = PriorityQueue() states put(( 0, count, start )) states_history = { start } came_from = {} f_score = [ float("inf" ) for row in Grid.data for _ in row] f_score[ flat ( start, Grid size)] = heu(start, end ) while not states empty(): if abortCatch():
9 return ( , ) 0 0 current = states get()[2] # start point if current == end: came_from pop(start, None ) return came_from, count for nei in Grid neighbors[flat( current , Grid.size)]: f_score[ flat ( nei, Grid size)] = heu(nei, end ) if nei in states_history: continue came_from[nei] = current count += 1 states put ((f_score[ flat (nei, Grid size)], count nei , )) states_history add(nei) if nei != end: simulate(GUI, nei ) return 0, 0
Hình 4 Code cho thuật toán Greedy
Giải thuật A*
Thuật toán A* là một thuật toán tìm đường đi từ mộ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 một diề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 các nút theo thứ tự của đánh giá heuristic này Do đó, thuật toán A* 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 đường – bài toán mà A* thường được dùng để giải A* xây dựng tăng dần tất cả 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 chạm tới đích Tuy nhiên, cũng như tất cả các thuật toán tìm kiếm có thông tin nó chỉ xây dựng các tuyến đường “có vẻ” như dẫn về phía đích.
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 Hàm f(x) có giá trị càng thấp thì độ ưu tiên của x càng cao (do đó có thể sử dụng một cấu trúc heap tối thiểu để cài đặt hàng đợi ưu tiên này).
2.7.2 Mô tả trong code def a_star(GUI Grid start end , , , ):
Grid.generateNeighbors() count = 0 states = PriorityQueue() states put(( 0, count, start )) states_history = { start } came_from = {} g_score = [ float("inf" ) for row in Grid.data for _ in row] g_score[ flat ( start, Grid size)] = 0 f_score = [ float("inf" ) for row in Grid.data for _ in row] f_score[ flat ( start, Grid size)] = heu(start, end ) while not states empty(): if abortCatch(): return ( , ) 0 0 current = states get()[2] # start point states_history remove(current) if current == end: return came_from, count for nei in Grid neighbors[flat( current , Grid size)]: temp_g = g_score[ flat ( current, Grid size)] + 1 if temp_g >= g_score[ flat ( nei, Grid.size)]: continue came_from[nei] = current g_score[ flat ( nei, Grid size)] = temp_g f_score[ flat ( nei, Grid size)] = temp_g + heu(nei, end ) if nei in states_history: continue count += 1 states put ((f_score[ flat (nei, Grid size)], count nei , )) states_history add(nei) if nei != end: simulate(GUI, nei ) return 0, 0
Hình 5 Code cho thuật toán Astar
Giải thuật ID
Thuật toán tìm kiếm ID là một thuật toán tìm kiếm không gian trạng trái với phiên bản giới hạn độ sâu của tìm kiếm theo chiều sâu được chạy lặp đi lặp lại với giới hạn độ sâu tăng dần cho đến khi đạt được mục tiêu được tìm thấy
Iterative Deepening Search gọi DFS cho các độ sâu khác nhau bắt đầu từ giá trị ban đầu Trong mọi cuộc gọi, DFS bị hạn chế vượt quá độ sâu nhất định Vì vậy, về cơ bản chúng thực hiện DFS theo kiểu BFS.
Bắt đầu tìm kiếm theo DFS với độ sâu tối đa là 0 Nếu không tìm thấy giải pháp ở độ sâu này thì năng lên độ sâu tiếp theo
2.8.2 Mô tả trong code def ideep(GUI Grid start end , , , ):
Grid.generateNeighbors() count = 0 states = [] states append(( count, start )) states_history = { start } came_from = {} depth = 0 depth_limit = 2 depth_limit_max = Grid.size ** 2 step = GUI.stepIDS while depth_limit