วิธีสร้างเส้นทางที่ดูเป็นธรรมชาติด้วย A * บนกริด


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)

ฉันไม่รู้ว่าจะตั้งค่า D ให้เป็นเส้นทางที่ดูเป็นธรรมชาติได้อย่างไรในบทความฉันตั้งค่า D เป็นต้นทุนที่ต่ำที่สุดระหว่างสี่เหลี่ยมที่อยู่ติดกันอย่างที่มันบอกไว้และฉันไม่รู้ว่าพวกเขาหมายถึงอะไรเกี่ยวกับฮิวริสติก เป็น 4 * D ที่ดูเหมือนจะไม่เปลี่ยนแปลงอะไร

นี่คือฟังก์ชันฮิวริสติกของฉันและฟังก์ชั่นย้าย:

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
นี่เป็นเพียงแนวคิดเพิ่มค่าใช้จ่ายในการย้ายจากไทล์หนึ่งไปอีกไทล์สำหรับเอเจนต์ทุกขั้นตอนจะเคลื่อนที่ไปในทิศทางเดียวกัน
Ali1S232

@ จิมมี่ฉันลอง sqrt (pow (goal.x - node.x, 2) + pow (goal.y - node.y, 2)) และสำหรับเส้นทางตัวอย่างเล็ก ๆ ของฉันมันคืนค่าที่แน่นอนเหมือนกับรูปภาพในคำถามของฉัน .
นิรนาม

คำตอบ:


10

A * ให้เส้นทางที่สั้นที่สุดในกราฟ เมื่อใช้ตารางเป็นกราฟของคุณมักจะมีเส้นทางที่สั้นที่สุดหลายเส้นทาง ในแผนภาพแรกของคุณนั่นเป็นหนึ่งในเส้นทางที่สั้นที่สุด มันทำให้การเคลื่อนไหวตามแนวแกนทั้งหมดก่อนและการเคลื่อนไหวในแนวทแยงทั้งหมดในภายหลัง แต่นั่นคือเส้นทางที่มีความยาวเท่ากันถ้าคุณใส่เส้นทแยงมุมทั้งหมดก่อนหรือถ้าคุณผสมการเคลื่อนที่ตามแนวแกนและแนวทแยง ทั้งหมดนี้สั้นพอ ๆ กันและตัวเลือก A * ตัวใดตัวหนึ่งขึ้นอยู่กับวิธีเขียนโค้ดและวิธีแสดงกราฟ

ฉันคิดว่าสิ่งที่คุณต้องการคือ:

  1. คุณต้องเคลื่อนที่บนตะแกรง แต่คุณต้องการผสมขั้นตอนตามแนวแกนและแนวทแยงมุมเพื่อให้ดูดีขึ้น วิธีหนึ่งคือการเลือกเส้นทางที่สั้นพอ ๆ กัน อ่านต่อไปว่าหน้าการวิเคราะห์พฤติกรรมเพื่อค้นหา“ การแหกกฎ” อีกวิธีคือเมื่อคุณประเมินเพื่อนบ้านเลือกแบบสุ่มที่จะประเมินก่อนเพื่อไม่ให้เลือกแบบใดแบบหนึ่งก่อนเสมอ ฉันไม่แนะนำให้ใช้ระยะทางแบบยุคลิด / คาร์ทีเซียนถ้าคุณต้องการที่จะย้ายบนตาราง; มันไม่ตรงกันที่ทำให้ A * ทำงานช้าลง
  2. คุณไม่จำเป็นต้องย้ายไปที่ตารางและต้องการย้ายเป็นเส้นตรง วิธีการหนึ่งคือยืดเส้นทางให้ตรงโดยใช้ "การดึงสตริง" คุณกำลังมองหาสถานที่ที่เส้นทางเปลี่ยนและวาดเส้นตรงระหว่างจุดเหล่านั้น อีกวิธีหนึ่งคือการใช้สิ่งนี้กับกราฟพื้นฐาน แทนที่จะค้นหาเส้นทางบนกริดให้ค้นหาจุดสำคัญบนแผนที่แล้วเลื่อนไปตามเส้นตรงระหว่างจุดสำคัญเหล่านั้น คุณสามารถดูตัวอย่างที่นี่ แต่อีกวิธีหนึ่งคือขั้นตอนวิธีการที *

คำตอบที่ดี. ฉันอัปเดตคำถามของฉันด้วยข้อมูลใหม่ฉันหวังว่าคุณจะสามารถระบุคำตอบของคุณได้บ้าง
นิรนาม

ฉันคิดว่าคาดหวังเรื่องอุปสรรคเล็กน้อย มีไดอะแกรมบนหน้าการวิเคราะห์พฤติกรรมที่มีชื่อว่า“ สวยน้อยกว่ากับสิ่งกีดขวาง” การเข้าใกล้ไม่ได้ช่วยอะไรมากนัก หนึ่งในวิธีการอื่น ๆ (เช่น Theta *) อาจเป็นสิ่งที่คุณต้องการ
amitp

2

อัลกอริทึม A * ช่วยให้คุณกำหนดค่าใช้จ่ายที่แตกต่างให้กับขอบเส้นทาง นอกจากนี้คุณยังสามารถกำหนดค่าใช้จ่ายขึ้นอยู่กับสถานการณ์ นี่คือเครื่องมือหลักของคุณในการกำหนดรูปร่างของเส้นทาง A * เพื่อค้นหาวิธีที่คุณต้องการให้มันดู

เมื่อคุณต้องการกีดกันเส้นทแยงมุมยาว ๆ คุณสามารถลงโทษพวกเขาได้ เพิ่มค่าใช้จ่ายเล็กน้อยในแต่ละครั้งที่เส้นทางไปในทิศทางเดียวกัน เมื่อคุณทำเช่นนี้อัลกอริทึมจะพยายามกระจายขั้นตอนในแนวทแยงอย่างสม่ำเสมอเท่าที่เป็นไปได้ทั่วทั้งเส้นทาง เพียงตรวจสอบให้แน่ใจว่าค่าใช้จ่ายเพิ่มเติมนี้จะไม่มีค่าใช้จ่ายเพิ่มเติมอีกต่อไปมิฉะนั้นอัลกอริทึมจะเริ่มต้นสร้างเส้นทางที่ไม่จำเป็นโดยสมบูรณ์เพื่อหลีกเลี่ยงเส้นตรง

สูตรที่ดีอาจเป็น:

cost = normal_cost * (1.1 - 0.1 / num_of_steps_in_the_same_direction)

โปรดทราบว่าต้องมีการติดตามเส้นทางต้นทุนนั้นเป็นค่าจุดลอยตัวไม่ใช่จำนวนเต็ม


1

ปรับ A *

ดังที่ Philipp กล่าวไว้คุณควรเพิ่มค่าใช้จ่ายเมื่อทิศทางไม่เปลี่ยนแปลงเป็นเวลานาน แต่ฟังก์ชั่นโดย Philipp อาจนำไปสู่การสรุปค่าใช้จ่ายเพิ่มเติมอย่างรวดเร็วซึ่งสูงกว่าค่าใช้จ่ายสำหรับการสำรวจกระเบื้องเพิ่มเติม แต่ความคิดหลักของเขานั้นถูกต้อง!

ดูเหมือนง่ายที่จะปรับ A * เพื่อคำนวณเส้นทางที่ดีที่สุด "ทั้งหมด" (ที่มีความยาวสั้นที่สุด) จากนั้นเลือกหนึ่งในนั้นด้วยวิธีแก้ปัญหาแบบอื่น แต่มีปัญหา หากคุณมีเส้นทางยาวอาจมีทางออกมากมายที่มีความยาวพอเหมาะ สิ่งนี้ทำให้อัลกอริทึม A * ใช้เวลานานกว่าในการคำนวณโซลูชันอื่น ๆ เหล่านี้ทั้งหมดเช่นกัน นี่เป็นเพราะกริด คุณไม่สามารถเดินได้ 80 องศาแทนที่จะเป็น 90 องศาซึ่งจะนำไปสู่การแก้ปัญหาแบบไม่ต้องจ่ายเงินจำนวนมากแทนที่จะเป็นทางออกที่ดีที่สุด สำหรับจินตนาการให้จินตนาการแผนที่โดยไม่มีอุปสรรค ระยะ x คือ 2 y- ระยะทางคือ 3 ซึ่งหมายความว่าเส้นทางที่สั้นที่สุดทั้งหมดมีการเคลื่อนไหวในแนวทแยง 2 ครั้งและการเคลื่อนที่ 1 ครั้ง มีการรวมกันที่ถูกต้อง 3 แบบ: SDD, DSD, DDS (โดยที่ D = diagonal, S = straight) สำหรับเส้นทางที่เรียบง่ายนี้ "ความสนุก" ที่แท้จริงจะเริ่มขึ้นเมื่อคุณมีเส้นทางด้วยเช่น 3 เส้นตรงและแนวทแยง 2 จังหวะ: SSSDD, SSDSD, SSDDS, SDSSD, SDSDS, SDDSS, DSSSD, DSSDS, DSDSS, DDSSS (10 รูปแบบของเส้นทางที่สั้นที่สุดถ้าฉันไม่พลาด) ฉันคิดว่าคุณควรมีความคิด ...

ดังนั้นเราควรแก้ไขปัญหานี้โดยการปรับฟังก์ชั่นค่าใช้จ่ายในแบบที่โซลูชั่นที่น้อยลง (หรือแม้แต่โซลูชันเดียวเท่านั้น) จึงเป็น "ดีที่สุด"

ปรับฟังก์ชั่นต้นทุน

การปรับตัวตามที่ Philipp แนะนำไว้ในสูตรตัวอย่างของเขาจะให้ผลลัพธ์ที่ดีกว่ากับคุณมาก แต่ก็ยังมีปัญหาอยู่บ้าง มันจะไม่กระจาย "ส่วน" ที่สั้นกว่าอย่างสม่ำเสมอไปตามเส้นทางความหมาย: การเปลี่ยนทิศทางจะบ่อยขึ้นในตอนต้นของเส้นทางหรือในทางกลับกัน

นอกจากนี้เส้นทางที่มีนักแสดงที่จะ "เปลี่ยน" อย่างไม่มีที่สิ้นสุดดูเหมือนว่าจะไม่ดีเมื่อสังเกตโดยมนุษย์ เนื่องจากต้องใช้เวลา (เพื่อแสดงภาพเคลื่อนไหวรอบ) และดังนั้นจึงต้องช้าลง

วิธีแทนที่จะใช้ลอยสำหรับต้นทุนคุณสามารถใช้ "ต้นทุนรอง" หรือเกณฑ์การจัดเรียงรอง หากต้นทุนหลักเหมือนกันจะมีการใช้ต้นทุนรองเพื่อประเมินโซลูชันที่ต้องการ สิ่งนี้จะไม่ทำให้ค่าใช้จ่ายหลัก (ความยาวเส้นทางในหน่วยวัดกริด) เพิ่มขึ้นโดยไม่ตั้งใจ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.