红宝石和指针
Posted
技术标签:
【中文标题】红宝石和指针【英文标题】:Ruby and pointers 【发布时间】:2011-05-24 20:23:59 【问题描述】:我正在为一个小游戏编写地牢生成器。
地牢由房间组成。一个room
有connections
到其他房间。
room.connections = [room_a, room_b]
和room.number = 1 # unique id
现在我需要按房间号选择房间。
我首先使用recursive_scan
方法执行此操作,但该方法不起作用,因为房间可能会导致循环,这会引发 ***Error。所以我放置了一个名为already_scanned
的数组,其中包含房间号,这些房间号已经被选入方法的参数中。然后它没有扫描所有房间 - 顺便说一句,我不知道为什么,按照我的逻辑理解它应该有效。
然后我尝试将所有房间也放入一个数组中,然后为想要的房间迭代数组 - 但在这里我遇到了问题,每个房间基本上都与其他房间相连,至少在它之间还有一些其他房间;所以数组变得和dungeon_size * array_of_rooms.length
一样大。
我现在需要的是一个显式指针——我知道几乎所有 ruby 中的 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
【问题讨论】:
从你描述的recursive_scan
和already_scanned
应该可以工作,不久前我对边缘查找算法使用了完全相同的方法。也许发布您的代码,我们会看看它是否可以修复。
【参考方案1】:
Ruby 中的一切都已经是一个引用。
为什么不只维护一个房间索引?
rooms[room.number] = room
然后你可以通过rooms[i]
得到任何东西。我会通过简单地修改 Room 的 initialize 方法来逐步更新索引。
def initialize
rooms[self.number] = self
. . .
end
这不会占用太多空间,因为数组只是一个索引,它实际上并没有房间的副本。从数组中获得的每个引用本质上与通过程序中的任何其他机制获得的引用相同,引用和经典指针之间唯一真正的区别是垃圾收集的一些开销。
如果房间曾经被删除(除了在退出之前),您需要在删除时设置rooms[x] = nil
。
我不明白为什么你需要先创建数据结构然后索引房间,但是 FWIW 你应该能够进行递归枚举并将房间索引数组中的房间作为一直在这里的标志.我不知道为什么它以前不起作用,但如果仔细编写它确实必须这样做。
【讨论】:
我应该补充一点,您可能希望将rooms
索引设为Room
的类变量。所以:@@rooms[self.number] = self
我已经完成了这个解决方案,但是因为我需要转换房间 .to_yaml
,所以我得到的数组不仅仅是引用,而是大小为 all_rooms * array.length
。【参考方案2】:
这是一个经典的图问题。使用图形库将处理大部分这些问题。尝试使用rgl
gem。
将每个房间定义为图中的一个顶点。连接将是边缘。
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)
【讨论】:
【参考方案3】:真正的hackish 让所有房间都在内存中的方法是:
all_rooms = ObjectSpace.each_object(Room).to_a
【讨论】:
【参考方案4】:您可能想查看NArray gem,它可以使用数字数组加快速度。您可能会尝试使用这种方法将方形钉子强制插入圆孔中。
【讨论】:
如果你需要加快线性搜索,只需将其转换为 O(1) 操作即可;)以上是关于红宝石和指针的主要内容,如果未能解决你的问题,请参考以下文章