SOLVED: Storing multiple values in 1 ds grid position

Bentley

Member
Is there an easier way to store multiple values in one grid position than something like this:

Code:
//Pseudocode
var grid_width = 10;
var grid_height = 10;
cell_type = ds_grid_create(grid_width, grid_height); //ds_grid of the cell's type
cell_h = ds_grid_create(grid_width, grid_height); //ds_grid of that same cell's h value
//etc. for other values I'd need the cell to have
for (var xx = 0; xx < grid_width; xx++)
{
    for (var yy = 0; yy < grid_height ; yy++)
    {
        cell_type[# xx, yy] = NULL;
        cell_h[# xx, yy] = point_distance(xx, yy, goal.x div CELL_SIZE, goal.y div CELL_SIZE);
    }
}
When browsing this forum, I came across these ideas: set each grid position to an object, to an array, or to a ds list. I was just curious if there's an easier way. I'd imagine the above code gets pretty messy, especially when you need to add up several values a cell has. I'd imagine a ds_list for each position would be messy too, because that's a lot of lists to destroy. Is setting each ds_grid position to an object, and then using that object to store that position's values the best way to go?

I'm probably missing something obvious : ( Any ideas / suggestions are welcomed. Thanks for reading.
 
Last edited:

PNelly

Member
Is there an easier way to store multiple values in one grid position than something like this:

Code:
//Pseudocode
var grid_width = 10;
var grid_height = 10;
cell_type = ds_grid_create(grid_width, grid_height); //ds_grid of the cell's type
cell_h = ds_grid_create(grid_width, grid_height); //ds_grid of that same cell's h value
//etc. for other values I'd need the cell to have
for (var xx = 0; xx < grid_width - 1; xx++)
{
    for (var yy = 0; yy < grid_height - 1; yy++)
    {
        cell_type[# xx, yy] = NULL;
        cell_h[# xx, yy] = point_distance(xx, yy, goal.x div CELL_SIZE, goal.y div CELL_SIZE);
    }
}
When browsing this forum, I came across these ideas: set each grid position to an object, to an array, or to a ds list. I was just curious if there's an easier way. I'd imagine the above code gets pretty messy, especially when you need to add up several values a cell has. I'd imagine a ds_list for each position would be messy too, because that's a lot of lists to destroy. Is setting each ds_grid position to an object, and then using that object to store that position's values the best way to go?

I'm probably missing something obvious : ( Any ideas / suggestions are welcomed. Thanks for reading.
If you want to store multiple values in one spot there's no getting around creating space for those multiple values. Your multiple grids/arrays approach does work, but will waste space if you have lots of empty cells (not really a concern if these are small grids and there aren't very many). Personally I'd find that approach annoying because there's a lot of grids you have to remember.

I'd suggest pointing each entry in the grid to a ds_map. The key/value pairing makes it easy both to remember what you're doing and you don't have to concern yourself with the internal ordering of the elements.

So something like:
Code:
grid_of_maps = ds_grid_create(width, height);

var _x, _y, _cell_map;

for(_x = 0; _x<width; _x++){
  for(_y = 0; _y<height; _y++){
    
    _cell_map = ds_map_create();
    grid_of_maps[# _x, _y] = _cell_map;

    _cell_map[? "type"] = "null";
    _cell_map[? "distance"] = point_distance(_x, _y, goal.x div cell_size, goal.y div cell_size);
    _cell_map[? "another_property"] = "whatever you want";

  }
}
I'd suggest you steer clear of pointing grid cells to objects representing the cell contents because it introduces unnecessary overhead for each of those instances that won't be doing you any good. And whether your grid points to objects, lists, or maps, you still have to tidy up or you'll be leaking memory.
 

DukeSoft

Member
But that would create an entire map for every item in the grid. Maps aren't _that_ fast and you'd be better off using arrays - they are stored as pointers in memory and get automatically cleaned up. The ds_save functions also all work with arrays in the grids (tested this!) and in general they take up very little memory and are easy to access.
Code:
enum enumData{
    type = 0,
    distance = 1,
    another_property = 2
}
myGrid = ds_grid_create(width, height);
var arrayPointer;
for(var _x = 0; _x<width; _x++) {
  for(var _y = 0; _y<height; _y++) {
    arrayPointer = 0; //Reset to NO array, otherwise you'll keep the old array pointer in place
    arrayPointer[enumData.type] = 0;
    arrayPointer[enumData.distance] = point_distance(_x, _y, goal.x div cell_size, goal.y div cell_size);
    arrayPointer[enumData.another_property] = "Hodor";
   myGrid[# _x, _y] = arrayPointer;
  }
}
Please do note that if you want to _change_ data inside of the REAL array, you will need the array accessor:
Code:
var arrayThing = myGrid[# 2, 3];
arrayThing[enumData.type] = 4; //Works for this arrayTHing reference only (its now a copy of the pointed array)
arrayThing[@ enumData.type] = 4; //Changes the actual data in the real array
EDIT: This is also why I'm hoping that stacked accessors will soon be available :) Then you could do;
Code:
    var type = myGrid[# 2, 3][@enumData.type];
 

Bentley

Member
If you want to store multiple values in one spot there's no getting around creating space for those multiple values. Your multiple grids/arrays approach does work, but will waste space if you have lots of empty cells (not really a concern if these are small grids and there aren't very many). Personally I'd find that approach annoying because there's a lot of grids you have to remember.

I'd suggest pointing each entry in the grid to a ds_map.
Thanks for the reply PNelly. I appreciate the explanation. You're right, "there is no getting around creating space for those multiple values".

To be honest, I think I've only used a ds_map once haha. But now that you suggest it, I'll look into them and try the solution you offered. Thanks again.
 

Bentley

Member
Hey DukeSoft, thanks for the replies. I like this code you posted:
Code:
enum enumData{
    type = 0,
    distance = 1,
    another_property = 2
}
myGrid = ds_grid_create(width, height);
var arrayPointer;
for(var _x = 0; _x<width; _x++) {
  for(var _y = 0; _y<height; _y++) {
    arrayPointer = 0; //Reset to NO array, otherwise you'll keep the old array pointer in place
    arrayPointer[enumData.type] = 0;
    arrayPointer[enumData.distance] = point_distance(_x, _y, goal.x div cell_size, goal.y div cell_size);
    arrayPointer[enumData.another_property] = "Hodor";
   myGrid[# _x, _y] = arrayPointer;
  }
}
So you're setting every grid position to an array and naming the positions in that array using an enumerator for readability? Sounds like a great solution. Forgive this silly question (I'm a beginner), but how would I access a grid position's array? Is that what you were showing me in the second block of code you posted? For ex, let's say I want to access grid 0,0's array:
Code:
var this_cells_array = my_grid[# 0, 0]; //This line brings up this grid position's array?
if (this_cells_array[enum.type] == OPEN) //test this cell's value
this_cells_array[@ enum.distance] = 20; //change this cell's value
If so, that would be ideal. Thanks again for the replies.
 
Last edited:

DukeSoft

Member
Exactly! Thats what I ment, and thats the way you can use it. Allthough it shouldn't make a difference on the outcome - I suggest you use the array acessor (@) as well for reading. I'm not sure what happens internally if you read without an accessor, but worst case it generates a copy of the array and then reads that.
So indeed;
var this_cells_array = my_grid[# 0, 0]; This returns an array pointer
if (this_cells_array[@ enumname.enumvalue] == myvalue) Checks if the value from that array equals that
this_cells_array[@ enum.distance] = 20; Writes 20 to that value

If you have empty slots in the grid (e.g. an inventory system where there's nothing there) you won't need to add an array in to there. You could add a number (e.g. 0) there, and then use the is_array() function to check if there's an array at that position.
 

Bentley

Member
Exactly! Thats what I ment, and thats the way you can use it. Allthough it shouldn't make a difference on the outcome - I suggest you use the array acessor (@) as well for reading. I'm not sure what happens internally if you read without an accessor, but worst case it generates a copy of the array and then reads that.
So indeed;
var this_cells_array = my_grid[# 0, 0]; This returns an array pointer
if (this_cells_array[@ enumname.enumvalue] == myvalue) Checks if the value from that array equals that
this_cells_array[@ enum.distance] = 20; Writes 20 to that value

If you have empty slots in the grid (e.g. an inventory system where there's nothing there) you won't need to add an array in to there. You could add a number (e.g. 0) there, and then use the is_array() function to check if there's an array at that position.
Awesome : ) Problem solved. Thanks again.
 

Bentley

Member
If you want to store multiple values in one spot there's no getting around creating space for those multiple values. Your multiple grids/arrays approach does work, but will waste space if you have lots of empty cells (not really a concern if these are small grids and there aren't very many). Personally I'd find that approach annoying because there's a lot of grids you have to remember.

I'd suggest pointing each entry in the grid to a ds_map. The key/value pairing makes it easy both to remember what you're doing and you don't have to concern yourself with the internal ordering of the elements.

So something like:
Code:
grid_of_maps = ds_grid_create(width, height);

var _x, _y, _cell_map;

for(_x = 0; _x<width; _x++){
  for(_y = 0; _y<height; _y++){
 
    _cell_map = ds_map_create();
    grid_of_maps[# _x, _y] = _cell_map;

    _cell_map[? "type"] = "null";
    _cell_map[? "distance"] = point_distance(_x, _y, goal.x div cell_size, goal.y div cell_size);
    _cell_map[? "another_property"] = "whatever you want";

  }
}
I'd suggest you steer clear of pointing grid cells to objects representing the cell contents because it introduces unnecessary overhead for each of those instances that won't be doing you any good. And whether your grid points to objects, lists, or maps, you still have to tidy up or you'll be leaking memory.
That's actually a really good idea (I know this post is way later): one grid holds all the maps. One map per grid position, and that map contains all the info for that grid position.

So to clean up, something like this?

Code:
for (var i = 0; i < ds_grid_height(grid_of_maps); i++)
{
 for (var j = 0; j < ds_grid_width(grid_of_maps); j++)
 {
  ds_map_destroy(grid_of_maps[# i, j]); 
 }
}
ds_grid_destroy(grid_of_maps);
 
Last edited:

PNelly

Member
That's actually a really good idea (I know this post is way later): one grid holds all the maps. One map per grid position, and that map contains all the info for that grid position.

So to clean up, something like this?

Code:
for (var i = 0; i < ds_grid_height(grid_of_maps); i++)
{
 for (var j = 0; j < ds_grid_width(grid_of_maps); j++)
 {
  ds_map_destroy(grid_of_maps[# i, j]);
 }
}
ds_grid_destroy(grid_of_maps);
Looks good to me!
 
Top