ฉันจะสร้างโครงสร้างข้อมูลสำหรับ "เขาวงกต" ที่มีขนาดไม่ จำกัด ได้อย่างไร


43

ฉันไม่แน่ใจจริงๆว่า "เขาวงกต" เป็นคำที่ถูกต้อง ผู้ใช้โดยทั่วไปเริ่มต้นในซิงเกิลRoomที่มี 4 ประตู (N, S, E และ W) พวกเขาสามารถไปในทิศทางใดก็ได้และห้องถัดไปแต่ละห้องจะมีอีกห้องหนึ่งโดยมีประตูตั้งแต่ 1 ถึง 4 ประตูที่ไปยังห้องอื่น

"เขาวงกต" ควรจะมีขนาดไม่ จำกัด และเพิ่มขึ้นเมื่อคุณย้ายห้อง มีจำนวน จำกัดRoomsแต่จำนวนที่มีอยู่นั้นเป็นแบบไดนามิกและสามารถเปลี่ยนแปลงได้

ปัญหาของฉันคือฉันไม่แน่ใจว่าโครงสร้างข้อมูลที่ดีที่สุดสำหรับรูปแบบประเภทนี้

ครั้งแรกที่ฉันคิดว่าจะใช้แค่ชุดของRoomวัตถุ[X] [X] แต่ฉันค่อนข้างจะหลีกเลี่ยงเพราะสิ่งนี้ควรจะเติบโตในทุกทิศทางและควรสร้างห้องที่ "เยี่ยมชม" เท่านั้น

อีกความคิดหนึ่งคือการให้แต่ละRoomคลาสมี 4 Roomคุณสมบัติที่เชื่อมโยงสำหรับ N, S, E และ W และเพียงแค่เชื่อมโยงไปยังก่อนหน้านี้Roomแต่ปัญหาของการที่ฉันไม่รู้วิธีระบุว่าผู้ใช้เข้าห้องหรือไม่ มีห้องที่อยู่ติดกันแล้ว "สร้าง"

ตัวอย่างเช่น,

--- --- ----------
| | | |
   เริ่ม 5 4
| | | |
--- --- --- ---
--- --- ---------- --- ---
| | | | | |
| 1 2 3
| | | | | |
--- --- --- --- ----------

หากผู้ใช้ย้ายจาก Start> 1> 2> 3> 4> 5 ดังนั้นRoom# 5 จำเป็นต้องรู้ว่า W มีห้องเริ่มต้น S คือห้อง # 2 และในกรณีนี้ไม่ควรพร้อมใช้งานและ N อาจเป็น ใหม่Roomหรือกำแพง (ไม่มีอะไร)

บางทีฉันอาจต้องมีการผสมผสานของอาเรย์และห้องที่เชื่อมโยงกันหรือบางทีฉันอาจจะมองแค่นี้ผิด

มีวิธีที่ดีกว่าในการสร้างโครงสร้างข้อมูลสำหรับ "เขาวงกต" ประเภทนี้หรือไม่? หรือฉันอยู่ในแนวทางที่ถูกต้องกับกระบวนการคิดในปัจจุบันของฉันและฉันขาดข้อมูลบางอย่าง

(ในกรณีที่คุณสนใจโครงการเป็นเกมที่คล้ายกับMunchkin Quest )


ฉันไม่คิดว่าอาเรย์ใด ๆ จะใช้ได้เพราะห้องจะโตขึ้นในทุกทิศทาง ... ดังนั้นถ้าคุณเริ่มที่ [0,0] แล้วเลื่อนไปทางซ้าย? มันจะลอง [-1, 0]
พอล

@Paul ผนวกแถว / คอลัมน์เลื่อนข้อมูลอาร์เรย์ทั้งหมดทั้งหมดแล้วเลื่อนตำแหน่งผู้เล่นทั้งหมดเช่นกันเพื่อจับคู่อาร์เรย์แผนที่ใหม่ ช้าและอาจเป็นเรื่องยากขึ้นอยู่กับว่าจะต้องขยับตัวมากแค่ไหน แต่เป็นไปได้ ถึงกระนั้นคำตอบของ Bubblewrap ก็ดีกว่ามาก
Izkata

ฉันอาจจะผิด แต่สิ่งนี้จะไม่ดีกว่าใน GameDev.SE ใช่ไหม
แบบไดนามิก

1
@Dynamic คำถามนี้เป็นคำถามเกี่ยวกับโครงสร้างข้อมูล
Izkata

คำตอบ:


44

ให้แต่ละพิกัดห้อง (เริ่มจะเป็น (0,0)) และเก็บแต่ละห้องที่สร้างขึ้นในพจนานุกรม / hashmap ตามพิกัด

มันเป็นเรื่องเล็กน้อยที่จะกำหนดพิกัดที่อยู่ติดกันสำหรับแต่ละห้องซึ่งคุณสามารถใช้เพื่อตรวจสอบว่ามีห้องพักอยู่แล้ว คุณสามารถแทรกค่า Null เพื่อเป็นตัวแทนสถานที่ซึ่งได้มีการพิจารณาแล้วว่าไม่มีห้อง (หรือถ้าเป็นไปไม่ได้ฉันไม่แน่ใจว่า atm พจนานุกรมแยก / hasmap สำหรับพิกัดที่ไม่มีห้อง)


2
ทำให้วัตถุแต่ละห้องมีข้อมูลทิศตะวันออกเฉียงเหนือ - ตะวันตก - ตะวันตกไปยังวัตถุอื่นในห้องดังนั้นคุณสามารถใช้พจนานุกรม / hashmap เช่นเดียวกับทิศทางของห้องสำคัญเพื่อนำทางเขาวงกต (บางครั้งคุณต้องการค้นหาด้วยพิกัดที่แน่นอนและ บางครั้งคุณอาจต้องการทราบว่าทางเหนือของ Room object X) คืออะไร
Neil

2
@ พอลฉันคิดว่าความคิดคือการสร้างพจนานุกรมของห้องและเมื่อสร้างใหม่Roomให้มองหาห้องที่อยู่ติดกันในพจนานุกรมและเพิ่มลิงก์ไปยังRoomวัตถุก่อนเพิ่มห้องใหม่ไปยังส่วนที่เหลือ ดังนั้นครั้งเดียวที่การค้นหาพจนานุกรมจะเกิดขึ้นคือเมื่อสร้างRoomวัตถุใหม่ไม่ใช่เมื่อเดินทางระหว่างRooms
ราเชล

7
ไม่มีเหตุผลที่จะจัดเก็บลิงค์ไปยังห้องอื่น ๆ ภายในRoomวัตถุเลย หากคุณอยู่ในห้อง(x,y)และต้องการเดินทางไปทางเหนือคุณจะมองหาห้อง(x,y+1)ในพจนานุกรมและสร้างมันหากไม่มีอยู่ O(1)การค้นหาพจนานุกรมมีความรวดเร็ว
Karl Bielefeldt

3
@KarlBielefeldt: ห้อง @ (x,y+1)อาจมีอยู่ แต่ไม่สามารถนำทางได้จากการ(x,y)ไปทางเหนือ กล่าวคือที่ขอบอาจจะไม่ไปจากการ(x,y) (x,y+1)
Steven Evers

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

15

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

ฉันไม่แน่ใจว่าสิ่งที่ภาษาที่คุณกำลังใช้ แต่ดีกวดวิชา / คำอธิบายที่มีรายละเอียดการดำเนินงานสำหรับกราฟดำเนินการกับรายการถ้อยคำใน NET เป็นที่นี่


1
ไม่แน่ใจว่ากราฟเพียงพอที่จะอธิบายสิ่งนี้เนื่องจาก N / E / S / W ไม่ได้เป็นส่วนหนึ่งของแนวคิดกราฟ มีการเชื่อมต่อเท่านั้นและอาจเข้า / ออก
Edward Strange

3
@CrazyEddie: โปรดทราบว่า / a โครงสร้างข้อมูลไม่ได้มีวัตถุประสงค์เพื่อแมปโดยตรงกับโดเมนเฉพาะใด ๆ (แน่นอนว่าเป็นประโยชน์ของพวกเขา) ในตัวอย่างนี้กราฟจะเป็นทิศทางและขอบสามารถทำหมายเหตุประกอบเล็กน้อยด้วย enum
Steven Evers

บันทึกย่ออาจบังคับใช้ความสัมพันธ์ระหว่างตะวันออก - ตะวันตกและเหนือ - ใต้ได้เล็กน้อย สิ่งนี้จะขจัดปัญหาการไปทางตะวันตกจากห้อง A ไปที่ห้อง B จากนั้นไปทางตะวันออกจากห้อง B ไปที่ห้อง C (แทนที่จะเป็นห้อง A) เนื่องจากลิงก์ไม่ถูกต้อง
ปีเตอร์สมิ ธ

3
ให้บอกว่าเราต้องการใช้ห้องที่มีพ่อมดที่ปกป้องตัวเองโดยการเคลื่อนย้ายผู้เล่นสิบกำลังสองในทิศทางที่สุ่ม การหาจุดนั้นในโครงสร้างข้อมูลแบบกราฟจะมีราคาแพงมากโดยเฉพาะถ้าห้องนั้นไม่มีอยู่และคุณต้องสร้างห้องทั้งหมดที่เชื่อมโยงห้องนั้นกับห้องอื่นในกราฟ (เนื่องจากโครงสร้างจะไม่อนุญาตให้มีหลาย ๆ ส่วนที่ไม่ได้เชื่อมต่อซึ่งกันและกันของดันเจี้ยน)
Mark Booth

2
@ MarkBooth แต่แล้วเราได้เปลี่ยนข้อกำหนดใช่ไหม
Joshua Drake

9

ความคิดสองสามข้อเกี่ยวกับการนำไปใช้ (ฉันนึกถึงการ์กาซอนซึ่งมีแง่มุมที่ท้าทายอื่น ๆ อีกมากมายในการสร้างเมทริกซ์ - มันเป็นคำถามสัมภาษณ์ที่ฉันเคยถาม)

มีคำถามที่ถามเกี่ยวกับโครงสร้างนี้:

  1. มีห้องที่ X, Y ไหม
  2. มีห้อง [N / S / E / W] ของตำแหน่งว่าง X, Y หรือไม่

ปัญหาเกี่ยวกับรายการและกราฟอย่างง่าย

ความยากลำบากในการใช้รายการง่ายๆคือต้องเดินโครงสร้างเพื่อทดสอบว่าสามารถวางสิ่งของในตำแหน่งที่กำหนดได้หรือไม่ ระบบต้องการวิธีการเข้าถึงตำแหน่งโดยพลการ O (1)

พิจารณา:

1 2 3 ? 4
5 . . * 6
7 8 9 A B

เพื่อค้นหาข้อมูลตำแหน่งที่เป็นไปได้ '?' เมื่ออายุ 3 ปีต้องเดินไปรอบ ๆ เพื่อไปที่ 4 คำตอบของลิงก์พร้อมข้อมูลเพิ่มเติมเกี่ยวกับจำนวนโหนดที่กระโดด (ดังนั้น 3 จะเชื่อมโยงกับ 4 ด้วยข้อมูลเพิ่มเติม 'jump 1') ยังคงต้องเดินเมื่อค้นหา adjacency ของ '*' จาก 6 หรือ A

ง่ายใหญ่อาร์เรย์

มีจำนวนห้องพัก จำกัด

หากนี่ไม่ใช่ตัวเลขขนาดใหญ่เพียงแค่สร้างอาร์เรย์ 2N x 2N แล้วปล่อยไว้ที่นั่น อาร์เรย์ 100 x 100 เป็น 'พอยน์เตอร์' 10,000 ตัวและวัตถุ 50 รายการเท่านั้น ดัชนีลงในอาร์เรย์โดยตรง

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

อาร์เรย์กระจัดกระจายและเมทริกซ์

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

วิธีที่ฉันชอบคือให้ห้องเป็นโครงสร้าง (ตัวชี้ไปยังห้องที่อยู่ติดกันและพิกัด) และให้ห้องมีตัวชี้จากตารางแฮชซึ่งถูกแฮชบนพิกัด ในสถานการณ์นี้เพื่อถามว่าห้องใด [N / S / E / W] จากห้องว่างใครจะสอบถามตารางแฮช นี่คือรูปแบบ 'DOK' โดยบังเอิญสำหรับการจัดเก็บเมทริกซ์ที่กระจัดกระจาย


1
คำตอบที่ดีอย่างBubblewrapชี้ให้เห็นว่าพจนานุกรมที่มีอันดับอันดับเป็นกุญแจสำคัญคือโครงสร้างที่เหมาะสมในการใช้งานเมทริกซ์ที่กระจัดกระจาย
Mark Booth

2

แล้วเรื่องนี้ ..

ให้ลิงก์แต่ละเซลล์กับเพื่อนบ้านแต่ละคน ตั้งชื่อให้กับแต่ละเซลล์ (เช่น "0/0", "-10/0" (สมมติว่าคุณเริ่มต้นที่ 0,0)) เพิ่ม HashSet พร้อมชื่อทั้งหมดในนั้น ในขณะที่คุณพยายามย้ายไปยังเซลล์อื่นเพียงตรวจสอบว่าเพื่อนบ้านไม่มีอยู่ใน HashSet

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

   Empty   
   (0,1)        

---    ---            ----------
|        |            |        |
    0,0       1,0        2,0       Empty
|        |            |        |   (3,0)
---    --- ---------- ---    ---
|        | |        | |        |
|   0,-1      1,-1       2,-1      Empty
|        | |        | |        |   (3,-1)
---    --- ---    --- ----------

   Empty     Empty   
  (0,-2)    (1,-2)

HashSet = {0 | 0, 1 | 0, 2 | 0, 3 | 0, 0 | -1, 1 | -1 .... .... 1,0: W = 0,0 / ประตู; 1,0: N = 1,1 / ว่างเปล่า E = 2,0 / ประตู; S = 1, -1 / กำแพง

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


1

สิ่งที่คุณกำลังออกแบบฟังดูคล้ายกับกราฟ

กราฟของเขาวงกต

เหล่านี้มักจะแสดงเป็นชุดของรัฐQเป็นสถานะเริ่มต้นQ 0Qและการเปลี่ยนบางΔ ดังนั้นฉันขอแนะนำให้คุณเก็บมันไว้เช่นนี้

  • ชุดQ : {s, 1, 2, 3, 5, 6}
  • สถานะเริ่มต้นq 0 : s
  • แผนที่ของการเปลี่ยนแปลงความสัมพันธ์Δ : {s → 1, s → 5, 1 → 2, 2 → 3, 3 → 4, 4 → 5}

ภาษาที่เหมาะสมส่วนใหญ่มีทั้งแผนที่และชุด


0

คุณสามารถพิจารณารายการที่เชื่อมโยง 4 ทิศทาง ...

ฉันแรกคิดเกี่ยวกับการใช้ [X] [X] อาร์เรย์ของวัตถุในห้องเท่านั้น แต่ฉันค่อนข้างจะหลีกเลี่ยงเพราะสิ่งนั้นควรจะเติบโตในทุกทิศทางและควรสร้างห้องที่ "เยี่ยมชม" เท่านั้น

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

คุณสามารถสร้างห้องที่เยี่ยมชมเท่านั้นโดยใช้การประเมินผลที่ขี้เกียจ วัตถุสามารถอยู่ในสถานที่ที่มีห้องและไม่สร้างห้องนั้นจนกว่าroom()จะมีการเรียกใช้ จากนั้นมันจะส่งคืนค่าเดิมทุกครั้งหลังจากนั้น ไม่ยากที่จะทำ


1
คุณสามารถขยายความหมายของรายการ 4 ลิงก์ที่เชื่อมโยงกันได้ไหม? สิ่งเดียวที่ฉันสามารถค้นหาได้คือบทความ CodeProject ซึ่งเริ่มต้นด้วยการเป็นรายการ adjacency
Steven Evers

0

ฉันเรียนรู้ที่จะทำสิ่งนี้ผ่านหนังสือ "การสร้างเกมผจญภัยบนคอมพิวเตอร์ของคุณ" หากคุณยินดีที่จะขุดรหัส BASIC (หนังสือเก่าแก่) ไปอ่านที่นี่:

http://www.atariarchives.org/adventure/chapter1.php

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

room {
 int north_dir;
 int south_dir;
 int west_dir;
 int east_dir;
 // All other variables and code you care about being attached to the rooms here
}

จากนั้นคุณอาจมีอาร์เรย์หรือโครงสร้างรายการเชื่อมโยงหรืออื่น ๆ ที่คุณต้องการจัดการห้องของคุณ สำหรับ array-style (หรือ C ++ vectors) ฉันจะใช้รหัสนั้นและทิศทางจะเก็บดัชนีของห้องที่พวกเขาเชื่อมโยงไป สำหรับรายการที่เชื่อมโยงคุณสามารถใช้ตัวชี้ไปยังห้องถัดไป

อย่างที่คนอื่นพูดถ้าคุณต้องการสร้างห้องใหม่เมื่อมีคนเข้ามาคุณก็สามารถทำเช่นนั้นได้


0

อย่าพยายามแก้ไขปัญหาทั้งหมดด้วยโครงสร้างเดียว

กำหนดวัตถุในห้องของคุณเพื่อเก็บสิ่งต่าง ๆ เกี่ยวกับห้องไม่ใช่ความสัมพันธ์กับห้องอื่น จากนั้นอาร์เรย์ 1D รายการ ฯลฯ สามารถเติบโตได้ตามที่คุณต้องการ

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

หลีกเลี่ยงการปรับให้เหมาะสมก่อน ใช้โครงสร้างที่เรียบง่ายจริง ๆ และเป็นอัลกอริธึมที่เข้าใจได้ง่าย ๆ

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