KyoGren / Intro_AI_

0 stars 0 forks source link

ÁP DỤNG GIẢI THUẬT A* ĐỂ TÌM LỜI GIẢI TRONG GAME SOKOBAN #6

Open ghost opened 1 year ago

ghost commented 1 year ago

Ý tưởng: Để áp dụng giải thuật A* vào game Sokoban, ta cần thực hiện các bước sau:

1, Định nghĩa trạng thái của trò chơi: Trạng thái của trò chơi Sokoban bao gồm vị trí của nhân vật và các thùng hàng trong mê cung.

2, Xác định các hành động có thể thực hiện: Trong Sokoban, nhân vật có thể di chuyển lên, xuống, trái hoặc phải. Mỗi lần di chuyển, nhân vật có thể đẩy một thùng hàng nếu thùng hàng đó đứng ngay phía trước nhân vật và ô trống phía sau thùng hàng.

3, Xác định hàm chi phí: Hàm chi phí được sử dụng để đánh giá chi phí di chuyển từ trạng thái hiện tại đến trạng thái đích. Trong Sokoban, hàm chi phí có thể là khoảng cách Euclid giữa vị trí hiện tại của nhân vật và vị trí đích của thùng hàng.

4, Xác định trạng thái đích: Trong trò chơi Sokoban, trạng thái đích là khi tất cả các thùng hàng được đặt đúng vị trí của chúng.

5, Áp dụng giải thuật A: Với các thông tin trên, ta có thể áp dụng giải thuật A để tìm đường đi tối ưu từ trạng thái hiện tại đến trạng thái đích. Trong quá trình tìm kiếm, ta sử dụng một hàng đợi ưu tiên để lưu trữ các trạng thái được duyệt. Các trạng thái được duyệt sẽ được xếp theo thứ tự tăng dần của hàm f(n) = g(n) + h(n), trong đó g(n) là chi phí từ trạng thái ban đầu đến trạng thái n, h(n) là ước lượng chi phí từ trạng thái n đến trạng thái đích.

6, Trả về đường đi tối ưu: Khi giải thuật tìm thấy trạng thái đích, ta sử dụng thông tin lưu trữ trên hàng đợi ưu tiên để truy vết lại đường đi từ trạng thái ban đầu đến trạng thái đích.

ghost commented 1 year ago

Mã giả(Python):

class SokobanNode:

def __init__(self, state, parent=None, action=None, g=0, h=0):

    self.state = state  # Trạng thái hiện tại của trò chơi

    self.prevState = prevState  # Trạng thái trước của trạng thái hiện tại

    self.action = action  # Hành động được thực hiện để đạt được trạng thái hiện tại từ trạng thái trước đó

    self.g = g  # Chi phí từ trạng thái ban đầu đến trạng thái hiện tại

    self.h = h  # Ước lượng chi phí từ trạng thái hiện tại đến trạng thái đích

def f(self):
    return self.g + self.h  # Tổng chi phí của trạng thái hiện tại

def __lt__(self, other):   #So sánh tổng chi phí giữa trạng thái hiện tại và trạng thái khác.
    return self.f() < other.f()

def __eq__(self, other):   #So sánh trạng thái hiện tại với trạng thái khác.
    return self.state == other.state

def __hash__(self):    #Tạo một mã băm (hash) đại diện cho trạng thái hiện tại, giúp cho việc tìm kiếm và so sánh trạng thái 
    return hash(self.state)                                                                                                                                              #nhanh hơn.

class SokobanSolver:

def __init__(self, initial_state, goal_state):  #Khởi tạo đối tượng SokobanSolver với trạng thái ban đầu và trạng thái đích cho trò 
    self.initial_node = SokobanNode(initial_state, g=0, h=self.heuristic(initial_state, goal_state))                                  #chơi.
    self.goal_state = goal_state

def heuristic(self, state, goal_state):
    # Hàm ước lượng chi phí từ trạng thái hiện tại đến trạng thái đích
    # Trong Sokoban, ta có thể sử dụng khoảng cách Euclid giữa các thùng hàng và ô đích để ước lượng chi phí
    ...

def is_goal(self, node):
    # Kiểm tra xem trạng thái hiện tại có phải là trạng thái đích không
    return node.state == self.goal_state

def get_successors(self, node):
    # Trả về danh sách các trạng thái kế tiếp có thể đạt được từ trạng thái hiện tại
    ...

def solve(self):
    # Áp dụng giải thuật A* để tìm đường đi tối ưu từ trạng thái ban đầu đến trạng thái đích
    open_set = PriorityQueue()
    open_set.put(self.initial_node)
    closed_set = set()

    while not open_set.empty():
        current_node = open_set.get()

        if self.is_goal(current_node):
            path = []
            while current_node:
                path.append(current_node.action)
                current_node = current_node.parent
            return path[::-1]

        closed_set.add(current_node)

        for successor in self.get_successors(current_node):
            if successor in closed_set:
                continue

            g = current_node.g + 1
            h = self.heuristic(successor.state, self.goal_state)
            successor_node = SokobanNode(successor.state, parent=current_node, action=successor.action, g=g, h=h)

            if successor_node not in open_set.queue:
                open_set.put