Bagaimana saya harus membangun struktur data untuk "labirin" yang dinamis dan tidak terbatas?

43

Saya sebenarnya tidak yakin bahwa "maze" adalah istilah yang benar. Pada dasarnya pengguna mulai dalam satu Roomyang memiliki 4 pintu (N, S, E, dan W). Mereka dapat pergi ke segala arah, dan setiap kamar berikutnya berisi ruangan lain dengan 1 hingga 4 pintu masuk yang menuju ke kamar lain.

"Labirin" seharusnya berukuran tidak terbatas, dan tumbuh saat Anda memindahkan kamar. Ada jumlah terbatas yang Roomstersedia, namun jumlah yang tersedia adalah dinamis dan dapat berubah.

Masalah saya adalah, saya tidak yakin dengan struktur data terbaik untuk jenis pola ini

Saya pertama kali berpikir tentang hanya menggunakan array [X] [X] Roomobjek, tapi saya lebih suka menghindari hal itu karena benda itu seharusnya tumbuh ke segala arah, dan hanya kamar yang "dikunjungi" yang harus dibangun.

Pikiran lain adalah membuat setiap Roomkelas berisi 4 Roomproperti yang ditautkan untuk N, S, E, dan W, dan hanya tautan ke sebelumnya Room, tetapi masalah dengan itu saya tidak tahu bagaimana mengidentifikasi apakah pengguna masuk ke ruangan yang memiliki kamar yang berdekatan sudah "dibangun"

Sebagai contoh,

--- --- ----------
| | | |
   Mulai 5 4
| | | |
--- --- --- ---
--- --- ---------- --- ---
| | | | | |
| 1 2 3
| | | | | |
--- --- --- --- ----------

Jika pengguna berpindah dari Mulai> 1> 2> 3> 4> 5, maka Room# 5 perlu tahu bahwa W berisi ruang awal, S adalah ruang # 2 dan dalam hal ini seharusnya tidak tersedia, dan N dapat berupa baru Roomatau tembok (tidak ada).

Mungkin saya perlu campuran array dan kamar terkait, atau mungkin saya hanya melihat ini dengan cara yang salah.

Apakah ada cara yang lebih baik untuk membangun struktur data untuk jenis "labirin" ini? Atau apakah saya berada di jalur yang benar dengan proses pemikiran saya saat ini, dan saya hanya kehilangan beberapa informasi?

(Jika Anda tertarik, proyek ini adalah game yang sangat mirip dengan Munchkin Quest )

Rachel
sumber
Saya tidak berpikir array apa pun akan bekerja karena kamar akan tumbuh ke segala arah ... Jadi jika Anda mulai dari [0,0] dan bergerak ke kiri? itu akan mencoba [-1, 0].
Paul
@Paul Tambahkan baris / kolom, geser semua data array, lalu geser semua posisi pemain juga agar cocok dengan array peta baru. Lambat dan bisa sulit tergantung pada seberapa banyak yang harus digeser, tetapi mungkin. Meski begitu, jawaban Bubblewrap jauh lebih baik.
Izkata
Saya mungkin salah, tetapi bukankah ini lebih baik di GameDev.SE?
Dinamis
1
@ Dinamis Ini adalah pertanyaan struktur data, jadi cocok di sini.
Izkata

Jawaban:

44

Berikan setiap Koordinat Kamar (mulai akan (0,0)) dan simpan setiap Kamar yang dihasilkan dalam kamus / peta hash oleh koordinat.

Itu sepele untuk menentukan koordinat yang berdekatan untuk setiap Kamar, yang dapat Anda gunakan untuk memeriksa apakah Kamar sudah ada. Anda dapat memasukkan nilai nol untuk mewakili lokasi yang sudah ditentukan bahwa tidak ada Kamar. (atau jika itu tidak mungkin, saya tidak yakin atm, kamus terpisah / peta untuk koordinat yang tidak mengandung Kamar)

Plastik gelembung
sumber
2
Jadikan setiap objek Kamar berisi informasi utara-timur-barat daya ke objek Kamar lainnya, sehingga Anda dapat menggunakan kamus / hashmap serta arah mata angin Kamar untuk menavigasi labirin (kadang-kadang Anda ingin menemukan dengan koordinat absolut dan kadang-kadang Anda ingin tahu apa yang utara dari objek Room X).
Neil
2
@ Paul Saya pikir idenya adalah untuk membuat kamus kamar, dan ketika membangun yang baru Room, mencari kamar yang berdekatan di kamus dan menambahkan tautan mereka ke Roomobjek sebelum menambahkan kamar baru ke sisi yang tersisa. Jadi satu-satunya waktu pencarian kamus akan terjadi adalah ketika membuat Roomobjek baru , bukan saat bepergian di antaraRooms
Rachel
7
Tidak ada alasan untuk menyimpan tautan ke kamar lain di dalam Roomobjek sama sekali. Jika Anda berada di kamar (x,y)dan ingin bepergian ke Utara, Anda mencari kamar (x,y+1)di kamus, membuatnya jika tidak ada. Pencarian kamus sangat cepat O(1),.
Karl Bielefeldt
3
@KarlBielefeldt: Kamar @ (x,y+1)mungkin ada, tetapi tidak dapat dilalui untuk (x,y)pergi ke Utara. Dengan kata lain, bahwa keunggulan mungkin tidak langsung dari (x,y)ke (x,y+1).
Steven Evers
2
Kalian membuat ini rumit. Ini pada dasarnya sama dengan array .. kecuali Anda mencarinya di kamus daripada array dua dimensi. Setiap masalah yang Anda temui dengan array juga akan ada di sana ... tapi dia tetap akan menggunakan array.
user606723
15

Dalam kebanyakan kasus, apa yang Anda gambarkan terdengar seperti grafik. Mengingat beberapa persyaratan Anda (aspek yang berkembang), saya mungkin akan memilih daftar adjacency sebagai implementasinya (opsi umum lainnya adalah matriks adjacency ).

Saya tidak yakin bahasa apa yang Anda gunakan, tetapi tutorial / penjelasan yang bagus dengan detail implementasi untuk grafik yang diimplementasikan dengan daftar adjacency di .NET ada di sini .

Steven Evers
sumber
1
Tidak yakin grafik cukup untuk menggambarkan ini karena N / E / S / W tidak benar-benar bagian dari konsep grafik; hanya ada yang terhubung dan mungkin masuk / keluar.
Edward Strange
3
@CrazyEddie: Perlu diingat bahwa / a struktur data tidak dimaksudkan untuk memetakan langsung ke domain tertentu (memang, itulah manfaatnya). Dalam contoh khusus ini, grafik akan menjadi terarah dan ujung-ujungnya dapat dijelaskan dengan sepele dengan enum.
Steven Evers
Anotasi itu secara sepele dapat menegakkan hubungan timur-barat, utara-selatan. Ini akan menghilangkan masalah pergi ke barat dari kamar A ke kamar B dan kemudian pergi ke timur dari kamar B ke kamar C (bukan kamar A) karena hubungan yang buruk.
Peter Smith
3
Mari kita katakan bahwa kita ingin menerapkan ruangan yang dihuni oleh penyihir yang melindungi dirinya dengan memindahkan sepuluh kotak pemain secara acak. Menemukan titik itu dalam struktur data berbasis grafik akan sangat mahal, terutama jika ruangan itu tidak ada dan Anda harus membuat semua kamar yang menghubungkan ruangan itu ke ruangan lain dalam grafik (karena struktur tidak akan memungkinkan banyak, bagian ruang bawah tanah yang saling terputus).
Mark Booth
2
@MarkBooth tapi kemudian kami telah mengubah persyaratan, bukan?
Joshua Drake
9

Beberapa pemikiran tentang implementasi (saya sudah memikirkan Carcassonne yang memiliki sejumlah aspek menantang lainnya untuk membangun matriks - itu bahkan pertanyaan wawancara yang pernah saya tanyakan).

Ada beberapa pertanyaan yang diajukan dari struktur ini:

  1. apakah ada kamar di X, Y?
  2. apakah ada kamar [N / S / E / W] dari lokasi kosong X, Y?

Masalah dengan daftar dan grafik sederhana

Kesulitan dengan daftar sederhana adalah bahwa seseorang harus berjalan struktur untuk menguji apakah sesuatu dapat ditempatkan di lokasi tertentu. Sistem membutuhkan cara untuk mengakses lokasi sewenang-wenang O (1).

Mempertimbangkan:

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

Untuk menemukan informasi lokasi yang mungkin '?', Ketika pada usia 3, seseorang harus berjalan jauh-jauh untuk sampai ke 4. Jawaban tautan dengan informasi tambahan tentang berapa banyak node yang dilompati (sehingga 3 akan dihubungkan ke 4 dengan info tambahan 'jump 1') masih memerlukan jalan kaki ketika menemukan kedekatan '*' dari 6 atau A.

Sederhana, besar, array

Ada sejumlah kamar yang tersedia

Jika ini bukan jumlah yang besar, buat saja array 2N x 2N dan tinggalkan di sana. Array 100 x 100 adalah 'hanya' 10.000 pointer dan 50 objek. Indeks langsung ke array.

Ini dapat dikurangi menjadi hanya NxN jika kegiatan di luar batas menggeser array sekitar untuk selalu berada dalam batasan. Misalnya, jika sebuah ruangan akan ditambahkan yang akan mengurangi array, minta grid untuk menggeser setiap elemen satu posisi sehingga tidak akan ada underflow lagi. Pada titik ini, ukuran dunia untuk 50 kamar akan menjadi 2.500 pointer dan 50 objek.

Array dan matriks yang jarang

Untuk membuat ini lebih optimal, lihat ke array jarang di mana sebagian besar elemen adalah 0 atau nol. Untuk dua dimensi, ini dikenal sebagai matriks jarang . Banyak bahasa pemrograman memiliki berbagai pustaka untuk bekerja dengan struktur ini. Jika perpustakaan membatasi ke bilangan bulat, orang bisa menggunakan bilangan bulat ini sebagai indeks ke dalam array kamar tetap.

Pendekatan pilihan saya adalah memiliki kamar sebagai struktur (pointer ke kamar yang berdekatan, dan koordinat) dan memiliki kamar juga pointer dari tabel hash yang di hash pada koordinat. Dalam situasi ini untuk menanyakan kamar apa [N / S / E / W] dari kamar nol, orang akan meminta tabel hash. Ini, kebetulan, adalah format 'DOK' untuk menyimpan matriks jarang.

Komunitas
sumber
1
Jawaban yang bagus, seperti yang disarankan Bubblewrap , kamus dengan posisi tuple sebagai kunci adalah struktur yang masuk akal untuk digunakan untuk mengimplementasikan matriks jarang.
Mark Booth
2

Bagaimana dengan ini..

Berikan setiap sel tautan ke masing-masing tetangganya. Beri setiap sel semacam nama (yaitu "0/0", "-10/0" (Asumsikan Anda mulai dari 0,0)). Tambahkan HashSet dengan semua nama di dalamnya. Saat Anda mencoba untuk pindah ke sel lain, cukup periksa bahwa tetangga belum ada di HashSet.

Juga, jika Anda membuat celah ke kamar lain, apakah itu menyiratkan bahwa kamar itu ada? Jadi, Anda akan membuat tautan ke kamar kosong tanpa tautan ke kamar apa pun. Anda mungkin juga ingin memeriksa tetangga kamar baru. Jika ada, dan akan terbuka ke kamar baru Anda, tambahkan pintu ke kamar itu.

   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 | 0, 1 | -1 ....} 1.0: W = 0,0 / Pintu; 1,0: N = 1,1 / Kosong; E = 2,0 / Pintu; S = 1, -1 / Dinding

Anda juga harus memastikan bahwa Anda memberikan setiap kamar baru setidaknya satu pintu (ke ruangan lain) yang tidak berdekatan sehingga labirin dapat tumbuh ke arah itu.

Paul
sumber
1

Apa yang Anda rancang terdengar sangat mirip grafik.

Grafik labirin

Ini sering direpresentasikan sebagai seperangkat keadaan Q , keadaan awal q 0Q , dan beberapa transisi Δ . Jadi, saya sarankan Anda menyimpannya seperti ini.

  • Kumpulan Q : {s, 1, 2, 3, 5, 6}
  • Keadaan awal q 0 : s
  • Peta hubungan transisi Δ : {s → 1, s → 5, 1 → 2, 2 → 3, 3 → 4, 4 → 5}

Sebagian besar bahasa yang masuk akal memiliki peta dan set.

kba
sumber
0

Anda dapat mempertimbangkan daftar tertaut 4 arah ...

Saya pertama kali berpikir tentang hanya menggunakan array [X] [X] objek Kamar, tapi saya lebih baik menghindari itu karena benda itu seharusnya tumbuh ke segala arah, dan hanya kamar yang "dikunjungi" yang harus dibangun.

Anda masih dapat menggunakan [] [] untuk itu. Pertumbuhan dinamis mungkin lambat, terutama saat menambahkan di awal, tapi mungkin tidak terlalu buruk. Anda harus profil untuk memeriksa. Mencoba memanipulasi beberapa daftar atau peta yang terhubung mungkin sebenarnya lebih buruk, dan pada tingkat yang konstan daripada sesekali.

Anda hanya dapat membangun kamar yang dikunjungi dengan menerapkan evaluasi malas. Objek dapat berada di tempat yang berisi ruangan, dan tidak membangun ruangan itu sampai room()dipanggil. Maka itu hanya mengembalikan yang sama setiap kali setelah itu. Tidak sulit untuk dilakukan.

Edward Strange
sumber
1
Bisakah Anda memperluas apa yang Anda maksud dengan "daftar yang terhubung 4 arah"? Satu-satunya hal yang bisa saya temukan adalah artikel CodeProject, yang akhirnya menjadi daftar adjacency.
Steven Evers
0

Saya belajar melakukan ini melalui buku "Membuat Game Petualangan Di Komputer Anda". Jika Anda ingin menggali melalui kode BASIC (buku itu setua itu) baca di sini:

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

Untuk pintasan, yang mereka lakukan adalah memiliki array kamar, dengan elemen di setiap array menjadi pointer ke ruangan lain yang bisa Anda kunjungi, dengan 0 (saya akan menggunakan -1 hari ini) untuk menunjukkan bahwa Anda tidak bisa pergi ke sana. Misalnya, Anda akan membuat struktur ruang (atau kelas atau apa pun)

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
}

Maka Anda bisa memiliki susunan atau struktur daftar tertaut atau bagaimana pun Anda ingin mengelola kamar Anda. Untuk array-style (atau vektor C ++) saya akan menggunakan kode itu dan arah akan menahan indeks ruangan yang mereka tautkan; untuk daftar tertaut, Anda bisa menggunakan pointer ke kamar sebelah.

Seperti yang dikatakan orang lain, jika Anda perlu secara dinamis menghasilkan kamar baru ketika orang memasukinya, Anda juga bisa melakukannya.

tertawa
sumber
0

Jangan mencoba dan menyelesaikan semua masalah dengan satu struktur.

Tentukan objek kamar Anda untuk menyimpan sesuatu tentang ruangan, bukan hubungannya dengan kamar lain. Kemudian array 1D, daftar dll dapat tumbuh sesuka Anda.

Struktur terpisah dapat menampung "reachability" - ruangan mana yang dapat diakses dari ruangan tempat saya berada. Kemudian putuskan apakah jangkauan transitif perlu perhitungan cepat atau tidak. Anda mungkin ingin perhitungan brute force dan cache.

Hindari pengoptimalan awal. Gunakan struktur yang sangat sederhana dan algoritma yang mudah dipahami bodoh kemudian optimalkan yang digunakan.

Julian
sumber