I would like to know what is the best way to manage a large 3d array with something like :
x = 1000
y = 1000
z = 100
=> 100000000 objects
And each cell is an object with some amount of data.
Simple methods are very loooooong even if all data are collapsed (I a first tryed an array of array of array of objects)
class Test
def initialize
#name = "Test"
end
end
qtt = 1000*1000*100
Array.new(qtt).each { |e| e = Test.new }
I read somewhere that DB could be a good thing for such cases.
What do you think about this ?
What am I trying to do ?
This "matrix" represents a world. And each element is a 1mx1mx2m block who could be a different kind (water, mud, stone, ...) Some block could be empty too.
But the user should be able to remove blocks everywhere and change everything around (if they where water behind, it will flow through the hole for exemple.
In fact what I wish to do is not Minecraft be a really small clone of DwarfFortress (http://www.bay12games.com/dwarves/)
Other interesting things
In my model the groud is at level 10. It means that [0,10] is empty sky in most of cases.
Only hills and parts of mountains could be present on those layers.
Underground is basicaly unknown and not dug. So we should not have to add instances for unused blocks.
What we should add from the beginning to the model : gems, gold, water who could stored without having to store the adjacent stone/mood/earth blocks.
At the beginning of the game, 80% of the cube doesn't need to be loaded in memory.
Each time we dig we create new blocks : the empty block we dug and the blocks around.
The only things we should index is :
underground rivers
underground lakes
lava rivers
Holding that many objects in memory is never a good thing. A flat-file or database-centric approach would be a lot more efficient and easier to maintain.
What I would do - The object-oriented approach
Store the parameters of the blocks as simple data and construct the objects dynamically.
Create a Block class to represent a block in the game, and give it variables to hold the parameters of that particular 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
I'd then create a few methods that would enable me to serialise/de-serialise the data to a file or database.
As you've stated it works on a board, you'd also need a Board class to represent it that would maintain the state of the game as well as perform actions on the Block objects. Using the x, y, z attributes from each Block you can determine its location within the game. Using this information you can then write a method in the Block class that locates those blocks adjacent to the current one. This would enable you to perform the "cascading" effects you talk about where one Block is affected by actions on another.
Accessing the data efficiently
This will rely entirely on how you choose to serialise the Block objects. I would probably choose a binary format to reduce unnecessary data reads and store the objects via their id parameter, and then use something like MMIO to quickly do random-access reads/writes on a large data file in an Array-like manner. This will allow you to access the data quickly and efficiently, without the memory overhead. How you read the data will relate to your adjacent blocks method above.
You can of course also choose the DB storage route which will allow you to isolate the Blocks and do lookups on particular blocks in a higher-level manner, however that might give you a bit of extra overhead.
It sounds like an interesting project, I hope this helps a bit! :)
P.S With regards to the comment above by #Linuxious about choosing a different language. Yes this might be true in some cases, but a skilled programmer never blames his tools. A program is only as efficient as the programmer makes it...unless you're writing it in Java ;)
Related
I am working on a basic engine to draw sprites on screen and I wanted to implement a frame - rate method that works as such:
I have a background image stored in a 2D array (that never changes, if I need a different background I need to load a new image) that gets copied every time a new frame has to be made;
all sprites are contained in a list contained in a list ordered in ascending z order. I am yet unsure wether to tap into multithreading or not as far as blitting is concerned. This list is mutable, so if a sprite is inserted , it's locked and sorted after insertion;
the sprites are blitted on the 2D array mentioned in point 1 and after that it's displayed on screen.
The question I have is , if I want to bump the framerate up , will this cause an out of memory exception/error of some sort? Basically , will this eat all my memory before the language has enough time to free any? I know this is the case for some applications in Java that have to deal with many small instances being created, where the program can just crash (at least , it happened to me on a few instances). Is there a better way or is this good enough?
For clarification, my console / raster will never be wider or longer than a few hundred units, so say abot 100 * 80 is probably as big as it gets. Finally , my pixel class takes up 24 bytes (1 character , 1 background color , 1 foreground color).
In general, the garbage collector should be good enough to collect unused objects on the fly. It is hard to give any specific comment about how efficient this will be for your purposes - I think you just have to write a prototype to test the performance and see if that is good enough for you.
One important thing is that F# (and .NET) support "value types" (structs) which are not going to be allocated as individual objects on the heap. When you create a (2D) array of value types, it will be just a single continuous block of memory (rather than 1+80,000 separate object instances).
To define a value type, you can use the Struct attribute:
open System.Drawing
[<Struct>]
type Pixel(c:char, bg:Color, fg:Color) =
member x.Char = c
member x.Background = bg
member x.Foreground = fg
let a2d =
Array2D.init 100 80 (fun i j ->
Pixel('a', Color.Red, Color.Black))
Is it possible to have a class method that prints the name of the variable its parent class is assigned to? Example:
class Test
def who_am_I_assigned_to
puts "#{??}"
end
end
THIS = Test.new
THIS.who_am_I_assigned_to
# >> THIS
Technically yes, sort of.
But you'd have to recursively search through all the instance_variables of every object. And, as Cary points out, an object can be assigned to more than one variable at a time.
Don't do that.
The reason I was looking for this behavior was to use the variable name but also as a position within a grid of data. So if had a 2 dimensional Grid the variable names would be like "AA", "AB", "BC", etc. It is knew its name it would also know its position.
What you're describing is an "action at a distance" anti-pattern where changes to one part of a program change another part of a program with no obvious connection. This violates encapsulation; good encapsulation allows you to understand a single piece of a system by just looking at its inputs and outputs. Violating encapsulation means in order to understand one part of the system you have to understand every part of the system leading to a maintenance nightmare. Modern languages and practices strive to avoid this as much as possible.
For example, a variable's name should never matter to the behavior of the program. You should be able to safely perform a Rename Variable refactoring to name a variable according to what makes sense to the user of the object. In your example this would alter the behavior of the program violating the Principle of Least Astonishment.
Instead you'd have an object to represent your Grid and this would manage the relationships between Nodes in the Grid. Rather than passing around individual Nodes you'd pass around the Grid.
Or each Node can know who their neighboring Nodes are. An example of this would be a traditional Tree, Graph, or Linked List structure. The advantage here is there is no fixed position and the data structure can grow or shrink in any direction. Any Node can be passed around and it knows its position within the structure.
I'm trying to create a game, which I want to always run the same given the same seed. That means that random events - be them what they may - will always be the same for two players using the same seed.
However, given the user's ability to save and load the game, Ruby's Random would reset every time the save loaded, making the whole principle void if two players save and load at different points.
The only solution I have imagined for this is, whenever a save file is loaded, to generate the same number of points as before, and thus getting Ruby's Random to the same state as it was before load. However, to do that I'd need to extend it so a counter is updated every time a random number is generated.
Does anyone know how to do that or has a better way to restore the state of Ruby's Random?
PS: I cannot use an instance of Random (Random.new) and Marshall it. I have to use Ruby's default.
Sounds like Marshal.dump/Marshal.load may be exactly what you want. The Random class documentation explicitly states "Random objects can be marshaled, allowing sequences to be saved and resumed."
You may still have problems with synchronization across games, since different user-based decisions can take you through different logic paths and thus use the sequence of random numbers in entirely different ways.
I'd suggest maybe saving the 'current' data to a file when the user decides to save (or when the program closes) depending on what you prefer.
This can be done using the File class in ruby.
This would mean you'd need to keep track of turns and pass that along with the save data. Or you could loop through the data in the file and find out how many turns have occurred that way I suppose.
So you'd have something like:
def loadGame(loadFile)
loadFile.open
data = loadFile.read
# What you do below here depends on how you decide to store the data in saveGame.
end
def saveGame(saveFile)
saveFile.open
saveFile.puts data
end
Havent really tried the above code so it could be bad syntax or such. It's mainly just the concept I'm trying to get across.
Hopefully that helps?
There are many generators that compute each random number in the sequence from the previous value alone, so if you used one of those you need only save the last random number as part of the state of the game. An example is a basic linear congruential generator, which has the form:
z(n+1) = (az(n) + b) mod c
where a, b and c are typically large (known) constants, and z(0) is the seed.
An arguably better one is the so-called "mulitply-with-carry" method.
I am designing a factory that creates objects of Maze type. The factory requires three distinct steps to create the mazes and one optional step.
partition (split) the 2d or 3d closed space into Partitions (rooms). This step is called Partitioning.
Check which Partitions' surfaces overlap sufficiently (which rooms share a wall) so that it's possible to (add a door between them and) connect them. This step I call Graphing.
Run a Spanning Tree or a similar algorithm that connects all Partitions as a Tree or a similar connected Graph structure. I call this Linkning.
Optional*: Create the actual doors between Partitions.
I have a class called MazeGenerator that accepts a Partitioning(1), Graphing(2), Linking(3) and possibly a DoorGeneration(4) method.
Alright, the issue is with flexibility and usability:
Some methods of spliting the space, are very rigid (for instance spliting it into a grid) and allow us to use a much faster method in step [2], we may not have to do anything actually cause we know exactly which walls are shared by which rooms and can continue to step [3].
On the other hand, some methods for partitioning are very random and require a lot more work on step [2]. I want to allow users (other devs) to apply the fast method when it is viable but to constraint and convey that they need to use another method when they split the space with a more random method.
The issue is, how do I convey or constraint people that use this API?
So far I thought about adding a protected const array to each method step class called viableNextStep that lists all the classes that describe possible methods that can be used in conjunction with this method.
So for instance, PartitionIntoRigidGrid2D would have
Array viableMethods = [SimpleGridGraph2D, findOverlap2D] // Hope that makes sense
I'm programming a Dungeon Generator for a litte game.
Dungeons are made of rooms. A room has connections to other rooms.
room.connections = [room_a, room_b]
and
room.number = 1 # unique id
Now I need to pick a room by it's number.
I did this first with a recursive_scan method, which did not work because rooms can lead into circles, which throws a StackOverflowError. So I put an array called already_scanned with the room numbers, which were already picked into the args of the method. Then it didn't scan all rooms - btw, I have no idea why, by my logical undstandness it should have worked.
Then I tried to put all rooms also in an array and then iterate the array for the wanted room - but here I get the problem, every room is basically connected to every other room, at least with some other rooms betwenn it; so the array gets as big as dungeon_size * array_of_rooms.length.
What I need now is an explicit pointer - I know almost every var in ruby is a pointer, except Fixnums and Float (and maybe some other). Even though, the array gets to big, so I need a real pointer.
(I also tried to setup an array of object_ids and load them via ObectSpace, but sadly - because I often have to load the rooms - the rooms with the wanted object_id are already recycled then, as an error message explains.)
This is my recursive scan method:
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
Everything in Ruby is already a reference.
Why not just maintain a room index?
rooms[room.number] = room
Then you can get anything with rooms[i]. I would keep the index up to date incrementally by simply modifying the initialize method of Room.
def initialize
rooms[self.number] = self
. . .
end
This won't take up much space because the array is just an index, it doesn't actually have copies of the rooms. Each reference obtained from the array is essentially the same thing as a reference obtained via any other mechanism in your program, and the only real difference between the reference and a classic pointer is a bit of overhead for garbage collection.
If rooms are ever deleted (other than just before exit) you will want to set the rooms[x] = nil when on deletion.
I don't see why you need to create the data structure first and then index the rooms, but FWIW you should be able to do that recursive enumeration and use the rooms presence in the room index array as the been-here flag. I'm not sure why it didn't work before but it really has to if written carefully.
It is a classical graph problem. Using graph library will handle most of these issues. Try using the rgl gem.
Define each room as a vertex in the graph. The connections will be the edges.
require "rgl/adjacency"
map = RGL::AdjacencyGraph.new
rooms.each {|room| map.add_vertex room}
rooms.connections.each {|room1, room2| map.add_edge room1, room2}
Now you can test whether two rooms are directly connected in O(1):
map.has_edge? room1, room2
Or get the list of all rooms:
map.vertices
You can also get the list of all adjacent rooms:
map.adjacent_vertices(room)
A really hackish way to get all Rooms in memory would be:
all_rooms = ObjectSpace.each_object(Room).to_a
You may want to look at the NArray gem, which will speed up using arrays of numbers. You may be trying to force a square peg into a round hole here with this approach.