2011-05-24 64 views
3

我正在爲小型遊戲編寫一個地下城發電機。地下室由房間組成。 A roomconnections到其他房間。紅寶石和指針

room.connections = [room_a, room_b]

​​

現在我需要選擇一個房間由它的編號。

我這樣做是先用recursive_scan方法,沒有工作,因爲房間可導致成圈,這將引發StackOverflowError。所以我把一個名爲already_scanned的數組與房間號碼相關聯,這些數字已經被選入了方法的參數中。然後,它沒有掃描所有的房間 - 順便說一句,我不知道爲什麼,根據我的邏輯不可靠性,它應該起作用。

然後我試着把所有的房間都放在一個數組中,然後爲想要的房間迭代數組 - 但是在這裏我得到了這個問題,每個房間基本上都與其他房間相連,至少與其他房間相連;所以這個數組大到dungeon_size * array_of_rooms.length

我現在需要的是一個明確的指針 - 我知道幾乎每紅寶石var爲指針,除了Fixnums和float(以及可能其他一些)。儘管數組變大了,所以我需要一個真正的指針。 (我也嘗試設置一個object_id的數組,並通過ObectSpace加載它們,但令人傷心的是 - 因爲我經常需要加載房間 - 具有想要的object_id的房間已經被回收了,然後如錯誤信息所解釋的那樣)。

這是我的遞歸掃描方法:

def room(number) 
    recursive_scan(@map, number, []) # @map is the entrance room 
end 

private 

def recursive_scan(room, number, scanned) 
    scanned << room.room_number 
    if room.room_number == number 
    room 
    else 
    r = nil 
    room.connections.each do |next_room| 
     if !scanned.include?(next_room.room_number) 
     r = recursive_scan(next_room, number, scanned) 
     end 
    end 
    r 
    end 
end 
+0

不,你沒有。期。 – delnan 2011-05-24 20:33:18

+1

從你描述'recursive_scan'和'already_scanned'應該可以工作,我在不久前使用了與邊緣尋找算法完全相同的方法。也許發佈你的代碼,我們會看看它是否可以修復。 – 2011-05-24 20:41:45

回答

6

Ruby中的所有內容都已經是一個參考。

爲什麼不只是維持房間指數?

rooms[room.number] = room 

然後你可以用rooms[i]得到任何東西。我只需修改初始化房間的方法,即可逐步保持索引的最新狀態。因爲陣列只是一個索引

def initialize 
    rooms[self.number] = self 
    . . . 
end 

這不會佔用太多的空間,實際上它並不具備客房副本。從數組獲得的每個引用與通過程序中的任何其他機制獲得的引用基本上是相同的,並且引用和經典指針之間的唯一真正區別是垃圾收集的一點開銷。

如果房間都被徹底刪除,您將要設置的rooms[x] = nil上刪除時(不只是退出前等)。

我不明白爲什麼你需要先創建數據結構然後爲房間建立索引,但是FWIW你應該可以做這個遞歸枚舉並且使用房間索引數組中的房間存在性作爲這裏旗。我不確定爲什麼它以前沒有工作,但是如果仔細寫的話,它真的需要。

+0

我應該補充一點,您可能希望將「房間」索引設置爲「房間」的*類變量*。所以:'@@ rooms [self.number] = self' – DigitalRoss 2011-05-24 20:59:35

+0

我已經完成了這個解決方案,但是因爲我需要轉換房間'.to_yaml',所以我得到的數組不是隻有引用,而是大小是'all_rooms * array.length'。 – 2011-05-25 15:18:14

+0

好吧我現在意識到這個解決方案,至少它正在工作...... – 2011-05-25 15:36:55

0

你可能想看看NArray gem,這將加快利用數字陣列。採用這種方法,您可能試圖在這裏強制使用方形掛釘進入圓孔。

+0

如果您需要加速線性搜索,只需將其轉換爲O(1)操作;) – delnan 2011-05-24 20:34:55

3

這是一個經典的圖形問題。使用圖庫將處理大多數這些問題。嘗試使用rgl寶石。

將每個房間定義爲圖中的頂點。連接將是邊緣。

require "rgl/adjacency" 

map = RGL::AdjacencyGraph.new 
rooms.each {|room| map.add_vertex room} 
rooms.connections.each {|room1, room2| map.add_edge room1, room2} 

現在可以測試兩個房間是否直接連接在O(1):

map.has_edge? room1, room2 

或者獲得的所有房間列表:

map.vertices 

你也可以得到所有相鄰房間的列表:

map.adjacent_vertices(room) 
1

一個真正的hackish方式來獲得內存中的所有房間將是:

all_rooms = ObjectSpace.each_object(Room).to_a