ГоловнаШІ та Машинне навчанняПошук шляху NPC у грі

🎮 Пошук шляху NPC у грі — A* пошук наживо

Спостерігайте, як справжній алгоритм пошуку A* розширює вузли симульованої ігрової карти наживо за справжньою вартістю f=g+h, знаходячи доведено найкоротші шляхи NPC навколо перешкод швидше за звичайний алгоритм Дейкстри.

ШІ та Машинне навчання3DСередній60 FPS
ai-game-npc-pathfinding ↗ Відкрити окремо

Про симуляцію «A* пошук наживо»

Ігрові рушії постійно ставлять одне й те саме питання: який найкоротший прохідний маршрут від NPC до його цілі через карту, повну стін, місцевості та інших перешкод? Пошук A* (Харт, Нільссон і Рафаель, 1968) — це робоча відповідь: пошук найкращого-першого в графі, який підтримує справжню чергу з пріоритетом, впорядковану за f(n) = g(n) + h(n), де g(n) — це реальна накопичена вартість від старту, а h(n) — допустима евристична оцінка відстані, що залишилася. Ця симуляція виконує справжній алгоритм — справжній відкритий набір, справжній закритий набір, справжні батьківські вказівники — на ігровій карті-сітці, яку ви можете редагувати, і водночас виконує звичайний алгоритм Дейкстри (A* з h(n) = 0) на ідентичній карті, тож ви можете спостерігати, вузол за вузлом, скільки саме роботи заощаджує евристика.

🔬 Що показано

Дві сітки поруч, що спільно використовують одну карту перешкод: ліва сітка виконує справжній A* з октильно-відстаневою евристикою, права сітка виконує Дейкстру з евристикою, примусово зведеною до нуля. Блакитні клітинки належать до відкритого набору (виявлені, у черзі, ще не розширені), бурштинові клітинки — до закритого набору (розширені, завершені), а шлях акцентного кольору — це найкоротший маршрут, відновлений через батьківські вказівники, щойно вузол цілі витягується. Живі лічильники підсумовують реальну кількість вузлів, які кожна черга з пріоритетом справді витягнула.

🎮 Як користуватися

Оберіть режим — Стіна, Старт або Ціль — потім клацніть будь-яку клітинку на будь-якій сітці, щоб редагувати спільну карту; обидва пошуки миттєво перезапускаються. Використовуйте «Випадковий лабіринт», щоб згенерувати нову схему перешкод, «Очистити стіни», щоб почати з відкритого поля, і повзунок швидкості розширення, щоб уповільнити показ для навчання або пришвидшити, щоб одразу побачити фінальний шлях. «Повтор» перезапускає покрокову анімацію без повторного обчислення пошуку.

💡 А чи знали ви?

Оскільки алгоритм Дейкстри математично ідентичний A* з h(n)=0, обидві панелі виконують точно той самий шлях коду зі зміненим одним числом — саме тому це чесне, порівнюване зіставлення, а не дві непов'язані реалізації. На відкритих картах A* часто розширює менше половини вузлів, ніж Дейкстра; на картах, де стіна змушує обидва алгоритми йти довгим обхідним шляхом, розрив зменшується, бо жоден не може скоротити геометрію, яку евристика не бачить наскрізь.

Часті питання

Що таке пошук A* і чим він відрізняється від алгоритму Дейкстри?

Обидва — це пошуки найкращого-першого в графі, які на кожному кроці витягують вузол з найменшою вартістю з черги з пріоритетом (відкритого набору). Алгоритм Дейкстри впорядковує цю чергу виключно за g(n), реальною накопиченою вартістю від початкового вузла, тож він досліджує назовні в усіх напрямках однаково, як брижі на ставку. A* впорядковує ту саму чергу за f(n) = g(n) + h(n), додаючи допустиму евристичну оцінку h(n) відстані, що залишилася до цілі. Цей додатковий член зміщує розширення в бік цілі, тож A* зазвичай закриває набагато менше вузлів, ніж Дейкстра, при цьому гарантовано повертаючи той самий найкоротший шлях, оскільки виконання Дейкстри математично ідентичне виконанню A* з h(n) = 0 для кожного вузла — саме так ця симуляція реалізує порівняння на одній спільній карті.

Що робить евристику допустимою і чому це гарантує, що A* знаходить найкоротший шлях?

Евристика h(n) є допустимою, якщо вона ніколи не переоцінює справжню решту вартості від вузла n до цілі — вона може недооцінювати або бути точно правильною, але ніколи не бути надто оптимістичною в неправильному напрямку. На сітці, де діагональні кроки коштують √2, а ортогональні — 1, пряма (октильна) відстань до цілі завжди менша або дорівнює справжній решті вартості шляху навколо перешкод, тож вона допустима. З допустимою евристикою A* гарантовано ніколи не завершує вузол із неоптимальним g-значенням: будь-який шлях, який він повідомляє як найкоротший, дійсно є найкоротшим, тому симуляція може стверджувати, що A* і Дейкстра завжди дають однакову вартість шляху, а не лише схожу.

Що таке октильна відстань і навіщо її використовують на картах-сітках, що дозволяють діагональний рух?

Октильна відстань — це евристика для 8-напрямкових сіток: маючи |dx| і |dy| клітинок горизонтального й вертикального розділення, найкоротший можливий шлях (ігноруючи перешкоди) рухається по діагоналі min(|dx|,|dy|) разів вартістю √2 кожен, потім покриває решту |dx|−|dy| клітинок ортогонально вартістю 1 кожна. Формула (|dx|+|dy|) + (√2−2)·min(|dx|,|dy|) обчислює точно це. Звичайна евклідова чи манхеттенська відстань або переоцінювала б (порушуючи допустимість на сітці з діагональним рухом), або недооцінювала б надто грубо, тож октильна відстань — це точний, допустимий вибір, який ця симуляція використовує для h(n) алгоритму A*.

Чому A* зазвичай розширює менше вузлів, ніж Дейкстра?

Дейкстра не має уявлення про те, де ціль, тож її фронт розширення росте як приблизно кругова хвиля, центрована на старті, торкаючись кожного вузла в межах заданого радіуса вартості, перш ніж досягти цілі. Впорядкування f = g + h алгоритму A* тримає вузли, що вказують у бік цілі, ближче до початку черги з пріоритетом, тож його фронт витягується в подовжену, спрямовану до цілі форму й пропускає великі регіони з дальнього боку карти, які Дейкстрі все одно довелося б відвідати. Живі лічильники в цій симуляції підсумовують реальну кількість вузлів, які кожен алгоритм справді витягнув і закрив зі своєї власної черги з пріоритетом на ідентичній карті перешкод, тож розрив, який ви бачите, є справжньою, виміряною різницею, а не припущеною — а на картах, де пряму лінію до цілі блокує велика перешкода, розрив може зменшитися або навіть зникнути, що симуляція чесно покаже.

Яка різниця між відкритим набором і закритим набором?

Відкритий набір — це фронт: вузли, які були виявлені (досягнуті від якогось сусіда) і поміщені в чергу з пріоритетом, але ще не розширені. Закритий набір — це вузли, які вже витягнуті з черги, і всі їхні сусіди були розглянуті — їхня найкоротша g-вартість від старту завершена і більше не зміниться. У візуалізації блакитні клітинки належать до відкритого набору (кандидати, що все ще розглядаються), а бурштинові клітинки — до закритого набору (повністю оброблені); щойно ціль витягується із закритого набору, алгоритм зупиняється й відновлює шлях, проходячи батьківські вказівники назад від цілі до старту.

Чи може A* коли-небудь не знайти найкоротший шлях або взагалі не знайти шлях?

A* гарантовано знаходить найкоротший шлях, якщо він існує, а його евристика допустима — октильно-відстанева евристика цієї симуляції задовольняє цю умову на кожній карті, яку ви будуєте. Чого A* не може зробити, це знайти шлях, якого не існує: якщо ви повністю відгородите ціль стінами, і A*, і Дейкстра вичерпають свої відкриті набори й повідомлять про відсутність шляху, що панель статистики покаже явно, а не мовчки показуватиме застарілий маршрут.

📚 Дослідіть більше симуляцій зі ШІ та Машинного навчання →
⚙ Під капотом

Черга з пріоритетом на основі бінарної купи розширює вузли у справжньому порядку найкращого-першого за f(n)=g(n)+h(n) на лівій сітці та f(n)=g(n) на правій; обидві відновлюють найкоротший шлях через справжні батьківські вказівники, щойно ціль витягується із закритого набору.

A* SearchDijkstraPathfindingPriority QueueGame AI

3D · рушій Three.js / WebGL · ціль 60 FPS · працює повністю на клієнті, без встановлення

Що ви знайшли?

Додати кроки відтворення (необов'язково)