【问题标题】:Ruby : The best way to manage a large 3d arrayRuby:管理大型 3d 数组的最佳方式
【发布时间】:2012-07-09 00:49:28
【问题描述】:

我想知道管理大型 3d 数组的最佳方法是:

x = 1000 y = 1000 z = 100

=> 100000000 个对象

每个单元格都是一个包含一定数量数据的对象。

即使所有数据都折叠起来,简单的方法也非常冗长(我第一次尝试了对象数组的数组)

class Test

    def initialize
        @name = "Test"
    end

end

qtt = 1000*1000*100
Array.new(qtt).each { |e| e = Test.new }

我在某处读到数据库对于这种情况可能是一件好事。

您对此有何看法?

我想做什么?

这个“矩阵”代表一个世界。每个元素都是一个 1mx1mx2m 的方块,可能是不同的类型(水、泥、石头……)有些方块也可能是空的。

但是用户应该能够在任何地方移除方块并改变周围的一切(如果他们后面有水,它会从洞中流过。

事实上,我想做的不是 Minecraft 成为 DwarfFortress 的一个非常小的克隆 (http://www.bay12games.com/dwarves/)

其他有趣的事情

在我的模型中,地面处于 10 级。这意味着在大多数情况下 [0,10] 是空旷的天空。 在这些图层上只能存在丘陵和部分山脉。

地下基本上是未知的,没有挖掘。所以我们不应该为未使用的块添加实例。

我们应该从一开始就在模型中添加:宝石、金子、水,它们可以存储而无需存储相邻的石头/情绪/土块。

游戏开始时,80%的立方体不需要加载到内存中。

每次我们挖掘我们都会创建新的块:我们挖掘的空块和周围的块。

我们应该索引的唯一内容是:

  • 地下河流
  • 地下湖泊
  • 熔岩河流

【问题讨论】:

  • 一切都取决于你想做什么!如果你想要一些持久性,所以是的 DB 可能是一件好事,如果你只是想做简单的工作,也许你应该把它们包装在一个班级。这个问题有点太模糊了。
  • 你能把你的问题说得更清楚吗?如果您真的需要大量数据的高性能,您需要一种不同的语言。
  • 我添加了更多关于我想做的事情的信息。
  • 你能举例说明你的方法在做什么吗?如果方法在整个矩阵上运行并触及每个单元格,那么这确实是一个大问题。但是,如果您的单元格中有许多相似的对象,并且您不需要每个对象都有自己的特定字符,那么您可以使用一些设计模式来加快速度。无论如何,对于这种大小的数据,幼稚的方法是行不通的。
  • 例如,每滴水都会腐蚀相邻的立方体,因此受影响的立方体的硬度会降低。这将在水块的所有边界上计算(不是经常,但它会)。最常见的事件是角色挖掘并移除立方体时:我必须控制周围的所有立方体。这更像是一种“级联效应”,肯定不会一次对所有董事会产生影响。

标签: ruby large-data-volumes


【解决方案1】:

在内存中保存这么多对象绝不是一件好事。以平面文件或以数据库为中心的方法会更高效且更易于维护。

我会做什么 - 面向对象的方法

将块的参数存储为简单数据并动态构造对象。

创建一个Block 类来表示游戏中的一个方块,并为其提供变量来保存该特定方块的参数:

class Block
  # location of the Block
  attr_accessor :x, :y, :z

  # an individual id for the Block
  attr_accessor :id

  # to define the block type (rock, water etc.)
  attr_accessor :block_type

  # and add any other attributes of a Block...
end

然后我将创建一些方法,使我能够将数据序列化/反序列化到文件或数据库。

正如您所说,它可以在棋盘上运行,您还需要一个 Board 类来表示它,以保持游戏状态并对 Block 对象执行操作。使用来自每个Block 的x, y, z 属性,您可以确定其在游戏中的位置。然后,您可以使用此信息在Block 类中编写一个方法,该方法定位与当前块相邻的那些块。这将使您能够执行您所说的“级联”效果,其中一个块受到另一个块的操作的影响。

高效访问数据

这将完全取决于您选择如何序列化 Block 对象。我可能会选择二进制格式来减少不必要的数据读取并通过它们的id 参数存储对象,然后使用MMIO 之类的东西快速对类似数组的大型数据文件进行随机访问读/写方式。这将允许您快速有效地访问数据,而不会产生内存开销。您如何读取数据将与上面的相邻块方法有关。

您当然也可以选择 DB 存储路径,这将允许您隔离块并以更高级别的方式对特定块进行查找,但这可能会给您带来一些额外的开销。

这听起来像是一个有趣的项目,我希望这会有所帮助! :)

P.S 关于@Linuxious 上面关于选择不同语言的评论。是的,在某些情况下这可能是正确的,但熟练的程序员从不怪罪他的工具。程序的效率取决于程序员的效率……除非你是用 Java 编写的 ;)

【讨论】:

  • 非常感谢您的出色回答 :) 我考虑了我的问题并发现了一些问题:我是否需要为所有块创建一个实例?不 !只有地面和洞穴,它应该代表最大体积的 30%...我默认放置在第 10 层的地面,所以 [0,10] 几乎是空的(只有一些山丘,可能还有部分山脉)。地下将被挖掘,但不是在所有层面上,也不是在所有表面上。这就是为什么我尝试初始化一个充满nil 并且只有几个真正的block 的多维数据集的原因,它的速度要快得多。现在我来看看你说什么。这很有趣:)
猜你喜欢
  • 2012-01-10
  • 1970-01-01
  • 2021-04-22
  • 2016-11-27
  • 2010-09-13
  • 1970-01-01
  • 2016-05-17
  • 2010-11-28
  • 1970-01-01
相关资源
最近更新 更多