2011-05-24 66 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