Là tìm đường tiền mã hóa vẫn còn có liên quan?


12

Bối cảnh

Old Lucas Arts (kỷ nguyên ScummVM) và nhấp vào các trò chơi phiêu lưu đồ họa được sử dụng tìm đường dẫn được tính toán trước. Đây là một phác thảo sơ bộ của kỹ thuật.

Bước 1

Tầng trong mỗi phòng được chia thành cái mà họ gọi là "hộp đi bộ", tương đối giống với các nút trong lưới điều hướng, nhưng giới hạn ở hình dạng hình thang. Ví dụ:

 ______ _____ _________ _____
\   A  |  B  |    C    |  D   \
 \_____|     |         |_______\
       |_____|         |
             |_________|

Bước 2

Một thuật toán ngoại tuyến (ví dụ Dijkstra hoặc A *) sẽ tính toán đường đi ngắn nhất giữa mỗi và mỗi cặp nút và lưu trữ bước đầu tiên của đường dẫn trong ma trận 2D, được lập chỉ mục theo từng chiều bởi nút bắt đầu và kết thúc được sử dụng. Ví dụ: sử dụng các hộp đi bộ ở trên:

      ___ ___ ___ ___
     | A | B | C | D | <- Start Node
  ___|___|___|___|___|
 | A | A | A | B | C |  ---
 |___|___|___|___|___|     |
 | B | B | B | B | C |     |
 |___|___|___|___|___|     |-- Next node in shortest path
 | C | B | C | C | C |     |   from Start to End
 |___|___|___|___|___|     | 
 | D | B | C | D | D |  ---
 |___|___|___|___|___| 
   ^
   |
End Node

Như bạn có thể đoán, các yêu cầu bộ nhớ tăng nhanh khi số lượng nút tăng (N ^ 2). Vì một đoạn ngắn thường sẽ đủ lớn để lưu trữ từng mục trong ma trận, với một bản đồ phức tạp gồm 300 nút sẽ dẫn đến việc lưu trữ thêm:

300^2 * sizeof(short) = 176 kilobytes

Bước 3

Mặt khác, việc tính toán con đường ngắn nhất giữa hai nút là cực kỳ nhanh và tầm thường, chỉ là một loạt các tra cứu vào ma trận. Cái gì đó như:

// Find shortest path from Start to End
Path = {Start}
Current = Start
WHILE Current != End
    Current = LookUp[Current, End]
    Path.Add(Current)
ENDWHILE

Áp dụng thuật toán đơn giản này để tìm đường đi ngắn nhất từ ​​C đến A trả về:

1) Path = { C }, Current = C
2) Path = { C, B }, Current = B
3) Path = { C, B, A }, Current = A, Exit

Câu hỏi

Tôi nghi ngờ rằng với phần cứng mạnh mẽ ngày nay, cùng với các yêu cầu về bộ nhớ để thực hiện điều này cho mọi cấp độ, bất kỳ lợi ích nào mà kỹ thuật này từng có hiện nay đều vượt trội khi chỉ cần thực hiện A * khi chạy.

Tôi cũng đã nghe nói rằng ngày nay việc tra cứu bộ nhớ thậm chí có thể chậm hơn so với tính toán chung, đó là lý do tại sao việc tạo các bảng tra cứu sin và cos không còn phổ biến nữa.

Nhưng tôi phải thừa nhận rằng tôi chưa quá am hiểu về những vấn đề này về hiệu quả phần cứng cấp thấp, vì vậy tôi nhân cơ hội này để hỏi ý kiến ​​của những người quen thuộc hơn với chủ đề này.

Trên công cụ của tôi, tôi cũng cần khả năng tự động thêm và xóa các nút vào biểu đồ khi chạy ( xem phần này ) để tuyến đường được tính toán trước chỉ làm cho mọi thứ trở nên phức tạp hơn, vì vậy tôi đã loại bỏ nó (không đề cập đến giải pháp A * thời gian chạy của tôi đã chạy hoàn hảo ). Tuy nhiên, tôi vẫn còn băn khoăn ...

Điểm mấu chốt, kỹ thuật này ngày nay vẫn còn phù hợp trong bất kỳ kịch bản nào?


2
Tôi nghĩ nó vẫn phù hợp nếu bạn có ngân sách CPU eo hẹp. Nhưng một khi bạn muốn các đường dẫn động, nó không còn hữu ích nữa. Btw Tôi đã xem xét nơi bạn có thuật toán A * của mình và bạn có thể tối ưu hóa nó hơn nữa bằng cách sử dụng minheap và một số thủ thuật khác. Tôi đã thực hiện một vài lần lặp lại để cải thiện A * trong C # mà bạn có thể thấy ở đây: roy-t.nl/index.php/2011/09/24/ có thể hữu ích.
Roy T.

1
Cảm ơn, tôi đã đánh dấu nó và sẽ xem xét nó khi tôi bắt đầu tối ưu hóa ứng dụng của mình. Tôi đã sử dụng khá nhiều giải pháp của Eric Lippert với một vài sửa đổi nhỏ vì nó rất sạch sẽ và dễ làm theo ... Và đối với tất cả các trường hợp thử nghiệm của tôi, nó chạy khá nhiều "ngay lập tức" vì vậy tôi thậm chí không bận tâm đến việc tối ưu hóa nó.
David Gouveia

1
BTW nếu bạn quyết định theo đuổi tiền mã hóa, bạn có thể muốn xem xét thuật toán Floyd-Warshall . Nó xây dựng ma trận bước tiếp theo của Google hiệu quả hơn so với việc sử dụng Dijkstra / A * nhiều lần.
amitp

@amitp Cảm ơn vì tiền boa, thật tốt khi biết về những lựa chọn thay thế này! Mặc dù, vì trong hầu hết các trường hợp, việc tính toán trước sẽ được thực hiện ngoại tuyến, sẽ không có nhiều lợi ích từ việc làm cho nó hiệu quả hơn. Trừ khi bạn thực sự thiếu kiên nhẫn. :-)
David Gouveia

Đồng ý, mặc dù Floyd-Warshall cũng thực hiện đơn giản hơn nhiều so với thuật toán của Dijkstra, vì vậy nếu bạn chưa triển khai Dijkstra, thì đáng để xem :)
amitp 8/212

Câu trả lời:


3

Trên công cụ của tôi, tôi cũng cần khả năng tự động thêm và xóa các nút vào biểu đồ khi chạy (xem phần này) để tuyến đường được tính toán trước chỉ làm cho mọi thứ trở nên phức tạp hơn, vì vậy tôi đã loại bỏ nó (không đề cập đến giải pháp A * thời gian chạy của tôi đã chạy hoàn hảo ). Tuy nhiên, tôi vẫn còn băn khoăn ...

Điểm mấu chốt, kỹ thuật này ngày nay vẫn còn phù hợp trong bất kỳ kịch bản nào?

Tôi có thể thấy không có lợi ích từ việc sử dụng một kỹ thuật như vậy.

Tôi thiếu tính linh hoạt của Biểu đồ (bạn có thể có các LOD khác nhau, chúng không phải là bất kỳ hình dạng cụ thể nào, v.v ...). Ngoài ra, bất kỳ người dùng động cơ nào của bạn cũng sẽ biết biểu đồ là gì và cách sử dụng biểu đồ. Vì vậy, nếu họ muốn thêm chức năng bổ sung, họ sẽ phải học cách triển khai tiện ích mở rộng bằng cách sử dụng một tình huống hoàn toàn mới lạ đối với họ.

Như bạn đã đề cập, có vẻ như nó sẽ mở rộng quy mô khủng khiếp. Ngoài ra, đáng lưu ý rằng nếu một biểu đồ phù hợp với tiền mặt và bạn chạy tất cả các phát hiện đường dẫn của bạn trở lại thì nó thực sự cắt giảm thời gian IO. Có vẻ như bạn thực hiện sẽ sớm phát triển quá lớn để phù hợp với bất kỳ bộ đệm.

Tôi cũng đã nghe nói rằng ngày nay việc tra cứu bộ nhớ thậm chí có thể chậm hơn so với tính toán chung, đó là lý do tại sao việc tạo các bảng tra cứu sin và cos không còn phổ biến nữa.

Trừ khi bạn có thể phù hợp với tất cả các chương trình của bạn và bộ nhớ cần thiết của nó trong bộ đệm, bạn sẽ giữ cổ chai trong việc kéo mọi thứ vào và ra khỏi bộ nhớ trước khi bạn đóng cổ bộ xử lý.

Tôi nghi ngờ rằng với phần cứng mạnh mẽ ngày nay, cùng với các yêu cầu về bộ nhớ để thực hiện điều này cho mọi cấp độ, bất kỳ lợi ích nào mà kỹ thuật này từng có giờ trở nên vượt trội khi chỉ cần thực hiện A * khi chạy

Cũng nhận ra rằng nhiều trò chơi có các vòng lặp riêng biệt để cập nhật AI. Tôi tin rằng cách mà dự án của tôi được thiết lập là có một vòng cập nhật cho đầu vào của người dùng ở mức 60hz, AI chỉ là 20hz và các trò chơi rút ra càng nhanh càng tốt.

Cũng như một lưu ý phụ, tôi đã thực hiện một số chương trình GBA chỉ để giải trí và không có gì chuyển sang sử dụng một thiết bị hiện đại. Đối với GBA, mọi thứ là về việc giảm thiểu khối lượng công việc của bộ xử lý (vì nó rất thảm hại). Bạn cũng phải nhận ra rằng hầu hết các ngôn ngữ cấp cao C # và Java (không quá nhiều C ++ hoặc C) thực hiện hàng tấn tối ưu hóa cho bạn. Để tối ưu hóa mã của bạn, chúng không phải làm gì nhiều ngoài việc truy cập bộ nhớ càng ít càng tốt và khi bạn chạy càng nhiều tính toán trên nó càng tốt trước khi đưa vào bộ nhớ mới sẽ xóa nó khỏi bộ nhớ cache và đảm bảo bạn sẽ chỉ làm việc một lần.

Chỉnh sửa: Cũng để trả lời tiêu đề của bạn, đúng vậy. Tính toán trước các đường dẫn được sử dụng thường xuyên là một ý tưởng tuyệt vời và có thể được thực hiện với A * ở bất cứ đâu ngoài vòng lặp trò chơi của bạn. Ví dụ: từ cơ sở của bạn đến một tài nguyên trong RTS để tập hợp không phải tính toán lại mỗi khi họ muốn nghỉ hoặc quay lại.


Về chỉnh sửa của bạn, tôi không thực sự nói về việc tính toán trước các đường dẫn được sử dụng thường xuyên, nhưng nghiêm túc về kỹ thuật được phác thảo trước khi tính toán từng đường dẫn có thể . Tôi cũng có một chút bối rối về cách hầu hết câu trả lời của bạn chống lại việc sử dụng tính năng tìm đường được tính toán trước, nhưng cuối cùng, bạn nói rằng đó sẽ là một ý tưởng tuyệt vời. Vì vậy, nó có hữu ích trên môi trường hạn chế CPU như GBA không?
David Gouveia

1
Thật tệ, tôi đã cố gắng chỉ ra rằng câu trả lời cho tiêu đề của bạn được đưa ra khỏi bối cảnh là có. Trong khi câu trả lời liên quan đến thuật toán cụ thể được mô tả trong câu hỏi của bạn là không. Vì vậy, trong ngắn hạn, tất cả các đường dẫn có thể là một ý tưởng tồi nhưng việc tính toán trước một vài đường dẫn được sử dụng rất thường xuyên có thể là một ý tưởng tốt.
ClassicThunder

2
@ClassicThunder: Kỹ thuật tính toán trước tất cả các đường dẫn từ một vài mốc thường được gọi là ALT : A-star với Cột mốc & Tam giác bất đẳng thức : cs.princeton.edu/cifts/archive/spr06/cos423/Handouts/GW05. pdf
Pieter Geerkens 23/11/13
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.