A * yol bulma nasıl çalışır?


67

A * yol bulma çalışmalarının nasıl yürüdüğünü temel düzeyde anlamak istiyorum. Herhangi bir kod veya psuedo kodu uygulamaları ve görselleştirmeler yararlı olacaktır.


İşte Dijkstra'nın Algoritmasını harekete geçiren bir animasyonlu GIF ile ilgili küçük bir makale .
furlafur Waage

Amit'in A * Sayfaları benim için iyi bir giriş oldu. Youtube'da AStar Algoritması'nı arayan birçok görselleştirme bulabilirsiniz .
jdeseno

Bu harika öğreticiyi bulmadan önce A * 'in bazı açıklamaları ile şaşırmıştım : policyalmanac.org/games/aStarTutorial.htm
saat

4
-1 wikipedia'da A * makalesi ile ilgili açıklama, kaynak kod, görselleştirme ve… . Buradaki cevapların bazıları o wiki sayfasından Dış Bağlantılara sahip.
user712092

4
Ayrıca, bu oyun geliştiricileri için oldukça ilgi çekici bir konu olduğundan, buradaki bilgiyi istediğimizi düşünüyorum. Joel'i bir keresinde, insanların Google'ı programlama soruları sorduğunda StackOverflow'un en çok etkilenmesini istediğini söylediğini hatırlıyorum.
25'te jhocking

Yanıtlar:


63

feragat

İnternette bulunabilecek A * kod örnekleri ve açıklamaları vardır. Bu soru aynı zamanda birçok faydalı bağlantı içeren birçok harika yanıt aldı. Cevabımda, koddan veya tanımlardan daha kolay anlaşılması için algoritmanın resimli bir örneğini sunmaya çalışacağım.


Dijkstra'nın algoritması

A'yı anlamak için, öncelikle Dijkstra'nın algoritmasına bir göz atmanızı öneririm . Dijkstra'nın algoritmasının bir arama için gerçekleştireceği adımlar konusunda size rehberlik etmeme izin verin.

Bizim başlangıç ​​düğümümüz, Aen kısa yolu bulmak istiyoruz F. Grafiğin her kenarı, kendisiyle ilişkili bir hareket maliyetine sahiptir (kenarların yanında siyah rakam olarak belirtilmiştir). Amacımız, hedef düğümümüze ulaşana kadar grafiğin her bir tepe noktası (veya düğümü) için minimum seyahat maliyetini değerlendirmektir.

Dijkstra en resimli, bölüm 1

Bu bizim başlangıç ​​noktamız. İncelenecek bir liste düğümümüz var, bu liste şu anda:

{ A(0) }

Abir bedeli varsa 0, diğer tüm düğümler sonsuzluğa ayarlanır (tipik bir uygulamada bu, bunun gibi int.MAX_VALUEveya benzeri bir şey olur ).

Dijkstra's resimli, bölüm 2

Düğüm listemizden en düşük maliyete sahip düğümü alırız (listemiz yalnızca içerdiğinden A, bu bizim adayımızdır) ve tüm komşularını ziyaret ederiz. Her komşunun ücretini şu şekilde belirledik :

Cost_of_Edge + Cost_of_previous_Node

ve önceki düğümün kaydını tutun (düğümün altında küçük pembe harf ile gösterilir). Aşimdi çözüldü (kırmızı) olarak işaretlenebilir, böylece onu tekrar ziyaret etmeyiz. Aday listemiz şunun gibi görünüyor:

{ B(2), D(3), C(4) }

Dijkstra'nın resimi, bölüm 3

Yine listeden ( B) en düşük maliyetli düğümü alıyoruz ve komşularını değerlendiriyoruz. Bu yol Dşu anki maliyetinden daha pahalıdır D, bu nedenle bu yol atılabilir. Eşimdi buna benzeyen aday listemize eklenecek:

{ D(3), C(4), E(4) }

Dijkstra's resimli, bölüm 4

İncelenecek bir sonraki düğüm şimdi D. CYol mevcut maliyetten daha kısa olmadığından bağlantı kesilebilir . Yine de daha kısa bir yol bulduk E, dolayısıyla maliyeti Eve önceki düğümü güncellenecek. Listemiz şimdi şöyle görünüyor:

{ E(3), C(4) }

Dijkstra's resimli, 5. bölüm

Daha önce yaptığımız gibi, şu anda olan listemizdeki en düşük maliyetli düğümü inceliyoruz E. Esadece bir tane çözülmemiş komşusu vardır, ki bu aynı zamanda hedef düğümdür. Hedef düğüme ulaşma maliyeti 10ve önceki düğümü olarak belirlenir E. Aday listemiz şunun gibi görünüyor:

{ C(4), F(10) }

Dijkstra's resimli, bölüm 6

Daha sonra inceleyeceğiz C. İçin maliyeti ve önceki düğümü güncelleyebiliriz F. Listemiz şimdi Fen düşük maliyetli düğüme sahip olduğundan, işimiz bitti. Yolumuz önceki en kısa düğümleri geri alarak oluşturulabilir.


A * algoritması

Öyleyse neden A * algoritması yerine Dijkstra'yı size anlattığımı merak ediyor olabilirsiniz ? Eh, tek fark, adaylarınızı nasıl tartıştığınız (veya sıraladığınız). Dijkstra ile bu:

Cost_of_Edge + Cost_of_previous_Node

A * ile:

Cost_of_Edge + Cost_of_previous_Node + Estimated_Cost_to_reach_Target_from(Node)

Nerede Estimated_Cost_to_reach_Target_fromyaygın bir denir Sezgisel fonksiyon. Bu, hedef düğüme ulaşmanın maliyetini tahmin etmeye çalışacak bir fonksiyondur. İyi bir sezgisel işlev, hedefi bulmak için daha az düğümün ziyaret edilmesi gerekecek. Dijkstra'nın algoritması tüm taraflara yayılırken, A * (sezgisel tarama sayesinde) hedef yönünde arama yapar.

Amit'in buluşsal araştırma hakkındaki sayfası , genel buluşsal araştırma üzerine iyi bir genel bakışa sahiptir.


2
Sezginin her zaman en iyi rotayı bulmak için aramaya zorlamayacağına dikkat çekmek önemlidir. Örneğin, sezgiseliniz hedefe olan mesafedeyse, ancak uygun rota haritanın kenarı çevresindeyse - bu durumda arama, doğru rotayı almadan önce tüm haritayı arayacaktır. Elbette o zaman, düşünmelisin, anlamadığım bir şey mi var? Bu işe yaramıyor! - Anlaşılması gereken şey, bir sezgisel araştırmanın amacının ÇOK vakalarında aramayı kesmektir ve işiniz, özel ihtiyaçlarınız için mevcut tüm çözümlerin en iyisi olanı bulmaktır.
SirYakalot

2
@AsherEinhorn Hala Djikstra'nınki gibi bilgisiz bir aramadan daha iyi (ya da en kötü durumda eşit) olacak.
Şubat'ta

evet evet, kesinlikle haklısın. Belki de net değildim, yukarıdaki yorumda bahsettiğim bu örnek A * için teorik bir 'en kötü durum' senaryosudur, ancak bu sezgisel AMA ile Dijkstra her zaman ne yapardı. A * çoğu zaman basit bir sezgisel buluşmada bile daha iyi olacaktır. Amacım, sezgiselin ilk başta kafa karıştırıcı olabileceği idi; çünkü 'hedefe olan uzaklık' her senaryo için her zaman bir anlam ifade etmiyor.
SirYakalot


Bu cevap, A * 'nın en kısa yolu bulacağını garanti etmek için bir buluşsal kabul edilebilir kılandan bahseder. (. Kısaca: kabul edilebilmesi için, sezgisel Sigara kabul sezgisel bazen yararlı olabilir hedefe gerçek mesafeyi olduğundan fazla asla ama A * optimal yolları geri dönmesine neden olabilir.)
Ilmari Karonen

26

A * yol bulma, ek bir sezgisel tarama kullanan en iyi ilk arama türüdür.

Yapmanız gereken ilk şey, arama alanınızı bölmektir. Bu açıklama için harita kare bir kiremit ızgarasıdır, çünkü çoğu 2B oyun bir kiremit ızgarası kullanır ve çünkü görselleştirilmesi kolaydır. Ancak, arama alanının istediğiniz şekilde ayrılabileceğine dikkat edin: belki bir altıgen ızgara, hatta Risk gibi rasgele şekiller. Çeşitli harita konumlarına "düğümler" denir ve bu algoritma, geçiş yapmak için bir demet düğümünüz olduğunda ve düğümler arasındaki bağlantıları tanımladığınızda çalışacaktır.

Neyse, belirli bir başlangıç ​​döşemesinden başlayarak:

  • Başlangıç ​​döşemesinin etrafındaki 8 döşeme, a) mevcut döşemeden bir sonraki döşemeye geçme maliyetine (genellikle yatay veya dikey hareketler için 1, çapraz hareket için sqrt (2)) dayalı olarak puanlanır.

  • Her karoya daha sonra ek bir "sezgisel" puan atanır - her karoya hareket etmenin görece değerinin yaklaşık bir değeri. Farklı buluşsal yöntemler kullanılır, en basit olanı belirtilen karo merkezleriyle son karo merkezleri arasındaki düz çizgi mesafesidir.

  • Mevcut döşeme daha sonra "kapatılır" ve ajan açık olan komşu karoya hareket eder, en düşük hareket puanı ve en düşük sezgisel puanı vardır.

  • Bu işlem, hedef düğüme ulaşılana kadar tekrar edilir veya başka açık düğüm yoktur (aracının engellendiği anlamına gelir).

Bu adımları gösteren diyagramlar için bu iyi başlangıç ​​öğreticisine bakın .

Başta buluşsal bulguyu geliştirmede yapılabilecek bazı iyileştirmeler var:

  • Arazi farklılıkları, pürüzlülük, diklik vb.

  • Haritanın verimli yollar olmayan alanlarını engellemek için ızgara boyunca bir "tarama" yapmak da bazen yararlı olabilir: örneğin araca bakan bir U şekli. Bir süpürme testi olmadan, ajan önce U'ya girer, arkanı dönüp sonra U'nun kenarına gider ve gider. "Gerçek" bir akıllı ajan, U şeklindeki tuzağı not eder ve basitçe bundan kaçınırdı. Süpürme, bunun benzetimine yardımcı olabilir.


1
Grafik, düğümler, kenarlar ile ilgili açıklama, karolardan çok daha açık olacaktır. Oyununuzun uzay yapısı ne olursa olsun, bu alandaki birbiriyle bağlantılı konum bilgileriniz olduğu sürece aynı algoritmayı uygulayabileceğinizi anlamamıza yardımcı olur.
Klaim

Bunun daha az açık olacağını savunuyorum, çünkü görselleştirmek daha zor. Ancak evet, bu açıklama bir çini ızgarasının gerekmediğinden bahsetmelidir; Aslında, bu noktayı düzenleyeceğim.
jhocking

14

En iyisi olmaktan uzak, ancak bu birkaç yıl önce C ++ ' da A *' da yaptığım bir uygulama .

Algoritmanın tamamını açıklamaya çalışmak yerine, sizi kaynaklara yöneltmem daha iyi olur. Ayrıca, wiki makalesini okurken, demo ile oynayın ve nasıl çalıştığını görselleştirip göremediğinizi görün. Belirli bir sorunuz varsa yorum bırakın.

  1. A * Wikipedia'da
  2. A * Java gösterisi

4
Python örneğiniz C ++ 'dadır.
Aluminium Buns

@finish - Birisinin onu yakaladığını görmek güzel! Günlük aktiviteler bugünlerde Python etrafında dönüyor. Teşekkürler!
David McGraw

3
C ++ örneğiniz C olabilir.
deceleratedcaviar

4
Örnek, sahip olduğu tüm yapı için montajcı da olabilir. A * bile değil, bu kabul edilen cevap nasıl?

4
Üzgünüm, bu kadar değil, arkadaşlarım, başladığımda ilk kodlama girişimlerimden biriydi. Kendi çözümünüzü paylaşmak için yorumlara katkıda bulunmaktan çekinmeyin / yazıyı düzenleyin.
David McGraw

6

ActiveTut'un Yol Bulma ile ilgili makalesini yararlı bulabilirsiniz. Hem A * hem de Dijkstra'nın Algoritması ile aralarındaki farkların üzerinden geçer. Flash geliştiricilerine yöneliktir, ancak Flash kullanmasanız bile teori hakkında iyi bir fikir vermelidir.


4

A * ve Dijkstra'nın Algoritması ile uğraşırken görselleştirmesi gereken önemli bir şey, A * 'nın yönlendirilmesidir; hangi yöne bakılacağını "tahmin ederek" belirli bir noktaya giden en kısa yolu bulmaya çalışır. Dijkstra's Algoritması, her / noktaya en kısa yolu bulur.


1
Bu gerçekten A * ve Dijkstra arasındaki farkın kesin bir açıklaması değildir. Dijkstra'nın tek noktadan bütün noktalara çözdüğü doğrudur, ancak oyunlarda kullanıldığında, hedefe bir yol bulduğunuzda genellikle kesilir. İkisi arasındaki asıl fark, A * 'nın sezgisel tarafından bilgilendirilmesi ve bu hedefi daha az sayıda dalda bulabilmesidir.

Joe'nun açıklamasını eklemek için: A * izin verirseniz tüm noktaların yolunu da bulacaktır, ancak oyunlarda genellikle erken durmak istiyoruz. A * Dijsktra'nın algoritması gibi çalışır, ancak sezgisel tarama ilk önce en umut verici yolları keşfetmek için düğümlerin yeniden sıralanmasına yardımcı olur. Bu şekilde genellikle Dijkstra'nın algoritmasından daha erken durabilirsiniz. Örneğin, haritanın merkezinden doğu tarafına giden bir yol bulmak istiyorsanız, Dijkstra'nın algoritması her yöne eşit olarak araştırır ve doğu tarafını bulduğunda durur. A *, batıdan doğuya doğru daha fazla zaman geçirecek ve oraya daha erken varacak.
amitp

3

Dolayısıyla, ilk ifade olarak, A * kalbinde bir grafik keşif algoritmasıdır. Genellikle oyunlarda, fayans veya diğer dünya geometrisini grafik olarak kullanırız, ancak A * 'ı başka şeyler için kullanabilirsiniz. Grafik geçişi için iki ur algoritması derinlik ilk arama ve genişlik ilk aramadır. DFS'de, geçerli düğümün kardeşlerine bakmadan önce daima geçerli dalınızı tamamen keşfedersiniz ve BFS'de daima önce çocuklara, sonra kardeşlere bakarsınız. A *, istediğiniz hedefe yaklaştığınızda bir daldan aşağıya (DFS gibi daha fazla) keşfettiğinizde, aralarında daha iyi sonuçlar doğuracaksa, bazen bir kardeşi durdurmaya ve denemeye çalışırken aralarında bir orta yol bulmaya çalışır. Gerçek matematik, her birinin bir "iyiliğe" sahip olduğu bir sonraki bölgeyi keşfetmek için olası düğümlerin bir listesini tutmanızdır. puan (ne kadar soyut bir anlamda) hedefe ne kadar yakın olduğunu belirten puan, düşük puanların daha iyi olması (0, hedefi bulduğunuz anlamına gelir). Skorun minimumunu artı kökten uzakta bulunan düğüm sayısını (genellikle mevcut konfigürasyon veya yol bulmadaki mevcut konumdur) bularak hangisinin kullanılacağını seçersiniz. Bir düğümü her keşfettiğinizde, tüm çocuklarını bu listeye ekler ve sonra yenisini seçersiniz.


3

Soyut bir düzeyde, A * şöyle çalışır:

  • Dünyaya ayrı sayıda bağlı düğüm gibi davranıyorsunuz, örneğin. bir ızgara veya bir grafik.
  • O dünya genelinde bir yol bulmak için, o alandaki bitişik 'düğümlerin' bir listesini bulmanız gerekir, bu da başlangıçtan hedefe götürür.
  • Naif yaklaşım şu şekilde olacaktır: başlangıç ​​düğümü ile başlayan ve son düğümde biten tüm düğümlerin olası permütasyonlarını hesaplayın ve en ucuzunu seçin. Bu tabii ki en ufak alanların dışında sonsuza dek sürecek.
  • Bu nedenle, alternatif yaklaşımlar, dünya hakkında bazı bilgileri ilk önce hangi permütasyonların dikkate alınmaya değer olduğunu tahmin etmek ve verilen bir çözümün yenilebilir olup olmadığını bilmek için kullanmaya çalışır. Bu tahmine sezgisel denir.
  • A * kabul edilebilir bir buluşsal buluş gerektirir . Bu asla fazla abartmadığı anlamına gelir.
    • Yol bulma problemleri için iyi bir sezgisel buluş Öklid mesafesidir, çünkü 2 nokta arasındaki en kısa yolun düz bir çizgi olduğunu biliyoruz. Bu, gerçek dünya simülasyonlarındaki mesafeyi asla abartmaz.
  • A * başlangıç ​​düğümü ile başlar ve daha sonra hangi izin verileceğine karar vermek için buluşsal yöntemi kullanarak o düğüm artı her bir komşunun ve komşusunun komşularının ardışık izinlerini dener.
  • Her adımda, A * şimdiye kadarki en ümit vaat eden yola bakar ve şimdiye kadar gidilen mesafeye ve sezgisel kişinin bu noktadan ne kadar uzağa gideceğine dair tahminine dayanarak “en iyi” görünen bir sonraki komşu düğümü seçer. düğümü.
  • Sezgisel asla aşırı tahmin etmediğinden ve şu ana kadar kat edilen mesafenin doğru olduğu bilindiğinden, bir sonraki adımı her zaman en iyimser seçecektir.
    • Eğer bir sonraki adım hedefe ulaşırsa, son pozisyondan en kısa rotayı bulduğunu biliyorsunuzdur, çünkü kalan geçerli olanların en iyimser tahminiydi.
    • Hedefe ulaşmadıysa, daha sonra keşfedilmesi muhtemel bir nokta olarak bırakılmıştır. Algoritma şimdi bir sonraki en umut verici olasılığı seçiyor, bu yüzden yukarıdaki mantık hala geçerli.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.