• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

GameMaker Converting C++ to GML Help

dialgpalkia

Member
Hi everyone,

I'm working on trying to convert some C++ to GMS2 but I'm struggling to truly understand a certain section and how to convert it to GML.

Here are the two codes:

C++:
vector<double> values; //Definition
values.erase(std::remove_if(values.begin(), values.end(), [&](const double& x) { return x < chart_options.start || x > chart_options.end; }), values.end());

std::vector<double> rtn;
rtn.erase(std::unique(rtn.begin(), rtn.end()), rtn.end());
I tried to convert the first code:
GML:
for(var _x = 0; _x < ds_list_size(_spiralValues); _x++){
    if((_x < chart_optionsstart) || (_x > chart_optionsend)){
        ds_list_delete(_spiralValues, _x);
    }
}
But I'm not sure if I'm on the right track.
I have no idea how to code in the second code, though.

Can anyone help me out? Thank you!

dialgpalkia
 
Last edited:

Nidoking

Member
Do you understand what those statements are doing? That would be my first step - figure out what you're trying to do, then ignore the code you have and write that in GML.
 

chamaeleon

Member
If you're going to delete entries of a ds_list as you are iterating over it, you have two options.
1. Iterate from the end to the beginning
2. Don't increment the index when you are removing an entry
Either of these will do the right thing, but if you iterate from the start and always increment the index every loop iteration, you will skip performing actions for the following entry as all entries following the just removed position now has shifted down one step.
 

dialgpalkia

Member
Do you understand what those statements are doing? That would be my first step - figure out what you're trying to do, then ignore the code you have and write that in GML.
I have an idea, the issue with it though is C++ documentation isn't the clearest. My understanding is that both codes erase values from a vector from the beginning of the vector to the end of the vector (according to the C++ documentation).
I'm struggling with the added code in the section that's supposed to be the "beginning of the vector". The first one seems to be telling it to only erase from the first instance of "x" being greater than shartoptionsend or "x" less than chartoptionsstart. That's what I think is happening - but then "remove_if" seems to be the same thing, so it's redundant?

The second one seems to be removing all non-unique consecutive entries in the vector (the unique() ) part and then using that as the start point for the vector erase. eg. [10 10 10 20 20 30 30 30 10] -> [10 20 30 10]


If you're going to delete entries of a ds_list as you are iterating over it, you have two options.
1. Iterate from the end to the beginning
2. Don't increment the index when you are removing an entry
Either of these will do the right thing, but if you iterate from the start and always increment the index every loop iteration, you will skip performing actions for the following entry as all entries following the just removed position now has shifted down one step.
That is a great point I hadn't even considered that, thank you! Easiest way I can think of is just add a _x-- into the code. Is that the best way to do it?
 

chamaeleon

Member
That is a great point I hadn't even considered that, thank you! Easiest way I can think of is just add a _x-- into the code. Is that the best way to do it?
It would do the trick, if you add it in at the end of the loop. But it's shorter doing it the other way, and eliminates calculating the length more than once without using another variable
Code:
for(var _x = ds_list_size(_spiralValues)-1; _x >= 0; _x--){
    if((_x < chart_optionsstart) || (_x > chart_optionsend)){
        ds_list_delete(_spiralValues, _x);
    }
}
As for the second C++ code, the container looped over isn't a vector, it's a map, where all keys are unqiue by definition, which means the unique iterator would return all of them, and therefore rtn.erase() would erase all keys, leaving you with the equivalent of rtn.clear(). The equivalent in GMS would be simply ds_map_clear(my_map). Having said all that, Visual C++ does not seem to like this piece of code at all, and complains with a compile error indicating the unique iterator does not like being an iterator for std::pair elements (which is what an iterator for a map is, containing both the key and the value).
C++:
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>

int main() {
    std::map<double, std::vector<double>> rtn;
    rtn.erase(std::unique(rtn.begin(), rtn.end()), rtn.end());
    return EXIT_SUCCESS;
}
Code:
1>C:\Devtools\VS2019\VC\Tools\MSVC\14.26.28801\include\algorithm(2597,1): error C2679: binary '=': no operator found which takes a right-hand operand of type 'std::pair<const double,std::vector<double,std::allocator<double>>>' (or there is no acceptable conversion)
 

dialgpalkia

Member
It would do the trick, if you add it in at the end of the loop. But it's shorter doing it the other way, and eliminates calculating the length more than once without using another variable
Code:
for(var _x = ds_list_size(_spiralValues)-1; _x >= 0; _x--){
    if((_x < chart_optionsstart) || (_x > chart_optionsend)){
        ds_list_delete(_spiralValues, _x);
    }
}
As for the second C++ code, the container looped over isn't a vector, it's a map, where all keys are unqiue by definition, which means the unique iterator would return all of them, and therefore rtn.erase() would erase all keys, leaving you with the equivalent of rtn.clear(). The equivalent in GMS would be simply ds_map_clear(my_map). Having said all that, Visual C++ does not seem to like this piece of code at all, and complains with a compile error indicating the unique iterator does not like being an iterator for std::pair elements (which is what an iterator for a map is, containing both the key and the value).
C++:
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>

int main() {
    std::map<double, std::vector<double>> rtn;
    rtn.erase(std::unique(rtn.begin(), rtn.end()), rtn.end());
    return EXIT_SUCCESS;
}
Code:
1>C:\Devtools\VS2019\VC\Tools\MSVC\14.26.28801\include\algorithm(2597,1): error C2679: binary '=': no operator found which takes a right-hand operand of type 'std::pair<const double,std::vector<double,std::allocator<double>>>' (or there is no acceptable conversion)
Ahh I see, that way if you remove a value it'll still loop. That makes sense! Thank you. I'm still not sure if I'm converting it right though, have I converted it correctly to GML?

Re. the second C++ code - I realised I included the wrong "rtn" definition (there's a lot of them)... Here's the correct definition:
C++:
std::vector<double> rtn;
rtn.erase(std::unique(rtn.begin(), rtn.end()), rtn.end());
 

chamaeleon

Member
Ahh I see, that way if you remove a value it'll still loop. That makes sense! Thank you. I'm still not sure if I'm converting it right though, have I converted it correctly to GML?
Actually, I imagine what you want is more along the lines of the below code. Plain forgot that what is being compared is the value stored in the vector/ds_list, not the index
GML:
for(var _x = ds_list_size(_spiralValues)-1; _x >= 0; _x--){
    if((_spiralValues[| _x] < chart_optionsstart) || (_spiralValues[| _x] > chart_optionsend)){
        ds_list_delete(_spiralValues, _x);
    }
}
The _spiralValues[| _x] part is shorthand for ds_list_find_value(_spiralValues, _x). There are similar Accessors for ds_maps and ds_grids (? and #, respectively).
 

chamaeleon

Member
Re. the second C++ code - I realised I included the wrong "rtn" definition (there's a lot of them)... Here's the correct definition:
C++:
std::vector<double> rtn;
rtn.erase(std::unique(rtn.begin(), rtn.end()), rtn.end());
The second code snippet might be translated to
GML:
var _x = 0;
while (_x < ds_list_size(rtn)-2) {
    if (rtn[| _x] == rtn[| _x+1]
        ds_list_delete(rtn, _x+1);
    else
        ++_x;
}
 
Last edited:

dialgpalkia

Member
Thanks Chamaeleon! I think I understand how that was converted, my only question is why do you go through the while loop up until ds_list_size(rtn) - 2 instead of ds_list_size(rtn)? I would then also use ds_list_delete as ds_list_erase doesn't exist. This would then remove the following non-unique entry in the list, which would truncate the list by one.
 

chamaeleon

Member
Thanks Chamaeleon! I think I understand how that was converted, my only question is why do you go through the while loop up until ds_list_size(rtn) - 2 instead of ds_list_size(rtn)? I would then also use ds_list_delete as ds_list_erase doesn't exist. This would then remove the following non-unique entry in the list, which would truncate the list by one.
Sorry about the incorrect function. Just a typo while writing the post.

As the highest index you can use to get an element out of a ds_list is one less than the size of the list (due to index starting at zero), because I check the entry following the current position, I can only iterate to size-2 to ensure the next position (at most size-1) is not out of bounds at the end.
 
Top