ग्रिड पर ए * के साथ प्राकृतिक दिखने वाले रास्ते कैसे बनाएं?


13

मैं इसे पढ़ रहा हूं: http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html

लेकिन कुछ चीजें हैं जो मुझे समझ में नहीं आती हैं, उदाहरण के लिए लेख विकर्ण आंदोलन के साथ पाथफाइंडिंग के लिए कुछ इस तरह का उपयोग करने के लिए कहता है:

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

मुझे नहीं पता कि लेख में डी की तरह दिखने वाला प्राकृतिक रास्ता पाने के लिए डी कैसे सेट किया जाता है, मैंने डी को बगल के वर्गों के बीच सबसे कम लागत पर सेट किया है, जैसे कि मैंने कहा, और मुझे नहीं पता कि हेयुरिस्टिक के बारे में उन्हें क्या करना चाहिए 4 * डी, कि किसी भी चीज को बदलने के लिए प्रतीत नहीं होता है।

यह मेरा विधर्मी कार्य और चालन कार्य है:

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

परिणाम:

यहाँ छवि विवरण दर्ज करें

हम चाहते हैं कि चिकनी नौकायन पथ:

यहाँ छवि विवरण दर्ज करें

मेरे बाकी कोड: http://pastebin.com/TL2cEkeX


अपडेट करें

यह अब तक का सबसे अच्छा समाधान है:

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

यह दूसरी तस्वीर से वांछित पथ का निर्माण करता है, लेकिन बाधाओं को बहुत अच्छी तरह से संभालता नहीं है (दीवारों पर क्रॉल करता है) और कभी-कभी लंबी दूरी पर इष्टतम पथ का उत्पादन करने में विफल रहता है।

इसे सुधारने के लिए मैं कुछ ट्वीक और अनुकूलन क्या कर सकता हूं?


2
क्या होगा यदि आप अपने उत्तराधिकारी के रूप में कार्टेशियन दूरी का उपयोग करते हैं?
जिमी

2
यहां सिर्फ एक विचार है, एक ही दिशा में हर कदम एजेंट चाल के लिए एक टाइल से दूसरे तक जाने की लागत में वृद्धि करें।
अली

@ जिमी मैंने sqrt (pow (goal.x - node.x, 2) + pow (goal.y - node.y, 2)) आज़माया और अपने छोटे से उदाहरण पथ के लिए यह वास्तव में मेरे प्रश्न में चित्र के समान सटीक रिटर्न देता है। ।
अनाम एंटिटी

जवाबों:


10

A * आपको ग्राफ में सबसे छोटा रास्ता देता है। अपने ग्राफ के रूप में एक ग्रिड का उपयोग करते समय अक्सर कई सबसे छोटे रास्ते होते हैं। अपना पहला चित्र में, कि है कम से कम पथ में से एक। यह सभी अक्षीय आंदोलनों को पहले रखता है और बाद में सभी विकर्ण आंदोलनों को। लेकिन यह वही लंबाई वाला रास्ता है जैसे कि आप पहले सभी विकर्ण डालते हैं, या यदि आप अक्षीय और विकर्ण आंदोलनों को मिलाते हैं। ये सभी समान रूप से छोटे हैं, और कौन सा A * चुनता है यह इस बात पर निर्भर करता है कि कोड कैसे लिखा जाता है और ग्राफ़ का प्रतिनिधित्व कैसे किया जाता है।

मुझे लगता है कि आप जो चाहते हैं वह या तो है:

  1. आपको ग्रिड पर जाने की आवश्यकता है, लेकिन आप अक्षीय और विकर्ण चरणों को मिलाना चाहते हैं ताकि यह बेहतर दिखे। एक दृष्टिकोण दूसरे समान रूप से छोटे रास्तों में से एक को चुनना है; "टाई ब्रेकिंग" को खोजने के लिए उस आंकड़े पेज को पढ़ते रहें। एक और दृष्टिकोण यह है कि जब आप पड़ोसियों का मूल्यांकन कर रहे हों, तो बेतरतीब ढंग से चुनें कि पहले कौन सा मूल्यांकन करें ताकि यह हमेशा एक दूसरे से पहले न चुने। यदि आप ग्रिड पर जाना चाहते हैं तो मैं यूक्लिडियन / कार्टेशियन दूरी का उपयोग करने की सलाह नहीं देता ; यह एक बेमेल है जो A * रन को धीमा बनाता है।
  2. आपको ग्रिड पर जाने की आवश्यकता नहीं है, और एक सीधी रेखा में चलना चाहते हैं। एक दृष्टिकोण "स्ट्रिंग पुलिंग" का उपयोग करके पथ को सीधा करना है। आप उन स्थानों की तलाश कर रहे हैं, जहाँ मार्ग मुड़ता है, और उन बिंदुओं के बीच सीधी रेखाएँ खींचता है। एक अन्य तरीका यह है कि इसे अंतर्निहित ग्राफ में ही लागू किया जाए। ग्रिड पर पाथफाइंडिंग के बजाय, मानचित्र पर मुख्य बिंदुओं पर पाथफाइन्ड करें, और फिर उन प्रमुख बिंदुओं के बीच सीधी रेखाओं के साथ आगे बढ़ें। आप यहां एक उदाहरण देख सकते हैं । अभी तक एक और दृष्टिकोण थीटा * एल्गोरिथ्म है

अच्छा उत्तर। मैंने अपने प्रश्न को कुछ नई जानकारी के साथ अद्यतन किया, मुझे आशा है कि आप अपना उत्तर थोड़ा निर्दिष्ट कर सकते हैं।
बेनामी इकाई

मुझे लगता है कि बाधाओं के बारे में थोड़ा अपेक्षित है; Heuristics पृष्ठ पर एक आरेख है जिसे "बाधाओं के साथ कम सुंदर" शीर्षक दिया गया है। टाई ब्रेकिंग दृष्टिकोण बाधाओं के आसपास ज्यादा मदद नहीं करता है। अन्य दृष्टिकोणों में से एक (जैसे थीटा *) वह हो सकता है जो आप चाहते हैं।
एमटीपी

2

ए * एल्गोरिथ्म आपको पथ किनारों पर विभिन्न लागतों को असाइन करने की अनुमति देता है। आप परिस्थितियों के आधार पर लागत भी असाइन कर सकते हैं। यह आपका मुख्य उपकरण है ए * पाथ को आकार देने के लिए जिस तरह से आप उन्हें देखना चाहते हैं।

जब आप लंबे विकर्णों को हतोत्साहित करना चाहते हैं, तो आप उन्हें दंडित कर सकते हैं। जब भी रास्ता एक ही दिशा में जाता है, तो हर बार एक छोटी सी लागत जोड़ें। जब आप ऐसा करते हैं, तो एल्गोरिथ्म स्वचालित रूप से विकर्ण चरणों को पूरे पथ पर समान रूप से वितरित करने का प्रयास करेगा। बस यह सुनिश्चित करें कि यह अतिरिक्त लागत कभी भी अतिरिक्त बढ़त लेने की लागत नहीं है, या एल्गोरिथ्म सीधे लाइनों से बचने के लिए पूरी तरह से अनावश्यक डिटर्जेस बनाना शुरू कर देगा।

एक अच्छा सूत्र हो सकता है:

cost = normal_cost * (1.1 - 0.1 / num_of_steps_in_the_same_direction)

ध्यान दें कि इसके लिए आवश्यक है कि पथ-लागत को फ़्लोटिंग-पॉइंट मानों के रूप में ट्रैक किया जाए, न कि पूर्णांकों के रूप में।


1

गोद लेना A *

जैसा कि फिलिप ने कहा, आपको लागतों को जोड़ना चाहिए जब दिशा लंबे समय तक नहीं बदलती है। लेकिन, फिलीपिंस द्वारा किए गए कार्य से अतिरिक्त लागतों का योग हो सकता है, जो एक अतिरिक्त टाइल को पार करने की लागत से अधिक है। लेकिन उनका मुख्य विचार सही है!

"सभी" इष्टतम रास्तों (सबसे कम लंबाई के साथ) की गणना करने के लिए ए * को अनुकूलित करना आसान लगता है और फिर उनमें से किसी एक को अन्य अनुमानी द्वारा चुनना। लेकिन एक समस्या है। यदि आपके पास एक लंबा रास्ता है, तो इष्टतम लंबाई के साथ बहुत सारे समाधान हो सकते हैं। यह ए * एल्गोरिथ्म को इन सभी अन्य समाधानों की गणना करने में बहुत अधिक समय लगता है। इसकी वजह है ग्रिड। आप 90 डिग्री के बजाय 80 डिग्री नहीं चल सकते हैं, जो एक इष्टतम समाधान के बजाय कई उप-अपनाने वाले समाधानों की ओर जाता है। कल्पना के लिए, बाधाओं के बिना एक मानचित्र की कल्पना करें। एक्स-डिस्टेंस 2 है y- डिस्टेंस है 3. इसका मतलब है, सभी छोटे रास्तों में 2 विकर्ण चाल और 1 सीधी चाल है। इस सरल पथ के लिए 3 मान्य संयोजन हैं: SDD, DSD, DDS (जहाँ D = विकर्ण, S = सीधा)। वास्तविक "मज़ा" पहले से ही शुरू हो जाता है जब आपके पास उदाहरण के साथ रास्ते होते हैं 3 सीधी और 2 विकर्ण चालें: SSSDD, SSDSD, SSDDS, SDSSD, SDSDS, SDDSS, DSSSD, DSSDS, DSDDS, DDSSS (सबसे छोटे पथ के 10 रूपांतर, अगर मुझे कोई याद नहीं है)। मुझे लगता है कि आपको यह विचार करना चाहिए था ...

इसलिए हमें लागत फ़ंक्शन को इस तरह से निर्धारित करके इसे ठीक करना चाहिए कि कम समाधान (या केवल एक समाधान) "इष्टतम" हैं।

लागत समारोह को अपनाना

जैसा कि फिलिप्पुस अपने उदाहरण सूत्र में बताता है कि अनुकूलन करना आपको बहुत बेहतर परिणाम देगा, लेकिन अभी भी कुछ समस्याएं हैं। यह पथ के साथ छोटे / लंबे "भागों" को समान रूप से वितरित नहीं करेगा, जिसका अर्थ है: पथ की शुरुआत या इसके विपरीत दिशा में परिवर्तन अक्सर अधिक होगा।

इसके अतिरिक्त, एक ऐसा रास्ता जिसके पास अभिनेता को "बारी" करने के लिए एक मानव द्वारा देखा जाने पर सबप्टिमल लगता है। जैसा कि समय लगता है (टर्न एनीमेशन दिखाने के लिए) और इसलिए यह धीमा होना चाहिए।

कभी भी, लागतों के लिए फ़्लोट्स का उपयोग करने के बजाय आप "माध्यमिक लागत" या माध्यमिक प्रकार के मानदंडों को लागू कर सकते हैं। यदि प्राथमिक लागतें समान हैं तो द्वितीयक लागत का उपयोग अनुमान लगाने के लिए किया जाता है कि कौन सा समाधान पसंद किया जाना है। इससे गलती से प्राथमिक लागत (ग्रिड माप में मार्ग की लंबाई) नहीं बढ़ेगी।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.