Bir ızgarada A * ile doğal görünümlü yollar nasıl yapılır?


13

Bunu okudum: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html

Ama anlamadığım bazı şeyler var, örneğin makale diyagonal hareketle yol bulma için böyle bir şey kullandığını söylüyor:

function heuristic(node) =
    dx = abs(node.x - goal.x)
    dy = abs(node.y - goal.y)
    return D * max(dx, dy)

D'yi makalede olduğu gibi doğal görünümlü bir yol elde etmek için nasıl bilmiyorum, D'yi dediğim gibi bitişik kareler arasındaki en düşük maliyete ayarladım ve sezgisel meseleyle ilgili ne anlama geldiğini bilmiyorum 4 * D olsun, bu hiçbir şeyi değiştirmiyor gibi görünüyor.

Bu benim sezgisel fonksiyonum ve hareket fonksiyonum:

def heuristic(self, node, goal):
    D = 5
    dx = abs(node.x - goal.x)
    dy = abs(node.y - goal.y)
    return D * max(dx, dy)

def move_cost(self, current, node):
   cross = abs(current.x - node.x) == 1 and abs(current.y - node.y) == 1
   return 7 if cross else 5

Sonuç:

resim açıklamasını buraya girin

Gerçekleşmek istediğimiz pürüzsüz yelken yolu:

resim açıklamasını buraya girin

Kodumun geri kalanı: http://pastebin.com/TL2cEkeX


Güncelleme

Bu şimdiye kadar bulduğum en iyi çözüm:

def heuristic(node, start, goal):
    dx1 = node.x - goal.x
    dy1 = node.y - goal.y
    dx2 = start.x - goal.x
    dy2 = start.y - goal.y
    cross = abs(dx1*dy2 - dx2*dy1)

    dx3 = abs(dx1)
    dy3 = abs(dy1)

    return 5 + (cross*0.01) * (dx3+dy3) + (sqrt(2)-2) * min(dx3, dy3)

def move_cost(current, node):
    cross = abs(current.x - node.x) == 1 and abs(current.y - node.y) == 1
    return 7 if cross else 5

İkinci resimden istenen yolu üretir, ancak engelleri çok iyi idare etmez (duvarlara sürünme eğilimi gösterir) ve bazen daha uzun mesafelerde optimum yollar üretemez.

Geliştirmek için uygulayabileceğim bazı ince ayarlar ve optimizasyonlar nelerdir?


2
Sezgisel olarak kartezyen mesafeyi kullanırsanız ne olur?
Jimmy

2
burada sadece bir fikir, aynı yönde hareket her adım ajan için bir kiremit diğerine taşıma maliyetini artırmak.
Ali1S232

@Jimmy sqrt (pow (goal.x - node.x, 2) + pow (goal.y - node.y, 2)) denedim ve küçük örnek yolum için aslında sorumdaki resimle tam olarak aynı döndürüyor .
Anonim Varlık

Yanıtlar:


10

A * size grafikteki en kısa yolu verir. Grafiğiniz olarak bir ızgara kullanırken, genellikle birden çok en kısa yol vardır. İlk şemasında, bu ise en kısa yol biri. Önce tüm eksenel hareketleri, daha sonra tüm çapraz hareketleri koyar. Ancak bu, tüm çaprazları ilk sıraya koyduğunuz veya eksenel ve çapraz hareketleri karıştırdığınızla aynı uzunluktaki yol. Bunların hepsi aynı derecede kısadır ve hangi A * 'nın seçtiği kodun nasıl yazıldığına ve grafiğin nasıl temsil edildiğine bağlıdır.

Bence istediğin şey ya:

  1. Izgara üzerinde hareket etmeniz gerekir, ancak daha iyi görünmesi için eksenel ve çapraz adımları karıştırmak istersiniz. Bir yaklaşım, diğer eşit derecede kısa yollardan birini seçmektir; “kravat kırma” bulmak için sezgisel tarama sayfasını okumaya devam edin. Başka bir yaklaşım, komşuları değerlendirirken, hangisini önce değerlendireceğini rastgele seç, böylece her zaman birini diğerinden önce seçmez. Ben do not sen ızgara üzerinde hareket etmek istiyorsanız Öklit / Kartezyen mesafe kullanmanızı tavsiye; A * 'nın daha yavaş çalışmasını sağlayan bir uyumsuzluktur.
  2. Izgara üzerinde hareket etmenize gerek yoktur ve düz bir çizgide hareket etmek istersiniz. Bir yaklaşım “string pulling” kullanarak yolları düzeltmektir. Yolun döndüğü yerleri arıyorsunuz ve bu noktalar arasında düz çizgiler çiziyorsunuz. Başka bir yaklaşım, bunu alttaki grafiğin kendisine uygulamaktır. Izgara üzerinde yol bulma yerine, haritadaki anahtar noktalarda yol bulma ve ardından bu anahtar noktalar arasında düz çizgiler boyunca hareket etme. Burada bir örnek görebilirsiniz . Yine başka bir yaklaşım Theta * algoritmasıdır .

İyi cevap. Sorumu yeni bilgilerle güncelledim, umarım cevabınızı biraz belirtebilirsiniz.
İsimsiz Varlık

Bence engellerle ilgili biraz beklenir; Sezgisel tarama sayfasında “engellerle daha az güzel” başlıklı bir diyagram var. Eşitliği bozma yaklaşımları engellere pek yardımcı olmaz. Diğer yaklaşımlardan biri (Theta * gibi) istediğiniz şey olabilir.
amitp

2

A * algoritması, yol kenarlarına farklı maliyetler atamanıza olanak tanır. Ayrıca koşullara bağlı olarak maliyetler de atayabilirsiniz. Bu, A * yollarını görünmelerini istediğiniz şekilde şekillendirmek için ana aracınızdır.

Uzun köşegenleri caydırmak istediğinizde onları cezalandırabilirsiniz. Yolun aynı yöne gittiği her sefer için küçük bir maliyet ekleyin. Bunu yaptığınızda, algoritma çapraz adımları otomatik olarak tüm yol boyunca eşit olarak dağıtmaya çalışır. Sadece bu ek maliyetin asla ek bir kenar alma maliyeti olmadığından emin olun, yoksa algoritma sadece düz çizgileri önlemek için tamamen gereksiz sapmalar yapmaya başlayacaktır.

İyi bir formül şöyle olabilir:

cost = normal_cost * (1.1 - 0.1 / num_of_steps_in_the_same_direction)

Bunun, yol maliyetinin tamsayı olarak değil kayan nokta değeri olarak izlenmesini gerektirdiğini unutmayın.


1

Uyarlama A *

Philipp'in dediği gibi, yön uzun süre değişmediğinde maliyet eklemelisiniz. Ancak, Philipp'in işlevi hızlı bir şekilde, ek bir döşemeyi geçme maliyetinden daha yüksek ek maliyetlerin toplanmasına yol açabilir. Ama ana fikri doğru!

"Tüm" optimal yolları (en kısa uzunlukta) hesaplamak ve sonra bunlardan birini başka bir buluşsal yöntemle seçmek için A * 'yı uyarlamak kolaydır. Ama bir problem var. Uzun bir yolunuz varsa, en uygun uzunlukta birçok çözüm olabilir. Bu, A * algoritmasının diğer tüm çözümlerin hesaplanması için çok daha uzun sürmesine neden olur. Bunun nedeni ızgara. 90 derece yerine 80 derece yürüyemezsiniz, bu da tek bir optimum çözüm yerine birden fazla yetersiz çözümlere yol açar. Hayal gücü için engelsiz bir harita hayal edin. X-mesafesi 2, y-mesafesi 3'tür. Bu, en kısa yolların 2 diyagonal hareketi ve 1 düz hareketi olduğu anlamına gelir. 3 geçerli kombinasyon vardır: Bu basit yol için SDD, DSD, DDS (burada D = diyagonal, S = düz). Gerçek "eğlence", ör. 3 düz ve 2 diyagonal hareket: SSSDD, SSDSD, SSDDS, SDSSD, SDSDS, SDDSS, DSSSD, DSSDS, DSDSS, DDSSS (hiç özlemediysem en kısa yolun 10 varyasyonu). Bence bu fikre sahip olmalısın ...

Bu yüzden, maliyet fonksiyonunu daha az sayıda çözümün (veya yalnızca bir çözümün) "optimal" olacak şekilde adapte ederek düzeltmeliyiz.

Maliyet İşlevinin Uyarlanması

Uyarlamayı Philipp'in örnek formülünde önerdiği gibi yapmak size çok daha iyi sonuçlar verecektir, ancak yine de bazı sorunları var. Kısa / uzun "parçaları" yol boyunca eşit olarak dağıtmaz, yani: yön değişiklikleri yolun başlangıcında daha sık olur ya da tam tersi olur.

Ek olarak, aktörün "dönmesi" için sonsuz bir yolu olan bir yol, bir insan tarafından gözlemlendiğinde yetersiz gözükmektedir. Zaman alır (dönüş animasyonunu göstermek için) ve bu nedenle daha yavaş olmalıdır.

Her ne kadar, maliyetler için şamandıralar kullanmak yerine bir "ikincil maliyet" veya ikincil sıralama ölçütleri uygulayabilirsiniz. Birincil maliyetler aynı ise, hangi çözümün tercih edileceğini tahmin etmek için ikincil maliyet kullanılır. Bu yanlışlıkla birincil maliyetlerin (şebeke ölçüsündeki rota uzunluğu) artmasına neden olmaz.

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.