GameMaker How to call a random key from ds_map?

sinigrimi

Member
How do I call a random key from a ds_map structure? or will i have to create ds_list? a bunch of variables are created in ds_list, if for example I have 300 keys?

I tried to do something with this, but my head is not working as it should
Code:
    var arts = global.artefacts;
    var arts_size = ds_map_size(arts);
    var rand = irandom_range(1,arts_size), ar = arts_size;
    while ar {
        rand++;
        if rand > arts_size //if rand becomes larger than ds_map_size it will continue from the beginning of the list
            rand = 1;
        ar--;//every time 1 is taken away so that the check does not become infinite
    }
 
Last edited:

Nocturne

Friendly Tyrant
Forum Staff
Admin
You can use ds lists and automate it by using the ds_map_find_first function and a for loop, eg:

Code:
var _key = ds_map_find_first(map);
var _size = ds_map_size(map);
for (var i = 0; i < _size; ++i;)
{
ds_list_add(list, _key);
_key = ds_map_find_next(map);
}
ds_list_shuffle(list);

With the above method, you would have a random list of keys all taken from the map. You can then get the key from list position o and delete the key from the list when used each time. Eventually you'd have an empty list which would mean that all the map keys have been used and you can then do something else.

Hope that helps!
 

sinigrimi

Member
how can this be implemented (code below)? I get the error apparently because gms cannot read the letters from the ds_map value via ds_list or I make a blunder. The idea is that a random item will spawn and when a player picks it up it will be deleted from the list and will not spawn anymore, as I understand it, you need to do a random order ds_map, and it seems to work. But now the question is how to call an object from this all into the string instance_create_layer
Code:
global.artefacts = ds_map_create()
var arts = global.artefacts
 global.artefacts_list = ds_list_create()
var arts_list = global.artefacts_list

if ds_exists(arts,ds_type_list){
    if ds_map_empty(arts){
        ds_map_add(arts,"artBoots","artBoots")   
    }   
}
 _key[0] = ds_map_find_first(arts);
var _size = ds_map_size(arts);
for (var i = 0; i < _size; ++i;)
{
    ds_list_add(arts_list, _key);
    _key[i+1] = ds_map_find_next(arts, _key[i]);
    }
    ds_list_shuffle(arts_list);
    
var rand_item = irandom(ds_list_size(arts_list)-1)
var item = ds_list_find_value(arts_list,rand_item)
instance_create_layer(room_width/2,room_height/2,"Instances",string_lettersdigits(item))
Code:
___________________________________________
############################################################################################
FATAL ERROR in
action number 1
of Create Event
for object obj_RoomGen_DEMO_Control:

string_lettersdigits argument 1 incorrect type (undefined) expecting a String (YYGS)
 at gml_Object_obj_RoomGen_DEMO_Control_Create_0 (line 206) - instance_create_layer(room_width/2,room_height/2,"Instances",string_lettersdigits(item))
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_obj_RoomGen_DEMO_Control_Create_0 (line 206)
 

Nocturne

Friendly Tyrant
Forum Staff
Admin
I'm not sure what this line is doing "ds_exists(arts,ds_type_list)"... arts is a variable that poiints to the global variable that holds a MAP not a list, yet you're checking for a list. SO, either check for a map, or just omit this check altogether as it's not required since you make the ds map in the same step with the code above it so of course the map exists! I think this'll be the issue as it looks like that's where you are populating the map, so if the check is wrong the map isn't being populated so none of the other code will work. Also, you don't need this line "var rand_item = irandom(ds_list_size(arts_list)-1)". This list already in a random order as it's been shuffled so just get the item from list position 0 every time, then delete it from that position. Each time you delete list[|0] the list will shrink and the zero position will be occupied by a new map key. :)
 

sinigrimi

Member
I'm not sure what this line is doing "ds_exists(arts,ds_type_list)"... arts is a variable that poiints to the global variable that holds a MAP not a list, yet you're checking for a list. SO, either check for a map, or just omit this check altogether as it's not required since you make the ds map in the same step with the code above it so of course the map exists! I think this'll be the issue as it looks like that's where you are populating the map, so if the check is wrong the map isn't being populated so none of the other code will work. Also, you don't need this line "var rand_item = irandom(ds_list_size(arts_list)-1)". This list already in a random order as it's been shuffled so just get the item from list position 0 every time, then delete it from that position. Each time you delete list[|0] the list will shrink and the zero position will be occupied by a new map key. :)
I found out that in ds_map it makes no sense to directly insert objects since the compiler counts them as numbers. I also tried to enter the object in quotation marks and this worked for show_message, but it did not work for instance_create.
I looked on the forum for did not find something like that, maybe I didn’t choose the right word, because how do I use Google translator, is there any other way to get an object in instance_create from ds_map?

Code:
 instance_create_layer (room_width / 2, room_height / 2, "Instances", string_lettersdigits (ds_map_find_first (arts))) // "artBoots") //// item)) [/ COD] [/ CODE]
GameMakerStudio_ZoumLltl3e.png
 
Last edited:

TsukaYuriko

☄️
Forum Staff
Moderator
There is no such thing as objects being "converted" to numbers. Any type of resource is identified by its ID, which is a number. There's no conversion going on here - when you create an instance of obj_player, for example, that's creating an instance of the object with the ID of obj_player, namely an integer that starts at 0 for the first and increments by 1 afterwards.

Object IDs being a number is perfectly normal. Why is this a problem in your case? Feeding a number to instance_create_layer for the object to be created is correct.
 

sinigrimi

Member
There is no such thing as objects being "converted" to numbers. Any type of resource is identified by its ID, which is a number. There's no conversion going on here - when you create an instance of obj_player, for example, that's creating an instance of the object with the ID of obj_player, namely an integer that starts at 0 for the first and increments by 1 afterwards.

Object IDs being a number is perfectly normal. Why is this a problem in your case? Feeding a number to instance_create_layer for the object to be created is correct.

you were right if you substitute a number there an object is created but when I substitute ds_map it doesn’t work

Code:
var arts = global.artefacts
ds_map_add(arts,"artBoots",oPlayer)
instance_create_layer(room_width/2,room_height/2,"Instances",arts[?"artBoots"])
show_message(string_letters(arts[?"artBoots"]))

Code:
FATAL ERROR in
action number 1
of Key Press Event for <Space> Key
for object oPlayer:

instance_create_layer argument 4 incorrect type (string) expecting a Number (YYGI32)
 at gml_Object_oPlayer_KeyPress_32 (line 6) - instance_create_layer(room_width/2,room_height/2,"Instances",arts[?"artBoots"])
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_oPlayer_KeyPress_32 (line 6)
 

chamaeleon

Member
you were right if you substitute a number there an object is created but when I substitute ds_map it doesn’t work

Code:
var arts = global.artefacts
ds_map_add(arts,"artBoots",oPlayer)
instance_create_layer(room_width/2,room_height/2,"Instances",arts[?"artBoots"])
show_message(string_letters(arts[?"artBoots"]))

Code:
FATAL ERROR in
action number 1
of Key Press Event for <Space> Key
for object oPlayer:

instance_create_layer argument 4 incorrect type (string) expecting a Number (YYGI32)
 at gml_Object_oPlayer_KeyPress_32 (line 6) - instance_create_layer(room_width/2,room_height/2,"Instances",arts[?"artBoots"])
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Object_oPlayer_KeyPress_32 (line 6)
You should be able to see from the error message that you need to store the object in your arts ds_map, not the name of the object as a string.
 

TsukaYuriko

☄️
Forum Staff
Moderator
The error message states that whatever is contained in arts[?"artBoots"] is a string, not a number. This matches what you are adding to it earlier in your code. If artBoots is supposed to be an object, don't store it as a string, as resource IDs are not strings, but - as you noticed - numbers.
 

sinigrimi

Member
I'm not sure what this line is doing "ds_exists(arts,ds_type_list)"... arts is a variable that poiints to the global variable that holds a MAP not a list, yet you're checking for a list. SO, either check for a map, or just omit this check altogether as it's not required since you make the ds map in the same step with the code above it so of course the map exists! I think this'll be the issue as it looks like that's where you are populating the map, so if the check is wrong the map isn't being populated so none of the other code will work. Also, you don't need this line "var rand_item = irandom(ds_list_size(arts_list)-1)". This list already in a random order as it's been shuffled so just get the item from list position 0 every time, then delete it from that position. Each time you delete list[|0] the list will shrink and the zero position will be occupied by a new map key. :)
You should be able to see from the error message that you need to store the object in your arts ds_map, not the name of the object as a string.
The error message states that whatever is contained in arts[?"artBoots"] is a string, not a number. This matches what you are adding to it earlier in your code. If artBoots is supposed to be an object, don't store it as a string, as resource IDs are not strings, but - as you noticed - numbers.
Thank you so much, because of my lack of knowledge of English, I miss some words and lose the essence of the problem, now I will carefully read the manual. Many thanks to you!

And the code for those who need a solution in the future

Code:
var arts = global.artefacts
arts[?"artBoots"]=oPlayer;

instance_create_layer(room_width/2,room_height/2,"Instances",ds_map_find_value(arts,ds_map_find_first(arts)))//arts[?"artBoots"])
show_message((arts[?"artBoots"]))
 
Top